lexmachine/frontend/ast.go
zhouzhihong 879a86b6b7 新特性 (#1)
1. 增加utf8文本的行数和列数计算字段

Co-authored-by: zhouzhihong <zhouzhihong@ijunhai.com>
Reviewed-on: https://gitea.xintech.co/zhouzhihong/lexmachine/pulls/1
2022-08-25 14:41:32 +08:00

267 lines
4.9 KiB
Go

package frontend
import (
"fmt"
"strings"
)
// AST is an abstract syntax tree for a regular expression.
type AST interface {
String() string
Children() []AST
Equals(AST) bool
}
// AltMatch either match A or B and then finalize matching the string
type AltMatch struct {
A AST
B AST
}
// Children returns a list of the child nodes
func (a *AltMatch) Children() []AST {
return []AST{a.A, a.B}
}
// String humanizes the subtree
func (a *AltMatch) String() string {
return fmt.Sprintf("(AltMatch %v, %v)", a.A, a.B)
}
// EOS end of string
type EOS struct{}
// Children returns a list of the child nodes
func (e *EOS) Children() []AST {
return []AST{}
}
// String humanizes the subtree
func (e *EOS) String() string {
return "(EOS)"
}
// Match the tree AST finalizes the matching
type Match struct {
AST
}
// Children returns a list of the child nodes
func (m *Match) Children() []AST {
return []AST{m.AST}
}
// String humanizes the subtree
func (m *Match) String() string {
return fmt.Sprintf("(Match %v)", m.AST)
}
// Alternation matches A or B
type Alternation struct {
A AST
B AST
}
// Children returns a list of the child nodes
func (a *Alternation) Children() []AST {
return []AST{a.A, a.B}
}
// String humanizes the subtree
func (a *Alternation) String() string {
return fmt.Sprintf("(Alternation %v, %v)", a.A, a.B)
}
// Star is a kleene star (that is a repetition operator). Matches 0 or more times.
type Star struct {
AST
}
// Children returns a list of the child nodes
func (s *Star) Children() []AST {
return []AST{s.AST}
}
// String humanizes the subtree
func (s *Star) String() string {
return fmt.Sprintf("(* %v)", s.AST)
}
// Plus matches 1 or more times
type Plus struct {
AST
}
// Children returns a list of the child nodes
func (p *Plus) Children() []AST {
return []AST{p.AST}
}
// String humanizes the subtree
func (p *Plus) String() string {
return fmt.Sprintf("(+ %v)", p.AST)
}
// Maybe matches 0 or 1 times
type Maybe struct {
AST
}
// Children returns a list of the child nodes
func (m *Maybe) Children() []AST {
return []AST{m.AST}
}
// String humanizes the subtree
func (m *Maybe) String() string {
return fmt.Sprintf("(? %v)", m.AST)
}
// Concat matches each item in sequence
type Concat struct {
Items []AST
}
// Children returns a list of the child nodes
func (c *Concat) Children() []AST {
return c.Items
}
// String humanizes the subtree
func (c *Concat) String() string {
s := "(Concat "
items := make([]string, 0, len(c.Items))
for _, i := range c.Items {
items = append(items, i.String())
}
s += strings.Join(items, ", ") + ")"
return s
}
// Range matches byte ranges From-To inclusive
type Range struct {
From byte
To byte
}
// Children returns a list of the child nodes
func (r *Range) Children() []AST {
return []AST{}
}
// String humanizes the subtree
func (r *Range) String() string {
return fmt.Sprintf(
"(Range %d %d)",
r.From,
r.To,
)
}
// Character matches a single byte
type Character struct {
Char byte
}
// Children returns a list of the child nodes
func (c *Character) Children() []AST {
return []AST{}
}
// String humanizes the subtree
func (c *Character) String() string {
return fmt.Sprintf(
"(Character %s)",
string([]byte{c.Char}),
)
}
// NewAltMatch creates an AltMatch
func NewAltMatch(a, b AST) AST {
if a == nil || b == nil {
panic("Alt match does not except nils")
}
return &AltMatch{a, b}
}
// NewMatch create a Match
func NewMatch(ast AST) AST {
return &Match{NewConcat(ast, NewEOS())}
}
// NewEOS creates a EOS
func NewEOS() AST {
return &EOS{}
}
// NewAlternation creates an Alternation
func NewAlternation(choice, alternation AST) AST {
if alternation == nil {
return choice
}
return &Alternation{choice, alternation}
}
// NewApplyOp applies a given op (Star, Plus, Maybe) to a tree
func NewApplyOp(op, atomic AST) AST {
switch o := op.(type) {
case *Star:
o.AST = atomic
case *Plus:
o.AST = atomic
case *Maybe:
o.AST = atomic
default:
panic("unexpected op")
}
return op
}
// NewOp constructs a Star, Plus, or Maybe from *, +, ? respectively
func NewOp(op string) AST {
switch op {
case "*":
return &Star{}
case "+":
return &Plus{}
case "?":
return &Maybe{}
default:
panic("unexpected op")
}
}
// NewConcat concatenates two tree together
func NewConcat(char, concat AST) AST {
if concat == nil {
return char
}
if cc, ok := concat.(*Concat); ok {
items := make([]AST, len(cc.Items)+1)
items[0] = char
for i, item := range cc.Items {
items[i+1] = item
}
return &Concat{items}
}
return &Concat{[]AST{char, concat}}
}
// NewCharacter constructs a character
func NewCharacter(b byte) *Character {
return &Character{b}
}
// NewAny constructs the . operator
func NewAny() *Range {
return &Range{From: 0, To: 255}
}
// NewRange constructs a range operator
func NewRange(from, to byte) *Range {
if from <= to {
return &Range{From: from, To: to}
}
return &Range{From: to, To: from}
}