lang: ast, gapi, interfaces, parser: Print line numbers on error
This adds an initial implementation of printing line numbers on type unification errors. It also attempts to print a visual position indicator for most scenarios. This patch was started by Felix Frank and finished by James Shubin. Co-authored-by: Felix Frank <Felix.Frank.de@gmail.com>
This commit is contained in:
@@ -35,6 +35,7 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
@@ -45,8 +46,9 @@ import (
|
||||
langUtil "github.com/purpleidea/mgmt/lang/util"
|
||||
"github.com/purpleidea/mgmt/util"
|
||||
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
godiff "github.com/kylelemons/godebug/diff"
|
||||
"github.com/kylelemons/godebug/pretty"
|
||||
"github.com/sanity-io/litter"
|
||||
)
|
||||
|
||||
func TestLexParse0(t *testing.T) {
|
||||
@@ -2221,6 +2223,36 @@ func TestLexParse0(t *testing.T) {
|
||||
}
|
||||
// double check because DeepEqual is different since the func exists
|
||||
|
||||
lo := &litter.Options{
|
||||
//Compact: false,
|
||||
StripPackageNames: true,
|
||||
HidePrivateFields: true,
|
||||
HideZeroValues: true,
|
||||
FieldExclusions: regexp.MustCompile(`^(Textarea)$`),
|
||||
//FieldFilter func(reflect.StructField, reflect.Value) bool
|
||||
//HomePackage string
|
||||
//Separator string
|
||||
DisablePointerReplacement: true,
|
||||
}
|
||||
|
||||
// The litter package adds pointer comments everywhere,
|
||||
// which make it not diff correctly. Clean them here!
|
||||
pattern := regexp.MustCompile(`\ \/\/\ p[0-9]+$`) // the p0, p1 comments...
|
||||
clean := func(s string) string {
|
||||
lines := []string{}
|
||||
for _, line := range strings.Split(s, "\n") {
|
||||
s := pattern.ReplaceAllLiteralString(line, "")
|
||||
lines = append(lines, s)
|
||||
}
|
||||
return strings.Join(lines, "\n")
|
||||
}
|
||||
|
||||
lo1 := clean(lo.Sdump(exp))
|
||||
lo2 := clean(lo.Sdump(xast))
|
||||
if lo1 == lo2 { // simple diff
|
||||
return
|
||||
}
|
||||
|
||||
// more details, for tricky cases:
|
||||
diffable := &pretty.Config{
|
||||
Diffable: true,
|
||||
@@ -2228,18 +2260,22 @@ func TestLexParse0(t *testing.T) {
|
||||
//PrintStringers: false, // always false!
|
||||
//PrintTextMarshalers: false,
|
||||
SkipZeroFields: true,
|
||||
//Formatter: map[reflect.Type]interface{}{
|
||||
// reflect.TypeOf(ast.Textarea{}): func(x ast.Textarea) string {
|
||||
// return ""
|
||||
// },
|
||||
//},
|
||||
}
|
||||
diff := diffable.Compare(exp, xast)
|
||||
if diff == "" { // bonus
|
||||
return
|
||||
}
|
||||
diff = godiff.Diff(lo1, lo2) // for printing
|
||||
|
||||
t.Errorf("test #%d: AST did not match expected", index)
|
||||
// TODO: consider making our own recursive print function
|
||||
t.Logf("test #%d: actual: \n\n%s\n", index, spew.Sdump(xast))
|
||||
t.Logf("test #%d: expected: \n\n%s", index, spew.Sdump(exp))
|
||||
|
||||
t.Logf("test #%d: actual: \n\n%s\n", index, diffable.Sprint(xast))
|
||||
t.Logf("test #%d: expected: \n\n%s", index, diffable.Sprint(exp))
|
||||
t.Logf("test #%d: actual: \n\n%s\n", index, lo1)
|
||||
t.Logf("test #%d: expected: \n\n%s", index, lo2)
|
||||
t.Logf("test #%d: diff:\n%s", index, diff)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -58,12 +58,12 @@ func init() {
|
||||
|
||||
//err error // TODO: if we ever match ERROR in the parser
|
||||
|
||||
bool bool
|
||||
str string
|
||||
int int64 // this is the .int as seen in lexer.nex
|
||||
float float64
|
||||
bool bool
|
||||
str string
|
||||
int int64 // this is the .int as seen in lexer.nex
|
||||
float float64
|
||||
|
||||
typ *types.Type
|
||||
typ *types.Type
|
||||
|
||||
stmts []interfaces.Stmt
|
||||
stmt interfaces.Stmt
|
||||
@@ -166,54 +166,55 @@ 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
|
||||
{
|
||||
posLast(yylex, yyDollar) // our pos
|
||||
$$.stmt = &ast.StmtIf{
|
||||
Condition: $2.expr,
|
||||
ThenBranch: $4.stmt,
|
||||
//ElseBranch: nil,
|
||||
}
|
||||
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
|
||||
$$.stmt = &ast.StmtIf{
|
||||
Condition: $2.expr,
|
||||
ThenBranch: $4.stmt,
|
||||
ElseBranch: $8.stmt,
|
||||
}
|
||||
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.stmt)
|
||||
}
|
||||
// this is the named version, iow, a user-defined function (statement)
|
||||
// `func name() { <expr> }`
|
||||
@@ -221,7 +222,6 @@ stmt:
|
||||
// `func name(<arg>, <arg>) { <expr> }`
|
||||
| FUNC_IDENTIFIER IDENTIFIER OPEN_PAREN args CLOSE_PAREN OPEN_CURLY expr CLOSE_CURLY
|
||||
{
|
||||
posLast(yylex, yyDollar) // our pos
|
||||
$$.stmt = &ast.StmtFunc{
|
||||
Name: $2.str,
|
||||
Func: &ast.ExprFunc{
|
||||
@@ -230,11 +230,11 @@ stmt:
|
||||
Body: $7.expr,
|
||||
},
|
||||
}
|
||||
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.stmt)
|
||||
}
|
||||
// `func name(...) <type> { <expr> }`
|
||||
| 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
|
||||
@@ -271,191 +271,192 @@ stmt:
|
||||
Func: fn,
|
||||
Type: typ, // sam says add the type here instead...
|
||||
}
|
||||
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.stmt)
|
||||
}
|
||||
// `class name { <prog> }`
|
||||
| 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(<arg>) { <prog> }`
|
||||
// `class name(<arg>, <arg>) { <prog> }`
|
||||
| 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:
|
||||
@@ -473,18 +474,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:
|
||||
@@ -513,7 +514,6 @@ 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,
|
||||
}
|
||||
@@ -546,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,
|
||||
@@ -565,34 +564,34 @@ call:
|
||||
// prefix to the Name, but I felt this was more elegant.
|
||||
Var: true, // lambda
|
||||
}
|
||||
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr)
|
||||
}
|
||||
// calling an inline function
|
||||
| func OPEN_PAREN call_args CLOSE_PAREN
|
||||
{
|
||||
posLast(yylex, yyDollar) // our pos
|
||||
$$.expr = &ast.ExprCall{
|
||||
Name: "", // anonymous!
|
||||
Args: $3.exprs,
|
||||
Anon: $1.expr,
|
||||
}
|
||||
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{
|
||||
&ast.ExprStr{ // operator first
|
||||
V: $2.str, // for PLUS this is a `+` character
|
||||
&ast.ExprStr{ // operator first
|
||||
V: $2.str, // for PLUS this is a `+` character
|
||||
},
|
||||
$1.expr,
|
||||
$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{
|
||||
@@ -603,10 +602,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{
|
||||
@@ -617,10 +616,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{
|
||||
@@ -631,10 +630,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{
|
||||
@@ -645,10 +644,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{
|
||||
@@ -659,10 +658,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{
|
||||
@@ -673,10 +672,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{
|
||||
@@ -687,10 +686,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{
|
||||
@@ -701,10 +700,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{
|
||||
@@ -715,10 +714,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{
|
||||
@@ -729,10 +728,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{
|
||||
@@ -743,10 +742,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{
|
||||
@@ -756,13 +755,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{
|
||||
@@ -771,13 +770,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{
|
||||
@@ -786,13 +785,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{
|
||||
@@ -803,13 +802,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{
|
||||
@@ -820,10 +819,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{
|
||||
@@ -831,6 +830,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!
|
||||
@@ -856,10 +856,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:
|
||||
@@ -869,17 +869,16 @@ func:
|
||||
// `func(<arg>, <arg>) { <expr> }`
|
||||
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(...) <type> { <expr> }`
|
||||
| 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
|
||||
@@ -909,6 +908,7 @@ func:
|
||||
yylex.Error(fmt.Sprintf("%s: %+v", ErrParseSetType, err))
|
||||
}
|
||||
}
|
||||
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr)
|
||||
}
|
||||
;
|
||||
args:
|
||||
@@ -949,17 +949,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 {
|
||||
@@ -971,6 +970,7 @@ bind:
|
||||
Value: expr,
|
||||
Type: $2.typ, // sam says add the type here instead...
|
||||
}
|
||||
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.stmt)
|
||||
}
|
||||
;
|
||||
panic:
|
||||
@@ -981,7 +981,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,
|
||||
@@ -1000,6 +999,7 @@ panic:
|
||||
ThenBranch: res,
|
||||
//ElseBranch: nil,
|
||||
}
|
||||
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.stmt)
|
||||
}
|
||||
;
|
||||
/* TODO: do we want to include this?
|
||||
@@ -1007,7 +1007,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
|
||||
@@ -1015,6 +1014,7 @@ rbind:
|
||||
Ident: $1.str,
|
||||
Value: $3.stmt,
|
||||
}
|
||||
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr)
|
||||
}
|
||||
;
|
||||
*/
|
||||
@@ -1022,12 +1022,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:
|
||||
@@ -1080,53 +1080,52 @@ resource_body:
|
||||
resource_field:
|
||||
IDENTIFIER ROCKET expr COMMA
|
||||
{
|
||||
posLast(yylex, yyDollar) // our pos
|
||||
$$.resField = &ast.StmtResField{
|
||||
Field: $1.str,
|
||||
Value: $3.expr,
|
||||
}
|
||||
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.resField)
|
||||
}
|
||||
;
|
||||
conditional_resource_field:
|
||||
// content => $present ?: "hello",
|
||||
IDENTIFIER ROCKET expr ELVIS expr COMMA
|
||||
{
|
||||
posLast(yylex, yyDollar) // our pos
|
||||
$$.resField = &ast.StmtResField{
|
||||
Field: $1.str,
|
||||
Value: $5.expr,
|
||||
Condition: $3.expr,
|
||||
}
|
||||
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.resField)
|
||||
}
|
||||
;
|
||||
resource_edge:
|
||||
// Before => Test["t1"],
|
||||
CAPITALIZED_IDENTIFIER ROCKET edge_half COMMA
|
||||
{
|
||||
posLast(yylex, yyDollar) // our pos
|
||||
$$.resEdge = &ast.StmtResEdge{
|
||||
Property: $1.str,
|
||||
EdgeHalf: $3.edgeHalf,
|
||||
}
|
||||
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.resEdge)
|
||||
}
|
||||
;
|
||||
conditional_resource_edge:
|
||||
// Before => $present ?: Test["t1"],
|
||||
CAPITALIZED_IDENTIFIER ROCKET expr ELVIS edge_half COMMA
|
||||
{
|
||||
posLast(yylex, yyDollar) // our pos
|
||||
$$.resEdge = &ast.StmtResEdge{
|
||||
Property: $1.str,
|
||||
EdgeHalf: $5.edgeHalf,
|
||||
Condition: $3.expr,
|
||||
}
|
||||
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.resEdge)
|
||||
}
|
||||
;
|
||||
resource_meta:
|
||||
// Meta:noop => true,
|
||||
CAPITALIZED_IDENTIFIER COLON IDENTIFIER ROCKET expr COMMA
|
||||
{
|
||||
posLast(yylex, yyDollar) // our pos
|
||||
if strings.ToLower($1.str) != strings.ToLower(ast.MetaField) {
|
||||
// this will ultimately cause a parser error to occur...
|
||||
yylex.Error(fmt.Sprintf("%s: %s", ErrParseResFieldInvalid, $1.str))
|
||||
@@ -1135,6 +1134,7 @@ resource_meta:
|
||||
Property: $3.str,
|
||||
MetaExpr: $5.expr,
|
||||
}
|
||||
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.resMeta)
|
||||
}
|
||||
;
|
||||
conditional_resource_meta:
|
||||
@@ -1151,13 +1151,13 @@ conditional_resource_meta:
|
||||
MetaExpr: $7.expr,
|
||||
Condition: $5.expr,
|
||||
}
|
||||
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.resMeta)
|
||||
}
|
||||
;
|
||||
resource_meta_struct:
|
||||
// Meta => struct{meta => true, retry => 3,},
|
||||
CAPITALIZED_IDENTIFIER ROCKET expr COMMA
|
||||
{
|
||||
posLast(yylex, yyDollar) // our pos
|
||||
if strings.ToLower($1.str) != strings.ToLower(ast.MetaField) {
|
||||
// this will ultimately cause a parser error to occur...
|
||||
yylex.Error(fmt.Sprintf("%s: %s", ErrParseResFieldInvalid, $1.str))
|
||||
@@ -1166,13 +1166,13 @@ resource_meta_struct:
|
||||
Property: $1.str,
|
||||
MetaExpr: $3.expr,
|
||||
}
|
||||
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.resMeta)
|
||||
}
|
||||
;
|
||||
conditional_resource_meta_struct:
|
||||
// Meta => $present ?: struct{poll => 60, sema => ["foo:1", "bar:3",],},
|
||||
CAPITALIZED_IDENTIFIER ROCKET expr ELVIS expr COMMA
|
||||
{
|
||||
posLast(yylex, yyDollar) // our pos
|
||||
if strings.ToLower($1.str) != strings.ToLower(ast.MetaField) {
|
||||
// this will ultimately cause a parser error to occur...
|
||||
yylex.Error(fmt.Sprintf("%s: %s", ErrParseResFieldInvalid, $1.str))
|
||||
@@ -1182,6 +1182,7 @@ conditional_resource_meta_struct:
|
||||
MetaExpr: $5.expr,
|
||||
Condition: $3.expr,
|
||||
}
|
||||
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.resMeta)
|
||||
}
|
||||
;
|
||||
edge:
|
||||
@@ -1190,16 +1191,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,
|
||||
@@ -1207,6 +1207,7 @@ edge:
|
||||
},
|
||||
//Notify: false, // unused here, it is implied (i think)
|
||||
}
|
||||
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.stmt)
|
||||
}
|
||||
;
|
||||
edge_half_list:
|
||||
@@ -1225,24 +1226,24 @@ edge_half:
|
||||
// eg: Test["t1"]
|
||||
capitalized_res_identifier OPEN_BRACK expr CLOSE_BRACK
|
||||
{
|
||||
posLast(yylex, yyDollar) // our pos
|
||||
$$.edgeHalf = &ast.StmtEdgeHalf{
|
||||
Kind: $1.str,
|
||||
Name: $3.expr,
|
||||
//SendRecv: "", // unused
|
||||
}
|
||||
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.edgeHalf)
|
||||
}
|
||||
;
|
||||
edge_half_sendrecv:
|
||||
// eg: Test["t1"].foo_send
|
||||
capitalized_res_identifier OPEN_BRACK expr CLOSE_BRACK DOT IDENTIFIER
|
||||
{
|
||||
posLast(yylex, yyDollar) // our pos
|
||||
$$.edgeHalf = &ast.StmtEdgeHalf{
|
||||
Kind: $1.str,
|
||||
Name: $3.expr,
|
||||
SendRecv: $6.str,
|
||||
}
|
||||
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.edgeHalf)
|
||||
}
|
||||
;
|
||||
type:
|
||||
@@ -1496,7 +1497,21 @@ func cast(y yyLexer) *lexParseAST {
|
||||
return x.(*lexParseAST)
|
||||
}
|
||||
|
||||
// posLast pulls out the "last token" and does a pos with that. This is a hack!
|
||||
// locate should be called after creating AST nodes from lexer tokens to store
|
||||
// the positions of the involved tokens in the AST node.
|
||||
func locate(y yyLexer, first yySymType, last yySymType, node interface{}) {
|
||||
pos(y, last)
|
||||
// Only run Locate on nodes that look like they have not received
|
||||
// locations yet otherwise the parser will come back and overwrite them
|
||||
// with invalid ending positions.
|
||||
if pn, ok := node.(interfaces.PositionableNode); !ok {
|
||||
return
|
||||
} else if !pn.IsSet() {
|
||||
pn.Locate(first.row, first.col, last.row, last.col)
|
||||
}
|
||||
}
|
||||
|
||||
// posLast runs pos on the 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
|
||||
|
||||
Reference in New Issue
Block a user