From 5768f0bcb4048c10bb1f0957efbe59a217bf0074 Mon Sep 17 00:00:00 2001 From: Felix Frank Date: Thu, 21 Mar 2024 09:47:39 +0000 Subject: [PATCH 1/7] cli: run: Note an apparent UX issue --- cli/run.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/run.go b/cli/run.go index d124517de9..19df0871e8 100644 --- a/cli/run.go +++ b/cli/run.go @@ -152,7 +152,7 @@ func (obj *RunArgs) Run(ctx context.Context, data *cliUtil.Data) (bool, error) { deploy, err := gapiObj.Cli(info) if err != nil { - return false, cliUtil.CliParseError(err) // consistent errors + return false, cliUtil.CliParseError(err) // TODO: it seems unlikely that parsing the CLI failed at this stage, and then the error will be misleading } if cmd := obj.RunLang; cmd != nil && cmd.OnlyUnify && deploy == nil { From bfd832cc2339fa4c53687bd5748ff13f49b2c961 Mon Sep 17 00:00:00 2001 From: Felix Frank Date: Sat, 23 Mar 2024 17:48:22 +0000 Subject: [PATCH 2/7] lang: parser: Simple WiP implementation of code positions in AST nodes --- lang/ast/structs.go | 51 ++++++++++++++++++++++++++++++++++++++++++++ lang/parser/parser.y | 25 ++++++++++++++++------ 2 files changed, 69 insertions(+), 7 deletions(-) diff --git a/lang/ast/structs.go b/lang/ast/structs.go index b32e0fe82e..75fc8d6803 100644 --- a/lang/ast/structs.go +++ b/lang/ast/structs.go @@ -177,12 +177,43 @@ var ( orderingGraphSingleton = false ) +// TextArea stores the coordinates of a statement or expression in the form of +// starting line/column and ending line/column +type TextArea struct { + startLine int + startColumn int + endLine int + endColumn int + + // Bug5819 works around issue https://github.com/golang/go/issues/5819 + Bug5819 interface{} // XXX: workaround +} + +// Locate is used by the parser to store the token positions in AST nodes +func (a *TextArea) Locate(line int, col int, endline int, endcol int) { + a.startLine = line + a.startColumn = col + a.endLine = endline + a.endColumn = endcol +} + +// GetPosition returns the starting line/column of an AST node +func (a *TextArea) GetPosition() (int, int) { + return a.startLine, a.startColumn +} + +// GetEndPosition returns the end line/column of an AST node +func (a *TextArea) GetEndPosition() (int, int) { + return a.endLine, a.endColumn +} + // StmtBind is a representation of an assignment, which binds a variable to an // expression. type StmtBind struct { Ident string Value interfaces.Expr Type *types.Type + TextArea } // String returns a short representation of this statement. @@ -365,6 +396,7 @@ type StmtRes struct { Name interfaces.Expr // unique name for the res of this kind namePtr interfaces.Func // ptr for table lookup Contents []StmtResContents // list of fields/edges in parsed order + TextArea } // String returns a short representation of this statement. @@ -2059,6 +2091,7 @@ type StmtEdge struct { // TODO: should notify be an Expr? Notify bool // specifies that this edge sends a notification as well + TextArea } // String returns a short representation of this statement. @@ -2561,6 +2594,7 @@ type StmtIf struct { conditionPtr interfaces.Func // ptr for table lookup ThenBranch interfaces.Stmt // optional, but usually present ElseBranch interfaces.Stmt // optional + TextArea } // String returns a short representation of this statement. @@ -2923,6 +2957,7 @@ type StmtProg struct { importFiles []string // list of files seen during the SetScope import Body []interfaces.Stmt + TextArea } // String returns a short representation of this statement. @@ -4325,6 +4360,7 @@ type StmtFunc struct { Name string Func interfaces.Expr Type *types.Type + TextArea } // String returns a short representation of this statement. @@ -4531,6 +4567,7 @@ type StmtClass struct { Name string Args []*interfaces.Arg Body interfaces.Stmt // probably a *StmtProg + TextArea } // String returns a short representation of this statement. @@ -4733,6 +4770,7 @@ type StmtInclude struct { Name string Args []interfaces.Expr Alias string + TextArea } // String returns a short representation of this statement. @@ -5098,6 +5136,7 @@ func (obj *StmtInclude) Output(table map[interfaces.Func]types.Value) (*interfac type StmtImport struct { Name string Alias string + TextArea } // String returns a short representation of this statement. @@ -5279,6 +5318,7 @@ type ExprBool struct { scope *interfaces.Scope // store for referencing this later V bool + TextArea } // String returns a short representation of this expression. @@ -5424,6 +5464,7 @@ type ExprStr struct { scope *interfaces.Scope // store for referencing this later V string // value of this string + TextArea } // String returns a short representation of this expression. @@ -5619,6 +5660,7 @@ type ExprInt struct { scope *interfaces.Scope // store for referencing this later V int64 + TextArea } // String returns a short representation of this expression. @@ -5762,6 +5804,7 @@ type ExprFloat struct { scope *interfaces.Scope // store for referencing this later V float64 + TextArea } // String returns a short representation of this expression. @@ -5909,6 +5952,7 @@ type ExprList struct { //Elements []*ExprListElement Elements []interfaces.Expr + TextArea } // String returns a short representation of this expression. @@ -6262,6 +6306,7 @@ type ExprMap struct { typ *types.Type KVs []*ExprMapKV + TextArea } // String returns a short representation of this expression. @@ -6747,6 +6792,7 @@ type ExprStruct struct { typ *types.Type Fields []*ExprStructField // the list (fields) are intentionally ordered! + TextArea } // String returns a short representation of this expression. @@ -7179,6 +7225,7 @@ type ExprFunc struct { // XXX: is this necessary? //V func(interfaces.Txn, []pgraph.Vertex) (pgraph.Vertex, error) + TextArea } // String returns a short representation of this expression. @@ -7923,6 +7970,7 @@ type ExprCall struct { Args []interfaces.Expr // list of args in parsed order // Var specifies whether the function being called is a lambda in a var. Var bool + TextArea } // String returns a short representation of this expression. @@ -8654,6 +8702,7 @@ type ExprVar struct { typ *types.Type Name string // name of the variable + TextArea } // String returns a short representation of this expression. @@ -8917,6 +8966,7 @@ type ExprParam struct { typ *types.Type Name string // name of the parameter + TextArea } // String returns a short representation of this expression. @@ -9629,6 +9679,7 @@ type ExprIf struct { Condition interfaces.Expr ThenBranch interfaces.Expr // could be an ExprBranch ElseBranch interfaces.Expr // could be an ExprBranch + TextArea } // String returns a short representation of this expression. diff --git a/lang/parser/parser.y b/lang/parser/parser.y index f497b7997a..ff64df15c9 100644 --- a/lang/parser/parser.y +++ b/lang/parser/parser.y @@ -199,12 +199,13 @@ stmt: } | IF expr OPEN_CURLY prog CLOSE_CURLY { - posLast(yylex, yyDollar) // our pos - $$.stmt = &ast.StmtIf{ + result := &ast.StmtIf{ Condition: $2.expr, ThenBranch: $4.stmt, //ElseBranch: nil, } + posLastAndStore(yylex, yyDollar, &result.TextArea) + $$.stmt = result } | IF expr OPEN_CURLY prog CLOSE_CURLY ELSE OPEN_CURLY prog CLOSE_CURLY { @@ -1486,10 +1487,19 @@ func cast(y yyLexer) *lexParseAST { return x.(*lexParseAST) } -// postLast pulls out the "last token" and does a pos with that. This is a hack! +// The posLast variant that specifies a node will store the coordinates in the +// node. +func posLastAndStore(y yyLexer, dollars []yySymType, node *ast.TextArea) { + posLast(y, dollars) + first := dollars[0] + last := dollars[len(dollars)-1] + node.Locate(first.row, first.col, last.row, last.col) +} + +// postLast runs pos on the first and last token of the current stmt/expr. func posLast(y yyLexer, dollars []yySymType) { - // pick the last token in the set matched by the parser - pos(y, dollars[len(dollars)-1]) // our pos + pos(y, dollars[0]) + pos(y, dollars[len(dollars)-1]) } // cast is used to pull out the parser run-specific struct we store our AST in. @@ -1500,8 +1510,9 @@ func (yylex *Lexer) cast() *lexParseAST { // pos is a helper function used to track the position in the lexer. func (yylex *Lexer) pos(lval *yySymType) { - lval.row = yylex.Line() - lval.col = yylex.Column() + // add 1 because the lexer starts counting from 0 + lval.row = yylex.Line() + 1 + lval.col = yylex.Column() + 1 // TODO: we could use: `s := yylex.Text()` to calculate a delta length! //log.Printf("lexer: %d x %d", lval.row, lval.col) } From fa786fa82a9e9df9871f35491b4946810c5664a8 Mon Sep 17 00:00:00 2001 From: Felix Frank Date: Sat, 23 Mar 2024 18:20:08 +0000 Subject: [PATCH 3/7] lang: parser: Store locations in various AST nodes --- lang/ast/structs.go | 30 ++++---- lang/parser/parser.y | 159 ++++++++++++++++++++++--------------------- 2 files changed, 98 insertions(+), 91 deletions(-) diff --git a/lang/ast/structs.go b/lang/ast/structs.go index 75fc8d6803..03eb301894 100644 --- a/lang/ast/structs.go +++ b/lang/ast/structs.go @@ -197,13 +197,21 @@ func (a *TextArea) Locate(line int, col int, endline int, endcol int) { a.endColumn = endcol } +// LocalNode is the interface implemented by AST nodes that store their code +// position. It is implemented by node types that embed TextArea. +type LocalNode interface { + Locate(int, int, int, int) + GetPosition() (int, int) + GetEndPosition() (int, int) +} + // GetPosition returns the starting line/column of an AST node -func (a *TextArea) GetPosition() (int, int) { +func (a TextArea) GetPosition() (int, int) { return a.startLine, a.startColumn } // GetEndPosition returns the end line/column of an AST node -func (a *TextArea) GetEndPosition() (int, int) { +func (a TextArea) GetEndPosition() (int, int) { return a.endLine, a.endColumn } @@ -251,11 +259,9 @@ func (obj *StmtBind) Interpolate() (interfaces.Stmt, error) { if err != nil { return nil, err } - return &StmtBind{ - Ident: obj.Ident, - Value: interpolated, - Type: obj.Type, - }, nil + result := *obj + result.Value = interpolated + return &result, nil } // Copy returns a light copy of this struct. Anything static will not be copied. @@ -2676,11 +2682,11 @@ func (obj *StmtIf) Interpolate() (interfaces.Stmt, error) { return nil, errwrap.Wrapf(err, "could not interpolate ElseBranch") } } - return &StmtIf{ - Condition: condition, - ThenBranch: thenBranch, - ElseBranch: elseBranch, - }, nil + result := *obj + result.Condition = condition + result.ThenBranch = thenBranch + result.ElseBranch = elseBranch + return &result, nil } // Copy returns a light copy of this struct. Anything static will not be copied. diff --git a/lang/parser/parser.y b/lang/parser/parser.y index ff64df15c9..442828bc91 100644 --- a/lang/parser/parser.y +++ b/lang/parser/parser.y @@ -149,14 +149,13 @@ top: prog: /* end of list */ { - posLast(yylex, yyDollar) // our pos $$.stmt = &ast.StmtProg{ Body: []interfaces.Stmt{}, } + //locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.stmt) } | prog stmt { - posLast(yylex, yyDollar) // our pos // TODO: should we just skip comments for now? //if _, ok := $2.stmt.(*ast.StmtComment); !ok { //} @@ -166,50 +165,50 @@ prog: $$.stmt = &ast.StmtProg{ Body: stmts, } + //locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.stmt) } } ; stmt: COMMENT { - posLast(yylex, yyDollar) // our pos $$.stmt = &ast.StmtComment{ Value: $1.str, } + locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.stmt) } | bind { - posLast(yylex, yyDollar) // our pos $$.stmt = $1.stmt + locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.stmt) } | panic { - posLast(yylex, yyDollar) // our pos $$.stmt = $1.stmt + locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.stmt) } | resource { - posLast(yylex, yyDollar) // our pos $$.stmt = $1.stmt + locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.stmt) } | edge { - posLast(yylex, yyDollar) // our pos $$.stmt = $1.stmt + locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.stmt) } | IF expr OPEN_CURLY prog CLOSE_CURLY { - result := &ast.StmtIf{ + $$.stmt = &ast.StmtIf{ Condition: $2.expr, ThenBranch: $4.stmt, //ElseBranch: nil, } - posLastAndStore(yylex, yyDollar, &result.TextArea) - $$.stmt = result + locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.stmt) } | IF expr OPEN_CURLY prog CLOSE_CURLY ELSE OPEN_CURLY prog CLOSE_CURLY { - posLast(yylex, yyDollar) // our pos + locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.stmt) $$.stmt = &ast.StmtIf{ Condition: $2.expr, ThenBranch: $4.stmt, @@ -222,7 +221,7 @@ stmt: // `func name(, ) { }` | FUNC_IDENTIFIER IDENTIFIER OPEN_PAREN args CLOSE_PAREN OPEN_CURLY expr CLOSE_CURLY { - posLast(yylex, yyDollar) // our pos + locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.stmt) $$.stmt = &ast.StmtFunc{ Name: $2.str, Func: &ast.ExprFunc{ @@ -235,7 +234,6 @@ stmt: // `func name(...) { }` | FUNC_IDENTIFIER IDENTIFIER OPEN_PAREN args CLOSE_PAREN type OPEN_CURLY expr CLOSE_CURLY { - posLast(yylex, yyDollar) // our pos fn := &ast.ExprFunc{ Args: $4.args, Return: $6.typ, // return type is known @@ -272,191 +270,192 @@ stmt: Func: fn, Type: typ, // sam says add the type here instead... } + locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.stmt) } // `class name { }` | CLASS_IDENTIFIER colon_identifier OPEN_CURLY prog CLOSE_CURLY { - posLast(yylex, yyDollar) // our pos $$.stmt = &ast.StmtClass{ Name: $2.str, Args: nil, Body: $4.stmt, } + locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.stmt) } // `class name() { }` // `class name(, ) { }` | CLASS_IDENTIFIER colon_identifier OPEN_PAREN args CLOSE_PAREN OPEN_CURLY prog CLOSE_CURLY { - posLast(yylex, yyDollar) // our pos $$.stmt = &ast.StmtClass{ Name: $2.str, Args: $4.args, Body: $7.stmt, } + locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.stmt) } // `include name` | INCLUDE_IDENTIFIER dotted_identifier { - posLast(yylex, yyDollar) // our pos $$.stmt = &ast.StmtInclude{ Name: $2.str, } + locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.stmt) } // `include name(...)` | INCLUDE_IDENTIFIER dotted_identifier OPEN_PAREN call_args CLOSE_PAREN { - posLast(yylex, yyDollar) // our pos $$.stmt = &ast.StmtInclude{ Name: $2.str, Args: $4.exprs, } + locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.stmt) } // `include name as foo` // TODO: should we support: `include name as *` | INCLUDE_IDENTIFIER dotted_identifier AS_IDENTIFIER IDENTIFIER { - posLast(yylex, yyDollar) // our pos $$.stmt = &ast.StmtInclude{ Name: $2.str, Alias: $4.str, } + locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.stmt) } // `include name(...) as foo` // TODO: should we support: `include name(...) as *` | INCLUDE_IDENTIFIER dotted_identifier OPEN_PAREN call_args CLOSE_PAREN AS_IDENTIFIER IDENTIFIER { - posLast(yylex, yyDollar) // our pos $$.stmt = &ast.StmtInclude{ Name: $2.str, Args: $4.exprs, Alias: $7.str, } + locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.stmt) } // `import "name"` | IMPORT_IDENTIFIER STRING { - posLast(yylex, yyDollar) // our pos $$.stmt = &ast.StmtImport{ Name: $2.str, //Alias: "", } + locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.stmt) } // `import "name" as alias` | IMPORT_IDENTIFIER STRING AS_IDENTIFIER IDENTIFIER { - posLast(yylex, yyDollar) // our pos $$.stmt = &ast.StmtImport{ Name: $2.str, Alias: $4.str, } + locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.stmt) } // `import "name" as *` | IMPORT_IDENTIFIER STRING AS_IDENTIFIER MULTIPLY { - posLast(yylex, yyDollar) // our pos $$.stmt = &ast.StmtImport{ Name: $2.str, Alias: $4.str, } + locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.stmt) } /* // resource bind | rbind { - posLast(yylex, yyDollar) // our pos $$.stmt = $1.stmt + locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.stmt) } */ ; expr: BOOL { - posLast(yylex, yyDollar) // our pos $$.expr = &ast.ExprBool{ V: $1.bool, } + locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr) } | STRING { - posLast(yylex, yyDollar) // our pos $$.expr = &ast.ExprStr{ V: $1.str, } + locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr) } | INTEGER { - posLast(yylex, yyDollar) // our pos $$.expr = &ast.ExprInt{ V: $1.int, } + locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr) } | FLOAT { - posLast(yylex, yyDollar) // our pos $$.expr = &ast.ExprFloat{ V: $1.float, } + locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr) } | list { - posLast(yylex, yyDollar) // our pos // TODO: list could be squashed in here directly... $$.expr = $1.expr + locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr) } | map { - posLast(yylex, yyDollar) // our pos // TODO: map could be squashed in here directly... $$.expr = $1.expr + locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr) } | struct { - posLast(yylex, yyDollar) // our pos // TODO: struct could be squashed in here directly... $$.expr = $1.expr + locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr) } | call { - posLast(yylex, yyDollar) // our pos // TODO: call could be squashed in here directly... $$.expr = $1.expr + locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr) } | var { - posLast(yylex, yyDollar) // our pos // TODO: var could be squashed in here directly... $$.expr = $1.expr + locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr) } | func { - posLast(yylex, yyDollar) // our pos // TODO: var could be squashed in here directly... $$.expr = $1.expr + locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr) } | IF expr OPEN_CURLY expr CLOSE_CURLY ELSE OPEN_CURLY expr CLOSE_CURLY { - posLast(yylex, yyDollar) // our pos $$.expr = &ast.ExprIf{ Condition: $2.expr, ThenBranch: $4.expr, ElseBranch: $8.expr, } + locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr) } // parenthesis wrap an expression for precedence | OPEN_PAREN expr CLOSE_PAREN { - posLast(yylex, yyDollar) // our pos $$.expr = $2.expr + locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr) } ; list: // `[42, 0, -13]` OPEN_BRACK list_elements CLOSE_BRACK { - posLast(yylex, yyDollar) // our pos $$.expr = &ast.ExprList{ Elements: $2.exprs, } + locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr) } ; list_elements: @@ -474,18 +473,18 @@ list_elements: list_element: expr COMMA { - posLast(yylex, yyDollar) // our pos $$.expr = $1.expr + locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr) } ; map: // `{"hello" => "there", "world" => "big",}` OPEN_CURLY map_kvs CLOSE_CURLY { - posLast(yylex, yyDollar) // our pos $$.expr = &ast.ExprMap{ KVs: $2.mapKVs, } + locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr) } ; map_kvs: @@ -514,10 +513,10 @@ struct: // `struct{answer => 0, truth => false, hello => "world",}` STRUCT_IDENTIFIER OPEN_CURLY struct_fields CLOSE_CURLY { - posLast(yylex, yyDollar) // our pos $$.expr = &ast.ExprStruct{ Fields: $3.structFields, } + locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr) } ; struct_fields: @@ -547,18 +546,17 @@ call: // iter.map(...) dotted_identifier OPEN_PAREN call_args CLOSE_PAREN { - posLast(yylex, yyDollar) // our pos $$.expr = &ast.ExprCall{ Name: $1.str, Args: $3.exprs, //Var: false, // default } + locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr) } // calling a function that's stored in a variable (a lambda) // `$foo(4, "hey")` # call function value | dotted_var_identifier OPEN_PAREN call_args CLOSE_PAREN { - posLast(yylex, yyDollar) // our pos $$.expr = &ast.ExprCall{ Name: $1.str, Args: $3.exprs, @@ -566,10 +564,10 @@ call: // prefix to the Name, but I felt this was more elegant. Var: true, // lambda } + locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr) } | expr PLUS expr { - posLast(yylex, yyDollar) // our pos $$.expr = &ast.ExprCall{ Name: operators.OperatorFuncName, Args: []interfaces.Expr{ @@ -580,10 +578,10 @@ call: $3.expr, }, } + locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr) } | expr MINUS expr { - posLast(yylex, yyDollar) // our pos $$.expr = &ast.ExprCall{ Name: operators.OperatorFuncName, Args: []interfaces.Expr{ @@ -594,10 +592,10 @@ call: $3.expr, }, } + locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr) } | expr MULTIPLY expr { - posLast(yylex, yyDollar) // our pos $$.expr = &ast.ExprCall{ Name: operators.OperatorFuncName, Args: []interfaces.Expr{ @@ -608,10 +606,10 @@ call: $3.expr, }, } + locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr) } | expr DIVIDE expr { - posLast(yylex, yyDollar) // our pos $$.expr = &ast.ExprCall{ Name: operators.OperatorFuncName, Args: []interfaces.Expr{ @@ -622,10 +620,10 @@ call: $3.expr, }, } + locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr) } | expr EQ expr { - posLast(yylex, yyDollar) // our pos $$.expr = &ast.ExprCall{ Name: operators.OperatorFuncName, Args: []interfaces.Expr{ @@ -636,10 +634,10 @@ call: $3.expr, }, } + locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr) } | expr NEQ expr { - posLast(yylex, yyDollar) // our pos $$.expr = &ast.ExprCall{ Name: operators.OperatorFuncName, Args: []interfaces.Expr{ @@ -650,10 +648,10 @@ call: $3.expr, }, } + locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr) } | expr LT expr { - posLast(yylex, yyDollar) // our pos $$.expr = &ast.ExprCall{ Name: operators.OperatorFuncName, Args: []interfaces.Expr{ @@ -664,10 +662,10 @@ call: $3.expr, }, } + locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr) } | expr GT expr { - posLast(yylex, yyDollar) // our pos $$.expr = &ast.ExprCall{ Name: operators.OperatorFuncName, Args: []interfaces.Expr{ @@ -678,10 +676,10 @@ call: $3.expr, }, } + locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr) } | expr LTE expr { - posLast(yylex, yyDollar) // our pos $$.expr = &ast.ExprCall{ Name: operators.OperatorFuncName, Args: []interfaces.Expr{ @@ -692,10 +690,10 @@ call: $3.expr, }, } + locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr) } | expr GTE expr { - posLast(yylex, yyDollar) // our pos $$.expr = &ast.ExprCall{ Name: operators.OperatorFuncName, Args: []interfaces.Expr{ @@ -706,10 +704,10 @@ call: $3.expr, }, } + locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr) } | expr AND expr { - posLast(yylex, yyDollar) // our pos $$.expr = &ast.ExprCall{ Name: operators.OperatorFuncName, Args: []interfaces.Expr{ @@ -720,10 +718,10 @@ call: $3.expr, }, } + locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr) } | expr OR expr { - posLast(yylex, yyDollar) // our pos $$.expr = &ast.ExprCall{ Name: operators.OperatorFuncName, Args: []interfaces.Expr{ @@ -734,10 +732,10 @@ call: $3.expr, }, } + locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr) } | NOT expr { - posLast(yylex, yyDollar) // our pos $$.expr = &ast.ExprCall{ Name: operators.OperatorFuncName, Args: []interfaces.Expr{ @@ -747,13 +745,13 @@ call: $2.expr, }, } + locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr) } // lookup an index in a list or a key in a map // lookup($foo, $key) // `$foo[$key]` // no default specifier | expr OPEN_BRACK expr CLOSE_BRACK { - posLast(yylex, yyDollar) // our pos $$.expr = &ast.ExprCall{ Name: funcs.LookupFuncName, Args: []interfaces.Expr{ @@ -762,13 +760,13 @@ call: //$6.expr, // the default }, } + locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr) } // lookup an index in a list or a key in a map with a default // lookup_default($foo, $key, $default) // `$foo[$key] || "default"` | expr OPEN_BRACK expr CLOSE_BRACK DEFAULT expr { - posLast(yylex, yyDollar) // our pos $$.expr = &ast.ExprCall{ Name: funcs.LookupDefaultFuncName, Args: []interfaces.Expr{ @@ -777,13 +775,13 @@ call: $6.expr, // the default }, } + locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr) } // lookup a field in a struct // _struct_lookup($foo, "field") // $foo->field | expr ARROW IDENTIFIER { - posLast(yylex, yyDollar) // our pos $$.expr = &ast.ExprCall{ Name: funcs.StructLookupFuncName, Args: []interfaces.Expr{ @@ -794,13 +792,13 @@ call: //$5.expr, // the default }, } + locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr) } // lookup a field in a struct with a default // _struct_lookup_optional($foo, "field", "default") // $foo->field || "default" | expr ARROW IDENTIFIER DEFAULT expr { - posLast(yylex, yyDollar) // our pos $$.expr = &ast.ExprCall{ Name: funcs.StructLookupOptionalFuncName, Args: []interfaces.Expr{ @@ -811,10 +809,10 @@ call: $5.expr, // the default }, } + locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr) } | expr IN expr { - posLast(yylex, yyDollar) // our pos $$.expr = &ast.ExprCall{ Name: funcs.ContainsFuncName, Args: []interfaces.Expr{ @@ -822,6 +820,7 @@ call: $3.expr, }, } + locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr) } ; // list order gets us the position of the arg, but named params would work too! @@ -847,10 +846,10 @@ call_args: var: dotted_var_identifier { - posLast(yylex, yyDollar) // our pos $$.expr = &ast.ExprVar{ Name: $1.str, } + locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr) } ; func: @@ -860,22 +859,22 @@ func: // `func(, ) { }` FUNC_IDENTIFIER OPEN_PAREN args CLOSE_PAREN OPEN_CURLY expr CLOSE_CURLY { - posLast(yylex, yyDollar) // our pos $$.expr = &ast.ExprFunc{ Args: $3.args, //Return: nil, Body: $6.expr, } + locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr) } // `func(...) { }` | FUNC_IDENTIFIER OPEN_PAREN args CLOSE_PAREN type OPEN_CURLY expr CLOSE_CURLY { - posLast(yylex, yyDollar) // our pos $$.expr = &ast.ExprFunc{ Args: $3.args, Return: $5.typ, // return type is known Body: $7.expr, } + locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr) isFullyTyped := $5.typ != nil // true if set m := make(map[string]*types.Type) ord := []string{} @@ -940,17 +939,16 @@ bind: // `$s = "hey"` var_identifier EQUALS expr { - posLast(yylex, yyDollar) // our pos $$.stmt = &ast.StmtBind{ Ident: $1.str, Value: $3.expr, } + locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.stmt) } // `$x bool = true` // `$x int = if true { 42 } else { 13 }` | var_identifier type EQUALS expr { - posLast(yylex, yyDollar) // our pos var expr interfaces.Expr = $4.expr // XXX: We still need to do this for now it seems... if err := expr.SetType($2.typ); err != nil { @@ -962,6 +960,7 @@ bind: Value: expr, Type: $2.typ, // sam says add the type here instead... } + locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.stmt) } ; panic: @@ -972,7 +971,6 @@ panic: //} PANIC_IDENTIFIER OPEN_PAREN call_args CLOSE_PAREN { - posLast(yylex, yyDollar) // our pos call := &ast.ExprCall{ Name: $1.str, // the function name Args: $3.exprs, @@ -991,6 +989,7 @@ panic: ThenBranch: res, //ElseBranch: nil, } + locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.stmt) } ; /* TODO: do we want to include this? @@ -998,7 +997,6 @@ panic: rbind: var_identifier EQUALS resource { - posLast(yylex, yyDollar) // our pos // XXX: this kind of bind is different than the others, because // it can only really be used for send->recv stuff, eg: // foo.SomeString -> bar.SomeOtherString @@ -1006,6 +1004,7 @@ rbind: Ident: $1.str, Value: $3.stmt, } + locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr) } ; */ @@ -1013,12 +1012,12 @@ resource: // `file "/tmp/hello" { ... }` or `aws:ec2 "/tmp/hello" { ... }` colon_identifier expr OPEN_CURLY resource_body CLOSE_CURLY { - posLast(yylex, yyDollar) // our pos $$.stmt = &ast.StmtRes{ Kind: $1.str, Name: $2.expr, Contents: $4.resContents, } + locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.stmt) } ; resource_body: @@ -1181,16 +1180,15 @@ edge: // Test["t1"] -> Test["t2"] -> Test["t3"] # chain or pair edge_half_list { - posLast(yylex, yyDollar) // our pos $$.stmt = &ast.StmtEdge{ EdgeHalfList: $1.edgeHalfList, //Notify: false, // unused here } + locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.stmt) } // Test["t1"].foo_send -> Test["t2"].blah_recv # send/recv | edge_half_sendrecv ARROW edge_half_sendrecv { - posLast(yylex, yyDollar) // our pos $$.stmt = &ast.StmtEdge{ EdgeHalfList: []*ast.StmtEdgeHalf{ $1.edgeHalf, @@ -1198,6 +1196,7 @@ edge: }, //Notify: false, // unused here, it is implied (i think) } + locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.stmt) } ; edge_half_list: @@ -1489,16 +1488,19 @@ func cast(y yyLexer) *lexParseAST { // The posLast variant that specifies a node will store the coordinates in the // node. -func posLastAndStore(y yyLexer, dollars []yySymType, node *ast.TextArea) { - posLast(y, dollars) - first := dollars[0] - last := dollars[len(dollars)-1] - node.Locate(first.row, first.col, last.row, last.col) +func locate(y yyLexer, first yySymType, last yySymType, node interfaces.Node) { + posLast(y, []yySymType{last}) // TODO: is it really useful to store this in the Lexer? the values are erratic and likely unhelpful + if ln, ok := node.(ast.LocalNode) ; !ok { + return + // only run Locate on nodes that look like they have not received locations yet + // otherwise the parser will come back and overwrite with faux end positions + } else if row, col := ln.GetPosition() ; row == 0 && col == 0 { + ln.Locate(first.row, first.col, last.row, last.col) + } } -// postLast runs pos on the first and last token of the current stmt/expr. +// postLast runs pos on the last token of the current stmt/expr. func posLast(y yyLexer, dollars []yySymType) { - pos(y, dollars[0]) pos(y, dollars[len(dollars)-1]) } @@ -1510,9 +1512,8 @@ func (yylex *Lexer) cast() *lexParseAST { // pos is a helper function used to track the position in the lexer. func (yylex *Lexer) pos(lval *yySymType) { - // add 1 because the lexer starts counting from 0 - lval.row = yylex.Line() + 1 - lval.col = yylex.Column() + 1 + lval.row = yylex.Line() + lval.col = yylex.Column() // TODO: we could use: `s := yylex.Text()` to calculate a delta length! //log.Printf("lexer: %d x %d", lval.row, lval.col) } From 408ee8ca8d9c0145661c25dd61dba091a940d39b Mon Sep 17 00:00:00 2001 From: Felix Frank Date: Sun, 8 Sep 2024 22:52:40 +0200 Subject: [PATCH 4/7] lang: ast: Fix up Interpolate() for ExprCall --- lang/ast/structs.go | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/lang/ast/structs.go b/lang/ast/structs.go index 03eb301894..beb4c295ff 100644 --- a/lang/ast/structs.go +++ b/lang/ast/structs.go @@ -8032,19 +8032,11 @@ func (obj *ExprCall) Interpolate() (interfaces.Expr, error) { orig = obj.orig } - return &ExprCall{ - data: obj.data, - scope: obj.scope, - typ: obj.typ, - // XXX: Copy copies this, do we want to here as well? (or maybe - // we want to do it here, but not in Copy?) - expr: obj.expr, - orig: orig, - V: obj.V, - Name: obj.Name, - Args: args, - Var: obj.Var, - }, nil + result := *obj + result.orig = orig + result.Args = args + + return &result, nil } // Copy returns a light copy of this struct. Anything static will not be copied. From de77311d72734d5f63eacd8c35cd101223bb841b Mon Sep 17 00:00:00 2001 From: Felix Frank Date: Tue, 10 Sep 2024 23:05:05 +0200 Subject: [PATCH 5/7] lang: gapi: Identify the AST node that caused unification to fail --- examples/lang/faulty/simple_types.mcl | 9 ++++++++ lang/ast/structs.go | 28 +++++++++++++++++++++++ lang/ast/util.go | 20 ++++++++++++++++ lang/gapi/gapi.go | 4 ++++ lang/interfaces/unification.go | 11 +++++++++ lang/unification/fastsolver/fastsolver.go | 3 ++- 6 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 examples/lang/faulty/simple_types.mcl diff --git a/examples/lang/faulty/simple_types.mcl b/examples/lang/faulty/simple_types.mcl new file mode 100644 index 0000000000..0ed381d948 --- /dev/null +++ b/examples/lang/faulty/simple_types.mcl @@ -0,0 +1,9 @@ + +$string = "hi" +$number = 7 + +if $string == $number { + test "faulty" { + anotherstr => "this should not run through type checking", + } +} diff --git a/lang/ast/structs.go b/lang/ast/structs.go index beb4c295ff..f432c87db6 100644 --- a/lang/ast/structs.go +++ b/lang/ast/structs.go @@ -190,6 +190,8 @@ type TextArea struct { } // Locate is used by the parser to store the token positions in AST nodes +// TODO: also note down the file name containing the statement/expression +// ...this is currently hard because the parser is blissfully unaware func (a *TextArea) Locate(line int, col int, endline int, endcol int) { a.startLine = line a.startColumn = col @@ -357,6 +359,7 @@ func (obj *StmtBind) TypeCheck() ([]*interfaces.UnificationInvariant, error) { invar := &interfaces.UnificationInvariant{ Expr: obj.Value, + Node: obj, Expect: typExpr, // obj.Type Actual: typ, } @@ -667,6 +670,7 @@ func (obj *StmtRes) TypeCheck() ([]*interfaces.UnificationInvariant, error) { invar := &interfaces.UnificationInvariant{ Expr: obj.Name, + Node: obj, Expect: typExpr, // the name Actual: typ, } @@ -1427,6 +1431,7 @@ func (obj *StmtResField) TypeCheck(kind string) ([]*interfaces.UnificationInvari // XXX: Is this needed? invar := &interfaces.UnificationInvariant{ Expr: obj.Condition, + Node: obj, Expect: types.TypeBool, Actual: typ, } @@ -1467,6 +1472,7 @@ func (obj *StmtResField) TypeCheck(kind string) ([]*interfaces.UnificationInvari // regular scenario invar := &interfaces.UnificationInvariant{ Expr: obj.Value, + Node: obj, Expect: typExpr, Actual: typ, } @@ -1702,6 +1708,7 @@ func (obj *StmtResEdge) TypeCheck(kind string) ([]*interfaces.UnificationInvaria // XXX: Is this needed? invar := &interfaces.UnificationInvariant{ Expr: obj.Condition, + Node: obj, Expect: types.TypeBool, Actual: typ, } @@ -1963,6 +1970,7 @@ func (obj *StmtResMeta) TypeCheck(kind string) ([]*interfaces.UnificationInvaria // XXX: Is this needed? invar := &interfaces.UnificationInvariant{ Expr: obj.Condition, + Node: obj, Expect: types.TypeBool, Actual: typ, } @@ -2041,6 +2049,7 @@ func (obj *StmtResMeta) TypeCheck(kind string) ([]*interfaces.UnificationInvaria invar := &interfaces.UnificationInvariant{ Expr: obj.MetaExpr, + Node: obj, Expect: typExpr, Actual: typ, } @@ -2563,6 +2572,7 @@ func (obj *StmtEdgeHalf) TypeCheck() ([]*interfaces.UnificationInvariant, error) invar := &interfaces.UnificationInvariant{ Expr: obj.Name, + Node: obj, Expect: typExpr, // the name Actual: typ, } @@ -2848,6 +2858,7 @@ func (obj *StmtIf) TypeCheck() ([]*interfaces.UnificationInvariant, error) { typExpr := types.TypeBool // default invar := &interfaces.UnificationInvariant{ Expr: obj.Condition, + Node: obj, Expect: typExpr, // the condition Actual: typ, } @@ -4526,6 +4537,7 @@ func (obj *StmtFunc) TypeCheck() ([]*interfaces.UnificationInvariant, error) { invar := &interfaces.UnificationInvariant{ Expr: obj.Func, + Node: obj, Expect: typExpr, // obj.Type Actual: typ, } @@ -5092,6 +5104,7 @@ func (obj *StmtInclude) TypeCheck() ([]*interfaces.UnificationInvariant, error) if typExpr := obj.class.Args[i].Type; typExpr != nil { invar := &interfaces.UnificationInvariant{ Expr: x, + Node: obj, Expect: typExpr, // type of arg Actual: typ, } @@ -5402,6 +5415,7 @@ func (obj *ExprBool) Infer() (*types.Type, []*interfaces.UnificationInvariant, e return types.TypeBool, []*interfaces.UnificationInvariant{ { Expr: obj, + Node: obj, Expect: types.TypeBool, Actual: types.TypeBool, }, @@ -5600,6 +5614,7 @@ func (obj *ExprStr) Infer() (*types.Type, []*interfaces.UnificationInvariant, er return types.TypeStr, []*interfaces.UnificationInvariant{ { Expr: obj, + Node: obj, Expect: types.TypeStr, Actual: types.TypeStr, }, @@ -5744,6 +5759,7 @@ func (obj *ExprInt) Infer() (*types.Type, []*interfaces.UnificationInvariant, er return types.TypeInt, []*interfaces.UnificationInvariant{ { Expr: obj, + Node: obj, Expect: types.TypeInt, Actual: types.TypeInt, }, @@ -5890,6 +5906,7 @@ func (obj *ExprFloat) Infer() (*types.Type, []*interfaces.UnificationInvariant, return types.TypeFloat, []*interfaces.UnificationInvariant{ { Expr: obj, + Node: obj, Expect: types.TypeFloat, Actual: types.TypeFloat, }, @@ -6183,6 +6200,7 @@ func (obj *ExprList) Infer() (*types.Type, []*interfaces.UnificationInvariant, e // This must be added even if redundant, so that we collect the obj ptr. invar := &interfaces.UnificationInvariant{ Expr: obj, + Node: obj, Expect: typExpr, // This is the type that we return. Actual: typType, } @@ -6625,6 +6643,7 @@ func (obj *ExprMap) Infer() (*types.Type, []*interfaces.UnificationInvariant, er // This must be added even if redundant, so that we collect the obj ptr. invar := &interfaces.UnificationInvariant{ Expr: obj, + Node: obj, Expect: typExpr, // This is the type that we return. Actual: typType, } @@ -7050,6 +7069,7 @@ func (obj *ExprStruct) Infer() (*types.Type, []*interfaces.UnificationInvariant, // This must be added even if redundant, so that we collect the obj ptr. invar := &interfaces.UnificationInvariant{ Expr: obj, + Node: obj, Expect: typExpr, // This is the type that we return. Actual: typType, } @@ -7799,6 +7819,7 @@ func (obj *ExprFunc) Infer() (*types.Type, []*interfaces.UnificationInvariant, e // This must be added even if redundant, so that we collect the obj ptr. invar := &interfaces.UnificationInvariant{ Expr: obj, + Node: obj, Expect: typExpr, // This is the type that we return. Actual: typType, } @@ -8490,6 +8511,7 @@ func (obj *ExprCall) Infer() (*types.Type, []*interfaces.UnificationInvariant, e // This must be added even if redundant, so that we collect the obj ptr. invar := &interfaces.UnificationInvariant{ Expr: obj, + Node: obj, Expect: typExpr, // This is the type that we return. Actual: typType, } @@ -8560,6 +8582,7 @@ func (obj *ExprCall) Infer() (*types.Type, []*interfaces.UnificationInvariant, e invar := &interfaces.UnificationInvariant{ Expr: obj.expr, // this should NOT be obj + Node: obj, Expect: typFunc, // TODO: are these two reversed here? Actual: typFn, } @@ -8880,6 +8903,7 @@ func (obj *ExprVar) Infer() (*types.Type, []*interfaces.UnificationInvariant, er // This adds the obj ptr, so it's seen as an expr that we need to solve. invar := &interfaces.UnificationInvariant{ Expr: obj, + Node: obj, Expect: typ, Actual: typ, } @@ -9108,6 +9132,7 @@ func (obj *ExprParam) Infer() (*types.Type, []*interfaces.UnificationInvariant, // This adds the obj ptr, so it's seen as an expr that we need to solve. invar := &interfaces.UnificationInvariant{ Expr: obj, + Node: obj, Expect: typ, Actual: typ, } @@ -9415,6 +9440,7 @@ func (obj *ExprTopLevel) Infer() (*types.Type, []*interfaces.UnificationInvarian // This adds the obj ptr, so it's seen as an expr that we need to solve. invar := &interfaces.UnificationInvariant{ Expr: obj, + Node: obj, Expect: typ, Actual: typ, } @@ -9609,6 +9635,7 @@ func (obj *ExprSingleton) Infer() (*types.Type, []*interfaces.UnificationInvaria // to solve. invar := &interfaces.UnificationInvariant{ Expr: obj, + Node: obj, Expect: typ, Actual: typ, } @@ -9977,6 +10004,7 @@ func (obj *ExprIf) Infer() (*types.Type, []*interfaces.UnificationInvariant, err // This must be added even if redundant, so that we collect the obj ptr. invar := &interfaces.UnificationInvariant{ Expr: obj, + Node: obj, Expect: typExpr, // This is the type that we return. Actual: typType, } diff --git a/lang/ast/util.go b/lang/ast/util.go index 4c4e71237a..c951c2402d 100644 --- a/lang/ast/util.go +++ b/lang/ast/util.go @@ -393,3 +393,23 @@ func lambdaScopeFeedback(scope *interfaces.Scope, logf func(format string, v ... logf("$%s(...)", name) } } + +func AreaParentOf(needle, haystack interfaces.Node) LocalNode { + var LastArea LocalNode + + err := haystack.Apply(func(n interfaces.Node) error { + ln, ok := n.(LocalNode) + if ok { + LastArea = ln + } + if n == needle { + return fmt.Errorf("found") + } + return nil + }) + + if err != nil && err.Error() == "found" { + return LastArea + } + return haystack.(LocalNode) +} diff --git a/lang/gapi/gapi.go b/lang/gapi/gapi.go index 1013f140fc..93265af560 100644 --- a/lang/gapi/gapi.go +++ b/lang/gapi/gapi.go @@ -318,6 +318,10 @@ func (obj *GAPI) Cli(info *gapi.Info) (*gapi.Deploy, error) { if args.OnlyUnify { logf("type unification failed after %s", formatted) } + cause := unifyErr.(*interfaces.UnificationInvariant).Node + parent := ast.AreaParentOf(cause,iast) + line, col := parent.GetPosition() + logf("possible type issue found at line %d column %d", line, col) return nil, errwrap.Wrapf(unifyErr, "could not unify types") } diff --git a/lang/interfaces/unification.go b/lang/interfaces/unification.go index 59bd854a13..1484314cdd 100644 --- a/lang/interfaces/unification.go +++ b/lang/interfaces/unification.go @@ -43,11 +43,22 @@ type UnificationInvariant struct { // formerly the SamInvariant // our error messages. Expr Expr + // Node is the AST node holding that expression. This improves our error + // messages more. + Node Node + // Expect is one of the two types to unify. Expect *types.Type // Actual is one of the two types to unify. Actual *types.Type + + // An error string to pass along with this + Err string +} + +func (obj *UnificationInvariant) Error() string { + return obj.Err } // GenericCheck is the generic implementation of the Check Expr interface call. diff --git a/lang/unification/fastsolver/fastsolver.go b/lang/unification/fastsolver/fastsolver.go index a2ebd0b8f9..958d5493b1 100644 --- a/lang/unification/fastsolver/fastsolver.go +++ b/lang/unification/fastsolver/fastsolver.go @@ -135,7 +135,8 @@ func (obj *FastInvariantSolver) Solve(ctx context.Context, data *unification.Dat // Storing the Expr with this invariant is so that we // can generate this more helpful error message here. // TODO: Improve this error message! - return nil, errwrap.Wrapf(err, "unify error with: %s", x.Expr) + x.Err = errwrap.Wrapf(err, "unify error with: %s", x.Expr).Error() + return nil, x } if obj.Debug { e1, e2 := unificationUtil.Extract(x.Expect), unificationUtil.Extract(x.Actual) From 96cf458a999885ee4dd4ce6f5a3a6420a119649f Mon Sep 17 00:00:00 2001 From: Felix Frank Date: Thu, 19 Dec 2024 23:03:02 +0100 Subject: [PATCH 6/7] lang: Add examples with errors for testing --- examples/{lang/faulty => lang-errors}/simple_types.mcl | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename examples/{lang/faulty => lang-errors}/simple_types.mcl (100%) diff --git a/examples/lang/faulty/simple_types.mcl b/examples/lang-errors/simple_types.mcl similarity index 100% rename from examples/lang/faulty/simple_types.mcl rename to examples/lang-errors/simple_types.mcl From 1b0b92f2a25dfab95cd6aa189247c34e24754b30 Mon Sep 17 00:00:00 2001 From: Felix Frank Date: Thu, 26 Dec 2024 13:52:23 +0100 Subject: [PATCH 7/7] lang: Fix formatting --- lang/ast/structs.go | 8 ++++---- lang/gapi/gapi.go | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lang/ast/structs.go b/lang/ast/structs.go index f432c87db6..8c025627fc 100644 --- a/lang/ast/structs.go +++ b/lang/ast/structs.go @@ -180,10 +180,10 @@ var ( // TextArea stores the coordinates of a statement or expression in the form of // starting line/column and ending line/column type TextArea struct { - startLine int + startLine int startColumn int - endLine int - endColumn int + endLine int + endColumn int // Bug5819 works around issue https://github.com/golang/go/issues/5819 Bug5819 interface{} // XXX: workaround @@ -8583,7 +8583,7 @@ func (obj *ExprCall) Infer() (*types.Type, []*interfaces.UnificationInvariant, e invar := &interfaces.UnificationInvariant{ Expr: obj.expr, // this should NOT be obj Node: obj, - Expect: typFunc, // TODO: are these two reversed here? + Expect: typFunc, // TODO: are these two reversed here? Actual: typFn, } invariants = append(invariants, invar) diff --git a/lang/gapi/gapi.go b/lang/gapi/gapi.go index 93265af560..8cb62ae739 100644 --- a/lang/gapi/gapi.go +++ b/lang/gapi/gapi.go @@ -319,7 +319,7 @@ func (obj *GAPI) Cli(info *gapi.Info) (*gapi.Deploy, error) { logf("type unification failed after %s", formatted) } cause := unifyErr.(*interfaces.UnificationInvariant).Node - parent := ast.AreaParentOf(cause,iast) + parent := ast.AreaParentOf(cause, iast) line, col := parent.GetPosition() logf("possible type issue found at line %d column %d", line, col) return nil, errwrap.Wrapf(unifyErr, "could not unify types")