go-jsonnet/ast.go
2016-03-07 15:36:35 -08:00

511 lines
12 KiB
Go

/*
Copyright 2016 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package jsonnet
import (
"fmt"
)
// identifier represents a variable / parameter / field name.
//+gen set
type identifier string
type identifiers []identifier
// TODO(jbeda) implement interning of identifiers if necessary. The C++
// version does so.
// ---------------------------------------------------------------------------
type astNode interface {
Loc() *LocationRange
}
type astNodes []astNode
// ---------------------------------------------------------------------------
type astNodeBase struct {
loc LocationRange
}
func (n *astNodeBase) Loc() *LocationRange {
return &n.loc
}
// ---------------------------------------------------------------------------
// +gen stringer
type astCompKind int
const (
astCompFor astCompKind = iota
astCompIf
)
type astCompSpec struct {
kind astCompKind
varName *identifier // nil when kind != compSpecFor
expr astNode
}
type astCompSpecs []astCompSpec
// ---------------------------------------------------------------------------
// astApply represents a function call
type astApply struct {
astNodeBase
target astNode
arguments astNodes
trailingComma bool
tailStrict bool
}
// ---------------------------------------------------------------------------
// astApplyBrace represents e { }. Desugared to e + { }.
type astApplyBrace struct {
astNodeBase
left astNode
right astNode
}
// ---------------------------------------------------------------------------
// astArray represents array constructors [1, 2, 3].
type astArray struct {
astNodeBase
elements astNodes
trailingComma bool
}
// ---------------------------------------------------------------------------
// astArrayComp represents array comprehensions (which are like Python list
// comprehensions)
type astArrayComp struct {
astNodeBase
body astNode
trailingComma bool
specs astCompSpecs
}
// ---------------------------------------------------------------------------
// astAssert represents an assert expression (not an object-level assert).
//
// After parsing, message can be nil indicating that no message was
// specified. This AST is elimiated by desugaring.
type astAssert struct {
astNodeBase
cond astNode
message astNode
rest astNode
}
// ---------------------------------------------------------------------------
type binaryOp int
const (
bopMult binaryOp = iota
bopDiv
bopPercent
bopPlus
bopMinus
bopShiftL
bopShiftR
bopGreater
bopGreaterEq
bopLess
bopLessEq
bopManifestEqual
bopManifestUnequal
bopBitwiseAnd
bopBitwiseXor
bopBitwiseOr
bopAnd
bopOr
)
var bopStrings = []string{
bopMult: "*",
bopDiv: "/",
bopPercent: "%",
bopPlus: "+",
bopMinus: "-",
bopShiftL: "<<",
bopShiftR: ">>",
bopGreater: ">",
bopGreaterEq: ">=",
bopLess: "<",
bopLessEq: "<=",
bopManifestEqual: "==",
bopManifestUnequal: "!=",
bopBitwiseAnd: "&",
bopBitwiseXor: "^",
bopBitwiseOr: "|",
bopAnd: "&&",
bopOr: "||",
}
var bopMap = map[string]binaryOp{
"*": bopMult,
"/": bopDiv,
"%": bopPercent,
"+": bopPlus,
"-": bopMinus,
"<<": bopShiftL,
">>": bopShiftR,
">": bopGreater,
">=": bopGreaterEq,
"<": bopLess,
"<=": bopLessEq,
"==": bopManifestEqual,
"!=": bopManifestUnequal,
"&": bopBitwiseAnd,
"^": bopBitwiseXor,
"|": bopBitwiseOr,
"&&": bopAnd,
"||": bopOr,
}
func (b binaryOp) String() string {
if b < 0 || int(b) >= len(bopStrings) {
panic(fmt.Sprintf("INTERNAL ERROR: Unrecognised binary operator: %d", b))
}
return bopStrings[b]
}
// astBinary represents binary operators.
type astBinary struct {
astNodeBase
left astNode
op binaryOp
right astNode
}
// ---------------------------------------------------------------------------
// astBuiltin represents built-in functions.
//
// There is no parse rule to build this AST. Instead, it is used to build the
// std object in the interpreter.
type astBuiltin struct {
astNodeBase
id int
params identifiers
}
// ---------------------------------------------------------------------------
// astConditional represents if/then/else.
//
// After parsing, branchFalse can be nil indicating that no else branch
// was specified. The desugarer fills this in with a LiteralNull
type astConditional struct {
astNodeBase
cond astNode
branchTrue astNode
branchFalse astNode
}
// ---------------------------------------------------------------------------
// astDollar represents the $ keyword
type astDollar struct{ astNodeBase }
// ---------------------------------------------------------------------------
// astError represents the error e.
type astError struct {
astNodeBase
expr astNode
}
// ---------------------------------------------------------------------------
// astFunction represents a function call. (jbeda: or is it function defn?)
type astFunction struct {
astNodeBase
parameters identifiers
trailingComma bool
body astNode
}
// ---------------------------------------------------------------------------
// astImport represents import "file".
type astImport struct {
astNodeBase
file string
}
// ---------------------------------------------------------------------------
// astImportStr represents importstr "file".
type astImportStr struct {
astNodeBase
file string
}
// ---------------------------------------------------------------------------
// astIndex represents both e[e] and the syntax sugar e.f.
//
// One of index and id will be nil before desugaring. After desugaring id
// will be nil.
type astIndex struct {
astNodeBase
target astNode
index astNode
id *identifier
}
// ---------------------------------------------------------------------------
// astLocalBind is a helper struct for astLocal
type astLocalBind struct {
variable identifier
body astNode
functionSugar bool
params identifiers // if functionSugar is true
trailingComma bool
}
type astLocalBinds []astLocalBind
// astLocal represents local x = e; e. After desugaring, functionSugar is false.
type astLocal struct {
astNodeBase
binds astLocalBinds
body astNode
}
// ---------------------------------------------------------------------------
// astLiteralBoolean represents true and false
type astLiteralBoolean struct {
astNodeBase
value bool
}
// ---------------------------------------------------------------------------
// astLiteralNull represents the null keyword
type astLiteralNull struct{ astNodeBase }
// ---------------------------------------------------------------------------
// astLiteralNumber represents a JSON number
type astLiteralNumber struct {
astNodeBase
value float64
originalString string
}
// ---------------------------------------------------------------------------
// +gen stringer
type astLiteralStringKind int
const (
astStringSingle astLiteralStringKind = iota
astStringDouble
astStringBlock
)
// astLiteralString represents a JSON string
type astLiteralString struct {
astNodeBase
value string
kind astLiteralStringKind
blockIndent string
}
// ---------------------------------------------------------------------------
// +gen stringer
type astObjectFieldKind int
const (
astObjectAssert astObjectFieldKind = iota // assert expr2 [: expr3] where expr3 can be nil
astObjectFieldID // id:[:[:]] expr2
astObjectFieldExpr // '['expr1']':[:[:]] expr2
astObjectFieldStr // expr1:[:[:]] expr2
astObjectLocal // local id = expr2
)
// +gen stringer
type astObjectFieldHide int
const (
astObjectFieldHidden astObjectFieldHide = iota // f:: e
astObjectFieldInherit // f: e
astObjectFieldVisible // f::: e
)
type astObjectField struct {
kind astObjectFieldKind
hide astObjectFieldHide // (ignore if kind != astObjectField*)
superSugar bool // +: (ignore if kind != astObjectField*)
methodSugar bool // f(x, y, z): ... (ignore if kind == astObjectAssert)
expr1 astNode // Not in scope of the object
id *identifier
ids identifiers // If methodSugar == true then holds the params.
trailingComma bool // If methodSugar == true then remembers the trailing comma
expr2, expr3 astNode // In scope of the object (can see self).
}
// TODO(jbeda): Add constructor helpers here
type astObjectFields []astObjectField
// astObject represents object constructors { f: e ... }.
//
// The trailing comma is only allowed if len(fields) > 0. Converted to
// DesugaredObject during desugaring.
type astObject struct {
astNodeBase
fields astObjectFields
trailingComma bool
}
// ---------------------------------------------------------------------------
type astDesugaredObjectField struct {
hide astObjectFieldHide
name astNode
body astNode
}
type astDesugaredObjectFields []astDesugaredObjectField
// astDesugaredObject represents object constructors { f: e ... } after
// desugaring.
//
// The assertions either return true or raise an error.
type astDesugaredObject struct {
astNodeBase
asserts astNodes
fields astDesugaredObjectFields
}
// ---------------------------------------------------------------------------
// astObjectComp represents object comprehension
// { [e]: e for x in e for.. if... }.
type astObjectComp struct {
astNodeBase
fields astObjectFields
trailingComma bool
specs astCompSpecs
}
// ---------------------------------------------------------------------------
// astObjectComprehensionSimple represents post-desugaring object
// comprehension { [e]: e for x in e }.
type astObjectComprehensionSimple struct {
astNodeBase
field astNode
value astNode
id identifier
array astNode
}
// ---------------------------------------------------------------------------
// astSelf represents the self keyword.
type astSelf struct{ astNodeBase }
// ---------------------------------------------------------------------------
// astSuperIndex represents the super[e] and super.f constructs.
//
// Either index or identifier will be set before desugaring. After desugaring, id will be
// nil.
type astSuperIndex struct {
astNodeBase
index astNode
id *identifier
}
// ---------------------------------------------------------------------------
type unaryOp int
const (
uopNot unaryOp = iota
uopBitwiseNot
uopPlus
uopMinus
)
var uopStrings = []string{
uopNot: "!",
uopBitwiseNot: "~",
uopPlus: "+",
uopMinus: "-",
}
var uopMap = map[string]unaryOp{
"!": uopNot,
"~": uopBitwiseNot,
"+": uopPlus,
"-": uopMinus,
}
func (u unaryOp) String() string {
if u < 0 || int(u) >= len(uopStrings) {
panic(fmt.Sprintf("INTERNAL ERROR: Unrecognised unary operator: %d", u))
}
return uopStrings[u]
}
// astUnary represents unary operators.
type astUnary struct {
astNodeBase
op unaryOp
expr astNode
}
// ---------------------------------------------------------------------------
// astVar represents variables.
type astVar struct {
astNodeBase
id identifier
original identifier
}
// ---------------------------------------------------------------------------