mirror of
https://github.com/google/go-jsonnet.git
synced 2025-09-28 08:51:01 +02:00
First end-to-end test (addition of numbers)
This commit is contained in:
parent
c0060affd2
commit
563bbe12f4
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
*~
|
30
desugarer.go
Normal file
30
desugarer.go
Normal file
@ -0,0 +1,30 @@
|
||||
/*
|
||||
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
|
||||
|
||||
func desugar(ast astNode, objLevel int) (astNode, error) {
|
||||
return ast, nil
|
||||
}
|
||||
|
||||
func desugarFile(ast astNode) (astNode, error) {
|
||||
ast, err := desugar(ast, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// TODO(dcunnin): wrap in std local
|
||||
return ast, nil
|
||||
}
|
17
desugarer_test.go
Normal file
17
desugarer_test.go
Normal file
@ -0,0 +1,17 @@
|
||||
/*
|
||||
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
|
234
interpreter.go
Normal file
234
interpreter.go
Normal file
@ -0,0 +1,234 @@
|
||||
/*
|
||||
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 (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"math"
|
||||
)
|
||||
|
||||
// Misc top-level stuff
|
||||
|
||||
type vmExt struct {
|
||||
value string
|
||||
isCode bool
|
||||
}
|
||||
|
||||
type vmExtMap map[string]vmExt
|
||||
|
||||
type RuntimeError struct {
|
||||
StackTrace []traceFrame
|
||||
Msg string
|
||||
}
|
||||
|
||||
func makeRuntimeError(msg string) RuntimeError {
|
||||
return RuntimeError{
|
||||
Msg: msg,
|
||||
}
|
||||
}
|
||||
|
||||
func (err RuntimeError) Error() string {
|
||||
// TODO(dcunnin): Include stacktrace.
|
||||
return err.Msg
|
||||
}
|
||||
|
||||
// Values and state
|
||||
|
||||
type bindingFrame map[*identifier]thunk
|
||||
|
||||
type value interface {
|
||||
}
|
||||
|
||||
type valueString struct {
|
||||
value string
|
||||
}
|
||||
|
||||
func makeValueString(v string) *valueString {
|
||||
return &valueString{value: v}
|
||||
}
|
||||
|
||||
type valueBoolean struct {
|
||||
value bool
|
||||
}
|
||||
|
||||
func makeValueBoolean(v bool) *valueBoolean {
|
||||
return &valueBoolean{value: v}
|
||||
}
|
||||
|
||||
type valueNumber struct {
|
||||
value float64
|
||||
}
|
||||
|
||||
func makeValueNumber(v float64) *valueNumber {
|
||||
return &valueNumber{value: v}
|
||||
}
|
||||
|
||||
// TODO(dcunnin): Maybe intern values null, true, and false?
|
||||
type valueNull struct {
|
||||
}
|
||||
|
||||
func makeValueNull() *valueNull {
|
||||
return &valueNull{}
|
||||
}
|
||||
|
||||
type thunk struct {
|
||||
Content value // nil if not filled
|
||||
Name *identifier
|
||||
UpValues bindingFrame
|
||||
Self value
|
||||
Offset int
|
||||
Body astNode
|
||||
}
|
||||
|
||||
func makeThunk(name *identifier, self *value, offset int, body astNode) *thunk {
|
||||
return &thunk{
|
||||
Name: name,
|
||||
Self: self,
|
||||
Offset: offset,
|
||||
Body: body,
|
||||
}
|
||||
}
|
||||
|
||||
func (t *thunk) fill(v value) {
|
||||
t.Content = v
|
||||
t.Self = nil
|
||||
t.UpValues = make(bindingFrame) // clear the map
|
||||
}
|
||||
|
||||
type valueArray struct {
|
||||
Elements []thunk
|
||||
}
|
||||
|
||||
func makeValueArray(elements []thunk) *valueArray {
|
||||
return &valueArray{
|
||||
Elements: elements,
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(dcunnin): SimpleObject
|
||||
// TODO(dcunnin): ExtendedObject
|
||||
// TODO(dcunnin): ComprehensionObject
|
||||
// TODO(dcunnin): Closure
|
||||
|
||||
// The stack
|
||||
|
||||
type traceFrame struct {
|
||||
Loc LocationRange
|
||||
Name string
|
||||
}
|
||||
|
||||
type callFrame struct {
|
||||
bindings bindingFrame
|
||||
}
|
||||
|
||||
type callStack struct {
|
||||
Calls int
|
||||
Limit int
|
||||
Stack []callFrame
|
||||
}
|
||||
|
||||
func makeCallStack(limit int) callStack {
|
||||
return callStack{
|
||||
Calls: 0,
|
||||
Limit: limit,
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(dcunnin): Add import callbacks.
|
||||
// TODO(dcunnin): Add string output.
|
||||
// TODO(dcunnin): Add multi output.
|
||||
|
||||
type interpreter struct {
|
||||
Stack callStack
|
||||
ExternalVars vmExtMap
|
||||
}
|
||||
|
||||
func (this interpreter) execute(ast_ astNode) (value, error) {
|
||||
// TODO(dcunnin): All the other cases...
|
||||
switch ast := ast_.(type) {
|
||||
case *astBinary:
|
||||
// TODO(dcunnin): Assume it's + on numbers for now
|
||||
leftVal, err := this.execute(ast.left)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
leftNum := leftVal.(*valueNumber).value
|
||||
rightVal, err := this.execute(ast.right)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rightNum := rightVal.(*valueNumber).value
|
||||
return makeValueNumber(leftNum + rightNum), nil
|
||||
case *astLiteralNull:
|
||||
return makeValueNull(), nil
|
||||
case *astLiteralBoolean:
|
||||
return makeValueBoolean(ast.value), nil
|
||||
case *astLiteralNumber:
|
||||
return makeValueNumber(ast.value), nil
|
||||
default:
|
||||
return nil, makeRuntimeError("Executing this AST type not implemented yet.")
|
||||
}
|
||||
}
|
||||
|
||||
func unparseNumber(v float64) string {
|
||||
if v == math.Floor(v) {
|
||||
return fmt.Sprintf("%.0f", v)
|
||||
} else {
|
||||
// See "What Every Computer Scientist Should Know About Floating-Point Arithmetic"
|
||||
// Theorem 15
|
||||
// http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
|
||||
return fmt.Sprintf("%.17g", v)
|
||||
}
|
||||
}
|
||||
|
||||
func (this interpreter) manifestJson(
|
||||
v_ value, multiline bool, indent string, buf *bytes.Buffer) error {
|
||||
// TODO(dcunnin): All the other types...
|
||||
switch v := v_.(type) {
|
||||
case *valueBoolean:
|
||||
if v.value {
|
||||
buf.WriteString("true")
|
||||
} else {
|
||||
buf.WriteString("false")
|
||||
}
|
||||
case *valueNull:
|
||||
buf.WriteString("null")
|
||||
case *valueNumber:
|
||||
buf.WriteString(unparseNumber(v.value))
|
||||
default:
|
||||
return makeRuntimeError("Manifesting this value not implemented yet.")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func execute(ast astNode, ext vmExtMap, maxStack int) (string, error) {
|
||||
theInterpreter := interpreter{
|
||||
Stack: makeCallStack(maxStack),
|
||||
ExternalVars: ext,
|
||||
}
|
||||
result, err := theInterpreter.execute(ast)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
var buffer bytes.Buffer
|
||||
err = theInterpreter.manifestJson(result, true, "", &buffer)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return buffer.String(), nil
|
||||
}
|
17
interpreter_test.go
Normal file
17
interpreter_test.go
Normal file
@ -0,0 +1,17 @@
|
||||
/*
|
||||
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
|
56
main.go
Normal file
56
main.go
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
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
|
||||
|
||||
// Note: There are no garbage collection params because we're using the native Go garbage collector.
|
||||
type Vm struct {
|
||||
maxStack int
|
||||
maxTrace int
|
||||
ext vmExtMap
|
||||
}
|
||||
|
||||
func MakeVm() *Vm {
|
||||
return &Vm{
|
||||
maxStack: 500,
|
||||
maxTrace: 20,
|
||||
}
|
||||
}
|
||||
|
||||
func (vm *Vm) ExtVar(key string, val string) {
|
||||
vm.ext[key] = vmExt{value: val, isCode: false}
|
||||
}
|
||||
|
||||
func (vm *Vm) ExtCode(key string, val string) {
|
||||
vm.ext[key] = vmExt{value: val, isCode: true}
|
||||
}
|
||||
|
||||
func (vm *Vm) EvaluateSnippet(filename string, snippet string) (string, error) {
|
||||
tokens, err := lex(filename, snippet)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
ast, err := parse(tokens)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
ast, err = desugarFile(ast)
|
||||
output, err := execute(ast, vm.ext, vm.maxStack)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return output, nil
|
||||
}
|
57
main_test.go
Normal file
57
main_test.go
Normal file
@ -0,0 +1,57 @@
|
||||
/*
|
||||
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 (
|
||||
"testing"
|
||||
)
|
||||
|
||||
// Just a few simple sanity tests for now. Eventually we'll share end-to-end tests with the C++
|
||||
// implementation but unsure if that should be done here or via some external framework.
|
||||
|
||||
type mainTest struct {
|
||||
name string
|
||||
input string
|
||||
golden string
|
||||
errString string
|
||||
}
|
||||
|
||||
var mainTests = []mainTest{
|
||||
{"numeric_literal", "100", "100", ""},
|
||||
{"boolean_literal", "true", "true", ""},
|
||||
{"simple_arith1", "3 + 3", "6", ""},
|
||||
{"simple_arith2", "3 + 3 + 3", "9", ""},
|
||||
{"simple_arith3", "(3 + 3) + (3 + 3)", "12", ""},
|
||||
}
|
||||
|
||||
func TestMain(t *testing.T) {
|
||||
for _, test := range mainTests {
|
||||
vm := MakeVm()
|
||||
output, err := vm.EvaluateSnippet(test.name, test.input)
|
||||
var errString string
|
||||
if err != nil {
|
||||
errString = err.Error()
|
||||
}
|
||||
if errString != test.errString {
|
||||
t.Errorf("%s: error result does not match. got\n\t%+v\nexpected\n\t%+v",
|
||||
test.input, errString, test.errString)
|
||||
}
|
||||
if err == nil && output != test.golden {
|
||||
t.Errorf("%s: got\n\t%+v\nexpected\n\t%+v", test.name, output, test.golden)
|
||||
}
|
||||
}
|
||||
}
|
29
static_analyzer.go
Normal file
29
static_analyzer.go
Normal file
@ -0,0 +1,29 @@
|
||||
/*
|
||||
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
|
||||
|
||||
// TODO(dcunnin): Check for invalid use of self, super, and bound variables.
|
||||
// TODO(dcunnin): Compute free variables at each AST.
|
||||
func analyseVisit(ast astNode, inObject bool, vars identifierSet) (identifierSet, error) {
|
||||
var r identifierSet
|
||||
return r, nil
|
||||
}
|
||||
|
||||
func analyse(ast astNode) error {
|
||||
_, err := analyseVisit(ast, false, NewidentifierSet())
|
||||
return err
|
||||
}
|
17
static_analyzer_test.go
Normal file
17
static_analyzer_test.go
Normal file
@ -0,0 +1,17 @@
|
||||
/*
|
||||
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
|
Loading…
x
Reference in New Issue
Block a user