From 403ffe6ca229de8cb90814e1f2ea67247b67bb2b Mon Sep 17 00:00:00 2001 From: xushiwei Date: Sun, 2 Mar 2025 08:29:40 +0800 Subject: [PATCH 1/3] tpl demo: natural-lang --- demo/gop-parser/natural-lang/nlang.gop | 17 +++++++++++++++++ tpl/tpl.go | 10 ++++++---- 2 files changed, 23 insertions(+), 4 deletions(-) create mode 100644 demo/gop-parser/natural-lang/nlang.gop diff --git a/demo/gop-parser/natural-lang/nlang.gop b/demo/gop-parser/natural-lang/nlang.gop new file mode 100644 index 000000000..91f75933a --- /dev/null +++ b/demo/gop-parser/natural-lang/nlang.gop @@ -0,0 +1,17 @@ +import "os" + +cl := tpl` +expr = noun verb noun +noun = "I" | "you" | "he" | "she" | "it" | "dog" | "cat" +verb = "attack" | "love" | "eat" | "hate" +`! + +print "> " +for line <- os.Stdin { + e, err := cl.parseExpr(line, nil) + if err != nil { + print "${err}\n> " + } else { + print e, "\n > " + } +} diff --git a/tpl/tpl.go b/tpl/tpl.go index a0bd58677..20da7f22e 100644 --- a/tpl/tpl.go +++ b/tpl/tpl.go @@ -166,15 +166,17 @@ func isPlain(result []any) bool { // ----------------------------------------------------------------------------- -func Dump(result any) { - Fdump(os.Stdout, result, "", " ") +func Dump(result any, omitSemi ...bool) { + Fdump(os.Stdout, result, "", " ", omitSemi != nil && omitSemi[0]) } -func Fdump(w io.Writer, result any, prefix, indent string) { +func Fdump(w io.Writer, result any, prefix, indent string, omitSemi bool) { switch result := result.(type) { case *Token: if result.Tok != token.SEMICOLON { fmt.Fprint(w, prefix, result, "\n") + } else if !omitSemi { + fmt.Fprint(w, prefix, ";\n") } case []any: if isPlain(result) { @@ -189,7 +191,7 @@ func Fdump(w io.Writer, result any, prefix, indent string) { } else { fmt.Print(prefix, "[\n") for _, v := range result { - Fdump(w, v, prefix+indent, indent) + Fdump(w, v, prefix+indent, indent, omitSemi) } fmt.Print(prefix, "]\n") } From 47ae84bad5e3245963804b5c76dc1264fe4840f7 Mon Sep 17 00:00:00 2001 From: xushiwei Date: Sun, 2 Mar 2025 09:01:07 +0800 Subject: [PATCH 2/3] tpl/matcher: error message when errMultiMismatch --- tpl/matcher/match.go | 52 +++++++++++++++++++++++++------------------- 1 file changed, 30 insertions(+), 22 deletions(-) diff --git a/tpl/matcher/match.go b/tpl/matcher/match.go index 40b9767ae..15278cb9d 100644 --- a/tpl/matcher/match.go +++ b/tpl/matcher/match.go @@ -24,6 +24,13 @@ import ( "github.com/goplus/gop/tpl/types" ) +var ( + errMultiMismatch = errors.New("multiple mismatch") + + // ErrVarAssigned error + ErrVarAssigned = errors.New("variable is already assigned") +) + // ----------------------------------------------------------------------------- // Error represents a matching error. @@ -114,30 +121,25 @@ type gChoice struct { } func (p *gChoice) Match(src []*types.Token, ctx *Context) (n int, result any, err error) { - var nMax int + var nMax = -1 var errMax error - // var multiErr = true + var multiErr = true for _, g := range p.options { if n, result, err = g.Match(src, ctx); err == nil { return } if n >= nMax { - nMax, errMax = n, err - /* - if n == nMax { - multiErr = true - } else { - nMax, errMax, multiErr = n, err, false - } - */ + if n == nMax { + multiErr = true + } else { + nMax, errMax, multiErr = n, err, false + } } } - /* - if multiErr { - errMax = ctx.NewError(src[nMax].End(), "TODO: error msg") // TODO(xsw) - } - */ + if multiErr { + errMax = errMultiMismatch + } return nMax, nil, errMax } @@ -263,11 +265,6 @@ func List(a, b Matcher) Matcher { // ----------------------------------------------------------------------------- -var ( - // ErrVarAssigned error - ErrVarAssigned = errors.New("variable is already assigned") -) - type Var struct { Elem Matcher Name string @@ -277,9 +274,20 @@ type Var struct { func (p *Var) Match(src []*types.Token, ctx *Context) (n int, result any, err error) { g := p.Elem if g == nil { - return 0, nil, ctx.NewErrorf(p.Pos, "variable `%s` not found", p.Name) + return 0, nil, ctx.NewErrorf(p.Pos, "variable `%s` not assigned", p.Name) + } + n, result, err = g.Match(src, ctx) + if err == errMultiMismatch { + var posErr token.Pos + var tokErr any + if len(src) > 0 { + posErr, tokErr = src[0].Pos, src[0] + } else { + posErr, tokErr = ctx.FileEnd, "EOF" + } + err = ctx.NewErrorf(posErr, "expect `%s`, but got `%s`", p.Name, tokErr) } - return g.Match(src, ctx) + return } // Assign assigns a value to this variable. From 38eb8adc3c21f188a37161ed395468533a441f6f Mon Sep 17 00:00:00 2001 From: xushiwei Date: Sun, 2 Mar 2025 09:13:05 +0800 Subject: [PATCH 3/3] natural-lang --- demo/gop-parser/natural-lang/nlang.gop | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/demo/gop-parser/natural-lang/nlang.gop b/demo/gop-parser/natural-lang/nlang.gop index 91f75933a..f61708b7d 100644 --- a/demo/gop-parser/natural-lang/nlang.gop +++ b/demo/gop-parser/natural-lang/nlang.gop @@ -1,8 +1,9 @@ import "os" cl := tpl` -expr = noun verb noun -noun = "I" | "you" | "he" | "she" | "it" | "dog" | "cat" +expr = subject verb object +subject = "I" | "You" | "He" | "She" | "It" | "Dog" | "Cat" +object = "me" | "you" | "him" | "her" | "it" | "fish" | "apple" | "banana" | "dog" | "cat" verb = "attack" | "love" | "eat" | "hate" `!