Skip to content

Commit 6b259f2

Browse files
authored
Merge pull request #2215 from xushiwei/q
tpl/matcher: Choice.stops
2 parents 54ea3d7 + 92eb23d commit 6b259f2

File tree

2 files changed

+160
-15
lines changed

2 files changed

+160
-15
lines changed

doc/spec/mini/mini.gop

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -157,8 +157,8 @@ PrimaryExpr = Operand | PrimaryExpr (
157157
CallOrConversion | SelectorOrTypeAssertion | IndexOrSlice | LiteralValue)
158158

159159
Operand =
160-
IDENT | INT | FLOAT | STRING | CHAR | IMAG |
161-
CompositeLit | FunctionLit | "(" Expression ")"
160+
INT | FLOAT | STRING | CHAR | IMAG |
161+
CompositeLit | FunctionLit | "(" Expression ")" | IDENT
162162

163163
CompositeLit = LiteralTypeLit LiteralValue
164164

@@ -185,7 +185,7 @@ IndexOrSlice = "[" (":" ?Expression | Expression (":" ?Expression | ?",")) "]"
185185

186186
// -----------------------------------------------------------------
187187

188-
func ParseFile(fset *token.FileSet, filename string, src any) (f any, err error) {
188+
func ParseFile(fset *token.FileSet, filename string, src any) (any, error) {
189189
return cl.Parse(filename, src, &tpl.Config{
190190
Fset: fset,
191191
})

tpl/matcher/match.go

Lines changed: 157 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,17 @@ package matcher
1919
import (
2020
"errors"
2121
"fmt"
22+
"log"
2223

2324
"github.com/goplus/gop/tpl/token"
2425
"github.com/goplus/gop/tpl/types"
2526
)
2627

2728
var (
28-
errMultiMismatch = errors.New("multiple mismatch")
29-
3029
// ErrVarAssigned error
3130
ErrVarAssigned = errors.New("variable is already assigned")
31+
32+
errMultiMismatch = errors.New("multiple mismatch")
3233
)
3334

3435
// -----------------------------------------------------------------------------
@@ -92,12 +93,86 @@ func (p *Context) NewErrorf(pos token.Pos, format string, args ...any) error {
9293
return &Error{p.Fset, pos, fmt.Sprintf(format, args...), false}
9394
}
9495

96+
// -----------------------------------------------------------------------------
97+
98+
// MatchToken represents a matching literal.
99+
type MatchToken struct {
100+
Tok token.Token
101+
Lit string
102+
}
103+
104+
func (p *MatchToken) String() string {
105+
return p.Lit
106+
}
107+
108+
func hasConflictToken(me token.Token, next []any) bool {
109+
for _, n := range next {
110+
switch n := n.(type) {
111+
case *MatchToken:
112+
if n.Tok == me {
113+
return true
114+
}
115+
case token.Token:
116+
if n == me {
117+
return true
118+
}
119+
default:
120+
panic("unreachable")
121+
}
122+
}
123+
return false
124+
}
125+
126+
func hasConflictMatchToken(me *MatchToken, next []any) bool {
127+
for _, n := range next {
128+
switch n := n.(type) {
129+
case *MatchToken:
130+
if n.Tok == me.Tok && n.Lit == me.Lit {
131+
return true
132+
}
133+
case token.Token:
134+
default:
135+
panic("unreachable")
136+
}
137+
}
138+
return false
139+
}
140+
141+
func hasConflictMe(me any, next []any) bool {
142+
switch me := me.(type) {
143+
case token.Token:
144+
return hasConflictToken(me, next)
145+
case *MatchToken:
146+
return hasConflictMatchToken(me, next)
147+
}
148+
panic("unreachable")
149+
}
150+
151+
func hasConflict(me []any, next []any) bool {
152+
for _, m := range me {
153+
if hasConflictMe(m, next) {
154+
return true
155+
}
156+
}
157+
return false
158+
}
159+
160+
func conflictWith(me []any, next [][]any) int {
161+
for i, n := range next {
162+
if hasConflict(me, n) {
163+
return i
164+
}
165+
}
166+
return -1
167+
}
168+
95169
// -----------------------------------------------------------------------------
96170
// Matcher
97171

98172
// Matcher represents a matcher.
99173
type Matcher interface {
100174
Match(src []*types.Token, ctx *Context) (n int, result any, err error)
175+
First(in []any) []any // item can be token.Token or *MatchToken
101176
IsList() bool
102177
}
103178

@@ -109,6 +184,10 @@ func (p gTrue) Match(src []*types.Token, ctx *Context) (n int, result any, err e
109184
return 0, nil, nil
110185
}
111186

187+
func (p gTrue) First(in []any) []any {
188+
return in
189+
}
190+
112191
func (p gTrue) IsList() bool {
113192
return false
114193
}
@@ -135,6 +214,10 @@ func (p *gToken) Match(src []*types.Token, ctx *Context) (n int, result any, err
135214
return 1, t, nil
136215
}
137216

217+
func (p *gToken) First(in []any) []any {
218+
return append(in, p.tok)
219+
}
220+
138221
func (p *gToken) IsList() bool {
139222
return false
140223
}
@@ -146,22 +229,23 @@ func Token(tok token.Token) Matcher {
146229

147230
// -----------------------------------------------------------------------------
148231

149-
type gLiteral struct {
150-
tok token.Token
151-
lit string
152-
}
232+
type gLiteral MatchToken
153233

154234
func (p *gLiteral) Match(src []*types.Token, ctx *Context) (n int, result any, err error) {
155235
if len(src) == 0 {
156-
return 0, nil, ctx.NewErrorf(ctx.FileEnd, "expect `%s`, but got EOF", p.lit)
236+
return 0, nil, ctx.NewErrorf(ctx.FileEnd, "expect `%s`, but got EOF", p.Lit)
157237
}
158238
t := src[0]
159-
if t.Tok != p.tok || t.Lit != p.lit {
160-
return 0, nil, ctx.NewErrorf(t.Pos, "expect `%s`, but got `%s`", p.lit, t.Lit)
239+
if t.Tok != p.Tok || t.Lit != p.Lit {
240+
return 0, nil, ctx.NewErrorf(t.Pos, "expect `%s`, but got `%s`", p.Lit, t.Lit)
161241
}
162242
return 1, t, nil
163243
}
164244

245+
func (p *gLiteral) First(in []any) []any {
246+
return append(in, (*MatchToken)(p))
247+
}
248+
165249
func (p *gLiteral) IsList() bool {
166250
return false
167251
}
@@ -175,15 +259,40 @@ func Literal(tok token.Token, lit string) Matcher {
175259

176260
type gChoice struct {
177261
options []Matcher
262+
stops []bool
263+
}
264+
265+
func (p *gChoice) needStops() (stops []bool) {
266+
stops = p.stops
267+
if stops == nil { // make stops
268+
options := p.options
269+
n := len(options)
270+
firsts := make([][]any, n)
271+
for i, g := range options {
272+
firsts[i] = g.First(nil)
273+
}
274+
stops = make([]bool, n)
275+
for i, me := range firsts {
276+
at := conflictWith(me, firsts[i+1:])
277+
if at >= 0 {
278+
log.Println("conflict", me, "with:", firsts[at]) // TODO(xsw): conflict
279+
} else {
280+
stops[i] = true
281+
}
282+
}
283+
p.stops = stops
284+
}
285+
return
178286
}
179287

180288
func (p *gChoice) Match(src []*types.Token, ctx *Context) (n int, result any, err error) {
181289
var nMax = -1
182290
var errMax error
183291
var multiErr = true
184292

185-
for _, g := range p.options {
186-
if n, result, err = g.Match(src, ctx); err == nil {
293+
stops := p.needStops()
294+
for i, g := range p.options {
295+
if n, result, err = g.Match(src, ctx); err == nil || (n > 0 && stops[i]) {
187296
return
188297
}
189298
if n >= nMax {
@@ -200,13 +309,20 @@ func (p *gChoice) Match(src []*types.Token, ctx *Context) (n int, result any, er
200309
return nMax, nil, errMax
201310
}
202311

312+
func (p *gChoice) First(in []any) []any {
313+
for _, g := range p.options {
314+
in = g.First(in)
315+
}
316+
return in
317+
}
318+
203319
func (p *gChoice) IsList() bool {
204320
return false
205321
}
206322

207323
// Choice: R1 | R2 | ... | Rn
208324
func Choice(options ...Matcher) Matcher {
209-
return &gChoice{options}
325+
return &gChoice{options, nil}
210326
}
211327

212328
// -----------------------------------------------------------------------------
@@ -234,12 +350,19 @@ func (p *gSequence) Match(src []*types.Token, ctx *Context) (n int, result any,
234350
return
235351
}
236352

353+
func (p *gSequence) First(in []any) []any {
354+
return p.items[0].First(in)
355+
}
356+
237357
func (p *gSequence) IsList() bool {
238358
return true
239359
}
240360

241361
// Sequence: R1 R2 ... Rn
242362
func Sequence(items ...Matcher) Matcher {
363+
if len(items) == 0 {
364+
return gTrue{}
365+
}
243366
return &gSequence{items}
244367
}
245368

@@ -269,6 +392,10 @@ func (p *gRepeat0) Match(src []*types.Token, ctx *Context) (n int, result any, e
269392
}
270393
}
271394

395+
func (p *gRepeat0) First(in []any) []any {
396+
return p.r.First(in)
397+
}
398+
272399
func (p *gRepeat0) IsList() bool {
273400
return true
274401
}
@@ -309,6 +436,10 @@ func (p *gRepeat1) Match(src []*types.Token, ctx *Context) (n int, result any, e
309436
}
310437
}
311438

439+
func (p *gRepeat1) First(in []any) []any {
440+
return p.r.First(in)
441+
}
442+
312443
func (p *gRepeat1) IsList() bool {
313444
return true
314445
}
@@ -332,6 +463,10 @@ func (p *gRepeat01) Match(src []*types.Token, ctx *Context) (n int, result any,
332463
return
333464
}
334465

466+
func (p *gRepeat01) First(in []any) []any {
467+
return p.r.First(in)
468+
}
469+
335470
func (p *gRepeat01) IsList() bool {
336471
return false
337472
}
@@ -408,6 +543,16 @@ func (p *Var) Match(src []*types.Token, ctx *Context) (n int, result any, err er
408543
return
409544
}
410545

546+
func (p *Var) First(in []any) []any {
547+
elem := p.Elem
548+
if elem != nil {
549+
p.Elem = nil // to stop recursion
550+
in = elem.First(in)
551+
p.Elem = elem
552+
}
553+
return in
554+
}
555+
411556
func (p *Var) IsList() bool {
412557
return false
413558
}

0 commit comments

Comments
 (0)