mirror of
https://github.com/google/go-jsonnet.git
synced 2025-09-28 17:01:02 +02:00
Happy case tests for parser.
No testing of error cases or location reporting yet.
This commit is contained in:
parent
2b23986b9a
commit
566a2cf4f2
74
parser.go
74
parser.go
@ -26,7 +26,6 @@ type precedence int
|
||||
const (
|
||||
applyPrecedence precedence = 2 // Function calls and indexing.
|
||||
unaryPrecedence precedence = 4 // Logical and bitwise negation, unary + -
|
||||
beforeElsePrecedence precedence = 15 // True branch of an if.
|
||||
maxPrecedence precedence = 16 // Local, If, Import, Function, Error
|
||||
)
|
||||
|
||||
@ -189,6 +188,9 @@ func (p *parser) parseBind(binds *astLocalBinds) error {
|
||||
})
|
||||
} else {
|
||||
_, err = p.popExpectOp("=")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
body, err := p.parse(maxPrecedence)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -248,7 +250,6 @@ func (p *parser) parseObjectRemainder(tok *token) (astNode, *token, error) {
|
||||
literalFields := make(literalFieldSet)
|
||||
binds := make(identifierSet)
|
||||
|
||||
_ = "breakpoint"
|
||||
gotComma := false
|
||||
first := true
|
||||
|
||||
@ -914,6 +915,7 @@ func (p *parser) parse(prec precedence) (astNode, error) {
|
||||
// the operator.
|
||||
switch p.peek().kind {
|
||||
case tokenOperator:
|
||||
_ = "breakpoint"
|
||||
if p.peek().data == ":" {
|
||||
// Special case for the colons in assert. Since COLON is no-longer a
|
||||
// special token, we have to make sure it does not trip the
|
||||
@ -939,8 +941,74 @@ func (p *parser) parse(prec precedence) (astNode, error) {
|
||||
default:
|
||||
return lhs, nil
|
||||
}
|
||||
}
|
||||
|
||||
op := p.pop()
|
||||
switch op.kind {
|
||||
case tokenBracketL:
|
||||
index, err := p.parse(maxPrecedence)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
end, err := p.popExpect(tokenBracketR)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
lhs = &astIndex{
|
||||
astNodeBase: astNodeBase{loc: locFromTokens(begin, end)},
|
||||
target: lhs,
|
||||
index: index,
|
||||
}
|
||||
case tokenDot:
|
||||
fieldID, err := p.popExpect(tokenIdentifier)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
id := identifier(fieldID.data)
|
||||
lhs = &astIndex{
|
||||
astNodeBase: astNodeBase{loc: locFromTokens(begin, fieldID)},
|
||||
target: lhs,
|
||||
id: &id,
|
||||
}
|
||||
case tokenParenL:
|
||||
end, args, gotComma, err := p.parseCommaList(tokenParenR, "function argument")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tailStrict := false
|
||||
if p.peek().kind == tokenTailStrict {
|
||||
p.pop()
|
||||
tailStrict = true
|
||||
}
|
||||
lhs = &astApply{
|
||||
astNodeBase: astNodeBase{loc: locFromTokens(begin, end)},
|
||||
target: lhs,
|
||||
arguments: args,
|
||||
trailingComma: gotComma,
|
||||
tailStrict: tailStrict,
|
||||
}
|
||||
case tokenBraceL:
|
||||
obj, end, err := p.parseObjectRemainder(op)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
lhs = &astApplyBrace{
|
||||
astNodeBase: astNodeBase{loc: locFromTokens(begin, end)},
|
||||
left: lhs,
|
||||
right: obj,
|
||||
}
|
||||
default:
|
||||
rhs, err := p.parse(prec - 1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
lhs = &astBinary{
|
||||
astNodeBase: astNodeBase{loc: locFromTokenAST(begin, rhs)},
|
||||
left: lhs,
|
||||
op: bop,
|
||||
right: rhs,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -22,14 +22,90 @@ import (
|
||||
"github.com/kr/pretty"
|
||||
)
|
||||
|
||||
var tests = []string{
|
||||
`true`,
|
||||
`1`,
|
||||
`1.2e3`,
|
||||
`!true`,
|
||||
`null`,
|
||||
|
||||
`$.foo.bar`,
|
||||
`self.foo.bar`,
|
||||
`super.foo.bar`,
|
||||
`super[1]`,
|
||||
`error "Error!"`,
|
||||
|
||||
`"world"`,
|
||||
`'world'`,
|
||||
`|||
|
||||
world
|
||||
|||`,
|
||||
|
||||
`foo(bar)`,
|
||||
`foo.bar`,
|
||||
`foo[bar]`,
|
||||
|
||||
`true || false`,
|
||||
`0 && 1 || 0`,
|
||||
`0 && (1 || 0)`,
|
||||
|
||||
`local foo = "bar"; foo`,
|
||||
`local foo(bar) = bar; foo(1)`,
|
||||
`{ local foo = "bar", baz: 1}`,
|
||||
`{ local foo(bar) = bar, baz: foo(1)}`,
|
||||
|
||||
`{ foo(bar, baz): bar+baz }`,
|
||||
|
||||
`{ ["foo" + "bar"]: 3 }`,
|
||||
`{ ["field" + x]: x for x in [1, 2, 3] }`,
|
||||
`{ ["field" + x]: x for x in [1, 2, 3] if x <= 2 }`,
|
||||
`{ ["field" + x + y]: x + y for x in [1, 2, 3] if x <= 2 for y in [4, 5, 6]}`,
|
||||
|
||||
`[]`,
|
||||
`[a, b, c]`,
|
||||
`[x for x in [1,2,3] ]`,
|
||||
`[x for x in [1,2,3] if x <= 2]`,
|
||||
`[x+y for x in [1,2,3] if x <= 2 for y in [4, 5, 6]]`,
|
||||
|
||||
`{}`,
|
||||
`{ hello: "world" }`,
|
||||
`{ hello +: "world" }`,
|
||||
`{
|
||||
hello: "world",
|
||||
"name":: joe,
|
||||
'mood'::: "happy",
|
||||
|||
|
||||
key type
|
||||
|||: "block",
|
||||
}`,
|
||||
|
||||
`assert true: 'woah!'; true`,
|
||||
`{ assert true: 'woah!', foo: bar }`,
|
||||
|
||||
`if n > 1 then 'foos' else 'foo'`,
|
||||
|
||||
`local foo = function(x) x + 1; true`,
|
||||
|
||||
`import 'foo.jsonnet'`,
|
||||
`importstr 'foo.text'`,
|
||||
|
||||
`{a: b} + {c: d}`,
|
||||
`{a: b}{c: d}`,
|
||||
}
|
||||
|
||||
func TestParser(t *testing.T) {
|
||||
tokens, err := lex("test", `{hello: "world"}`)
|
||||
for _, s := range tests {
|
||||
tokens, err := lex("test", s)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected lex error: %v", err)
|
||||
t.Errorf("Unexpected lex error\n input: %v\n error: %v", s, err)
|
||||
continue
|
||||
}
|
||||
ast, err := parse(tokens)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected parse error: %v", err)
|
||||
t.Errorf("Unexpected parse error\n input: %v\n error: %v", s, err)
|
||||
}
|
||||
if false {
|
||||
fmt.Printf("input: %v\nast: %# v\n\n", s, pretty.Formatter(ast))
|
||||
}
|
||||
}
|
||||
fmt.Printf("%# v", pretty.Formatter(ast))
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user