Fix up lint errors.

Also:
* Made all types used in errors public.
* Made interpreter receiver a pointer.  This will reduce GC load for deep stacks.
This commit is contained in:
Joe Beda 2016-03-14 12:50:42 +00:00
parent bf2c1df9e5
commit 0eedf437b1
3 changed files with 42 additions and 30 deletions

View File

@ -31,8 +31,9 @@ type vmExt struct {
type vmExtMap map[string]vmExt type vmExtMap map[string]vmExt
// RuntimeError is an error discovered during evaluation of the program
type RuntimeError struct { type RuntimeError struct {
StackTrace []traceFrame StackTrace []TraceFrame
Msg string Msg string
} }
@ -127,7 +128,8 @@ func makeValueArray(elements []thunk) *valueArray {
// The stack // The stack
type traceFrame struct { // TraceFrame is a single frame of the call stack.
type TraceFrame struct {
Loc LocationRange Loc LocationRange
Name string Name string
} }
@ -158,17 +160,17 @@ type interpreter struct {
ExternalVars vmExtMap ExternalVars vmExtMap
} }
func (this interpreter) execute(ast_ astNode) (value, error) { func (i *interpreter) execute(a astNode) (value, error) {
// TODO(dcunnin): All the other cases... // TODO(dcunnin): All the other cases...
switch ast := ast_.(type) { switch ast := a.(type) {
case *astBinary: case *astBinary:
// TODO(dcunnin): Assume it's + on numbers for now // TODO(dcunnin): Assume it's + on numbers for now
leftVal, err := this.execute(ast.left) leftVal, err := i.execute(ast.left)
if err != nil { if err != nil {
return nil, err return nil, err
} }
leftNum := leftVal.(*valueNumber).value leftNum := leftVal.(*valueNumber).value
rightVal, err := this.execute(ast.right) rightVal, err := i.execute(ast.right)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -188,18 +190,17 @@ func (this interpreter) execute(ast_ astNode) (value, error) {
func unparseNumber(v float64) string { func unparseNumber(v float64) string {
if v == math.Floor(v) { if v == math.Floor(v) {
return fmt.Sprintf("%.0f", 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)
} }
// 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( func (i *interpreter) manifestJSON(v value, multiline bool, indent string, buf *bytes.Buffer) error {
v_ value, multiline bool, indent string, buf *bytes.Buffer) error {
// TODO(dcunnin): All the other types... // TODO(dcunnin): All the other types...
switch v := v_.(type) { switch v := v.(type) {
case *valueBoolean: case *valueBoolean:
if v.value { if v.value {
buf.WriteString("true") buf.WriteString("true")
@ -217,16 +218,16 @@ func (this interpreter) manifestJson(
} }
func execute(ast astNode, ext vmExtMap, maxStack int) (string, error) { func execute(ast astNode, ext vmExtMap, maxStack int) (string, error) {
theInterpreter := interpreter{ i := interpreter{
Stack: makeCallStack(maxStack), Stack: makeCallStack(maxStack),
ExternalVars: ext, ExternalVars: ext,
} }
result, err := theInterpreter.execute(ast) result, err := i.execute(ast)
if err != nil { if err != nil {
return "", err return "", err
} }
var buffer bytes.Buffer var buffer bytes.Buffer
err = theInterpreter.manifestJson(result, true, "", &buffer) err = i.manifestJSON(result, true, "", &buffer)
if err != nil { if err != nil {
return "", err return "", err
} }

35
main.go
View File

@ -16,29 +16,40 @@ limitations under the License.
package jsonnet package jsonnet
// Note: There are no garbage collection params because we're using the native Go garbage collector. // Note: There are no garbage collection params because we're using the native
type Vm struct { // Go garbage collector.
maxStack int
maxTrace int // VM is the core interpreter and is the touchpoint used to parse and execute
// Jsonnet.
type VM struct {
MaxStack int
MaxTrace int // The number of lines of stack trace to display (0 for all of them).
ext vmExtMap ext vmExtMap
} }
func MakeVm() *Vm { // MakeVM creates a new VM with default parameters.
return &Vm{ func MakeVM() *VM {
maxStack: 500, return &VM{
maxTrace: 20, MaxStack: 500,
MaxTrace: 20,
} }
} }
func (vm *Vm) ExtVar(key string, val string) { // ExtVar binds a Jsonnet external var to the given value.
func (vm *VM) ExtVar(key string, val string) {
vm.ext[key] = vmExt{value: val, isCode: false} vm.ext[key] = vmExt{value: val, isCode: false}
} }
func (vm *Vm) ExtCode(key string, val string) { // ExtCode binds a Jsonnet external code var to the given value.
func (vm *VM) ExtCode(key string, val string) {
vm.ext[key] = vmExt{value: val, isCode: true} vm.ext[key] = vmExt{value: val, isCode: true}
} }
func (vm *Vm) EvaluateSnippet(filename string, snippet string) (string, error) { // EvaluateSnippet evaluates a string containing Jsonnet code, return a JSON
// string.
//
// The filename parameter is only used for error messages.
func (vm *VM) EvaluateSnippet(filename string, snippet string) (string, error) {
tokens, err := lex(filename, snippet) tokens, err := lex(filename, snippet)
if err != nil { if err != nil {
return "", err return "", err
@ -48,7 +59,7 @@ func (vm *Vm) EvaluateSnippet(filename string, snippet string) (string, error) {
return "", err return "", err
} }
ast, err = desugarFile(ast) ast, err = desugarFile(ast)
output, err := execute(ast, vm.ext, vm.maxStack) output, err := execute(ast, vm.ext, vm.MaxStack)
if err != nil { if err != nil {
return "", err return "", err
} }

View File

@ -40,7 +40,7 @@ var mainTests = []mainTest{
func TestMain(t *testing.T) { func TestMain(t *testing.T) {
for _, test := range mainTests { for _, test := range mainTests {
vm := MakeVm() vm := MakeVM()
output, err := vm.EvaluateSnippet(test.name, test.input) output, err := vm.EvaluateSnippet(test.name, test.input)
var errString string var errString string
if err != nil { if err != nil {