1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
|
package peg
import(
//"fmt"
)
type (
Parser struct {
working string
rules map[string]*NonTerminal
}
Result struct {
*Parser
Valid bool
Offset int
Length int
Expression Exp
Children []*Result
}
)
// Result
func (this *Result) toTree() *ExpressionTree {
children := make([]*ExpressionTree, 0)
if this.Valid {
for _, r := range this.Children {
children = append(children, r.toTree())
}
switch exp := this.Expression.(type) {
case *Terminal:
return &ExpressionTree{"",children,exp.Character}
case *NonTerminal:
return &ExpressionTree{exp.Name,children,-1}
}
}
return &ExpressionTree{"",children,-1}
}
// Create a new PEG Parser
func NewParser() *Parser {
return &Parser{"",make(map[string]*NonTerminal)}
}
func (this *Parser) pass(offset, length int, exp Exp, children []*Result) *Result {
if children == nil {
children = make([]*Result, 0)
}
return &Result{this,true,offset,length,exp,children}
}
func (this *Parser) fail(offset, length int, exp Exp, children []*Result) *Result {
if children == nil {
children = make([]*Result, 0)
}
return &Result{this,false,offset,length,exp,children}
}
func (this *Parser) Terminal(ch int) *Terminal {
return &Terminal{this,ch}
}
func (this *Parser) NonTerminal(name string) *NonTerminal {
e := &NonTerminal{this,name,nil}
this.rules[name] = e
return e
}
func (this *Parser) Sequence(exps ... Exp) *Sequence {
return &Sequence{this,exps}
}
func (this *Parser) OrderedChoice(exps ... Exp) *OrderedChoice {
return &OrderedChoice{this,exps}
}
func (this *Parser) ZeroOrMore(exp Exp) *ZeroOrMore {
return &ZeroOrMore{this,exp}
}
func (this *Parser) OneOrMore(exp Exp) *OneOrMore {
return &OneOrMore{this,exp}
}
func (this *Parser) Optional(exp Exp) *Optional {
return &Optional{this,exp}
}
func (this *Parser) AndPredicate(exp Exp) *AndPredicate {
return &AndPredicate{this,exp}
}
func (this *Parser) NotPredicate(exp Exp) *NotPredicate {
return &NotPredicate{this,exp}
}
// Extensions for easier construction
func (this *Parser) Range(start, end int) *OrderedChoice {
exps := make([]Exp, (end - start)+1)
for i := start; i <= end; i++ {
exps[i-start] = &Terminal{this,i}
}
return &OrderedChoice{this,exps}
}
func (this *Parser) Parse(text string) *ExpressionTree {
this.working = text
if start, ok := this.rules["Start"]; ok {
_, r := start.Match(0)
t := r.toTree()
t.collapse()
return t
}
panic("No starting rule defined. Create a non terminal named \"Start\"")
}
|