package syntax
import (
)
type Prog struct {
Inst []Inst
Start int
NumCap int
}
type InstOp uint8
const (
InstAlt InstOp = iota
InstAltMatch
InstCapture
InstEmptyWidth
InstMatch
InstFail
InstNop
InstRune
InstRune1
InstRuneAny
InstRuneAnyNotNL
)
var instOpNames = []string{
"InstAlt",
"InstAltMatch",
"InstCapture",
"InstEmptyWidth",
"InstMatch",
"InstFail",
"InstNop",
"InstRune",
"InstRune1",
"InstRuneAny",
"InstRuneAnyNotNL",
}
func ( InstOp) () string {
if uint() >= uint(len(instOpNames)) {
return ""
}
return instOpNames[]
}
type EmptyOp uint8
const (
EmptyBeginLine EmptyOp = 1 << iota
EmptyEndLine
EmptyBeginText
EmptyEndText
EmptyWordBoundary
EmptyNoWordBoundary
)
func (, rune) EmptyOp {
var EmptyOp = EmptyNoWordBoundary
var byte
switch {
case IsWordChar():
= 1
case == '\n':
|= EmptyBeginLine
case < 0:
|= EmptyBeginText | EmptyBeginLine
}
switch {
case IsWordChar():
^= 1
case == '\n':
|= EmptyEndLine
case < 0:
|= EmptyEndText | EmptyEndLine
}
if != 0 {
^= (EmptyWordBoundary | EmptyNoWordBoundary)
}
return
}
func ( rune) bool {
return 'A' <= && <= 'Z' || 'a' <= && <= 'z' || '0' <= && <= '9' || == '_'
}
type Inst struct {
Op InstOp
Out uint32
Arg uint32
Rune []rune
}
func ( *Prog) () string {
var strings.Builder
dumpProg(&, )
return .String()
}
func ( *Prog) ( uint32) *Inst {
:= &.Inst[]
for .Op == InstNop || .Op == InstCapture {
= &.Inst[.Out]
}
return
}
func ( *Inst) () InstOp {
:= .Op
switch {
case InstRune1, InstRuneAny, InstRuneAnyNotNL:
= InstRune
}
return
}
func ( *Prog) () ( string, bool) {
:= .skipNop(uint32(.Start))
if .op() != InstRune || len(.Rune) != 1 {
return "", .Op == InstMatch
}
var strings.Builder
for .op() == InstRune && len(.Rune) == 1 && Flags(.Arg)&FoldCase == 0 {
.WriteRune(.Rune[0])
= .skipNop(.Out)
}
return .String(), .Op == InstMatch
}
func ( *Prog) () EmptyOp {
var EmptyOp
:= uint32(.Start)
:= &.Inst[]
:
for {
switch .Op {
case InstEmptyWidth:
|= EmptyOp(.Arg)
case InstFail:
return ^EmptyOp(0)
case InstCapture, InstNop:
default:
break
}
= .Out
= &.Inst[]
}
return
}
const noMatch = -1
func ( *Inst) ( rune) bool {
return .MatchRunePos() != noMatch
}
func ( *Inst) ( rune) int {
:= .Rune
switch len() {
case 0:
return noMatch
case 1:
:= [0]
if == {
return 0
}
if Flags(.Arg)&FoldCase != 0 {
for := unicode.SimpleFold(); != ; = unicode.SimpleFold() {
if == {
return 0
}
}
}
return noMatch
case 2:
if >= [0] && <= [1] {
return 0
}
return noMatch
case 4, 6, 8:
for := 0; < len(); += 2 {
if < [] {
return noMatch
}
if <= [+1] {
return / 2
}
}
return noMatch
}
:= 0
:= len() / 2
for < {
:= + (-)/2
if := [2*]; <= {
if <= [2*+1] {
return
}
= + 1
} else {
=
}
}
return noMatch
}
func ( *Inst) ( rune, rune) bool {
switch EmptyOp(.Arg) {
case EmptyBeginLine:
return == '\n' || == -1
case EmptyEndLine:
return == '\n' || == -1
case EmptyBeginText:
return == -1
case EmptyEndText:
return == -1
case EmptyWordBoundary:
return IsWordChar() != IsWordChar()
case EmptyNoWordBoundary:
return IsWordChar() == IsWordChar()
}
panic("unknown empty width arg")
}
func ( *Inst) () string {
var strings.Builder
dumpInst(&, )
return .String()
}
func ( *strings.Builder, ...string) {
for , := range {
.WriteString()
}
}
func ( *strings.Builder, *Prog) {
for := range .Inst {
:= &.Inst[]
:= strconv.Itoa()
if len() < 3 {
.WriteString(" "[len():])
}
if == .Start {
+= "*"
}
bw(, , "\t")
dumpInst(, )
bw(, "\n")
}
}
func ( uint32) string {
return strconv.FormatUint(uint64(), 10)
}
func ( *strings.Builder, *Inst) {
switch .Op {
case InstAlt:
bw(, "alt -> ", u32(.Out), ", ", u32(.Arg))
case InstAltMatch:
bw(, "altmatch -> ", u32(.Out), ", ", u32(.Arg))
case InstCapture:
bw(, "cap ", u32(.Arg), " -> ", u32(.Out))
case InstEmptyWidth:
bw(, "empty ", u32(.Arg), " -> ", u32(.Out))
case InstMatch:
bw(, "match")
case InstFail:
bw(, "fail")
case InstNop:
bw(, "nop -> ", u32(.Out))
case InstRune:
if .Rune == nil {
bw(, "rune <nil>")
}
bw(, "rune ", strconv.QuoteToASCII(string(.Rune)))
if Flags(.Arg)&FoldCase != 0 {
bw(, "/i")
}
bw(, " -> ", u32(.Out))
case InstRune1:
bw(, "rune1 ", strconv.QuoteToASCII(string(.Rune)), " -> ", u32(.Out))
case InstRuneAny:
bw(, "any -> ", u32(.Out))
case InstRuneAnyNotNL:
bw(, "anynotnl -> ", u32(.Out))
}
}