From 0df00eeab6b9d4cc060332378adb25ebe1d40e78 Mon Sep 17 00:00:00 2001 From: vircoys Date: Thu, 22 Dec 2022 18:35:47 +0800 Subject: [PATCH] feat: Optimize error message (#24) --- .gitignore | 1 + Makefile | 2 +- internal/cmd/platypus/run/run.go | 21 ++- internal/logger/logger.go | 8 +- pkg/ast/ast.go | 20 +-- pkg/ast/expr.go | 48 ++--- pkg/ast/stmt.go | 18 +- pkg/engine/callref.go | 86 ++++++--- pkg/engine/callref_test.go | 77 ++++++++ pkg/engine/engine.go | 13 +- pkg/engine/error.go | 6 - pkg/engine/op_test.go | 2 +- pkg/engine/runtime/checkstmt.go | 41 ++--- pkg/engine/runtime/context.go | 30 ++-- pkg/engine/runtime/error.go | 74 +------- pkg/engine/runtime/runtime.go | 50 +++--- pkg/engine/runtime/runtime_test.go | 15 +- pkg/errchain/error.go | 83 +++++++++ pkg/inimpl/guancecloud/funcs/all.go | 2 +- pkg/inimpl/guancecloud/funcs/fn_addkey.go | 10 +- pkg/inimpl/guancecloud/funcs/fn_addpattern.go | 5 +- pkg/inimpl/guancecloud/funcs/fn_cast.go | 5 +- pkg/inimpl/guancecloud/funcs/fn_datetime.go | 5 +- .../guancecloud/funcs/fn_default_time.go | 5 +- pkg/inimpl/guancecloud/funcs/fn_dropkey.go | 5 +- pkg/inimpl/guancecloud/funcs/fn_exit.go | 5 +- pkg/inimpl/guancecloud/funcs/fn_getkey.go | 5 +- pkg/inimpl/guancecloud/funcs/fn_grok.go | 5 +- pkg/inimpl/guancecloud/funcs/fn_len.go | 5 +- pkg/inimpl/guancecloud/funcs/fn_load_json.go | 5 +- pkg/inimpl/guancecloud/funcs/fn_printf.go | 5 +- pkg/inimpl/guancecloud/funcs/fn_rename.go | 5 +- pkg/inimpl/guancecloud/funcs/fn_replace.go | 5 +- .../guancecloud/funcs/fn_set_measurement.go | 5 +- pkg/inimpl/guancecloud/funcs/fn_set_tag.go | 7 +- pkg/inimpl/guancecloud/funcs/fn_sql_cover.go | 5 +- pkg/inimpl/guancecloud/funcs/fn_strfmt.go | 5 +- pkg/inimpl/guancecloud/funcs/fn_trim.go | 5 +- pkg/inimpl/guancecloud/funcs/fn_uppercase.go | 5 +- pkg/inimpl/guancecloud/funcs/fn_urldecode.go | 5 +- pkg/inimpl/guancecloud/funcs/fn_use.go | 24 ++- pkg/inimpl/guancecloud/funcs/fn_xml.go | 5 +- pkg/parser/gram.y | 8 +- pkg/parser/gram_y.go | 170 +++++++++--------- pkg/parser/parser.go | 91 ++++++---- pkg/parser/parser_test.go | 6 +- pkg/token/token.go | 79 +++++++- pkg/token/token_test.go | 77 ++++++++ scripts/test_fn_use/test_fn_use.sh | 4 +- .../test_nginx_access_log/nginx_access_log.p | 11 +- scripts/test_nginx_access_log/test_fn_use.sh | 12 ++ 51 files changed, 770 insertions(+), 426 deletions(-) create mode 100644 pkg/engine/callref_test.go delete mode 100644 pkg/engine/error.go create mode 100644 pkg/errchain/error.go create mode 100644 pkg/token/token_test.go create mode 100755 scripts/test_nginx_access_log/test_fn_use.sh diff --git a/.gitignore b/.gitignore index 1cdbf05..77a08d5 100644 --- a/.gitignore +++ b/.gitignore @@ -30,6 +30,7 @@ pkg/parser/y.output rl.sh dist/ test.output +tmp/ # Local Netlify folder .netlify diff --git a/Makefile b/Makefile index 4a2a080..066884d 100644 --- a/Makefile +++ b/Makefile @@ -22,7 +22,7 @@ test-cov: tools: mkdir -p ./dist rm -r ./dist/ - go build -o ./dist/ cmd/ppl/ppl.go + go build -o ./dist/platypus ./cmd/platypus/ .PHONY: generate generate: diff --git a/internal/cmd/platypus/run/run.go b/internal/cmd/platypus/run/run.go index 30c4c31..3d4f3d6 100644 --- a/internal/cmd/platypus/run/run.go +++ b/internal/cmd/platypus/run/run.go @@ -16,9 +16,10 @@ import ( "github.com/GuanceCloud/platypus/pkg/inimpl/guancecloud/input" "github.com/influxdata/influxdb1-client/models" influxdb "github.com/influxdata/influxdb1-client/v2" + "go.uber.org/zap/zapcore" ) -var l = logger.NewStdoutLogger("cli", "debug") +var l = logger.NewStdoutLogger("cli", zapcore.DebugLevel) func Run(ctx context.Context, options *Options) error { if options.Script == "" { @@ -27,14 +28,20 @@ func Run(ctx context.Context, options *Options) error { script, err := loadScript(ctx, options) if err != nil { - return err + l.Error(err) + return nil } + // check script only if options.Input == "" { return nil } - return runScript(ctx, options, script) + if err := runScript(ctx, options, script); err != nil { + l.Error(err) + } + + return nil } func loadScript(ctx context.Context, options *Options) (*plruntime.Script, error) { @@ -59,7 +66,7 @@ func loadScript(ctx context.Context, options *Options) (*plruntime.Script, error scripts, errs := engine.ParseScript(scriptsContent, funcs.FuncsMap, funcs.FuncsCheckMap) if len(errs) > 0 { if err, ok := errs[options.Script]; ok { - return nil, fmt.Errorf("parse script error: %w", err) + return nil, err } } @@ -118,7 +125,7 @@ func runScript(ctx context.Context, options *Options, script *plruntime.Script) errR := engine.RunScriptWithRMapIn(script, pt, nil) if errR != nil { - return fmt.Errorf("run script error: %w", errR.ChainError()) + return fmt.Errorf("run script error: %w", errR) } if dropped { @@ -139,13 +146,13 @@ func runScript(ctx context.Context, options *Options, script *plruntime.Script) }); err != nil { return fmt.Errorf("encode json output error: %w", err) } - l.Debugf("Platypus Output Data:\n%s", buf.String()) + l.Infof("Platypus Output Data:\n%s", buf.String()) case OutTypeLineProtocol: pt, err := influxdb.NewPoint(measurement, tags, fields, tn) if err != nil { return fmt.Errorf("encode point output error: %w", err) } - l.Debugf("Platypus Output Data:\n%s", pt.String()) + l.Infof("Platypus Output Data:\n%s", pt.String()) } return nil } diff --git a/internal/logger/logger.go b/internal/logger/logger.go index 035ec1b..1f048ee 100644 --- a/internal/logger/logger.go +++ b/internal/logger/logger.go @@ -30,10 +30,10 @@ type Logger interface { Fatalf(format string, args ...interface{}) } -func NewStdoutLogger(name, level string) Logger { +func NewStdoutLogger(name string, level zapcore.Level) Logger { cfg := &zap.Config{ - Level: zap.NewAtomicLevelAt(zapcore.DebugLevel), - Encoding: `json`, + Level: zap.NewAtomicLevelAt(level), + Encoding: `console`, EncoderConfig: zapcore.EncoderConfig{ NameKey: NameKeyMod, MessageKey: NameKeyMsg, @@ -47,6 +47,8 @@ func NewStdoutLogger(name, level string) Logger { }, } + cfg.OutputPaths = append(cfg.OutputPaths, "stdout") + l, err := cfg.Build() if err != nil { panic(err) diff --git a/pkg/ast/ast.go b/pkg/ast/ast.go index 457f34a..e09d7c2 100644 --- a/pkg/ast/ast.go +++ b/pkg/ast/ast.go @@ -18,7 +18,7 @@ type NodeType uint const ( // expr. - TypeInvaild NodeType = iota + TypeInvalid NodeType = iota TypeIdentifier TypeStringLiteral @@ -52,8 +52,8 @@ const ( func (t NodeType) String() string { switch t { - case TypeInvaild: - return "Invaild" + case TypeInvalid: + return "Invalid" case TypeIdentifier: return "Identifier" case TypeStringLiteral: @@ -358,17 +358,17 @@ func WrapeBlockStmt(node *BlockStmt) *Node { } } -func (node *Node) StartPos() token.Pos { +func (node *Node) StartPos() token.LnColPos { return NodeStartPos(node) } -func NodeStartPos(node *Node) token.Pos { +func NodeStartPos(node *Node) token.LnColPos { if node == nil { - return -1 + return token.InvalidLnColPos } switch node.NodeType { - case TypeInvaild: - return -1 + case TypeInvalid: + return token.InvalidLnColPos case TypeIdentifier: return node.Identifier.Start case TypeStringLiteral: @@ -413,7 +413,7 @@ func NodeStartPos(node *Node) token.Pos { if len(node.IfelseStmt.IfList) > 0 { return node.IfelseStmt.IfList[0].Start } else { - return -1 + return token.InvalidLnColPos } case TypeForStmt: @@ -425,5 +425,5 @@ func NodeStartPos(node *Node) token.Pos { case TypeBreakStmt: return node.BreakStmt.Start } - return -1 + return token.InvalidLnColPos } diff --git a/pkg/ast/expr.go b/pkg/ast/expr.go index b215021..1ef5586 100644 --- a/pkg/ast/expr.go +++ b/pkg/ast/expr.go @@ -41,7 +41,7 @@ const ( type Identifier struct { Name string - Start token.Pos + Start token.LnColPos } func (e *Identifier) IsExpr() bool { @@ -54,7 +54,7 @@ func (e *Identifier) String() string { type StringLiteral struct { Val string - Start token.Pos + Start token.LnColPos } func (e *StringLiteral) IsExpr() bool { @@ -69,13 +69,13 @@ func (e *StringLiteral) String() string { // IsInt bool // Float float64 // Int int64 -// Start token.Pos -// End token.Pos +// Start token.FilePos +// End token.FilePos // } type IntegerLiteral struct { Val int64 - Start token.Pos + Start token.LnColPos } func (e *IntegerLiteral) String() string { @@ -88,7 +88,7 @@ func (e *IntegerLiteral) IsExpr() bool { type FloatLiteral struct { Val float64 - Start token.Pos + Start token.LnColPos } func (e *FloatLiteral) String() string { @@ -101,7 +101,7 @@ func (e *FloatLiteral) IsExpr() bool { type BoolLiteral struct { Val bool - Start token.Pos + Start token.LnColPos } func (e *BoolLiteral) String() string { @@ -109,7 +109,7 @@ func (e *BoolLiteral) String() string { } type NilLiteral struct { - Start token.Pos + Start token.LnColPos } func (e *NilLiteral) IsExpr() bool { @@ -122,8 +122,8 @@ func (e *NilLiteral) String() string { type MapInitExpr struct { KeyValeList [][2]*Node // key,value list - LBrace token.Pos - RBrace token.Pos + LBrace token.LnColPos + RBrace token.LnColPos } func (e *MapInitExpr) IsExpr() bool { @@ -144,8 +144,8 @@ func (e *MapInitExpr) String() string { type ListInitExpr struct { List []*Node - LBracket token.Pos - RBracket token.Pos + LBracket token.LnColPos + RBracket token.LnColPos } func (e *ListInitExpr) IsExpr() bool { @@ -163,7 +163,7 @@ func (e *ListInitExpr) String() string { type ConditionalExpr struct { Op Op LHS, RHS *Node - OpPos token.Pos + OpPos token.LnColPos } func (e *ConditionalExpr) IsExpr() bool { @@ -177,7 +177,7 @@ func (e *ConditionalExpr) String() string { type ArithmeticExpr struct { Op Op LHS, RHS *Node - OpPos token.Pos + OpPos token.LnColPos } func (e *ArithmeticExpr) IsExpr() bool { @@ -191,7 +191,7 @@ func (e *ArithmeticExpr) String() string { type AttrExpr struct { Obj *Node Attr *Node - Start token.Pos + Start token.LnColPos } func (e *AttrExpr) IsExpr() bool { @@ -212,8 +212,8 @@ func (e *AttrExpr) String() string { type IndexExpr struct { Obj *Identifier Index []*Node // int float string bool - LBracket []token.Pos - RBracket []token.Pos + LBracket []token.LnColPos + RBracket []token.LnColPos } func (e *IndexExpr) IsExpr() bool { @@ -234,8 +234,8 @@ func (e *IndexExpr) String() string { type ParenExpr struct { Param *Node - LParen token.Pos - RParen token.Pos + LParen token.LnColPos + RParen token.LnColPos } func (e *ParenExpr) IsExpr() bool { @@ -251,15 +251,17 @@ type CallExpr struct { // Name *ast.Node // temporary record function name location - NamePos token.Pos // as 'Start' (token.Pos) + NamePos token.LnColPos // as 'Start' (token.FilePos) - LParen token.Pos - RParen token.Pos + LParen token.LnColPos + RParen token.LnColPos Name string Param []*Node + PrivateData interface{} + // ParamIndex []int Grok *grok.GrokRegexp @@ -280,7 +282,7 @@ func (e *CallExpr) String() string { type AssignmentExpr struct { LHS, RHS *Node - OpPos token.Pos + OpPos token.LnColPos } func (e *AssignmentExpr) IsExpr() bool { diff --git a/pkg/ast/stmt.go b/pkg/ast/stmt.go index 82f7ab6..e7b1302 100644 --- a/pkg/ast/stmt.go +++ b/pkg/ast/stmt.go @@ -15,7 +15,7 @@ type IfelseStmt struct { IfList IfList Else *BlockStmt - ElsePos token.Pos + ElsePos token.LnColPos } func (e *IfelseStmt) IsExpr() bool { @@ -48,7 +48,7 @@ type IfStmtElem struct { Condition *Node Block *BlockStmt - Start token.Pos + Start token.LnColPos } func (e *IfStmtElem) String() string { @@ -57,7 +57,7 @@ func (e *IfStmtElem) String() string { } type BreakStmt struct { - Start token.Pos + Start token.LnColPos } func (e *BreakStmt) String() string { @@ -65,7 +65,7 @@ func (e *BreakStmt) String() string { } type ContinueStmt struct { - Start token.Pos + Start token.LnColPos } func (e *ContinueStmt) String() string { @@ -77,8 +77,8 @@ type ForInStmt struct { Iter *Node Body *BlockStmt - ForPos token.Pos - InPos token.Pos + ForPos token.LnColPos + InPos token.LnColPos } func (e *ForInStmt) String() string { @@ -98,7 +98,7 @@ type ForStmt struct { // step2: -> step3 Body *BlockStmt - ForPos token.Pos + ForPos token.LnColPos } func (e *ForStmt) String() string { @@ -106,8 +106,8 @@ func (e *ForStmt) String() string { } type BlockStmt struct { - LBracePos token.Pos - RBracePos token.Pos + LBracePos token.LnColPos + RBracePos token.LnColPos Stmts Stmts } diff --git a/pkg/engine/callref.go b/pkg/engine/callref.go index 0736fd6..50d6721 100644 --- a/pkg/engine/callref.go +++ b/pkg/engine/callref.go @@ -9,7 +9,10 @@ import ( "fmt" "strings" + "github.com/GuanceCloud/platypus/pkg/ast" "github.com/GuanceCloud/platypus/pkg/engine/runtime" + "github.com/GuanceCloud/platypus/pkg/errchain" + "github.com/GuanceCloud/platypus/pkg/token" ) type searchPath struct { @@ -55,53 +58,96 @@ func (p *searchPath) String() string { return strings.Join(p.path, " -> ") } +type param struct { + name string + namePos token.LnColPos + + allNg map[string]*runtime.Script + retMap map[string]*runtime.Script + allErrNg map[string]error +} + func EngineCallRefLinkAndCheck(allNg map[string]*runtime.Script, allErrNg map[string]error) (map[string]*runtime.Script, map[string]error) { retMap := map[string]*runtime.Script{} retErrMap := map[string]error{} - for name, ng := range allNg { + for name, proc := range allNg { + p := ¶m{ + name: name, + namePos: token.InvalidLnColPos, + allNg: allNg, + allErrNg: allErrNg, + retMap: retMap, + } + sPath := newSearchPath() - if err := dfs(name, ng, allNg, sPath, retMap, retErrMap, allErrNg); err != nil { + if err := dfs(name, proc, sPath, p); err != nil { retErrMap[name] = err } else { - retMap[name] = ng + retMap[name] = proc } } return retMap, retErrMap } -func dfs(name string, procc *runtime.Script, allNg map[string]*runtime.Script, - sPath *searchPath, retMap map[string]*runtime.Script, retErrMap map[string]error, - allErrNg map[string]error, -) error { +func dfs(name string, procc *runtime.Script, sPath *searchPath, p *param) error { if err := sPath.Push(name); err != nil { - return err - } - if err, ok := retErrMap[name]; ok { - return err + return errchain.NewErr(p.name, p.namePos, err.Error()) } - if _, ok := retMap[name]; ok { + if _, ok := p.retMap[name]; ok { return nil } - for cName := range procc.CallRef { - if cNg, ok := allNg[cName]; !ok { - if err, ok := allErrNg[cName]; ok { - return fmt.Errorf("%s: %s", cName, err.Error()) + for _, expr := range procc.CallRef { + cName, err := getParamRefScript(expr) + p.namePos = expr.NamePos + if err != nil { + return err + } + + if cNg, ok := p.allNg[cName]; !ok { + if err, ok := p.allErrNg[cName]; ok { + if e, ok := err.(*errchain.PlError); ok { + return e.Copy().ChainAppend( + procc.Name, p.namePos) + } + return err } - return fmt.Errorf("%s: script %s not found", sPath.String(), cName) + return errchain.NewErr(procc.Name, p.namePos, + fmt.Sprintf("script %s not found", cName)) } else { - procc.CallRef[cName] = cNg - if err := dfs(cName, cNg, allNg, sPath, retMap, retErrMap, allErrNg); err != nil { + expr.PrivateData = cNg + if err := dfs(cName, cNg, sPath, p); err != nil { + if e, ok := err.(*errchain.PlError); ok { + return e.Copy().ChainAppend(procc.Name, p.namePos) + } return err } } } - retMap[name] = procc + p.retMap[name] = procc sPath.Pop() return nil } + +func getParamRefScript(expr *ast.CallExpr) (string, error) { + if expr == nil { + return "", fmt.Errorf("nil ptr") + } + if expr.Name != "use" { + return "", fmt.Errorf("function name is not 'use'") + } + if len(expr.Param) != 1 { + return "", fmt.Errorf("the number of parameters is not 1") + } + + if expr.Param[0].NodeType != ast.TypeStringLiteral { + return "", fmt.Errorf("param type expects StringLiteral got `%s`", expr.Param[0].NodeType) + } + + return expr.Param[0].StringLiteral.Val, nil +} diff --git a/pkg/engine/callref_test.go b/pkg/engine/callref_test.go new file mode 100644 index 0000000..3a66492 --- /dev/null +++ b/pkg/engine/callref_test.go @@ -0,0 +1,77 @@ +// Unless explicitly stated otherwise all files in this repository are licensed +// under the MIT License. +// This product includes software developed at Guance Cloud (https://www.guance.com/). +// Copyright 2021-present Guance, Inc. + +package engine + +import ( + "testing" + + "github.com/GuanceCloud/platypus/pkg/inimpl/guancecloud/funcs" + "github.com/stretchr/testify/assert" +) + +type testcase struct { + desc string + script map[string]string + err map[string]string +} + +func TestCallRefCheck(t *testing.T) { + cases := []testcase{ + { + desc: "0", + script: map[string]string{ + "a.p": "use(\"b.p\")", + "b.p": "a b", + }, + err: map[string]string{ + "a.p": "b.p:1:3: unexpected: id \"b\"\na.p:1:1:", + "b.p": "b.p:1:3: unexpected: id \"b\"", + }, + }, + { + desc: "1", + script: map[string]string{ + "a.p": "use(\"b.p\")", + "b.p": "use(\"c.p\")", + "c.p": "use(\"x.p\")", + }, + err: map[string]string{ + "a.p": "c.p:1:1: script x.p not found\nb.p:1:1:\na.p:1:1:", + "b.p": "c.p:1:1: script x.p not found\nb.p:1:1:", + "c.p": "c.p:1:1: script x.p not found", + }, + }, + { + desc: "2", + script: map[string]string{ + "a.p": "use(\"b.p\")", + "b.p": "use(\"c.p\")", + "c.p": "use(\"b.p\")", + }, + err: map[string]string{ + "a.p": "a.p:1:1: circular dependency: a.p -> b.p -> c.p -> b.p\nc.p:1:1:\nb.p:1:1:\na.p:1:1:", + "b.p": "b.p:1:1: circular dependency: b.p -> c.p -> b.p\nc.p:1:1:\nb.p:1:1:", + "c.p": "c.p:1:1: circular dependency: c.p -> b.p -> c.p\nb.p:1:1:\nc.p:1:1:", + }, + }, + { + desc: "3", + script: map[string]string{ + "c.p": "a = 1; {1:2}", + }, + err: map[string]string{"c.p": "c.p:1:9: map key expect string"}, + }, + } + + for _, c := range cases { + _, retE := ParseScript(c.script, funcs.FuncsMap, funcs.FuncsCheckMap) + actE := map[string]string{} + for k, v := range retE { + actE[k] = v.Error() + } + assert.Equal(t, c.err, actE) + } +} diff --git a/pkg/engine/engine.go b/pkg/engine/engine.go index 6607530..6c6d066 100644 --- a/pkg/engine/engine.go +++ b/pkg/engine/engine.go @@ -11,6 +11,7 @@ import ( "path/filepath" plruntime "github.com/GuanceCloud/platypus/pkg/engine/runtime" + "github.com/GuanceCloud/platypus/pkg/errchain" "github.com/GuanceCloud/platypus/pkg/parser" ) @@ -22,7 +23,7 @@ func ParseScript(scripts map[string]string, retMap := map[string]*plruntime.Script{} for name, content := range scripts { - stmts, err := parser.ParsePipeline(content) + stmts, err := parser.ParsePipeline(name, content) if err != nil { retErrMap[name] = err continue @@ -36,7 +37,7 @@ func ParseScript(scripts map[string]string, if err := CheckScript(p, check); err != nil { // TODO - retErrMap[name] = err.ChainError() + retErrMap[name] = err continue } retMap[name] = p @@ -50,19 +51,19 @@ func ParseScript(scripts map[string]string, return retMap, retErrMap } -func RunScriptWithoutMapIn(proc *plruntime.Script, data plruntime.InputWithoutMap, signal plruntime.Signal) *plruntime.RuntimeError { +func RunScriptWithoutMapIn(proc *plruntime.Script, data plruntime.InputWithoutMap, signal plruntime.Signal) *errchain.PlError { return plruntime.RunScriptWithoutMapIn(proc, data, signal) } -func RunScriptWithRMapIn(proc *plruntime.Script, data plruntime.InputWithRMap, signal plruntime.Signal) *plruntime.RuntimeError { +func RunScriptWithRMapIn(proc *plruntime.Script, data plruntime.InputWithRMap, signal plruntime.Signal) *errchain.PlError { return plruntime.RunScriptWithRMapIn(proc, data, signal) } -func RunScriptRef(ctx *plruntime.Context, proc *plruntime.Script) *plruntime.RuntimeError { +func RunScriptRef(ctx *plruntime.Context, proc *plruntime.Script) *errchain.PlError { return plruntime.RefRunScript(ctx, proc) } -func CheckScript(proc *plruntime.Script, funcsCheck map[string]plruntime.FuncCheck) *plruntime.RuntimeError { +func CheckScript(proc *plruntime.Script, funcsCheck map[string]plruntime.FuncCheck) *errchain.PlError { return plruntime.CheckScript(proc, funcsCheck) } diff --git a/pkg/engine/error.go b/pkg/engine/error.go deleted file mode 100644 index 3460164..0000000 --- a/pkg/engine/error.go +++ /dev/null @@ -1,6 +0,0 @@ -// Unless explicitly stated otherwise all files in this repository are licensed -// under the MIT License. -// This product includes software developed at Guance Cloud (https://www.guance.com/). -// Copyright 2021-present Guance, Inc. - -package engine diff --git a/pkg/engine/op_test.go b/pkg/engine/op_test.go index 8475c70..73c131e 100644 --- a/pkg/engine/op_test.go +++ b/pkg/engine/op_test.go @@ -101,7 +101,7 @@ for a = 0; a < 12; a = a + 1 { pt = input.InitPt(pt, "test", nil, nil, time.Now()) err := runtime.RunScriptWithRMapIn(script, pt, nil) if err != nil { - t.Fatal(err.ChainError()) + t.Fatal(err.Error()) } t.Log(pt) diff --git a/pkg/engine/runtime/checkstmt.go b/pkg/engine/runtime/checkstmt.go index 33046d7..32f3262 100644 --- a/pkg/engine/runtime/checkstmt.go +++ b/pkg/engine/runtime/checkstmt.go @@ -9,6 +9,7 @@ import ( "fmt" "github.com/GuanceCloud/platypus/pkg/ast" + "github.com/GuanceCloud/platypus/pkg/errchain" ) type ContextCheck struct { @@ -18,7 +19,7 @@ type ContextCheck struct { continuestmt bool } -func RunStmtsCheck(ctx *Context, ctxCheck *ContextCheck, nodes ast.Stmts) *RuntimeError { +func RunStmtsCheck(ctx *Context, ctxCheck *ContextCheck, nodes ast.Stmts) *errchain.PlError { for _, node := range nodes { if err := RunStmtCheck(ctx, ctxCheck, node); err != nil { return err @@ -27,12 +28,12 @@ func RunStmtsCheck(ctx *Context, ctxCheck *ContextCheck, nodes ast.Stmts) *Runti return nil } -func RunStmtCheck(ctx *Context, ctxCheck *ContextCheck, node *ast.Node) *RuntimeError { +func RunStmtCheck(ctx *Context, ctxCheck *ContextCheck, node *ast.Node) *errchain.PlError { if node == nil { return nil } switch node.NodeType { //nolint:exhaustive - case ast.TypeInvaild: + case ast.TypeInvalid: // skip case ast.TypeIdentifier: // skip @@ -85,22 +86,22 @@ func RunStmtCheck(ctx *Context, ctxCheck *ContextCheck, node *ast.Node) *Runtime return nil } -func RunListInitExprCheck(ctx *Context, ctxCheck *ContextCheck, expr *ast.ListInitExpr) *RuntimeError { +func RunListInitExprCheck(ctx *Context, ctxCheck *ContextCheck, expr *ast.ListInitExpr) *errchain.PlError { for _, v := range expr.List { if err := RunStmtCheck(ctx, ctxCheck, v); err != nil { - return err.ChainAppend(ctx, expr.LBracket) + return err.ChainAppend(ctx.name, expr.LBracket) } } return nil } -func RunMapInitExprCheck(ctx *Context, ctxCheck *ContextCheck, expr *ast.MapInitExpr) *RuntimeError { +func RunMapInitExprCheck(ctx *Context, ctxCheck *ContextCheck, expr *ast.MapInitExpr) *errchain.PlError { for _, v := range expr.KeyValeList { switch v[0].NodeType { //nolint:exhaustive case ast.TypeFloatLiteral, ast.TypeIntegerLiteral, ast.TypeBoolLiteral, ast.TypeNilLiteral, ast.TypeListInitExpr, ast.TypeMapInitExpr: - return NewRunError(ctx, "map key expect string: %s", + return NewRunError(ctx, "map key expect string", ast.NodeStartPos(v[0])) default: } @@ -114,11 +115,11 @@ func RunMapInitExprCheck(ctx *Context, ctxCheck *ContextCheck, expr *ast.MapInit return nil } -func RunParenExprCheck(ctx *Context, ctxCheck *ContextCheck, expr *ast.ParenExpr) *RuntimeError { +func RunParenExprCheck(ctx *Context, ctxCheck *ContextCheck, expr *ast.ParenExpr) *errchain.PlError { return RunStmtCheck(ctx, ctxCheck, expr.Param) } -func RunAttrExprCheck(ctx *Context, ctxCheck *ContextCheck, expr *ast.AttrExpr) *RuntimeError { +func RunAttrExprCheck(ctx *Context, ctxCheck *ContextCheck, expr *ast.AttrExpr) *errchain.PlError { if err := RunStmtCheck(ctx, ctxCheck, expr.Obj); err != nil { return err } @@ -129,7 +130,7 @@ func RunAttrExprCheck(ctx *Context, ctxCheck *ContextCheck, expr *ast.AttrExpr) return nil } -func RunArithmeticExprCheck(ctx *Context, ctxCheck *ContextCheck, expr *ast.ArithmeticExpr) *RuntimeError { +func RunArithmeticExprCheck(ctx *Context, ctxCheck *ContextCheck, expr *ast.ArithmeticExpr) *errchain.PlError { if err := RunStmtCheck(ctx, ctxCheck, expr.LHS); err != nil { return err } @@ -143,7 +144,7 @@ func RunArithmeticExprCheck(ctx *Context, ctxCheck *ContextCheck, expr *ast.Arit return nil } -func RunConditionExprCheck(ctx *Context, ctxCheck *ContextCheck, expr *ast.ConditionalExpr) *RuntimeError { +func RunConditionExprCheck(ctx *Context, ctxCheck *ContextCheck, expr *ast.ConditionalExpr) *errchain.PlError { if err := RunStmtCheck(ctx, ctxCheck, expr.LHS); err != nil { return err } @@ -153,7 +154,7 @@ func RunConditionExprCheck(ctx *Context, ctxCheck *ContextCheck, expr *ast.Condi return nil } -func RunIndexExprGetCheck(ctx *Context, ctxCheck *ContextCheck, expr *ast.IndexExpr) *RuntimeError { +func RunIndexExprGetCheck(ctx *Context, ctxCheck *ContextCheck, expr *ast.IndexExpr) *errchain.PlError { for _, v := range expr.Index { if err := RunStmtCheck(ctx, ctxCheck, v); err != nil { return err @@ -162,7 +163,7 @@ func RunIndexExprGetCheck(ctx *Context, ctxCheck *ContextCheck, expr *ast.IndexE return nil } -func RunCallExprCheck(ctx *Context, ctxCheck *ContextCheck, expr *ast.CallExpr) *RuntimeError { +func RunCallExprCheck(ctx *Context, ctxCheck *ContextCheck, expr *ast.CallExpr) *errchain.PlError { _, ok := ctx.GetFuncCall(expr.Name) if !ok { return NewRunError(ctx, fmt.Sprintf( @@ -170,7 +171,7 @@ func RunCallExprCheck(ctx *Context, ctxCheck *ContextCheck, expr *ast.CallExpr) } if err := RunStmtsCheck(ctx, ctxCheck, expr.Param); err != nil { - return err.ChainAppend(ctx, expr.NamePos) + return err.ChainAppend(ctx.name, expr.NamePos) } funcCheck, ok := ctx.GetFuncCheck(expr.Name) @@ -182,7 +183,7 @@ func RunCallExprCheck(ctx *Context, ctxCheck *ContextCheck, expr *ast.CallExpr) return funcCheck(ctx, expr) } -func RunAssignmentExprCheck(ctx *Context, ctxCheck *ContextCheck, expr *ast.AssignmentExpr) *RuntimeError { +func RunAssignmentExprCheck(ctx *Context, ctxCheck *ContextCheck, expr *ast.AssignmentExpr) *errchain.PlError { if err := RunStmtCheck(ctx, ctxCheck, expr.RHS); err != nil { return err } @@ -192,7 +193,7 @@ func RunAssignmentExprCheck(ctx *Context, ctxCheck *ContextCheck, expr *ast.Assi return nil } -func RunIfElseStmtCheck(ctx *Context, ctxCheck *ContextCheck, stmt *ast.IfelseStmt) *RuntimeError { +func RunIfElseStmtCheck(ctx *Context, ctxCheck *ContextCheck, stmt *ast.IfelseStmt) *errchain.PlError { ctx.StackEnterNew() defer ctx.StackExitCur() @@ -221,7 +222,7 @@ func RunIfElseStmtCheck(ctx *Context, ctxCheck *ContextCheck, stmt *ast.IfelseSt return nil } -func RunForStmtCheck(ctx *Context, ctxCheck *ContextCheck, stmt *ast.ForStmt) *RuntimeError { +func RunForStmtCheck(ctx *Context, ctxCheck *ContextCheck, stmt *ast.ForStmt) *errchain.PlError { ctx.StackEnterNew() defer ctx.StackExitCur() @@ -259,7 +260,7 @@ func RunForStmtCheck(ctx *Context, ctxCheck *ContextCheck, stmt *ast.ForStmt) *R return nil } -func RunForInStmtCheck(ctx *Context, ctxCheck *ContextCheck, stmt *ast.ForInStmt) *RuntimeError { +func RunForInStmtCheck(ctx *Context, ctxCheck *ContextCheck, stmt *ast.ForInStmt) *errchain.PlError { ctx.StackEnterNew() defer ctx.StackExitCur() @@ -294,7 +295,7 @@ func RunForInStmtCheck(ctx *Context, ctxCheck *ContextCheck, stmt *ast.ForInStmt return nil } -func RunBreakStmtCheck(ctx *Context, ctxCheck *ContextCheck, stmt *ast.BreakStmt) *RuntimeError { +func RunBreakStmtCheck(ctx *Context, ctxCheck *ContextCheck, stmt *ast.BreakStmt) *errchain.PlError { if len(ctxCheck.forstmt) == 0 { return NewRunError(ctx, "break not in loop", stmt.Start) } @@ -302,7 +303,7 @@ func RunBreakStmtCheck(ctx *Context, ctxCheck *ContextCheck, stmt *ast.BreakStmt return nil } -func RunContinueStmtCheck(ctx *Context, ctxCheck *ContextCheck, stmt *ast.ContinueStmt) *RuntimeError { +func RunContinueStmtCheck(ctx *Context, ctxCheck *ContextCheck, stmt *ast.ContinueStmt) *errchain.PlError { if len(ctxCheck.forstmt) == 0 { return NewRunError(ctx, "continue not in loop", stmt.Start) } diff --git a/pkg/engine/runtime/context.go b/pkg/engine/runtime/context.go index e7ae120..94a0010 100644 --- a/pkg/engine/runtime/context.go +++ b/pkg/engine/runtime/context.go @@ -21,7 +21,7 @@ const ( ) type Script struct { - CallRef map[string]*Script + CallRef []*ast.CallExpr FuncCall map[string]FuncCall @@ -60,7 +60,7 @@ type Context struct { procExit bool - callRCef map[string]*Script + callRCef []*ast.CallExpr name string content string @@ -68,6 +68,10 @@ type Context struct { // filepath string } +func (ctx *Context) Name() string { + return ctx.name +} + func (ctx *Context) InData() any { switch ctx.inType { case InRMap: @@ -78,7 +82,7 @@ func (ctx *Context) InData() any { } func InitCtxWithoutMap(ctx *Context, inWithoutMap InputWithoutMap, funcs map[string]FuncCall, - callRef map[string]*Script, signal Signal, name, content string, + callRef []*ast.CallExpr, signal Signal, name, content string, ) *Context { ctx.Regs.Reset() @@ -102,7 +106,7 @@ func InitCtxWithoutMap(ctx *Context, inWithoutMap InputWithoutMap, funcs map[str } func InitCtxWithRMap(ctx *Context, inWithRMap InputWithRMap, funcs map[string]FuncCall, - callRef map[string]*Script, signal Signal, name, content string, + callRef []*ast.CallExpr, signal Signal, name, content string, ) *Context { ctx.Regs.Reset() @@ -138,7 +142,7 @@ func InitCtxForCheck(ctx *Context, funcs map[string]FuncCall, funcsCheck map[str ctx.funcCall = funcs ctx.funcCheck = funcsCheck - ctx.callRCef = map[string]*Script{} + ctx.callRCef = []*ast.CallExpr{} ctx.loopBreak = false ctx.loopContinue = false @@ -163,21 +167,11 @@ func (ctx *Context) SetExit() { ctx.procExit = true } -func (ctx *Context) GetCallRef(name string) (*Script, bool) { - if ctx.callRCef == nil { - return nil, false - } - if v, ok := ctx.callRCef[name]; ok && v != nil { - return v, ok - } - return nil, false -} - -func (ctx *Context) SetCallRef(name string) { +func (ctx *Context) SetCallRef(expr *ast.CallExpr) { if ctx.callRCef == nil { - ctx.callRCef = map[string]*Script{} + ctx.callRCef = []*ast.CallExpr{} } - ctx.callRCef[name] = nil + ctx.callRCef = append(ctx.callRCef, expr) } func (ctx *Context) GetKey(key string) (*Varb, error) { diff --git a/pkg/engine/runtime/error.go b/pkg/engine/runtime/error.go index 88fa363..b5584e3 100644 --- a/pkg/engine/runtime/error.go +++ b/pkg/engine/runtime/error.go @@ -6,78 +6,10 @@ package runtime import ( - "fmt" - + "github.com/GuanceCloud/platypus/pkg/errchain" "github.com/GuanceCloud/platypus/pkg/token" ) -type FilePos struct { - Pos token.Pos - - Name string - - Ln int - Col int -} - -type RuntimeError struct { - pos []FilePos - err string -} - -func (e *RuntimeError) ChainError() error { - if len(e.pos) == 0 { - return nil - } - - var errr string - - for i := 0; i < len(e.pos); i++ { - pos := e.pos[i] - if i == 0 { - errr += fmt.Sprintf("%s:%d:%d: %s", pos.Name, pos.Ln, pos.Col, e.err) - } else { - errr += fmt.Sprintf( - "\n%s:%d:%d:", e.pos[i].Name, - e.pos[i].Ln, e.pos[i].Col) - } - } - - return fmt.Errorf(errr) -} - -func (e *RuntimeError) LastError() error { - if len(e.pos) > 0 { - pos := e.pos[0] - return fmt.Errorf("%s:%d:%d: %s", pos.Name, pos.Ln, pos.Col, e.err) - } - return fmt.Errorf(e.err) -} - -// func (e *RuntimeError) callChain() []FilePos { -// ret := []FilePos{} - -// for i := len(e.pos) - 1; i >= 0; i-- { -// ret = append(ret, e.pos[i]) -// } -// return ret -// } - -func (e *RuntimeError) ChainAppend(ctx *Context, pos token.Pos) *RuntimeError { - ln, col, _ := token.LnCol(ctx.content, pos) - e.pos = append(e.pos, FilePos{ - Pos: pos, - Ln: ln, - Col: col, - Name: ctx.name, - }) - return e -} - -func NewRunError(ctx *Context, err string, pos token.Pos) *RuntimeError { - runErr := &RuntimeError{ - err: err, - } - - return runErr.ChainAppend(ctx, pos) +func NewRunError(ctx *Context, err string, pos token.LnColPos) *errchain.PlError { + return errchain.NewErr(ctx.name, pos, err) } diff --git a/pkg/engine/runtime/runtime.go b/pkg/engine/runtime/runtime.go index 7f01535..3a8a34d 100644 --- a/pkg/engine/runtime/runtime.go +++ b/pkg/engine/runtime/runtime.go @@ -11,15 +11,16 @@ import ( "reflect" "github.com/GuanceCloud/platypus/pkg/ast" + "github.com/GuanceCloud/platypus/pkg/errchain" "github.com/spf13/cast" ) type ( - FuncCheck func(*Context, *ast.CallExpr) *RuntimeError - FuncCall func(*Context, *ast.CallExpr) *RuntimeError + FuncCheck func(*Context, *ast.CallExpr) *errchain.PlError + FuncCall func(*Context, *ast.CallExpr) *errchain.PlError ) -func RunScriptWithoutMapIn(proc *Script, data InputWithoutMap, signal Signal) *RuntimeError { +func RunScriptWithoutMapIn(proc *Script, data InputWithoutMap, signal Signal) *errchain.PlError { if proc == nil { return nil } @@ -28,11 +29,10 @@ func RunScriptWithoutMapIn(proc *Script, data InputWithoutMap, signal Signal) *R defer PutContext(ctx) ctx = InitCtxWithoutMap(ctx, data, proc.FuncCall, proc.CallRef, signal, proc.Name, proc.Content) - RunStmts(ctx, proc.Ast) - return nil + return RunStmts(ctx, proc.Ast) } -func RunScriptWithRMapIn(proc *Script, data InputWithRMap, signal Signal) *RuntimeError { +func RunScriptWithRMapIn(proc *Script, data InputWithRMap, signal Signal) *errchain.PlError { if proc == nil { return nil } @@ -44,7 +44,7 @@ func RunScriptWithRMapIn(proc *Script, data InputWithRMap, signal Signal) *Runti return RunStmts(ctx, proc.Ast) } -func RefRunScript(ctx *Context, proc *Script) *RuntimeError { +func RefRunScript(ctx *Context, proc *Script) *errchain.PlError { if proc == nil { return nil } @@ -65,7 +65,7 @@ func RefRunScript(ctx *Context, proc *Script) *RuntimeError { return RunStmts(newctx, proc.Ast) } -func CheckScript(proc *Script, funcsCheck map[string]FuncCheck) *RuntimeError { +func CheckScript(proc *Script, funcsCheck map[string]FuncCheck) *errchain.PlError { ctx := GetContext() defer PutContext(ctx) InitCtxForCheck(ctx, proc.FuncCall, funcsCheck, proc.Name, proc.Content) @@ -77,7 +77,7 @@ func CheckScript(proc *Script, funcsCheck map[string]FuncCheck) *RuntimeError { return nil } -func RunStmts(ctx *Context, nodes ast.Stmts) *RuntimeError { +func RunStmts(ctx *Context, nodes ast.Stmts) *errchain.PlError { for _, node := range nodes { if _, _, err := RunStmt(ctx, node); err != nil { ctx.procExit = true @@ -91,7 +91,7 @@ func RunStmts(ctx *Context, nodes ast.Stmts) *RuntimeError { return nil } -func RunIfElseStmt(ctx *Context, stmt *ast.IfelseStmt) (any, ast.DType, *RuntimeError) { +func RunIfElseStmt(ctx *Context, stmt *ast.IfelseStmt) (any, ast.DType, *errchain.PlError) { ctx.StackEnterNew() defer ctx.StackExitCur() @@ -167,7 +167,7 @@ func condTrue(val any, dtype ast.DType) bool { return true } -func RunForStmt(ctx *Context, stmt *ast.ForStmt) (any, ast.DType, *RuntimeError) { +func RunForStmt(ctx *Context, stmt *ast.ForStmt) (any, ast.DType, *errchain.PlError) { ctx.StackEnterNew() defer ctx.StackExitCur() @@ -224,7 +224,7 @@ func RunForStmt(ctx *Context, stmt *ast.ForStmt) (any, ast.DType, *RuntimeError) return nil, ast.Void, nil } -func RunForInStmt(ctx *Context, stmt *ast.ForInStmt) (any, ast.DType, *RuntimeError) { +func RunForInStmt(ctx *Context, stmt *ast.ForInStmt) (any, ast.DType, *errchain.PlError) { ctx.StackEnterNew() defer ctx.StackExitCur() @@ -334,18 +334,18 @@ func forcontinue(ctx *Context) { } } -func RunBreakStmt(ctx *Context, stmt *ast.BreakStmt) (any, ast.DType, *RuntimeError) { +func RunBreakStmt(ctx *Context, stmt *ast.BreakStmt) (any, ast.DType, *errchain.PlError) { ctx.loopBreak = true return nil, ast.Void, nil } -func RunContinueStmt(ctx *Context, stmt *ast.ContinueStmt) (any, ast.DType, *RuntimeError) { +func RunContinueStmt(ctx *Context, stmt *ast.ContinueStmt) (any, ast.DType, *errchain.PlError) { ctx.loopContinue = true return nil, ast.Void, nil } // RunStmt for all expr. -func RunStmt(ctx *Context, node *ast.Node) (any, ast.DType, *RuntimeError) { +func RunStmt(ctx *Context, node *ast.Node) (any, ast.DType, *errchain.PlError) { // TODO // 存在个别 node 为 nil 的情况 if node == nil { @@ -411,7 +411,7 @@ func RunStmt(ctx *Context, node *ast.Node) (any, ast.DType, *RuntimeError) { } } -func RunListInitExpr(ctx *Context, expr *ast.ListInitExpr) (any, ast.DType, *RuntimeError) { +func RunListInitExpr(ctx *Context, expr *ast.ListInitExpr) (any, ast.DType, *errchain.PlError) { ret := []any{} for _, v := range expr.List { v, _, err := RunStmt(ctx, v) @@ -423,7 +423,7 @@ func RunListInitExpr(ctx *Context, expr *ast.ListInitExpr) (any, ast.DType, *Run return ret, ast.List, nil } -func RunMapInitExpr(ctx *Context, expr *ast.MapInitExpr) (any, ast.DType, *RuntimeError) { +func RunMapInitExpr(ctx *Context, expr *ast.MapInitExpr) (any, ast.DType, *errchain.PlError) { ret := map[string]any{} for _, v := range expr.KeyValeList { @@ -463,7 +463,7 @@ func RunMapInitExpr(ctx *Context, expr *ast.MapInitExpr) (any, ast.DType, *Runti // } // } -func RunIndexExprGet(ctx *Context, expr *ast.IndexExpr) (any, ast.DType, *RuntimeError) { +func RunIndexExprGet(ctx *Context, expr *ast.IndexExpr) (any, ast.DType, *errchain.PlError) { key := expr.Obj.Name varb, err := ctx.GetKey(key) @@ -493,7 +493,7 @@ func RunIndexExprGet(ctx *Context, expr *ast.IndexExpr) (any, ast.DType, *Runtim return searchListAndMap(ctx, varb.Value, expr.Index) } -func searchListAndMap(ctx *Context, obj any, index []*ast.Node) (any, ast.DType, *RuntimeError) { +func searchListAndMap(ctx *Context, obj any, index []*ast.Node) (any, ast.DType, *errchain.PlError) { cur := obj for _, i := range index { @@ -540,13 +540,13 @@ func searchListAndMap(ctx *Context, obj any, index []*ast.Node) (any, ast.DType, return cur, dtype, nil } -func RunParenExpr(ctx *Context, expr *ast.ParenExpr) (any, ast.DType, *RuntimeError) { +func RunParenExpr(ctx *Context, expr *ast.ParenExpr) (any, ast.DType, *errchain.PlError) { return RunStmt(ctx, expr.Param) } // BinarayExpr -func RunConditionExpr(ctx *Context, expr *ast.ConditionalExpr) (any, ast.DType, *RuntimeError) { +func RunConditionExpr(ctx *Context, expr *ast.ConditionalExpr) (any, ast.DType, *errchain.PlError) { lhs, lhsT, err := RunStmt(ctx, expr.LHS) if err != nil { return nil, ast.Invalid, err @@ -577,7 +577,7 @@ func RunConditionExpr(ctx *Context, expr *ast.ConditionalExpr) (any, ast.DType, } } -func RunArithmeticExpr(ctx *Context, expr *ast.ArithmeticExpr) (any, ast.DType, *RuntimeError) { +func RunArithmeticExpr(ctx *Context, expr *ast.ArithmeticExpr) (any, ast.DType, *errchain.PlError) { // 允许字符串通过操作符 '+' 进行拼接 lhsVal, lhsValType, errOpInt := RunStmt(ctx, expr.LHS) @@ -634,7 +634,7 @@ func RunArithmeticExpr(ctx *Context, expr *ast.ArithmeticExpr) (any, ast.DType, return v, dtype, nil } -func RunAssignmentExpr(ctx *Context, expr *ast.AssignmentExpr) (any, ast.DType, *RuntimeError) { +func RunAssignmentExpr(ctx *Context, expr *ast.AssignmentExpr) (any, ast.DType, *errchain.PlError) { v, dtype, err := RunStmt(ctx, expr.RHS) if err != nil { return nil, ast.Invalid, err @@ -656,7 +656,7 @@ func RunAssignmentExpr(ctx *Context, expr *ast.AssignmentExpr) (any, ast.DType, } } -func changeListOrMapValue(ctx *Context, obj any, index []*ast.Node, val any, dtype ast.DType) (any, ast.DType, *RuntimeError) { +func changeListOrMapValue(ctx *Context, obj any, index []*ast.Node, val any, dtype ast.DType) (any, ast.DType, *errchain.PlError) { cur := obj lenIdx := len(index) @@ -713,7 +713,7 @@ func changeListOrMapValue(ctx *Context, obj any, index []*ast.Node, val any, dty return nil, ast.Nil, nil } -func RunCallExpr(ctx *Context, expr *ast.CallExpr) (any, ast.DType, *RuntimeError) { +func RunCallExpr(ctx *Context, expr *ast.CallExpr) (any, ast.DType, *errchain.PlError) { defer ctx.Regs.Reset() if funcCall, ok := ctx.GetFuncCall(expr.Name); ok { if err := funcCall(ctx, expr); err != nil { diff --git a/pkg/engine/runtime/runtime_test.go b/pkg/engine/runtime/runtime_test.go index af03b47..be82dd2 100644 --- a/pkg/engine/runtime/runtime_test.go +++ b/pkg/engine/runtime/runtime_test.go @@ -11,6 +11,7 @@ import ( "testing" "github.com/GuanceCloud/platypus/pkg/ast" + "github.com/GuanceCloud/platypus/pkg/errchain" "github.com/GuanceCloud/platypus/pkg/parser" "github.com/stretchr/testify/assert" ) @@ -183,7 +184,7 @@ add_key(len2, len("123")) errR = RunScriptWithRMapIn(script, inData, nil) if errR != nil { - t.Fatal(errR.ChainError()) + t.Fatal(errR.Error()) } assert.Equal(t, map[string]any{ "aa dw.": `{"1":2,"a":[1,2,5],"d":null}`, @@ -586,14 +587,14 @@ func TestCondOp(t *testing.T) { } func parseScript(content string) (ast.Stmts, error) { - return parser.ParsePipeline(content) + return parser.ParsePipeline("", content) } -func callexprtest(ctx *Context, callExpr *ast.CallExpr) *RuntimeError { +func callexprtest(ctx *Context, callExpr *ast.CallExpr) *errchain.PlError { return nil } -func addkeytest(ctx *Context, callExpr *ast.CallExpr) *RuntimeError { +func addkeytest(ctx *Context, callExpr *ast.CallExpr) *errchain.PlError { key := callExpr.Param[0].Identifier.Name if len(callExpr.Param) > 1 { val, dtype, err := RunStmt(ctx, callExpr.Param[1]) @@ -631,11 +632,11 @@ func addkeytest(ctx *Context, callExpr *ast.CallExpr) *RuntimeError { return nil } -func addkeycheck(ctx *Context, callExpr *ast.CallExpr) *RuntimeError { +func addkeycheck(ctx *Context, callExpr *ast.CallExpr) *errchain.PlError { return nil } -func lentest(ctx *Context, callExpr *ast.CallExpr) *RuntimeError { +func lentest(ctx *Context, callExpr *ast.CallExpr) *errchain.PlError { val, dtype, err := RunStmt(ctx, callExpr.Param[0]) if err != nil { return err @@ -653,6 +654,6 @@ func lentest(ctx *Context, callExpr *ast.CallExpr) *RuntimeError { return nil } -func lencheck(ctx *Context, callexpr *ast.CallExpr) *RuntimeError { +func lencheck(ctx *Context, callexpr *ast.CallExpr) *errchain.PlError { return nil } diff --git a/pkg/errchain/error.go b/pkg/errchain/error.go new file mode 100644 index 0000000..84cf7a5 --- /dev/null +++ b/pkg/errchain/error.go @@ -0,0 +1,83 @@ +// Unless explicitly stated otherwise all files in this repository are licensed +// under the MIT License. +// This product includes software developed at Guance Cloud (https://www.guance.com/). +// Copyright 2021-present Guance, Inc. + +package errchain + +import ( + "fmt" + "strings" + + "github.com/GuanceCloud/platypus/pkg/token" +) + +type FilePos struct { + FilePath string + Ln int + Col int +} + +type PlError struct { + pos []FilePos + err string +} + +type PlErrors []PlError + +func (e PlErrors) Error() string { + errs := []string{} + for _, v := range e { + errs = append(errs, v.Error()) + } + return strings.Join(errs, "\n") +} + +func (e *PlError) Error() string { + if len(e.pos) == 0 { + return "" + } + + var errr string + + for i := 0; i < len(e.pos); i++ { + pos := e.pos[i] + if i == 0 { + errr += fmt.Sprintf("%s:%d:%d: %s", pos.FilePath, pos.Ln, pos.Col, e.err) + } else { + errr += fmt.Sprintf( + "\n%s:%d:%d:", e.pos[i].FilePath, + e.pos[i].Ln, e.pos[i].Col) + } + } + return errr +} + +func (e *PlError) ChainAppend(filepath string, pos token.LnColPos) *PlError { + e.pos = append(e.pos, FilePos{ + Ln: pos.Ln, + Col: pos.Col, + FilePath: filepath, + }) + return e +} + +func (e *PlError) Copy() *PlError { + return &PlError{ + err: e.err, + pos: append([]FilePos{}, e.pos...), + } +} + +func NewErr(filepath string, pos token.LnColPos, err string) *PlError { + return &PlError{ + pos: []FilePos{ + { + FilePath: filepath, + Col: pos.Col, + Ln: pos.Ln, + }, + }, + err: err, + } +} diff --git a/pkg/inimpl/guancecloud/funcs/all.go b/pkg/inimpl/guancecloud/funcs/all.go index ebedc8e..29d45db 100644 --- a/pkg/inimpl/guancecloud/funcs/all.go +++ b/pkg/inimpl/guancecloud/funcs/all.go @@ -12,7 +12,7 @@ import ( "go.uber.org/zap" ) -var l logger.Logger = logger.NewStdoutLogger("funcs", "debug") +var l logger.Logger = logger.NewStdoutLogger("funcs", zap.DebugLevel) func InitLog(logger *zap.SugaredLogger) { l = logger diff --git a/pkg/inimpl/guancecloud/funcs/fn_addkey.go b/pkg/inimpl/guancecloud/funcs/fn_addkey.go index 7009d02..453a797 100644 --- a/pkg/inimpl/guancecloud/funcs/fn_addkey.go +++ b/pkg/inimpl/guancecloud/funcs/fn_addkey.go @@ -10,10 +10,12 @@ import ( "github.com/GuanceCloud/platypus/pkg/ast" "github.com/GuanceCloud/platypus/pkg/engine/runtime" + "github.com/GuanceCloud/platypus/pkg/errchain" "github.com/GuanceCloud/platypus/pkg/inimpl/guancecloud/input" + "github.com/GuanceCloud/platypus/pkg/token" ) -func AddkeyChecking(ctx *runtime.Context, funcExpr *ast.CallExpr) *runtime.RuntimeError { +func AddkeyChecking(ctx *runtime.Context, funcExpr *ast.CallExpr) *errchain.PlError { if len(funcExpr.Param) > 2 || len(funcExpr.Param) < 1 { return runtime.NewRunError(ctx, fmt.Sprintf( "func %s expected 1 or 2 args", funcExpr.Name), funcExpr.NamePos) @@ -26,9 +28,9 @@ func AddkeyChecking(ctx *runtime.Context, funcExpr *ast.CallExpr) *runtime.Runti return nil } -func AddKey(ctx *runtime.Context, funcExpr *ast.CallExpr) *runtime.RuntimeError { +func AddKey(ctx *runtime.Context, funcExpr *ast.CallExpr) *errchain.PlError { if funcExpr == nil { - return runtime.NewRunError(ctx, "unreachable", -1) + return runtime.NewRunError(ctx, "unreachable", token.InvalidLnColPos) } if len(funcExpr.Param) != 2 && len(funcExpr.Param) != 1 { return runtime.NewRunError(ctx, fmt.Sprintf( @@ -55,7 +57,7 @@ func AddKey(ctx *runtime.Context, funcExpr *ast.CallExpr) *runtime.RuntimeError val, dtype, errRun := runtime.RunStmt(ctx, funcExpr.Param[1]) if errRun != nil { - return errRun.ChainAppend(ctx, funcExpr.NamePos) + return errRun.ChainAppend(ctx.Name(), funcExpr.NamePos) } if err := addKey2PtWithVal(ctx.InData(), key, val, dtype, input.KindPtDefault); err != nil { l.Debug(err) diff --git a/pkg/inimpl/guancecloud/funcs/fn_addpattern.go b/pkg/inimpl/guancecloud/funcs/fn_addpattern.go index 0ab6789..1d293a2 100644 --- a/pkg/inimpl/guancecloud/funcs/fn_addpattern.go +++ b/pkg/inimpl/guancecloud/funcs/fn_addpattern.go @@ -11,9 +11,10 @@ import ( "github.com/GuanceCloud/grok" "github.com/GuanceCloud/platypus/pkg/ast" "github.com/GuanceCloud/platypus/pkg/engine/runtime" + "github.com/GuanceCloud/platypus/pkg/errchain" ) -func AddPatternChecking(ctx *runtime.Context, funcExpr *ast.CallExpr) *runtime.RuntimeError { +func AddPatternChecking(ctx *runtime.Context, funcExpr *ast.CallExpr) *errchain.PlError { if len(funcExpr.Param) != 2 { return runtime.NewRunError(ctx, fmt.Sprintf( "func %s expected 2 args", funcExpr.Name), funcExpr.NamePos) @@ -44,6 +45,6 @@ func AddPatternChecking(ctx *runtime.Context, funcExpr *ast.CallExpr) *runtime.R return nil } -func AddPattern(ctx *runtime.Context, funcExpr *ast.CallExpr) *runtime.RuntimeError { +func AddPattern(ctx *runtime.Context, funcExpr *ast.CallExpr) *errchain.PlError { return nil } diff --git a/pkg/inimpl/guancecloud/funcs/fn_cast.go b/pkg/inimpl/guancecloud/funcs/fn_cast.go index ef8f329..dc288b3 100644 --- a/pkg/inimpl/guancecloud/funcs/fn_cast.go +++ b/pkg/inimpl/guancecloud/funcs/fn_cast.go @@ -10,10 +10,11 @@ import ( "github.com/GuanceCloud/platypus/pkg/ast" "github.com/GuanceCloud/platypus/pkg/engine/runtime" + "github.com/GuanceCloud/platypus/pkg/errchain" "github.com/GuanceCloud/platypus/pkg/inimpl/guancecloud/input" ) -func CastChecking(ctx *runtime.Context, funcExpr *ast.CallExpr) *runtime.RuntimeError { +func CastChecking(ctx *runtime.Context, funcExpr *ast.CallExpr) *errchain.PlError { if len(funcExpr.Param) != 2 { return runtime.NewRunError(ctx, fmt.Sprintf( "func `%s' expected 2 args", funcExpr.Name), funcExpr.NamePos) @@ -37,7 +38,7 @@ func CastChecking(ctx *runtime.Context, funcExpr *ast.CallExpr) *runtime.Runtime return nil } -func Cast(ctx *runtime.Context, funcExpr *ast.CallExpr) *runtime.RuntimeError { +func Cast(ctx *runtime.Context, funcExpr *ast.CallExpr) *errchain.PlError { if len(funcExpr.Param) != 2 { return runtime.NewRunError(ctx, fmt.Sprintf( "func `%s' expected 2 args", funcExpr.Name), funcExpr.NamePos) diff --git a/pkg/inimpl/guancecloud/funcs/fn_datetime.go b/pkg/inimpl/guancecloud/funcs/fn_datetime.go index 2ab588f..30830c1 100644 --- a/pkg/inimpl/guancecloud/funcs/fn_datetime.go +++ b/pkg/inimpl/guancecloud/funcs/fn_datetime.go @@ -10,10 +10,11 @@ import ( "github.com/GuanceCloud/platypus/pkg/ast" "github.com/GuanceCloud/platypus/pkg/engine/runtime" + "github.com/GuanceCloud/platypus/pkg/errchain" "github.com/GuanceCloud/platypus/pkg/inimpl/guancecloud/input" ) -func DateTimeChecking(ctx *runtime.Context, funcExpr *ast.CallExpr) *runtime.RuntimeError { +func DateTimeChecking(ctx *runtime.Context, funcExpr *ast.CallExpr) *errchain.PlError { if len(funcExpr.Param) != 3 { return runtime.NewRunError(ctx, fmt.Sprintf( "func %s expected 3 args", funcExpr.Name), funcExpr.NamePos) @@ -41,7 +42,7 @@ func DateTimeChecking(ctx *runtime.Context, funcExpr *ast.CallExpr) *runtime.Run return nil } -func DateTime(ctx *runtime.Context, funcExpr *ast.CallExpr) *runtime.RuntimeError { +func DateTime(ctx *runtime.Context, funcExpr *ast.CallExpr) *errchain.PlError { if len(funcExpr.Param) != 3 { return runtime.NewRunError(ctx, fmt.Sprintf( "func %s expected 3 args", funcExpr.Name), funcExpr.NamePos) diff --git a/pkg/inimpl/guancecloud/funcs/fn_default_time.go b/pkg/inimpl/guancecloud/funcs/fn_default_time.go index 12d4035..1dfb726 100644 --- a/pkg/inimpl/guancecloud/funcs/fn_default_time.go +++ b/pkg/inimpl/guancecloud/funcs/fn_default_time.go @@ -11,10 +11,11 @@ import ( "github.com/GuanceCloud/platypus/pkg/ast" "github.com/GuanceCloud/platypus/pkg/engine/runtime" + "github.com/GuanceCloud/platypus/pkg/errchain" "github.com/GuanceCloud/platypus/pkg/inimpl/guancecloud/input" ) -func DefaultTimeChecking(ctx *runtime.Context, funcExpr *ast.CallExpr) *runtime.RuntimeError { +func DefaultTimeChecking(ctx *runtime.Context, funcExpr *ast.CallExpr) *errchain.PlError { if len(funcExpr.Param) < 1 { return runtime.NewRunError(ctx, fmt.Sprintf( "func %s Expect at least one arg", funcExpr.Name), funcExpr.NamePos) @@ -36,7 +37,7 @@ func DefaultTimeChecking(ctx *runtime.Context, funcExpr *ast.CallExpr) *runtime. return nil } -func DefaultTime(ctx *runtime.Context, funcExpr *ast.CallExpr) *runtime.RuntimeError { +func DefaultTime(ctx *runtime.Context, funcExpr *ast.CallExpr) *errchain.PlError { if len(funcExpr.Param) < 1 { return runtime.NewRunError(ctx, fmt.Sprintf( "func %s expect at least one arg", funcExpr.Name), funcExpr.NamePos) diff --git a/pkg/inimpl/guancecloud/funcs/fn_dropkey.go b/pkg/inimpl/guancecloud/funcs/fn_dropkey.go index 954cb13..9567938 100644 --- a/pkg/inimpl/guancecloud/funcs/fn_dropkey.go +++ b/pkg/inimpl/guancecloud/funcs/fn_dropkey.go @@ -10,9 +10,10 @@ import ( "github.com/GuanceCloud/platypus/pkg/ast" "github.com/GuanceCloud/platypus/pkg/engine/runtime" + "github.com/GuanceCloud/platypus/pkg/errchain" ) -func DropkeyChecking(ctx *runtime.Context, funcExpr *ast.CallExpr) *runtime.RuntimeError { +func DropkeyChecking(ctx *runtime.Context, funcExpr *ast.CallExpr) *errchain.PlError { if len(funcExpr.Param) != 1 { return runtime.NewRunError(ctx, fmt.Sprintf( "func %s expected 1 args", funcExpr.Name), funcExpr.NamePos) @@ -25,7 +26,7 @@ func DropkeyChecking(ctx *runtime.Context, funcExpr *ast.CallExpr) *runtime.Runt return nil } -func Dropkey(ctx *runtime.Context, funcExpr *ast.CallExpr) *runtime.RuntimeError { +func Dropkey(ctx *runtime.Context, funcExpr *ast.CallExpr) *errchain.PlError { if len(funcExpr.Param) != 1 { return runtime.NewRunError(ctx, fmt.Sprintf( "func %s expected 1 args", funcExpr.Name), funcExpr.NamePos) diff --git a/pkg/inimpl/guancecloud/funcs/fn_exit.go b/pkg/inimpl/guancecloud/funcs/fn_exit.go index 49d170f..9bd1a99 100644 --- a/pkg/inimpl/guancecloud/funcs/fn_exit.go +++ b/pkg/inimpl/guancecloud/funcs/fn_exit.go @@ -8,13 +8,14 @@ package funcs import ( "github.com/GuanceCloud/platypus/pkg/ast" "github.com/GuanceCloud/platypus/pkg/engine/runtime" + "github.com/GuanceCloud/platypus/pkg/errchain" ) -func ExitChecking(ctx *runtime.Context, node *ast.CallExpr) *runtime.RuntimeError { +func ExitChecking(ctx *runtime.Context, node *ast.CallExpr) *errchain.PlError { return nil } -func Exit(ctx *runtime.Context, node *ast.CallExpr) *runtime.RuntimeError { +func Exit(ctx *runtime.Context, node *ast.CallExpr) *errchain.PlError { ctx.SetExit() return nil } diff --git a/pkg/inimpl/guancecloud/funcs/fn_getkey.go b/pkg/inimpl/guancecloud/funcs/fn_getkey.go index 584f5fd..df000a6 100644 --- a/pkg/inimpl/guancecloud/funcs/fn_getkey.go +++ b/pkg/inimpl/guancecloud/funcs/fn_getkey.go @@ -10,9 +10,10 @@ import ( "github.com/GuanceCloud/platypus/pkg/ast" "github.com/GuanceCloud/platypus/pkg/engine/runtime" + "github.com/GuanceCloud/platypus/pkg/errchain" ) -func GetkeyChecking(ctx *runtime.Context, funcExpr *ast.CallExpr) *runtime.RuntimeError { +func GetkeyChecking(ctx *runtime.Context, funcExpr *ast.CallExpr) *errchain.PlError { if len(funcExpr.Param) != 1 { return runtime.NewRunError(ctx, fmt.Sprintf( "func %s expected 1 args", funcExpr.Name), funcExpr.NamePos) @@ -25,7 +26,7 @@ func GetkeyChecking(ctx *runtime.Context, funcExpr *ast.CallExpr) *runtime.Runti return nil } -func Getkey(ctx *runtime.Context, funcExpr *ast.CallExpr) *runtime.RuntimeError { +func Getkey(ctx *runtime.Context, funcExpr *ast.CallExpr) *errchain.PlError { if funcExpr == nil { return runtime.NewRunError(ctx, "unreachable", funcExpr.NamePos) } diff --git a/pkg/inimpl/guancecloud/funcs/fn_grok.go b/pkg/inimpl/guancecloud/funcs/fn_grok.go index 91173f0..7aa40f9 100644 --- a/pkg/inimpl/guancecloud/funcs/fn_grok.go +++ b/pkg/inimpl/guancecloud/funcs/fn_grok.go @@ -11,10 +11,11 @@ import ( "github.com/GuanceCloud/grok" "github.com/GuanceCloud/platypus/pkg/ast" "github.com/GuanceCloud/platypus/pkg/engine/runtime" + "github.com/GuanceCloud/platypus/pkg/errchain" "github.com/GuanceCloud/platypus/pkg/inimpl/guancecloud/input" ) -func GrokChecking(ctx *runtime.Context, funcExpr *ast.CallExpr) *runtime.RuntimeError { +func GrokChecking(ctx *runtime.Context, funcExpr *ast.CallExpr) *errchain.PlError { if funcExpr.Grok != nil { return nil } @@ -56,7 +57,7 @@ func GrokChecking(ctx *runtime.Context, funcExpr *ast.CallExpr) *runtime.Runtime return nil } -func Grok(ctx *runtime.Context, funcExpr *ast.CallExpr) *runtime.RuntimeError { +func Grok(ctx *runtime.Context, funcExpr *ast.CallExpr) *errchain.PlError { grokRe := funcExpr.Grok if grokRe == nil { ctx.Regs.ReturnAppend(false, ast.Bool) diff --git a/pkg/inimpl/guancecloud/funcs/fn_len.go b/pkg/inimpl/guancecloud/funcs/fn_len.go index 28a282d..bcd1be4 100644 --- a/pkg/inimpl/guancecloud/funcs/fn_len.go +++ b/pkg/inimpl/guancecloud/funcs/fn_len.go @@ -10,9 +10,10 @@ import ( "github.com/GuanceCloud/platypus/pkg/ast" "github.com/GuanceCloud/platypus/pkg/engine/runtime" + "github.com/GuanceCloud/platypus/pkg/errchain" ) -func LenChecking(ctx *runtime.Context, funcExpr *ast.CallExpr) *runtime.RuntimeError { +func LenChecking(ctx *runtime.Context, funcExpr *ast.CallExpr) *errchain.PlError { if len(funcExpr.Param) != 1 { return runtime.NewRunError(ctx, fmt.Sprintf( "func %s expected 1", funcExpr.Name), funcExpr.NamePos) @@ -20,7 +21,7 @@ func LenChecking(ctx *runtime.Context, funcExpr *ast.CallExpr) *runtime.RuntimeE return nil } -func Len(ctx *runtime.Context, funcExpr *ast.CallExpr) *runtime.RuntimeError { +func Len(ctx *runtime.Context, funcExpr *ast.CallExpr) *errchain.PlError { val, dtype, err := runtime.RunStmt(ctx, funcExpr.Param[0]) if err != nil { return err diff --git a/pkg/inimpl/guancecloud/funcs/fn_load_json.go b/pkg/inimpl/guancecloud/funcs/fn_load_json.go index 7fc4b1f..1840e27 100644 --- a/pkg/inimpl/guancecloud/funcs/fn_load_json.go +++ b/pkg/inimpl/guancecloud/funcs/fn_load_json.go @@ -11,9 +11,10 @@ import ( "github.com/GuanceCloud/platypus/pkg/ast" "github.com/GuanceCloud/platypus/pkg/engine/runtime" + "github.com/GuanceCloud/platypus/pkg/errchain" ) -func LoadJSONChecking(ctx *runtime.Context, funcExpr *ast.CallExpr) *runtime.RuntimeError { +func LoadJSONChecking(ctx *runtime.Context, funcExpr *ast.CallExpr) *errchain.PlError { if len(funcExpr.Param) != 1 { return runtime.NewRunError(ctx, fmt.Sprintf( "func %s expected 1", funcExpr.Name), funcExpr.NamePos) @@ -21,7 +22,7 @@ func LoadJSONChecking(ctx *runtime.Context, funcExpr *ast.CallExpr) *runtime.Run return nil } -func LoadJSON(ctx *runtime.Context, funcExpr *ast.CallExpr) *runtime.RuntimeError { +func LoadJSON(ctx *runtime.Context, funcExpr *ast.CallExpr) *errchain.PlError { val, dtype, err := runtime.RunStmt(ctx, funcExpr.Param[0]) if err != nil { return err diff --git a/pkg/inimpl/guancecloud/funcs/fn_printf.go b/pkg/inimpl/guancecloud/funcs/fn_printf.go index 4d06372..3f9c372 100644 --- a/pkg/inimpl/guancecloud/funcs/fn_printf.go +++ b/pkg/inimpl/guancecloud/funcs/fn_printf.go @@ -10,10 +10,11 @@ import ( "github.com/GuanceCloud/platypus/pkg/ast" "github.com/GuanceCloud/platypus/pkg/engine/runtime" + "github.com/GuanceCloud/platypus/pkg/errchain" "github.com/spf13/cast" ) -func PrintfChecking(ctx *runtime.Context, funcExpr *ast.CallExpr) *runtime.RuntimeError { +func PrintfChecking(ctx *runtime.Context, funcExpr *ast.CallExpr) *errchain.PlError { if len(funcExpr.Param) < 1 { return runtime.NewRunError(ctx, "function `%s' requires at least one argument", funcExpr.NamePos) } @@ -23,7 +24,7 @@ func PrintfChecking(ctx *runtime.Context, funcExpr *ast.CallExpr) *runtime.Runti return nil } -func Printf(ctx *runtime.Context, funcExpr *ast.CallExpr) *runtime.RuntimeError { +func Printf(ctx *runtime.Context, funcExpr *ast.CallExpr) *errchain.PlError { outdata := make([]interface{}, 0) if len(funcExpr.Param) < 1 { diff --git a/pkg/inimpl/guancecloud/funcs/fn_rename.go b/pkg/inimpl/guancecloud/funcs/fn_rename.go index a891f1f..538c446 100644 --- a/pkg/inimpl/guancecloud/funcs/fn_rename.go +++ b/pkg/inimpl/guancecloud/funcs/fn_rename.go @@ -10,9 +10,10 @@ import ( "github.com/GuanceCloud/platypus/pkg/ast" "github.com/GuanceCloud/platypus/pkg/engine/runtime" + "github.com/GuanceCloud/platypus/pkg/errchain" ) -func RenameChecking(ctx *runtime.Context, funcExpr *ast.CallExpr) *runtime.RuntimeError { +func RenameChecking(ctx *runtime.Context, funcExpr *ast.CallExpr) *errchain.PlError { if len(funcExpr.Param) != 2 { return runtime.NewRunError(ctx, fmt.Sprintf( "func %s expected 2 args", funcExpr.Name), funcExpr.NamePos) @@ -32,7 +33,7 @@ func RenameChecking(ctx *runtime.Context, funcExpr *ast.CallExpr) *runtime.Runti return nil } -func Rename(ctx *runtime.Context, funcExpr *ast.CallExpr) *runtime.RuntimeError { +func Rename(ctx *runtime.Context, funcExpr *ast.CallExpr) *errchain.PlError { if len(funcExpr.Param) != 2 { return runtime.NewRunError(ctx, fmt.Sprintf( "func %s expected 2 args", funcExpr.Name), funcExpr.NamePos) diff --git a/pkg/inimpl/guancecloud/funcs/fn_replace.go b/pkg/inimpl/guancecloud/funcs/fn_replace.go index c484167..40bd091 100644 --- a/pkg/inimpl/guancecloud/funcs/fn_replace.go +++ b/pkg/inimpl/guancecloud/funcs/fn_replace.go @@ -12,10 +12,11 @@ import ( "github.com/GuanceCloud/platypus/pkg/ast" "github.com/GuanceCloud/platypus/pkg/engine/runtime" + "github.com/GuanceCloud/platypus/pkg/errchain" "github.com/GuanceCloud/platypus/pkg/inimpl/guancecloud/input" ) -func ReplaceChecking(ctx *runtime.Context, funcExpr *ast.CallExpr) *runtime.RuntimeError { +func ReplaceChecking(ctx *runtime.Context, funcExpr *ast.CallExpr) *errchain.PlError { if len(funcExpr.Param) != 3 { return runtime.NewRunError(ctx, fmt.Sprintf( "func %s expects 3 args", funcExpr.Name), funcExpr.NamePos) @@ -42,7 +43,7 @@ func ReplaceChecking(ctx *runtime.Context, funcExpr *ast.CallExpr) *runtime.Runt return nil } -func Replace(ctx *runtime.Context, funcExpr *ast.CallExpr) *runtime.RuntimeError { +func Replace(ctx *runtime.Context, funcExpr *ast.CallExpr) *errchain.PlError { if len(funcExpr.Param) != 3 { return runtime.NewRunError(ctx, fmt.Sprintf( "func %s expects 3 args", funcExpr.Name), funcExpr.NamePos) diff --git a/pkg/inimpl/guancecloud/funcs/fn_set_measurement.go b/pkg/inimpl/guancecloud/funcs/fn_set_measurement.go index 1c7b6b0..b3f5a9c 100644 --- a/pkg/inimpl/guancecloud/funcs/fn_set_measurement.go +++ b/pkg/inimpl/guancecloud/funcs/fn_set_measurement.go @@ -10,9 +10,10 @@ import ( "github.com/GuanceCloud/platypus/pkg/ast" "github.com/GuanceCloud/platypus/pkg/engine/runtime" + "github.com/GuanceCloud/platypus/pkg/errchain" ) -func SetMeasurementChecking(ctx *runtime.Context, funcExpr *ast.CallExpr) *runtime.RuntimeError { +func SetMeasurementChecking(ctx *runtime.Context, funcExpr *ast.CallExpr) *errchain.PlError { if len(funcExpr.Param) != 2 && len(funcExpr.Param) != 1 { return runtime.NewRunError(ctx, fmt.Sprintf( "func `%s' expected 1 or 2 args", funcExpr.Name), funcExpr.NamePos) @@ -33,7 +34,7 @@ func SetMeasurementChecking(ctx *runtime.Context, funcExpr *ast.CallExpr) *runti return nil } -func SetMeasurement(ctx *runtime.Context, funcExpr *ast.CallExpr) *runtime.RuntimeError { +func SetMeasurement(ctx *runtime.Context, funcExpr *ast.CallExpr) *errchain.PlError { if len(funcExpr.Param) != 2 && len(funcExpr.Param) != 1 { return runtime.NewRunError(ctx, fmt.Sprintf( "func `%s' expected 1 or 2 args", funcExpr.Name), funcExpr.NamePos) diff --git a/pkg/inimpl/guancecloud/funcs/fn_set_tag.go b/pkg/inimpl/guancecloud/funcs/fn_set_tag.go index 1f79eb2..1182b11 100644 --- a/pkg/inimpl/guancecloud/funcs/fn_set_tag.go +++ b/pkg/inimpl/guancecloud/funcs/fn_set_tag.go @@ -10,10 +10,11 @@ import ( "github.com/GuanceCloud/platypus/pkg/ast" "github.com/GuanceCloud/platypus/pkg/engine/runtime" + "github.com/GuanceCloud/platypus/pkg/errchain" "github.com/GuanceCloud/platypus/pkg/inimpl/guancecloud/input" ) -func SetTagChecking(ctx *runtime.Context, funcExpr *ast.CallExpr) *runtime.RuntimeError { +func SetTagChecking(ctx *runtime.Context, funcExpr *ast.CallExpr) *errchain.PlError { if len(funcExpr.Param) != 2 && len(funcExpr.Param) != 1 { return runtime.NewRunError(ctx, fmt.Sprintf( "func `%s' expected 1 or 2 args", funcExpr.Name), funcExpr.NamePos) @@ -34,7 +35,7 @@ func SetTagChecking(ctx *runtime.Context, funcExpr *ast.CallExpr) *runtime.Runti return nil } -func SetTag(ctx *runtime.Context, funcExpr *ast.CallExpr) *runtime.RuntimeError { +func SetTag(ctx *runtime.Context, funcExpr *ast.CallExpr) *errchain.PlError { if len(funcExpr.Param) != 2 && len(funcExpr.Param) != 1 { return runtime.NewRunError(ctx, fmt.Sprintf( "func `%s' expected 1 or 2 args", funcExpr.Name), funcExpr.NamePos) @@ -48,7 +49,7 @@ func SetTag(ctx *runtime.Context, funcExpr *ast.CallExpr) *runtime.RuntimeError var val any var dtype ast.DType if len(funcExpr.Param) == 2 { - var errR *runtime.RuntimeError + var errR *errchain.PlError // 不限制值的数据类型,如果不是 string 类将在设置为 tag 时自动转换为 string val, dtype, errR = runtime.RunStmt(ctx, funcExpr.Param[1]) if errR != nil { diff --git a/pkg/inimpl/guancecloud/funcs/fn_sql_cover.go b/pkg/inimpl/guancecloud/funcs/fn_sql_cover.go index 0d96abe..0029c20 100644 --- a/pkg/inimpl/guancecloud/funcs/fn_sql_cover.go +++ b/pkg/inimpl/guancecloud/funcs/fn_sql_cover.go @@ -11,10 +11,11 @@ import ( "github.com/DataDog/datadog-agent/pkg/obfuscate" "github.com/GuanceCloud/platypus/pkg/ast" "github.com/GuanceCloud/platypus/pkg/engine/runtime" + "github.com/GuanceCloud/platypus/pkg/errchain" "github.com/GuanceCloud/platypus/pkg/inimpl/guancecloud/input" ) -func SQLCoverChecking(ctx *runtime.Context, funcExpr *ast.CallExpr) *runtime.RuntimeError { +func SQLCoverChecking(ctx *runtime.Context, funcExpr *ast.CallExpr) *errchain.PlError { if len(funcExpr.Param) != 1 { return runtime.NewRunError(ctx, fmt.Sprintf( "func %s expects 1 args", funcExpr.Name), funcExpr.NamePos) @@ -25,7 +26,7 @@ func SQLCoverChecking(ctx *runtime.Context, funcExpr *ast.CallExpr) *runtime.Run return nil } -func SQLCover(ctx *runtime.Context, funcExpr *ast.CallExpr) *runtime.RuntimeError { +func SQLCover(ctx *runtime.Context, funcExpr *ast.CallExpr) *errchain.PlError { o := obfuscate.NewObfuscator(obfuscate.Config{}) if len(funcExpr.Param) != 1 { return runtime.NewRunError(ctx, fmt.Sprintf( diff --git a/pkg/inimpl/guancecloud/funcs/fn_strfmt.go b/pkg/inimpl/guancecloud/funcs/fn_strfmt.go index 6dc9ec2..da4a1fd 100644 --- a/pkg/inimpl/guancecloud/funcs/fn_strfmt.go +++ b/pkg/inimpl/guancecloud/funcs/fn_strfmt.go @@ -10,10 +10,11 @@ import ( "github.com/GuanceCloud/platypus/pkg/ast" "github.com/GuanceCloud/platypus/pkg/engine/runtime" + "github.com/GuanceCloud/platypus/pkg/errchain" "github.com/GuanceCloud/platypus/pkg/inimpl/guancecloud/input" ) -func StrfmtChecking(ctx *runtime.Context, funcExpr *ast.CallExpr) *runtime.RuntimeError { +func StrfmtChecking(ctx *runtime.Context, funcExpr *ast.CallExpr) *errchain.PlError { if len(funcExpr.Param) < 2 { return runtime.NewRunError(ctx, fmt.Sprintf( "func `%s' expects more than 2 args", funcExpr.Name), funcExpr.NamePos) @@ -30,7 +31,7 @@ func StrfmtChecking(ctx *runtime.Context, funcExpr *ast.CallExpr) *runtime.Runti return nil } -func Strfmt(ctx *runtime.Context, funcExpr *ast.CallExpr) *runtime.RuntimeError { +func Strfmt(ctx *runtime.Context, funcExpr *ast.CallExpr) *errchain.PlError { outdata := make([]interface{}, 0) if len(funcExpr.Param) < 2 { diff --git a/pkg/inimpl/guancecloud/funcs/fn_trim.go b/pkg/inimpl/guancecloud/funcs/fn_trim.go index ff66cd9..ee8d282 100644 --- a/pkg/inimpl/guancecloud/funcs/fn_trim.go +++ b/pkg/inimpl/guancecloud/funcs/fn_trim.go @@ -11,10 +11,11 @@ import ( "github.com/GuanceCloud/platypus/pkg/ast" "github.com/GuanceCloud/platypus/pkg/engine/runtime" + "github.com/GuanceCloud/platypus/pkg/errchain" "github.com/GuanceCloud/platypus/pkg/inimpl/guancecloud/input" ) -func TrimChecking(ctx *runtime.Context, funcExpr *ast.CallExpr) *runtime.RuntimeError { +func TrimChecking(ctx *runtime.Context, funcExpr *ast.CallExpr) *errchain.PlError { if len(funcExpr.Param) < 1 || len(funcExpr.Param) > 2 { return runtime.NewRunError(ctx, fmt.Sprintf( "func `%s' expected 1 or 2 args", funcExpr.Name), funcExpr.NamePos) @@ -33,7 +34,7 @@ func TrimChecking(ctx *runtime.Context, funcExpr *ast.CallExpr) *runtime.Runtime return nil } -func Trim(ctx *runtime.Context, funcExpr *ast.CallExpr) *runtime.RuntimeError { +func Trim(ctx *runtime.Context, funcExpr *ast.CallExpr) *errchain.PlError { key, err := getKeyName(funcExpr.Param[0]) if err != nil { return runtime.NewRunError(ctx, err.Error(), funcExpr.Param[0].StartPos()) diff --git a/pkg/inimpl/guancecloud/funcs/fn_uppercase.go b/pkg/inimpl/guancecloud/funcs/fn_uppercase.go index 28c093b..e2b283b 100644 --- a/pkg/inimpl/guancecloud/funcs/fn_uppercase.go +++ b/pkg/inimpl/guancecloud/funcs/fn_uppercase.go @@ -11,10 +11,11 @@ import ( "github.com/GuanceCloud/platypus/pkg/ast" "github.com/GuanceCloud/platypus/pkg/engine/runtime" + "github.com/GuanceCloud/platypus/pkg/errchain" "github.com/GuanceCloud/platypus/pkg/inimpl/guancecloud/input" ) -func UppercaseChecking(ctx *runtime.Context, funcExpr *ast.CallExpr) *runtime.RuntimeError { +func UppercaseChecking(ctx *runtime.Context, funcExpr *ast.CallExpr) *errchain.PlError { if len(funcExpr.Param) != 1 { return runtime.NewRunError(ctx, fmt.Sprintf( "func %s expects 1 arg", funcExpr.Name), funcExpr.NamePos) @@ -25,7 +26,7 @@ func UppercaseChecking(ctx *runtime.Context, funcExpr *ast.CallExpr) *runtime.Ru return nil } -func Uppercase(ctx *runtime.Context, funcExpr *ast.CallExpr) *runtime.RuntimeError { +func Uppercase(ctx *runtime.Context, funcExpr *ast.CallExpr) *errchain.PlError { if len(funcExpr.Param) != 1 { return runtime.NewRunError(ctx, fmt.Sprintf( "func %s expects 1 args", funcExpr.Name), funcExpr.NamePos) diff --git a/pkg/inimpl/guancecloud/funcs/fn_urldecode.go b/pkg/inimpl/guancecloud/funcs/fn_urldecode.go index 0b7e835..c370662 100644 --- a/pkg/inimpl/guancecloud/funcs/fn_urldecode.go +++ b/pkg/inimpl/guancecloud/funcs/fn_urldecode.go @@ -10,10 +10,11 @@ import ( "github.com/GuanceCloud/platypus/pkg/ast" "github.com/GuanceCloud/platypus/pkg/engine/runtime" + "github.com/GuanceCloud/platypus/pkg/errchain" "github.com/GuanceCloud/platypus/pkg/inimpl/guancecloud/input" ) -func URLDecodeChecking(ctx *runtime.Context, funcExpr *ast.CallExpr) *runtime.RuntimeError { +func URLDecodeChecking(ctx *runtime.Context, funcExpr *ast.CallExpr) *errchain.PlError { if len(funcExpr.Param) != 1 { return runtime.NewRunError(ctx, fmt.Sprintf( "func `%s' expected 1 args", funcExpr.Name), funcExpr.NamePos) @@ -24,7 +25,7 @@ func URLDecodeChecking(ctx *runtime.Context, funcExpr *ast.CallExpr) *runtime.Ru return nil } -func URLDecode(ctx *runtime.Context, funcExpr *ast.CallExpr) *runtime.RuntimeError { +func URLDecode(ctx *runtime.Context, funcExpr *ast.CallExpr) *errchain.PlError { if len(funcExpr.Param) != 1 { return runtime.NewRunError(ctx, fmt.Sprintf( "func `%s' expected 1 args", funcExpr.Name), funcExpr.NamePos) diff --git a/pkg/inimpl/guancecloud/funcs/fn_use.go b/pkg/inimpl/guancecloud/funcs/fn_use.go index d02f693..1d7c2da 100644 --- a/pkg/inimpl/guancecloud/funcs/fn_use.go +++ b/pkg/inimpl/guancecloud/funcs/fn_use.go @@ -10,9 +10,10 @@ import ( "github.com/GuanceCloud/platypus/pkg/ast" "github.com/GuanceCloud/platypus/pkg/engine/runtime" + "github.com/GuanceCloud/platypus/pkg/errchain" ) -func UseChecking(ctx *runtime.Context, funcExpr *ast.CallExpr) *runtime.RuntimeError { +func UseChecking(ctx *runtime.Context, funcExpr *ast.CallExpr) *errchain.PlError { if len(funcExpr.Param) != 1 { return runtime.NewRunError(ctx, fmt.Sprintf( "func %s expects 1 args", funcExpr.Name), funcExpr.NamePos) @@ -20,16 +21,16 @@ func UseChecking(ctx *runtime.Context, funcExpr *ast.CallExpr) *runtime.RuntimeE switch funcExpr.Param[0].NodeType { //nolint:exhaustive case ast.TypeStringLiteral: - ctx.SetCallRef(funcExpr.Param[0].StringLiteral.Val) + ctx.SetCallRef(funcExpr) default: - return runtime.NewRunError(ctx, fmt.Sprintf("param key expects AttrExpr or Identifier, got %s", + return runtime.NewRunError(ctx, fmt.Sprintf("param key expects StringLiteral, got %s", funcExpr.Param[0].NodeType), funcExpr.Param[0].StartPos()) } return nil } -func Use(ctx *runtime.Context, funcExpr *ast.CallExpr) *runtime.RuntimeError { +func Use(ctx *runtime.Context, funcExpr *ast.CallExpr) *errchain.PlError { if len(funcExpr.Param) != 1 { return runtime.NewRunError(ctx, fmt.Sprintf( "func %s expects 1 args", funcExpr.Name), funcExpr.NamePos) @@ -38,8 +39,13 @@ func Use(ctx *runtime.Context, funcExpr *ast.CallExpr) *runtime.RuntimeError { var refScript *runtime.Script switch funcExpr.Param[0].NodeType { //nolint:exhaustive case ast.TypeStringLiteral: - if ng, ok := ctx.GetCallRef(funcExpr.Param[0].StringLiteral.Val); ok { - refScript = ng + if funcExpr.PrivateData != nil { + if s, ok := funcExpr.PrivateData.(*runtime.Script); ok { + refScript = s + } else { + l.Debugf("unknown error: %s", funcExpr.Param[0].StringLiteral.Val) + return nil + } } else { l.Debugf("script not found: %s", funcExpr.Param[0].StringLiteral.Val) return nil @@ -50,5 +56,9 @@ func Use(ctx *runtime.Context, funcExpr *ast.CallExpr) *runtime.RuntimeError { funcExpr.Param[0].NodeType), funcExpr.Param[0].StartPos()) } - return runtime.RefRunScript(ctx, refScript) + err := runtime.RefRunScript(ctx, refScript) + if err != nil { + return err.ChainAppend(ctx.Name(), funcExpr.NamePos) + } + return nil } diff --git a/pkg/inimpl/guancecloud/funcs/fn_xml.go b/pkg/inimpl/guancecloud/funcs/fn_xml.go index 428f8d5..45f1ae0 100644 --- a/pkg/inimpl/guancecloud/funcs/fn_xml.go +++ b/pkg/inimpl/guancecloud/funcs/fn_xml.go @@ -12,11 +12,12 @@ import ( "github.com/GuanceCloud/platypus/pkg/ast" "github.com/GuanceCloud/platypus/pkg/engine/runtime" + "github.com/GuanceCloud/platypus/pkg/errchain" "github.com/GuanceCloud/platypus/pkg/inimpl/guancecloud/input" "github.com/antchfx/xmlquery" ) -func XMLChecking(ctx *runtime.Context, funcExpr *ast.CallExpr) *runtime.RuntimeError { +func XMLChecking(ctx *runtime.Context, funcExpr *ast.CallExpr) *errchain.PlError { if len(funcExpr.Param) != 3 { return runtime.NewRunError(ctx, fmt.Sprintf( "func %s expects 3 args", funcExpr.Name), funcExpr.NamePos) @@ -47,7 +48,7 @@ func XMLChecking(ctx *runtime.Context, funcExpr *ast.CallExpr) *runtime.RuntimeE return nil } -func XML(ctx *runtime.Context, funcExpr *ast.CallExpr) *runtime.RuntimeError { +func XML(ctx *runtime.Context, funcExpr *ast.CallExpr) *errchain.PlError { var ( xmlKey, fieldName string xpathExpr string diff --git a/pkg/parser/gram.y b/pkg/parser/gram.y index d77d940..a501132 100644 --- a/pkg/parser/gram.y +++ b/pkg/parser/gram.y @@ -406,8 +406,8 @@ map_init : map_init_start RIGHT_BRACE } | empty_block { - $$ = yylex.(*parser).newMapInitStartExpr($1.LBracePos) - $$ = yylex.(*parser).newMapInitEndExpr($$, $1.RBracePos) + $$ = yylex.(*parser).newMapInitStartExpr($1.LBracePos.Pos) + $$ = yylex.(*parser).newMapInitEndExpr($$, $1.RBracePos.Pos) } ; @@ -478,10 +478,10 @@ number_literal : NUMBER case SUB: if num.NodeType == ast.TypeFloatLiteral { num.FloatLiteral.Val = -num.FloatLiteral.Val - num.FloatLiteral.Start = $1.Pos + num.FloatLiteral.Start = yylex.(*parser).posCache.LnCol($1.Pos) } else { num.IntegerLiteral.Val = -num.IntegerLiteral.Val - num.IntegerLiteral.Start = $1.Pos + num.IntegerLiteral.Start = yylex.(*parser).posCache.LnCol($1.Pos) } } diff --git a/pkg/parser/gram_y.go b/pkg/parser/gram_y.go index 875c6dd..07a4ac9 100644 --- a/pkg/parser/gram_y.go +++ b/pkg/parser/gram_y.go @@ -1,17 +1,17 @@ // Code generated by goyacc -o gram_y.go gram.y. DO NOT EDIT. -//line gram.y:2 +//line gram.y:7 package parser import __yyfmt__ "fmt" -//line gram.y:2 +//line gram.y:7 import ( ast "github.com/GuanceCloud/platypus/pkg/ast" ) -//line gram.y:10 +//line gram.y:15 type yySymType struct { yys int aststmts ast.Stmts @@ -159,7 +159,7 @@ const yyEofCode = 1 const yyErrCode = 2 const yyInitialStackSize = 16 -//line gram.y:502 +//line gram.y:507 //line yacctab:1 var yyExca = [...]int16{ @@ -733,19 +733,19 @@ yydefault: case 5: yyDollar = yyS[yypt-2 : yypt+1] -//line gram.y:124 +//line gram.y:129 { yylex.(*parser).parseResult = yyDollar[2].aststmts } case 7: yyDollar = yyS[yypt-1 : yypt+1] -//line gram.y:127 +//line gram.y:132 { yylex.(*parser).unexpected("", "") } case 8: yyDollar = yyS[yypt-2 : yypt+1] -//line gram.y:132 +//line gram.y:137 { s := yyDollar[1].aststmts s = append(s, yyDollar[2].node) @@ -753,25 +753,25 @@ yydefault: } case 10: yyDollar = yyS[yypt-1 : yypt+1] -//line gram.y:139 +//line gram.y:144 { yyVAL.aststmts = ast.Stmts{yyDollar[1].node} } case 11: yyDollar = yyS[yypt-2 : yypt+1] -//line gram.y:143 +//line gram.y:148 { yyVAL.aststmts = ast.Stmts{yyDollar[1].node} } case 12: yyDollar = yyS[yypt-1 : yypt+1] -//line gram.y:145 +//line gram.y:150 { yyVAL.aststmts = ast.Stmts{} } case 13: yyDollar = yyS[yypt-3 : yypt+1] -//line gram.y:147 +//line gram.y:152 { s := yyDollar[1].aststmts s = append(s, yyDollar[2].node) @@ -779,319 +779,319 @@ yydefault: } case 29: yyDollar = yyS[yypt-1 : yypt+1] -//line gram.y:171 +//line gram.y:176 { yyVAL.node = yylex.(*parser).newBreakStmt(yyDollar[1].item.Pos) } case 30: yyDollar = yyS[yypt-1 : yypt+1] -//line gram.y:175 +//line gram.y:180 { yyVAL.node = yylex.(*parser).newContinueStmt(yyDollar[1].item.Pos) } case 31: yyDollar = yyS[yypt-5 : yypt+1] -//line gram.y:184 +//line gram.y:189 { yyVAL.node = yylex.(*parser).newForInStmt(yyDollar[2].node, yyDollar[4].node, yyDollar[5].astblock, yyDollar[1].item, yyDollar[3].item) } case 32: yyDollar = yyS[yypt-7 : yypt+1] -//line gram.y:195 +//line gram.y:200 { yyVAL.node = yylex.(*parser).newForStmt(yyDollar[2].node, yyDollar[4].node, yyDollar[6].node, yyDollar[7].astblock) } case 33: yyDollar = yyS[yypt-6 : yypt+1] -//line gram.y:197 +//line gram.y:202 { yyVAL.node = yylex.(*parser).newForStmt(yyDollar[2].node, yyDollar[4].node, nil, yyDollar[6].astblock) } case 34: yyDollar = yyS[yypt-6 : yypt+1] -//line gram.y:199 +//line gram.y:204 { yyVAL.node = yylex.(*parser).newForStmt(nil, yyDollar[3].node, yyDollar[5].node, yyDollar[6].astblock) } case 35: yyDollar = yyS[yypt-5 : yypt+1] -//line gram.y:201 +//line gram.y:206 { yyVAL.node = yylex.(*parser).newForStmt(nil, yyDollar[3].node, nil, yyDollar[5].astblock) } case 36: yyDollar = yyS[yypt-6 : yypt+1] -//line gram.y:204 +//line gram.y:209 { yyVAL.node = yylex.(*parser).newForStmt(yyDollar[2].node, nil, yyDollar[5].node, yyDollar[6].astblock) } case 37: yyDollar = yyS[yypt-5 : yypt+1] -//line gram.y:206 +//line gram.y:211 { yyVAL.node = yylex.(*parser).newForStmt(yyDollar[2].node, nil, nil, yyDollar[5].astblock) } case 38: yyDollar = yyS[yypt-5 : yypt+1] -//line gram.y:208 +//line gram.y:213 { yyVAL.node = yylex.(*parser).newForStmt(nil, nil, yyDollar[4].node, yyDollar[5].astblock) } case 39: yyDollar = yyS[yypt-4 : yypt+1] -//line gram.y:210 +//line gram.y:215 { yyVAL.node = yylex.(*parser).newForStmt(nil, nil, nil, yyDollar[4].astblock) } case 40: yyDollar = yyS[yypt-1 : yypt+1] -//line gram.y:214 +//line gram.y:219 { yyVAL.node = yylex.(*parser).newIfElifStmt(yyDollar[1].iflist) } case 41: yyDollar = yyS[yypt-3 : yypt+1] -//line gram.y:218 +//line gram.y:223 { yyVAL.node = yylex.(*parser).newIfElifelseStmt(yyDollar[1].iflist, yyDollar[2].item, yyDollar[3].astblock) } case 42: yyDollar = yyS[yypt-3 : yypt+1] -//line gram.y:224 +//line gram.y:229 { yyVAL.ifitem = yylex.(*parser).newIfElem(yyDollar[1].item, yyDollar[2].node, yyDollar[3].astblock) } case 43: yyDollar = yyS[yypt-1 : yypt+1] -//line gram.y:228 +//line gram.y:233 { yyVAL.iflist = []*ast.IfStmtElem{yyDollar[1].ifitem} } case 44: yyDollar = yyS[yypt-2 : yypt+1] -//line gram.y:230 +//line gram.y:235 { yyVAL.iflist = append(yyDollar[1].iflist, yyDollar[2].ifitem) } case 45: yyDollar = yyS[yypt-3 : yypt+1] -//line gram.y:234 +//line gram.y:239 { yyVAL.ifitem = yylex.(*parser).newIfElem(yyDollar[1].item, yyDollar[2].node, yyDollar[3].astblock) } case 47: yyDollar = yyS[yypt-3 : yypt+1] -//line gram.y:240 +//line gram.y:245 { yyVAL.astblock = yylex.(*parser).newBlockStmt(yyDollar[1].item, yyDollar[2].aststmts, yyDollar[3].item) } case 48: yyDollar = yyS[yypt-2 : yypt+1] -//line gram.y:244 +//line gram.y:249 { yyVAL.astblock = yylex.(*parser).newBlockStmt(yyDollar[1].item, ast.Stmts{}, yyDollar[2].item) } case 49: yyDollar = yyS[yypt-4 : yypt+1] -//line gram.y:249 +//line gram.y:254 { yyVAL.node = yylex.(*parser).newCallExpr(yyDollar[1].node, yyDollar[3].nodes, yyDollar[2].item, yyDollar[4].item) } case 50: yyDollar = yyS[yypt-3 : yypt+1] -//line gram.y:253 +//line gram.y:258 { yyVAL.node = yylex.(*parser).newCallExpr(yyDollar[1].node, nil, yyDollar[2].item, yyDollar[3].item) } case 51: yyDollar = yyS[yypt-5 : yypt+1] -//line gram.y:257 +//line gram.y:262 { yyVAL.node = yylex.(*parser).newCallExpr(yyDollar[1].node, yyDollar[3].nodes, yyDollar[2].item, yyDollar[5].item) } case 52: yyDollar = yyS[yypt-4 : yypt+1] -//line gram.y:261 +//line gram.y:266 { yyVAL.node = yylex.(*parser).newCallExpr(yyDollar[1].node, nil, yyDollar[2].item, yyDollar[4].item) } case 53: yyDollar = yyS[yypt-3 : yypt+1] -//line gram.y:268 +//line gram.y:273 { yyVAL.nodes = append(yyVAL.nodes, yyDollar[3].node) } case 55: yyDollar = yyS[yypt-1 : yypt+1] -//line gram.y:273 +//line gram.y:278 { yyVAL.nodes = []*ast.Node{yyDollar[1].node} } case 59: yyDollar = yyS[yypt-3 : yypt+1] -//line gram.y:280 +//line gram.y:285 { yyVAL.node = yylex.(*parser).newAssignmentExpr(yyDollar[1].node, yyDollar[3].node, yyDollar[2].item) } case 60: yyDollar = yyS[yypt-3 : yypt+1] -//line gram.y:284 +//line gram.y:289 { yyVAL.node = yylex.(*parser).newConditionalExpr(yyDollar[1].node, yyDollar[3].node, yyDollar[2].item) } case 61: yyDollar = yyS[yypt-3 : yypt+1] -//line gram.y:286 +//line gram.y:291 { yyVAL.node = yylex.(*parser).newConditionalExpr(yyDollar[1].node, yyDollar[3].node, yyDollar[2].item) } case 62: yyDollar = yyS[yypt-3 : yypt+1] -//line gram.y:288 +//line gram.y:293 { yyVAL.node = yylex.(*parser).newConditionalExpr(yyDollar[1].node, yyDollar[3].node, yyDollar[2].item) } case 63: yyDollar = yyS[yypt-3 : yypt+1] -//line gram.y:290 +//line gram.y:295 { yyVAL.node = yylex.(*parser).newConditionalExpr(yyDollar[1].node, yyDollar[3].node, yyDollar[2].item) } case 64: yyDollar = yyS[yypt-3 : yypt+1] -//line gram.y:292 +//line gram.y:297 { yyVAL.node = yylex.(*parser).newConditionalExpr(yyDollar[1].node, yyDollar[3].node, yyDollar[2].item) } case 65: yyDollar = yyS[yypt-3 : yypt+1] -//line gram.y:294 +//line gram.y:299 { yyVAL.node = yylex.(*parser).newConditionalExpr(yyDollar[1].node, yyDollar[3].node, yyDollar[2].item) } case 66: yyDollar = yyS[yypt-3 : yypt+1] -//line gram.y:296 +//line gram.y:301 { yyVAL.node = yylex.(*parser).newConditionalExpr(yyDollar[1].node, yyDollar[3].node, yyDollar[2].item) } case 67: yyDollar = yyS[yypt-3 : yypt+1] -//line gram.y:298 +//line gram.y:303 { yyVAL.node = yylex.(*parser).newConditionalExpr(yyDollar[1].node, yyDollar[3].node, yyDollar[2].item) } case 68: yyDollar = yyS[yypt-3 : yypt+1] -//line gram.y:303 +//line gram.y:308 { yyVAL.node = yylex.(*parser).newArithmeticExpr(yyDollar[1].node, yyDollar[3].node, yyDollar[2].item) } case 69: yyDollar = yyS[yypt-3 : yypt+1] -//line gram.y:305 +//line gram.y:310 { yyVAL.node = yylex.(*parser).newArithmeticExpr(yyDollar[1].node, yyDollar[3].node, yyDollar[2].item) } case 70: yyDollar = yyS[yypt-3 : yypt+1] -//line gram.y:307 +//line gram.y:312 { yyVAL.node = yylex.(*parser).newArithmeticExpr(yyDollar[1].node, yyDollar[3].node, yyDollar[2].item) } case 71: yyDollar = yyS[yypt-3 : yypt+1] -//line gram.y:309 +//line gram.y:314 { yyVAL.node = yylex.(*parser).newArithmeticExpr(yyDollar[1].node, yyDollar[3].node, yyDollar[2].item) } case 72: yyDollar = yyS[yypt-3 : yypt+1] -//line gram.y:311 +//line gram.y:316 { yyVAL.node = yylex.(*parser).newArithmeticExpr(yyDollar[1].node, yyDollar[3].node, yyDollar[2].item) } case 73: yyDollar = yyS[yypt-3 : yypt+1] -//line gram.y:316 +//line gram.y:321 { yyVAL.node = yylex.(*parser).newParenExpr(yyDollar[1].item, yyDollar[2].node, yyDollar[3].item) } case 74: yyDollar = yyS[yypt-4 : yypt+1] -//line gram.y:318 +//line gram.y:323 { yyVAL.node = yylex.(*parser).newParenExpr(yyDollar[1].item, yyDollar[2].node, yyDollar[4].item) } case 77: yyDollar = yyS[yypt-4 : yypt+1] -//line gram.y:327 +//line gram.y:332 { yyVAL.node = yylex.(*parser).newIndexExpr(yyDollar[1].node, yyDollar[2].item, yyDollar[3].node, yyDollar[4].item) } case 78: yyDollar = yyS[yypt-4 : yypt+1] -//line gram.y:330 +//line gram.y:335 { yyVAL.node = yylex.(*parser).newIndexExpr(nil, yyDollar[2].item, yyDollar[3].node, yyDollar[4].item) } case 79: yyDollar = yyS[yypt-4 : yypt+1] -//line gram.y:332 +//line gram.y:337 { yyVAL.node = yylex.(*parser).newIndexExpr(yyDollar[1].node, yyDollar[2].item, yyDollar[3].node, yyDollar[4].item) } case 80: yyDollar = yyS[yypt-3 : yypt+1] -//line gram.y:339 +//line gram.y:344 { yyVAL.node = yylex.(*parser).newAttrExpr(yyDollar[1].node, yyDollar[3].node) } case 81: yyDollar = yyS[yypt-3 : yypt+1] -//line gram.y:343 +//line gram.y:348 { yyVAL.node = yylex.(*parser).newAttrExpr(yyDollar[1].node, yyDollar[3].node) } case 82: yyDollar = yyS[yypt-3 : yypt+1] -//line gram.y:347 +//line gram.y:352 { yyVAL.node = yylex.(*parser).newAttrExpr(yyDollar[1].node, yyDollar[3].node) } case 83: yyDollar = yyS[yypt-3 : yypt+1] -//line gram.y:351 +//line gram.y:356 { yyVAL.node = yylex.(*parser).newAttrExpr(yyDollar[1].node, yyDollar[3].node) } case 84: yyDollar = yyS[yypt-3 : yypt+1] -//line gram.y:355 +//line gram.y:360 { yyVAL.node = yylex.(*parser).newAttrExpr(yyDollar[1].node, yyDollar[3].node) } case 85: yyDollar = yyS[yypt-3 : yypt+1] -//line gram.y:359 +//line gram.y:364 { yyVAL.node = yylex.(*parser).newAttrExpr(yyDollar[1].node, yyDollar[3].node) } case 86: yyDollar = yyS[yypt-2 : yypt+1] -//line gram.y:366 +//line gram.y:371 { yyVAL.node = yylex.(*parser).newListInitEndExpr(yyVAL.node, yyDollar[2].item.Pos) } case 87: yyDollar = yyS[yypt-3 : yypt+1] -//line gram.y:370 +//line gram.y:375 { yyVAL.node = yylex.(*parser).newListInitEndExpr(yyVAL.node, yyDollar[2].item.Pos) } case 88: yyDollar = yyS[yypt-2 : yypt+1] -//line gram.y:374 +//line gram.y:379 { yyVAL.node = yylex.(*parser).newListInitStartExpr(yyDollar[1].item.Pos) yyVAL.node = yylex.(*parser).newListInitEndExpr(yyVAL.node, yyDollar[2].item.Pos) @@ -1099,96 +1099,96 @@ yydefault: } case 89: yyDollar = yyS[yypt-2 : yypt+1] -//line gram.y:382 +//line gram.y:387 { yyVAL.node = yylex.(*parser).newListInitStartExpr(yyDollar[1].item.Pos) yyVAL.node = yylex.(*parser).newListInitAppendExpr(yyVAL.node, yyDollar[2].node) } case 90: yyDollar = yyS[yypt-3 : yypt+1] -//line gram.y:387 +//line gram.y:392 { yyVAL.node = yylex.(*parser).newListInitAppendExpr(yyVAL.node, yyDollar[3].node) } case 92: yyDollar = yyS[yypt-2 : yypt+1] -//line gram.y:395 +//line gram.y:400 { yyVAL.node = yylex.(*parser).newMapInitEndExpr(yyVAL.node, yyDollar[2].item.Pos) } case 93: yyDollar = yyS[yypt-3 : yypt+1] -//line gram.y:399 +//line gram.y:404 { yyVAL.node = yylex.(*parser).newMapInitEndExpr(yyVAL.node, yyDollar[3].item.Pos) } case 94: yyDollar = yyS[yypt-1 : yypt+1] -//line gram.y:403 +//line gram.y:408 { - yyVAL.node = yylex.(*parser).newMapInitStartExpr(yyDollar[1].astblock.LBracePos) - yyVAL.node = yylex.(*parser).newMapInitEndExpr(yyVAL.node, yyDollar[1].astblock.RBracePos) + yyVAL.node = yylex.(*parser).newMapInitStartExpr(yyDollar[1].astblock.LBracePos.Pos) + yyVAL.node = yylex.(*parser).newMapInitEndExpr(yyVAL.node, yyDollar[1].astblock.RBracePos.Pos) } case 95: yyDollar = yyS[yypt-4 : yypt+1] -//line gram.y:410 +//line gram.y:415 { yyVAL.node = yylex.(*parser).newMapInitStartExpr(yyDollar[1].item.Pos) yyVAL.node = yylex.(*parser).newMapInitAppendExpr(yyVAL.node, yyDollar[2].node, yyDollar[4].node) } case 96: yyDollar = yyS[yypt-5 : yypt+1] -//line gram.y:415 +//line gram.y:420 { yyVAL.node = yylex.(*parser).newMapInitAppendExpr(yyDollar[1].node, yyDollar[3].node, yyDollar[5].node) } case 103: yyDollar = yyS[yypt-1 : yypt+1] -//line gram.y:439 +//line gram.y:444 { yyVAL.node = yylex.(*parser).newBoolLiteral(yyDollar[1].item.Pos, true) } case 104: yyDollar = yyS[yypt-1 : yypt+1] -//line gram.y:441 +//line gram.y:446 { yyVAL.node = yylex.(*parser).newBoolLiteral(yyDollar[1].item.Pos, false) } case 105: yyDollar = yyS[yypt-1 : yypt+1] -//line gram.y:446 +//line gram.y:451 { yyDollar[1].item.Val = yylex.(*parser).unquoteString(yyDollar[1].item.Val) yyVAL.node = yylex.(*parser).newStringLiteral(yyDollar[1].item) } case 106: yyDollar = yyS[yypt-1 : yypt+1] -//line gram.y:451 +//line gram.y:456 { yyDollar[1].item.Val = yylex.(*parser).unquoteMultilineString(yyDollar[1].item.Val) yyVAL.node = yylex.(*parser).newStringLiteral(yyDollar[1].item) } case 107: yyDollar = yyS[yypt-1 : yypt+1] -//line gram.y:459 +//line gram.y:464 { yyVAL.node = yylex.(*parser).newNilLiteral(yyDollar[1].item.Pos) } case 108: yyDollar = yyS[yypt-1 : yypt+1] -//line gram.y:461 +//line gram.y:466 { yyVAL.node = yylex.(*parser).newNilLiteral(yyDollar[1].item.Pos) } case 109: yyDollar = yyS[yypt-1 : yypt+1] -//line gram.y:467 +//line gram.y:472 { yyVAL.node = yylex.(*parser).newNumberLiteral(yyDollar[1].item) } case 110: yyDollar = yyS[yypt-2 : yypt+1] -//line gram.y:469 +//line gram.y:474 { num := yylex.(*parser).newNumberLiteral(yyDollar[2].item) switch yyDollar[1].item.Typ { @@ -1196,10 +1196,10 @@ yydefault: case SUB: if num.NodeType == ast.TypeFloatLiteral { num.FloatLiteral.Val = -num.FloatLiteral.Val - num.FloatLiteral.Start = yyDollar[1].item.Pos + num.FloatLiteral.Start = yylex.(*parser).posCache.LnCol(yyDollar[1].item.Pos) } else { num.IntegerLiteral.Val = -num.IntegerLiteral.Val - num.IntegerLiteral.Start = yyDollar[1].item.Pos + num.IntegerLiteral.Start = yylex.(*parser).posCache.LnCol(yyDollar[1].item.Pos) } } @@ -1207,13 +1207,13 @@ yydefault: } case 111: yyDollar = yyS[yypt-1 : yypt+1] -//line gram.y:488 +//line gram.y:493 { yyVAL.node = yylex.(*parser).newIdentifierLiteral(yyDollar[1].item) } case 112: yyDollar = yyS[yypt-1 : yypt+1] -//line gram.y:492 +//line gram.y:497 { yyDollar[1].item.Val = yylex.(*parser).unquoteString(yyDollar[1].item.Val) yyVAL.node = yylex.(*parser).newIdentifierLiteral(yyDollar[1].item) diff --git a/pkg/parser/parser.go b/pkg/parser/parser.go index c1ef042..6310e8e 100644 --- a/pkg/parser/parser.go +++ b/pkg/parser/parser.go @@ -30,11 +30,13 @@ import ( "github.com/GuanceCloud/platypus/internal/logger" "github.com/GuanceCloud/platypus/pkg/ast" + "github.com/GuanceCloud/platypus/pkg/errchain" + "go.uber.org/zap" plToken "github.com/GuanceCloud/platypus/pkg/token" ) -var log logger.Logger = logger.NewStdoutLogger("iploc", "debug") +var log logger.Logger = logger.NewStdoutLogger("iploc", zap.DebugLevel) func InitLog(logger logger.Logger) { log = logger @@ -56,6 +58,8 @@ type parser struct { inject ItemType injecting bool + + posCache plToken.PosCache } func (p *parser) InjectItem(typ ItemType) { @@ -148,42 +152,42 @@ func (p *parser) unquoteMultilineString(s string) string { func (p *parser) newBoolLiteral(pos plToken.Pos, val bool) *ast.Node { return ast.WrapBoolLiteral(&ast.BoolLiteral{ Val: val, - Start: pos, + Start: p.posCache.LnCol(pos), }) } func (p *parser) newNilLiteral(pos plToken.Pos) *ast.Node { return ast.WrapNilLiteral(&ast.NilLiteral{ - Start: pos, + Start: p.posCache.LnCol(pos), }) } func (p *parser) newIdentifierLiteral(name Item) *ast.Node { return ast.WrapIdentifier(&ast.Identifier{ Name: name.Val, - Start: name.Pos, + Start: p.posCache.LnCol(name.Pos), }) } func (p *parser) newStringLiteral(val Item) *ast.Node { return ast.WrapStringLiteral(&ast.StringLiteral{ Val: val.Val, - Start: val.Pos, + Start: p.posCache.LnCol(val.Pos), }) } func (p *parser) newParenExpr(lParen Item, node *ast.Node, rParen Item) *ast.Node { return ast.WrapParenExpr(&ast.ParenExpr{ Param: node, - LParen: lParen.Pos, - RParen: rParen.Pos, + LParen: p.posCache.LnCol(lParen.Pos), + RParen: p.posCache.LnCol(rParen.Pos), }) } func (p *parser) newListInitStartExpr(pos plToken.Pos) *ast.Node { return ast.WrapListInitExpr(&ast.ListInitExpr{ List: []*ast.Node{}, - LBracket: pos, + LBracket: p.posCache.LnCol(pos), }) } @@ -204,14 +208,14 @@ func (p *parser) newListInitEndExpr(initExpr *ast.Node, pos plToken.Pos) *ast.No "%s object is not ListInitExpr", initExpr.NodeType) return nil } - initExpr.ListInitExpr.RBracket = pos + initExpr.ListInitExpr.RBracket = p.posCache.LnCol(pos) return initExpr } func (p *parser) newMapInitStartExpr(pos plToken.Pos) *ast.Node { return ast.WrapMapInitExpr(&ast.MapInitExpr{ KeyValeList: [][2]*ast.Node{}, - LBrace: pos, + LBrace: p.posCache.LnCol(pos), }) } @@ -233,7 +237,7 @@ func (p *parser) newMapInitEndExpr(initExpr *ast.Node, pos plToken.Pos) *ast.Nod "%s object is not MapInitExpr", initExpr.NodeType) return nil } - initExpr.MapInitExpr.RBrace = pos + initExpr.MapInitExpr.RBrace = p.posCache.LnCol(pos) return initExpr } @@ -247,33 +251,33 @@ func (p *parser) newNumberLiteral(v Item) *ast.Node { } return ast.WrapFloatLiteral(&ast.FloatLiteral{ Val: f, - Start: v.Pos, + Start: p.posCache.LnCol(v.Pos), }) } else { return ast.WrapIntegerLiteral(&ast.IntegerLiteral{ Val: n, - Start: v.Pos, + Start: p.posCache.LnCol(v.Pos), }) } } func (p *parser) newBlockStmt(lBrace Item, stmts ast.Stmts, rBrace Item) *ast.BlockStmt { return &ast.BlockStmt{ - LBracePos: lBrace.Pos, + LBracePos: p.posCache.LnCol(lBrace.Pos), Stmts: stmts, - RBracePos: rBrace.Pos, + RBracePos: p.posCache.LnCol(rBrace.Pos), } } func (p *parser) newBreakStmt(pos plToken.Pos) *ast.Node { return ast.WrapBreakStmt(&ast.BreakStmt{ - Start: pos, + Start: p.posCache.LnCol(pos), }) } func (p *parser) newContinueStmt(pos plToken.Pos) *ast.Node { return ast.WrapContinueStmt(&ast.ContinueStmt{ - Start: pos, + Start: p.posCache.LnCol(pos), }) } @@ -286,7 +290,7 @@ func (p *parser) newForStmt(initExpr *ast.Node, condExpr *ast.Node, loopExpr *as Cond: condExpr, Body: body, - ForPos: pos.Start, + ForPos: p.posCache.LnCol(pos.Start), }) } @@ -309,8 +313,8 @@ func (p *parser) newForInStmt(varb *ast.Node, iter *ast.Node, body *ast.BlockStm Varb: varb, Iter: iter, Body: body, - ForPos: forTk.Pos, - InPos: inTk.Pos, + ForPos: p.posCache.LnCol(forTk.Pos), + InPos: p.posCache.LnCol(inTk.Pos), }) } @@ -339,7 +343,7 @@ func (p *parser) newIfElifelseStmt(ifElifList []*ast.IfStmtElem, &ast.IfelseStmt{ IfList: ast.IfList(ifElifList), Else: elseElem, - ElsePos: elseTk.Pos, + ElsePos: p.posCache.LnCol(elseTk.Pos), }, ) } @@ -353,7 +357,7 @@ func (p *parser) newIfElem(ifTk Item, condition *ast.Node, block *ast.BlockStmt) ifElem := &ast.IfStmtElem{ Condition: condition, Block: block, - Start: ifTk.Pos, + Start: p.posCache.LnCol(ifTk.Pos), } return ifElem @@ -363,7 +367,7 @@ func (p *parser) newAssignmentExpr(l, r *ast.Node, eqOp Item) *ast.Node { return ast.WrapAssignmentExpr(&ast.AssignmentExpr{ LHS: l, RHS: r, - OpPos: eqOp.Pos, + OpPos: p.posCache.LnCol(eqOp.Pos), }) } @@ -372,7 +376,7 @@ func (p *parser) newConditionalExpr(l, r *ast.Node, op Item) *ast.Node { RHS: r, LHS: l, Op: AstOp(op.Typ), - OpPos: op.Pos, + OpPos: p.posCache.LnCol(op.Pos), }) } @@ -399,7 +403,7 @@ func (p *parser) newArithmeticExpr(l, r *ast.Node, op Item) *ast.Node { LHS: l, Op: AstOp(op.Typ), - OpPos: op.Pos, + OpPos: p.posCache.LnCol(op.Pos), }, ) } @@ -410,7 +414,7 @@ func (p *parser) newAttrExpr(obj, attr *ast.Node) *ast.Node { return ast.WrapAttrExpr(&ast.AttrExpr{ Obj: obj, Attr: attr, - Start: pos.Start, + Start: p.posCache.LnCol(pos.Start), }) } @@ -424,8 +428,8 @@ func (p *parser) newIndexExpr(obj *ast.Node, lBracket Item, index *ast.Node, rBr // .[idx] return ast.WrapIndexExpr(&ast.IndexExpr{ Index: []*ast.Node{index}, - LBracket: []plToken.Pos{lBracket.Pos}, - RBracket: []plToken.Pos{rBracket.Pos}, + LBracket: []plToken.LnColPos{p.posCache.LnCol(lBracket.Pos)}, + RBracket: []plToken.LnColPos{p.posCache.LnCol(rBracket.Pos)}, }) } @@ -433,13 +437,13 @@ func (p *parser) newIndexExpr(obj *ast.Node, lBracket Item, index *ast.Node, rBr case ast.TypeIdentifier: return ast.WrapIndexExpr(&ast.IndexExpr{ Obj: obj.Identifier, Index: []*ast.Node{index}, - LBracket: []plToken.Pos{lBracket.Pos}, - RBracket: []plToken.Pos{rBracket.Pos}, + LBracket: []plToken.LnColPos{p.posCache.LnCol(lBracket.Pos)}, + RBracket: []plToken.LnColPos{p.posCache.LnCol(rBracket.Pos)}, }) case ast.TypeIndexExpr: obj.IndexExpr.Index = append(obj.IndexExpr.Index, index) - obj.IndexExpr.LBracket = append(obj.IndexExpr.LBracket, lBracket.Pos) - obj.IndexExpr.RBracket = append(obj.IndexExpr.RBracket, rBracket.Pos) + obj.IndexExpr.LBracket = append(obj.IndexExpr.LBracket, p.posCache.LnCol(lBracket.Pos)) + obj.IndexExpr.RBracket = append(obj.IndexExpr.RBracket, p.posCache.LnCol(rBracket.Pos)) return obj default: p.addParseErrf(p.yyParser.lval.item.PositionRange(), @@ -462,8 +466,8 @@ func (p *parser) newCallExpr(fn *ast.Node, args []*ast.Node, lParen, rParen Item f := &ast.CallExpr{ Name: fname, NamePos: fn.Identifier.Start, - LParen: lParen.Pos, - RParen: rParen.Pos, + LParen: p.posCache.LnCol(lParen.Pos), + RParen: p.posCache.LnCol(rParen.Pos), } // TODO: key-value param support @@ -525,10 +529,11 @@ func newParser(input string) *parser { input: input, state: lexStatements, } + p.posCache = *plToken.NewPosCache(input) return p } -func ParsePipeline(input string) (res ast.Stmts, err error) { +func ParsePipeline(name, input string) (res ast.Stmts, err error) { p := newParser(input) defer parserPool.Put(p) defer p.recover(&err) @@ -536,13 +541,23 @@ func ParsePipeline(input string) (res ast.Stmts, err error) { p.InjectItem(START_STMTS) p.yyParser.Parse(p) + if len(p.errs) != 0 { + err = conv2PlError(name, p.errs, &p.posCache) + return + } + if p.parseResult != nil { res = p.parseResult } - if len(p.errs) != 0 { - err = p.errs + return res, err +} + +func conv2PlError(name string, errs ParseErrors, posCache *plToken.PosCache) *errchain.PlError { + if len(errs) > 0 { + pos := posCache.LnCol(errs[0].Pos.Start) + return errchain.NewErr(name, pos, errs[0].Err.Error()) } - return res, err + return nil } diff --git a/pkg/parser/parser_test.go b/pkg/parser/parser_test.go index 48b97d3..600d277 100644 --- a/pkg/parser/parser_test.go +++ b/pkg/parser/parser_test.go @@ -238,7 +238,7 @@ func TestExprSeparation(t *testing.T) { // for idx := len(cases) - 1; idx >= 0; idx-- { for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { - Stmts, err := ParsePipeline(tc.in) + Stmts, err := ParsePipeline("", tc.in) if !tc.fail { assert.Equal(t, err, nil) @@ -395,7 +395,7 @@ func TestParserFor(t *testing.T) { // for idx := len(cases) - 1; idx >= 0; idx-- { for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { - Stmts, err := ParsePipeline(tc.in) + Stmts, err := ParsePipeline("", tc.in) if !tc.fail { assert.Nil(t, err) @@ -1297,7 +1297,7 @@ multiline-string // for idx := len(cases) - 1; idx >= 0; idx-- { for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { - Stmts, err := ParsePipeline(tc.in) + Stmts, err := ParsePipeline("", tc.in) if !tc.fail { assert.Nil(t, err) diff --git a/pkg/token/token.go b/pkg/token/token.go index 4250d17..8200b61 100644 --- a/pkg/token/token.go +++ b/pkg/token/token.go @@ -6,9 +6,84 @@ // Package token used package token -import "fmt" +import ( + "fmt" +) -type Pos int32 +var InvalidPos = -1 + +var InvalidLnColPos = LnColPos{ + Pos: -1, + Ln: -1, + Col: -1, +} + +type Pos int + +type LnColPos struct { + Pos Pos + Ln int + Col int +} + +type PosCache struct { + query string + lineStartPos []int +} + +func (c *PosCache) LnCol(pos Pos) LnColPos { + if len(c.lineStartPos) == 0 || pos > Pos(len(c.query)) || pos < 0 { + return InvalidLnColPos + } + + start := 0 + end := len(c.lineStartPos) + + ln := -1 + + for start < end { + m := start + (end-start)/2 + if pos < Pos(c.lineStartPos[m]) { + end = m + } else { + if m == len(c.lineStartPos)-1 { + ln = m + break + } + if pos < Pos(c.lineStartPos[m+1]) { + ln = m + break + } else { + start = m + 1 + } + } + } + + if ln == -1 { + return InvalidLnColPos + } + + return LnColPos{ + Ln: int(ln) + 1, + Col: int(pos) - c.lineStartPos[ln] + 1, + } +} + +func NewPosCache(query string) *PosCache { + + cache := PosCache{ + query: query, + lineStartPos: []int{0}, + } + + for i, c := range query { + if c == '\n' { + cache.lineStartPos = append(cache.lineStartPos, int(i+1)) + } + } + + return &cache +} func LnCol(query string, pos Pos) (int, int, error) { lastLineBrk := -1 diff --git a/pkg/token/token_test.go b/pkg/token/token_test.go new file mode 100644 index 0000000..18611a3 --- /dev/null +++ b/pkg/token/token_test.go @@ -0,0 +1,77 @@ +// Unless explicitly stated otherwise all files in this repository are licensed +// under the MIT License. +// This product includes software developed at Guance Cloud (https://www.guance.com/). +// Copyright 2021-present Guance, Inc. + +// Package token used +package token + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +type dataPos struct { + query string + pos [][4]int +} + +func TestPosCache(t *testing.T) { + testCases := []dataPos{ + { + query: `0123 + +`, + pos: [][4]int{ + {0, 1, 1, '0'}, + {5, 2, 1, '\n'}, + }, + }, + { + query: `0123 +56 +09 +abcde +ght +a`, + pos: [][4]int{ + {0, 1, 1, '0'}, + {5, 2, 1, '5'}, + {17, 5, 1, 'g'}, + {21, 6, 1, 'a'}, + }, + }, + { + query: `0123 +56 +09 + + +abcde +ght + +`, + pos: [][4]int{ + {0, 1, 1, '0'}, + {5, 2, 1, '5'}, + {19, 7, 1, 'g'}, + {22, 7, 4, '\n'}, + {23, 8, 1, '\n'}, + }, + }, + } + + for idx, c := range testCases { + nC := NewPosCache(c.query) + for ix, v := range c.pos { + pos := nC.LnCol(Pos(v[0])) + if pos == InvalidLnColPos { + t.Fatal(idx, " ", ix, " InvalidPos") + } + assert.Equal(t, pos.Ln, v[1], "ln not eq") + assert.Equal(t, pos.Col, v[2], "col not eq") + assert.Equal(t, v[3], int(c.query[v[0]])) + } + } +} diff --git a/scripts/test_fn_use/test_fn_use.sh b/scripts/test_fn_use/test_fn_use.sh index e5a0293..20be885 100755 --- a/scripts/test_fn_use/test_fn_use.sh +++ b/scripts/test_fn_use/test_fn_use.sh @@ -9,7 +9,7 @@ echo -e "\033[32m> platypus script (s.p):\033[0m" cat s.p echo -e "\033[32m> platypus run -s test_fn_use.p -i test_fn_use.data -t lineprotocol --output-type lineprotocol\033[0m" -go run ../../cmd/platypus/platypus.go run -s test_fn_use.p -i test_fn_use.data -t lineprotocol --output-type lineprotocol +go run ../../cmd/platypus/ run -s test_fn_use.p -i test_fn_use.data -t lineprotocol --output-type lineprotocol echo -e "\033[32m> platypus run -w . -s test_fn_use.p -i test_fn_use.data -t lineprotocol\033[0m" -go run ../../cmd/platypus/platypus.go run -w . -s test_fn_use.p -i test_fn_use.data -t lineprotocol +go run ../../cmd/platypus/ run -w . -s test_fn_use.p -i test_fn_use.data -t lineprotocol diff --git a/scripts/test_nginx_access_log/nginx_access_log.p b/scripts/test_nginx_access_log/nginx_access_log.p index 759a5d1..0c808ce 100644 --- a/scripts/test_nginx_access_log/nginx_access_log.p +++ b/scripts/test_nginx_access_log/nginx_access_log.p @@ -3,15 +3,6 @@ add_pattern("access_common", "%{NOTSPACE:client_ip} %{NOTSPACE:http_ident} %{NOT grok(_, '%{access_common} "%{NOTSPACE:referrer}" "%{GREEDYDATA:agent}"') -user_agent(agent) - -group_between(status_code, [200,299], "OK", status) -group_between(status_code, [300,399], "notice", status) -group_between(status_code, [400,499], "warning", status) -group_between(status_code, [500,599], "error", status) - -nullif(http_ident, "-") -nullif(http_auth, "-") -nullif(upstream, "") +set_tag(http_method) default_time(time) \ No newline at end of file diff --git a/scripts/test_nginx_access_log/test_fn_use.sh b/scripts/test_nginx_access_log/test_fn_use.sh new file mode 100755 index 0000000..3a21ce2 --- /dev/null +++ b/scripts/test_nginx_access_log/test_fn_use.sh @@ -0,0 +1,12 @@ +echo -e "\033[32m> input-type: text, data:\033[0m" + +echo $(cat nginx_access_log.data) + +echo -e "\033[32m> platypus script (nginx_access_log.p):\033[0m" +cat nginx_access_log.p + +echo -e "\033[32m> platypus run -s nginx_access_log.p -i nginx_access_log.data -t text --output-type lineprotocol\033[0m" +go run ../../cmd/platypus/ run -s nginx_access_log.p -i nginx_access_log.data -t text --output-type lineprotocol + +echo -e "\033[32m> platypus run -w . -s nginx_access_log.p -i nginx_access_log.data -t text\033[0m" +go run ../../cmd/platypus/ run -w . -s nginx_access_log.p -i nginx_access_log.data -t text