/
match.go
109 lines (97 loc) · 2.8 KB
/
match.go
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
105
106
107
108
109
package parser
import (
"errors"
"reflect"
"strings"
"github.com/HexmosTech/gabs/v2"
"github.com/HexmosTech/lama2/utils"
"github.com/rs/zerolog/log"
)
// Method Match is the most important of all in the
// parser package. Match takes in a slice of rules
// (essentially method names), and then executes
// them one by one. On successful match, we return
// a gabs Container with `error` set to `nil`
// When a rule fails to match, we reset the scan
// position to initial position; moreover, we keep
// a continuous track of the farthest/longest match
// till present. The farthest match error is potentially
// the most useful error message to the user; thus,
// for error report, Match returns the farthest matching
// error
func (p *Parser) Match(rules []string) (*gabs.Container, error) {
p.eatWhitespace()
lastErrorPos := -1
lastErrorLine := 0
lastErrorRules := []string{}
lastError := errors.New("")
for _, rule := range rules {
initialPos := p.Pos
log.Trace().Str("Rule", rule).Strs("Rules", rules).Msg("")
res := p.ruleMethodMap[rule].Call([]reflect.Value{})
op := res[0].Interface().(*gabs.Container)
log.Trace().Str("Rule res", op.String()).Msg("")
e := res[1]
log.Trace().Str("Rule error", e.String()).Msg("")
if e.IsNil() {
p.eatWhitespace()
return op, nil
}
p.Pos = initialPos
pe := e.Interface().(*utils.ParseError)
if pe.Pos > lastErrorPos {
lastError = pe
lastErrorPos = pe.Pos
lastErrorLine = pe.LineNum
lastErrorRules = nil
lastErrorRules = append(lastErrorRules, rule)
} else if pe.Pos == lastErrorPos {
lastErrorRules = append(lastErrorRules, rule)
}
}
if len(lastErrorRules) == 1 {
return nil, lastError
}
if lastErrorPos >= p.TotalLen {
lastErrorPos = p.TotalLen - 1
}
return nil, utils.NewParseError(lastErrorPos, lastErrorLine, "Expected %s but got %s", []string{strings.Join(lastErrorRules, ","), string(p.Text[lastErrorPos])})
}
func (p *Parser) LookAhead(rules []string) bool {
p.eatWhitespace()
for _, rule := range rules {
initialPos := p.Pos
log.Trace().Str("Rule", rule).Strs("Rules", rules).Msg("")
res := p.ruleMethodMap[rule].Call([]reflect.Value{})
op := res[0].Interface().(*gabs.Container)
log.Trace().Str("Rule res", op.String()).Msg("")
e := res[1]
log.Trace().Str("Rule error", e.String()).Msg("")
p.Pos = initialPos
if e.IsNil() {
p.eatWhitespace()
return true
}
}
return false
}
func (p *Parser) MatchUntil(end string) (*gabs.Container, error) {
chunk := make([]string, 0)
temp := gabs.New()
for {
oldPos := p.Pos
_, e1 := p.Keyword(end, false, false, false)
if e1 == nil {
p.Pos = oldPos
temp.Set(strings.Join(chunk, ""))
return temp, nil
}
r2, e2 := p.Char()
if e2 != nil {
break
}
chunk = append(chunk, string(r2))
}
temp.Set(strings.Join(chunk, ""))
return temp, nil
}