package syntax
import (
"bytes"
"fmt"
"math"
)
type InstOp int
const (
Onerep InstOp = 0
Notonerep InstOp = 1
Setrep InstOp = 2
Oneloop InstOp = 3
Notoneloop InstOp = 4
Setloop InstOp = 5
Onelazy InstOp = 6
Notonelazy InstOp = 7
Setlazy InstOp = 8
One InstOp = 9
Notone InstOp = 10
Set InstOp = 11
Multi InstOp = 12
Ref InstOp = 13
Bol InstOp = 14
Eol InstOp = 15
Boundary InstOp = 16
Nonboundary InstOp = 17
Beginning InstOp = 18
Start InstOp = 19
EndZ InstOp = 20
End InstOp = 21
Nothing InstOp = 22
Lazybranch InstOp = 23
Branchmark InstOp = 24
Lazybranchmark InstOp = 25
Nullcount InstOp = 26
Setcount InstOp = 27
Branchcount InstOp = 28
Lazybranchcount InstOp = 29
Nullmark InstOp = 30
Setmark InstOp = 31
Capturemark InstOp = 32
Getmark InstOp = 33
Setjump InstOp = 34
Backjump InstOp = 35
Forejump InstOp = 36
Testref InstOp = 37
Goto InstOp = 38
Prune InstOp = 39
Stop InstOp = 40
ECMABoundary InstOp = 41
NonECMABoundary InstOp = 42
Oneloopatomic InstOp = 43
Notoneloopatomic InstOp = 44
Setloopatomic InstOp = 45
UpdateBumpalong InstOp = 46
Grapheme InstOp = 47
Dispatch InstOp = 48
Mask InstOp = 63
Rtl InstOp = 64
Back InstOp = 128
Back2 InstOp = 256
Ci InstOp = 512
)
type Code struct {
Codes []int
Strings [][]rune
Sets []*CharSet
Dispatches []DispatchTable
TrackCount int
Caps map [int ]int
Capsize int
FcPrefix *Prefix
BmPrefix *BmPrefix
Anchors AnchorLoc
RightToLeft bool
FindOptimizations *FindOptimizations
QuickCodes []int
QuickDispatches []DispatchTable
CaptureSlotInUse []bool
}
type DispatchTable struct {
Sets []int
Branches []int
ASCII *[128 ]uint16
ASCIIMasks []uint64
}
func captureSlotsInUse(codes []int , capsize int ) []bool {
inUse := make ([]bool , capsize )
if capsize > 0 {
inUse [0 ] = true
}
for pos := 0 ; pos < len (codes ); {
op := InstOp (codes [pos ]) & Mask
switch op {
case Ref , Testref :
capnum := codes [pos +1 ]
if capnum >= 0 && capnum < len (inUse ) {
inUse [capnum ] = true
}
case Capturemark :
if codes [pos +2 ] != -1 {
for _ , capnum := range codes [pos +1 : pos +3 ] {
if capnum >= 0 && capnum < len (inUse ) {
inUse [capnum ] = true
}
}
}
}
pos += opcodeSize (op )
}
return inUse
}
func (c *Code ) PrepareCharSetASCIIBitmaps () {
if c == nil {
return
}
for _ , set := range c .Sets {
set .prepareASCIIBitmap ()
}
if c .FcPrefix != nil {
c .FcPrefix .PrefixSet .prepareASCIIBitmap ()
}
if c .FindOptimizations != nil {
for _ , set := range c .FindOptimizations .FixedDistanceSets {
set .Set .prepareASCIIBitmap ()
}
if c .FindOptimizations .LiteralAfterLoop != nil && c .FindOptimizations .LiteralAfterLoop .LoopNode != nil {
c .FindOptimizations .LiteralAfterLoop .LoopNode .Set .prepareASCIIBitmap ()
}
}
}
func opcodeBacktracks(op InstOp ) bool {
op &= Mask
switch op {
case Oneloop , Notoneloop , Setloop , Onelazy , Notonelazy , Setlazy , Lazybranch , Branchmark , Lazybranchmark ,
Nullcount , Setcount , Branchcount , Lazybranchcount , Setmark , Capturemark , Getmark , Setjump , Backjump ,
Forejump , Goto :
return true
default :
return false
}
}
func opcodeSize(op InstOp ) int {
op &= Mask
switch op {
case Nothing , Bol , Eol , Boundary , Nonboundary , ECMABoundary , NonECMABoundary , Beginning , Start , EndZ ,
End , Nullmark , Setmark , Getmark , Setjump , Backjump , Forejump , Stop , UpdateBumpalong , Grapheme :
return 1
case One , Notone , Multi , Ref , Testref , Goto , Nullcount , Setcount , Lazybranch , Branchmark , Lazybranchmark ,
Prune , Set , Dispatch :
return 2
case Capturemark , Branchcount , Lazybranchcount , Onerep , Notonerep , Oneloop , Notoneloop , Onelazy , Notonelazy ,
Setlazy , Setrep , Setloop , Oneloopatomic , Notoneloopatomic , Setloopatomic :
return 3
default :
panic (fmt .Errorf ("unexpected op code: %v" , op ))
}
}
var codeStr = []string {
"Onerep" , "Notonerep" , "Setrep" ,
"Oneloop" , "Notoneloop" , "Setloop" ,
"Onelazy" , "Notonelazy" , "Setlazy" ,
"One" , "Notone" , "Set" ,
"Multi" , "Ref" ,
"Bol" , "Eol" , "Boundary" , "Nonboundary" , "Beginning" , "Start" , "EndZ" , "End" ,
"Nothing" ,
"Lazybranch" , "Branchmark" , "Lazybranchmark" ,
"Nullcount" , "Setcount" , "Branchcount" , "Lazybranchcount" ,
"Nullmark" , "Setmark" , "Capturemark" , "Getmark" ,
"Setjump" , "Backjump" , "Forejump" , "Testref" , "Goto" ,
"Prune" , "Stop" ,
"ECMABoundary" , "NonECMABoundary" ,
"Oneloopatomic" , "Notoneloopatomic" , "Setloopatomic" ,
"Bumpalong" , "Grapheme" , "Dispatch" ,
}
func operatorDescription(op InstOp ) string {
desc := codeStr [op &Mask ]
if (op & Ci ) != 0 {
desc += "-Ci"
}
if (op & Rtl ) != 0 {
desc += "-Rtl"
}
if (op & Back ) != 0 {
desc += "-Back"
}
if (op & Back2 ) != 0 {
desc += "-Back2"
}
return desc
}
func (c *Code ) OpcodeDescription (offset int ) string {
buf := &bytes .Buffer {}
op := InstOp (c .Codes [offset ])
fmt .Fprintf (buf , "%06d " , offset )
if opcodeBacktracks (op & Mask ) {
buf .WriteString ("*" )
} else {
buf .WriteString (" " )
}
buf .WriteString (operatorDescription (op ))
buf .WriteString ("(" )
op &= Mask
switch op {
case One , Notone , Onerep , Notonerep , Oneloop , Notoneloop , Onelazy , Notonelazy ,
Oneloopatomic , Notoneloopatomic :
buf .WriteString ("Ch = " )
buf .WriteString (CharDescription (rune (c .Codes [offset +1 ])))
case Set , Setrep , Setloop , Setlazy , Setloopatomic :
buf .WriteString ("Set = " )
buf .WriteString (c .Sets [c .Codes [offset +1 ]].String ())
case Dispatch :
tableIndex := c .Codes [offset +1 ]
fmt .Fprintf (buf , "Table = %d" , tableIndex )
if tableIndex >= 0 && tableIndex < len (c .Dispatches ) {
table := &c .Dispatches [tableIndex ]
for i , setIndex := range table .Sets {
fmt .Fprintf (buf , ", %s -> %d" , c .Sets [setIndex ].String (), table .Branches [i ])
}
}
case Multi :
fmt .Fprintf (buf , "String = %s" , string (c .Strings [c .Codes [offset +1 ]]))
case Ref , Testref :
fmt .Fprintf (buf , "Index = %d" , c .Codes [offset +1 ])
case Capturemark :
fmt .Fprintf (buf , "Index = %d" , c .Codes [offset +1 ])
if c .Codes [offset +2 ] != -1 {
fmt .Fprintf (buf , ", Unindex = %d" , c .Codes [offset +2 ])
}
case Nullcount , Setcount :
fmt .Fprintf (buf , "Value = %d" , c .Codes [offset +1 ])
case Goto , Lazybranch , Branchmark , Lazybranchmark , Branchcount , Lazybranchcount :
fmt .Fprintf (buf , "Addr = %d" , c .Codes [offset +1 ])
}
switch op {
case Onerep , Notonerep , Oneloop , Notoneloop , Onelazy , Notonelazy , Setrep , Setloop , Setlazy ,
Oneloopatomic , Notoneloopatomic , Setloopatomic :
buf .WriteString (", Rep = " )
if c .Codes [offset +2 ] == math .MaxInt32 {
buf .WriteString ("inf" )
} else {
fmt .Fprintf (buf , "%d" , c .Codes [offset +2 ])
}
case Branchcount , Lazybranchcount :
buf .WriteString (", Limit = " )
if c .Codes [offset +2 ] == math .MaxInt32 {
buf .WriteString ("inf" )
} else {
fmt .Fprintf (buf , "%d" , c .Codes [offset +2 ])
}
}
buf .WriteString (")" )
return buf .String ()
}
func (c *Code ) Dump () string {
buf := &bytes .Buffer {}
if c .RightToLeft {
fmt .Fprintln (buf , "Direction: right-to-left" )
} else {
fmt .Fprintln (buf , "Direction: left-to-right" )
}
if c .FcPrefix == nil {
fmt .Fprintln (buf , "Firstchars: n/a" )
} else {
fmt .Fprintf (buf , "Firstchars: %v\n" , c .FcPrefix .PrefixSet .String ())
}
if c .BmPrefix == nil {
fmt .Fprintln (buf , "Prefix: n/a" )
} else {
fmt .Fprintf (buf , "Prefix: %v\n" , Escape (c .BmPrefix .String ()))
}
fmt .Fprintf (buf , "Anchors: %v\n" , c .Anchors )
if c .FindOptimizations != nil {
fmt .Fprint (buf , c .FindOptimizations .Dump ())
}
fmt .Fprintln (buf )
if c .BmPrefix != nil {
fmt .Fprintln (buf , "BoyerMoore:" )
fmt .Fprintln (buf , c .BmPrefix .Dump (" " ))
}
for i := 0 ; i < len (c .Codes ); i += opcodeSize (InstOp (c .Codes [i ])) {
fmt .Fprintln (buf , c .OpcodeDescription (i ))
}
return buf .String ()
}
The pages are generated with Golds v0.8.7 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .