assert and test changes
This commit is contained in:
@@ -91,9 +91,7 @@ func (c *Compiler) Compile(node ast.Node) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if !c.lastInstructionIs(code.OpNoop) {
|
c.emit(code.OpPop)
|
||||||
c.emit(code.OpPop)
|
|
||||||
}
|
|
||||||
|
|
||||||
case *ast.InfixExpression:
|
case *ast.InfixExpression:
|
||||||
if node.Operator == "<" || node.Operator == "<=" {
|
if node.Operator == "<" || node.Operator == "<=" {
|
||||||
@@ -182,9 +180,6 @@ func (c *Compiler) Compile(node ast.Node) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case *ast.IfExpression:
|
case *ast.IfExpression:
|
||||||
if c.lastInstructionIs(code.OpPop) {
|
|
||||||
c.removeLastPop()
|
|
||||||
}
|
|
||||||
c.l++
|
c.l++
|
||||||
err := c.Compile(node.Condition)
|
err := c.Compile(node.Condition)
|
||||||
c.l--
|
c.l--
|
||||||
@@ -240,6 +235,14 @@ func (c *Compiler) Compile(node ast.Node) error {
|
|||||||
}
|
}
|
||||||
c.l--
|
c.l--
|
||||||
|
|
||||||
|
if c.lastInstructionIs(code.OpPop) {
|
||||||
|
c.removeLastPop()
|
||||||
|
} else {
|
||||||
|
if !c.lastInstructionIs(code.OpReturn) {
|
||||||
|
c.emit(code.OpNull)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
case *ast.AssignmentStatement:
|
case *ast.AssignmentStatement:
|
||||||
symbol, ok := c.symbolTable.Resolve(node.Name.Value)
|
symbol, ok := c.symbolTable.Resolve(node.Name.Value)
|
||||||
if !ok {
|
if !ok {
|
||||||
@@ -366,8 +369,13 @@ func (c *Compiler) Compile(node ast.Node) error {
|
|||||||
if c.lastInstructionIs(code.OpPop) {
|
if c.lastInstructionIs(code.OpPop) {
|
||||||
c.replaceLastPopWithReturn()
|
c.replaceLastPopWithReturn()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the function doesn't end with a return statement add one with a
|
||||||
|
// `return null;` and also handle the edge-case of empty functions.
|
||||||
if !c.lastInstructionIs(code.OpReturn) {
|
if !c.lastInstructionIs(code.OpReturn) {
|
||||||
c.emit(code.OpNull)
|
if !c.lastInstructionIs(code.OpNull) {
|
||||||
|
c.emit(code.OpNull)
|
||||||
|
}
|
||||||
c.emit(code.OpReturn)
|
c.emit(code.OpReturn)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -231,15 +231,15 @@ func TestConditionals(t *testing.T) {
|
|||||||
code.Make(code.OpJumpNotTruthy, 10),
|
code.Make(code.OpJumpNotTruthy, 10),
|
||||||
// 0004
|
// 0004
|
||||||
code.Make(code.OpConstant, 0),
|
code.Make(code.OpConstant, 0),
|
||||||
// 0007
|
// 0008
|
||||||
code.Make(code.OpJump, 13),
|
code.Make(code.OpJump, 13),
|
||||||
// 0010
|
// 0011
|
||||||
code.Make(code.OpConstant, 1),
|
code.Make(code.OpConstant, 1),
|
||||||
// 0013
|
// 0013
|
||||||
code.Make(code.OpPop),
|
code.Make(code.OpPop),
|
||||||
// 0014
|
// 0014
|
||||||
code.Make(code.OpConstant, 2),
|
code.Make(code.OpConstant, 2),
|
||||||
// 0017
|
// 0018
|
||||||
code.Make(code.OpPop),
|
code.Make(code.OpPop),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -256,28 +256,34 @@ func TestConditionals(t *testing.T) {
|
|||||||
// 0006
|
// 0006
|
||||||
code.Make(code.OpTrue),
|
code.Make(code.OpTrue),
|
||||||
// 0007
|
// 0007
|
||||||
code.Make(code.OpJumpNotTruthy, 19),
|
code.Make(code.OpJumpNotTruthy, 20),
|
||||||
// 0010
|
// 0010
|
||||||
code.Make(code.OpConstant, 1),
|
code.Make(code.OpConstant, 1),
|
||||||
// 0013
|
// 0013
|
||||||
code.Make(code.OpAssignGlobal, 0),
|
code.Make(code.OpAssignGlobal, 0),
|
||||||
// 0016
|
// 0016
|
||||||
code.Make(code.OpJump, 20),
|
|
||||||
// 0019
|
|
||||||
code.Make(code.OpNull),
|
code.Make(code.OpNull),
|
||||||
|
// 0017
|
||||||
|
code.Make(code.OpJump, 21),
|
||||||
// 0020
|
// 0020
|
||||||
code.Make(code.OpFalse),
|
|
||||||
// 0021
|
|
||||||
code.Make(code.OpJumpNotTruthy, 33),
|
|
||||||
// 0024
|
|
||||||
code.Make(code.OpConstant, 2),
|
|
||||||
// 0027
|
|
||||||
code.Make(code.OpAssignGlobal, 0),
|
|
||||||
// 0030
|
|
||||||
code.Make(code.OpJump, 34),
|
|
||||||
// 0033
|
|
||||||
code.Make(code.OpNull),
|
code.Make(code.OpNull),
|
||||||
// 0034
|
// 0021
|
||||||
|
code.Make(code.OpPop),
|
||||||
|
// 0022
|
||||||
|
code.Make(code.OpFalse),
|
||||||
|
// 0023
|
||||||
|
code.Make(code.OpJumpNotTruthy, 36),
|
||||||
|
// 0025
|
||||||
|
code.Make(code.OpConstant, 2),
|
||||||
|
// 0029
|
||||||
|
code.Make(code.OpAssignGlobal, 0),
|
||||||
|
// 0032
|
||||||
|
code.Make(code.OpNull),
|
||||||
|
// 0033
|
||||||
|
code.Make(code.OpJump, 37),
|
||||||
|
// 0036
|
||||||
|
code.Make(code.OpNull),
|
||||||
|
// 0037
|
||||||
code.Make(code.OpPop),
|
code.Make(code.OpPop),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -487,7 +493,7 @@ func TestIndexExpressions(t *testing.T) {
|
|||||||
func TestFunctions(t *testing.T) {
|
func TestFunctions(t *testing.T) {
|
||||||
tests := []compilerTestCase{
|
tests := []compilerTestCase{
|
||||||
{
|
{
|
||||||
input: "fn() { return 5 + 10 }",
|
input: `fn() { return 5 + 10 }`,
|
||||||
expectedConstants: []interface{}{
|
expectedConstants: []interface{}{
|
||||||
5,
|
5,
|
||||||
10,
|
10,
|
||||||
@@ -504,24 +510,7 @@ func TestFunctions(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: `fn() { 5 + 10 }`,
|
input: `fn() { 1; return 2 }`,
|
||||||
expectedConstants: []interface{}{
|
|
||||||
5,
|
|
||||||
10,
|
|
||||||
[]code.Instructions{
|
|
||||||
code.Make(code.OpConstant, 0),
|
|
||||||
code.Make(code.OpConstant, 1),
|
|
||||||
code.Make(code.OpAdd),
|
|
||||||
code.Make(code.OpReturn),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expectedInstructions: []code.Instructions{
|
|
||||||
code.Make(code.OpClosure, 2, 0),
|
|
||||||
code.Make(code.OpPop),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: `fn() { 1; 2 }`,
|
|
||||||
expectedConstants: []interface{}{
|
expectedConstants: []interface{}{
|
||||||
1,
|
1,
|
||||||
2,
|
2,
|
||||||
@@ -566,8 +555,8 @@ func TestClosures(t *testing.T) {
|
|||||||
tests := []compilerTestCase{
|
tests := []compilerTestCase{
|
||||||
{
|
{
|
||||||
input: `fn(a) {
|
input: `fn(a) {
|
||||||
fn(b) {
|
return fn(b) {
|
||||||
a + b
|
return a + b
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
@@ -592,9 +581,9 @@ func TestClosures(t *testing.T) {
|
|||||||
{
|
{
|
||||||
input: `
|
input: `
|
||||||
fn(a) {
|
fn(a) {
|
||||||
fn(b) {
|
return fn(b) {
|
||||||
fn(c) {
|
return fn(c) {
|
||||||
a + b + c
|
return a + b + c
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -632,13 +621,13 @@ func TestClosures(t *testing.T) {
|
|||||||
fn() {
|
fn() {
|
||||||
let a = 66;
|
let a = 66;
|
||||||
|
|
||||||
fn() {
|
return fn() {
|
||||||
let b = 77;
|
let b = 77;
|
||||||
|
|
||||||
fn() {
|
return fn() {
|
||||||
let c = 88;
|
let c = 88;
|
||||||
|
|
||||||
global + a + b + c;
|
return global + a + b + c;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -737,7 +726,7 @@ func TestCompilerScopes(t *testing.T) {
|
|||||||
func TestFunctionCalls(t *testing.T) {
|
func TestFunctionCalls(t *testing.T) {
|
||||||
tests := []compilerTestCase{
|
tests := []compilerTestCase{
|
||||||
{
|
{
|
||||||
input: `fn() { 24 }();`,
|
input: `fn() { return 24 }();`,
|
||||||
expectedConstants: []interface{}{
|
expectedConstants: []interface{}{
|
||||||
24,
|
24,
|
||||||
[]code.Instructions{
|
[]code.Instructions{
|
||||||
@@ -753,7 +742,7 @@ func TestFunctionCalls(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: `
|
input: `
|
||||||
let noArg = fn() { 24 };
|
let noArg = fn() { return 24 };
|
||||||
noArg();
|
noArg();
|
||||||
`,
|
`,
|
||||||
expectedConstants: []interface{}{
|
expectedConstants: []interface{}{
|
||||||
@@ -773,7 +762,7 @@ func TestFunctionCalls(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: `
|
input: `
|
||||||
let oneArg = fn(a) { a };
|
let oneArg = fn(a) { return a };
|
||||||
oneArg(24);
|
oneArg(24);
|
||||||
`,
|
`,
|
||||||
expectedConstants: []interface{}{
|
expectedConstants: []interface{}{
|
||||||
@@ -794,7 +783,7 @@ func TestFunctionCalls(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: `
|
input: `
|
||||||
let manyArg = fn(a, b, c) { a; b; c };
|
let manyArg = fn(a, b, c) { a; b; return c };
|
||||||
manyArg(24, 25, 26);
|
manyArg(24, 25, 26);
|
||||||
`,
|
`,
|
||||||
expectedConstants: []interface{}{
|
expectedConstants: []interface{}{
|
||||||
@@ -881,7 +870,7 @@ func TestLetStatementScopes(t *testing.T) {
|
|||||||
{
|
{
|
||||||
input: `
|
input: `
|
||||||
let num = 55;
|
let num = 55;
|
||||||
fn() { num }
|
fn() { return num }
|
||||||
`,
|
`,
|
||||||
expectedConstants: []interface{}{
|
expectedConstants: []interface{}{
|
||||||
55,
|
55,
|
||||||
@@ -901,7 +890,7 @@ func TestLetStatementScopes(t *testing.T) {
|
|||||||
input: `
|
input: `
|
||||||
fn() {
|
fn() {
|
||||||
let num = 55;
|
let num = 55;
|
||||||
num
|
return num
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
expectedConstants: []interface{}{
|
expectedConstants: []interface{}{
|
||||||
@@ -923,7 +912,7 @@ func TestLetStatementScopes(t *testing.T) {
|
|||||||
fn() {
|
fn() {
|
||||||
let a = 55;
|
let a = 55;
|
||||||
let b = 77;
|
let b = 77;
|
||||||
a + b
|
return a + b
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
expectedConstants: []interface{}{
|
expectedConstants: []interface{}{
|
||||||
@@ -977,11 +966,11 @@ func TestBuiltins(t *testing.T) {
|
|||||||
`,
|
`,
|
||||||
expectedConstants: []interface{}{1},
|
expectedConstants: []interface{}{1},
|
||||||
expectedInstructions: []code.Instructions{
|
expectedInstructions: []code.Instructions{
|
||||||
code.Make(code.OpGetBuiltin, 4),
|
code.Make(code.OpGetBuiltin, 5),
|
||||||
code.Make(code.OpArray, 0),
|
code.Make(code.OpArray, 0),
|
||||||
code.Make(code.OpCall, 1),
|
code.Make(code.OpCall, 1),
|
||||||
code.Make(code.OpPop),
|
code.Make(code.OpPop),
|
||||||
code.Make(code.OpGetBuiltin, 7),
|
code.Make(code.OpGetBuiltin, 8),
|
||||||
code.Make(code.OpArray, 0),
|
code.Make(code.OpArray, 0),
|
||||||
code.Make(code.OpConstant, 0),
|
code.Make(code.OpConstant, 0),
|
||||||
code.Make(code.OpCall, 2),
|
code.Make(code.OpCall, 2),
|
||||||
@@ -989,10 +978,10 @@ func TestBuiltins(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: `fn() { len([]) }`,
|
input: `fn() { return len([]) }`,
|
||||||
expectedConstants: []interface{}{
|
expectedConstants: []interface{}{
|
||||||
[]code.Instructions{
|
[]code.Instructions{
|
||||||
code.Make(code.OpGetBuiltin, 4),
|
code.Make(code.OpGetBuiltin, 5),
|
||||||
code.Make(code.OpArray, 0),
|
code.Make(code.OpArray, 0),
|
||||||
code.Make(code.OpCall, 1),
|
code.Make(code.OpCall, 1),
|
||||||
code.Make(code.OpReturn),
|
code.Make(code.OpReturn),
|
||||||
@@ -1012,9 +1001,9 @@ func TestRecursiveFunctions(t *testing.T) {
|
|||||||
tests := []compilerTestCase{
|
tests := []compilerTestCase{
|
||||||
{
|
{
|
||||||
input: `
|
input: `
|
||||||
let countDown = fn(x) { countDown(x - 1); };
|
let countDown = fn(x) { return countDown(x - 1); };
|
||||||
countDown(1);
|
countDown(1);
|
||||||
`,
|
`,
|
||||||
expectedConstants: []interface{}{
|
expectedConstants: []interface{}{
|
||||||
1,
|
1,
|
||||||
[]code.Instructions{
|
[]code.Instructions{
|
||||||
@@ -1038,12 +1027,12 @@ func TestRecursiveFunctions(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: `
|
input: `
|
||||||
let wrapper = fn() {
|
let wrapper = fn() {
|
||||||
let countDown = fn(x) { countDown(x - 1); };
|
let countDown = fn(x) { return countDown(x - 1); };
|
||||||
countDown(1);
|
return countDown(1);
|
||||||
};
|
};
|
||||||
wrapper();
|
wrapper();
|
||||||
`,
|
`,
|
||||||
expectedConstants: []interface{}{
|
expectedConstants: []interface{}{
|
||||||
1,
|
1,
|
||||||
[]code.Instructions{
|
[]code.Instructions{
|
||||||
@@ -1088,15 +1077,15 @@ func TestIteration(t *testing.T) {
|
|||||||
// 0000
|
// 0000
|
||||||
code.Make(code.OpTrue),
|
code.Make(code.OpTrue),
|
||||||
// 0001
|
// 0001
|
||||||
code.Make(code.OpJumpNotTruthy, 11),
|
code.Make(code.OpJumpNotTruthy, 10),
|
||||||
// 0004
|
// 0004
|
||||||
code.Make(code.OpConstant, 0),
|
code.Make(code.OpConstant, 0),
|
||||||
// 0007
|
// 0007
|
||||||
code.Make(code.OpPop),
|
|
||||||
// 0008
|
|
||||||
code.Make(code.OpJump, 0),
|
code.Make(code.OpJump, 0),
|
||||||
// 0011
|
// 0010
|
||||||
code.Make(code.OpNoop),
|
code.Make(code.OpNoop),
|
||||||
|
// 0011
|
||||||
|
code.Make(code.OpPop),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,4 +40,4 @@ let map = fn(arr, f) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let numbers = [1, 1 + 1, 4 - 1, 2 * 2, 2 + 3, 12 / 2];
|
let numbers = [1, 1 + 1, 4 - 1, 2 * 2, 2 + 3, 12 / 2];
|
||||||
//map(numbers, fibonacci);
|
map(numbers, fibonacci);
|
||||||
@@ -5,4 +5,4 @@ let fact = fn(n) {
|
|||||||
return n * fact(n - 1)
|
return n * fact(n - 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
print(fact(5)
|
assert(fact(5) == 120, "fact(5) != 120")
|
||||||
@@ -11,15 +11,16 @@ import (
|
|||||||
|
|
||||||
// Builtins ...
|
// Builtins ...
|
||||||
var Builtins = map[string]*Builtin{
|
var Builtins = map[string]*Builtin{
|
||||||
"len": {Name: "len", Fn: Len},
|
"len": {Name: "len", Fn: Len},
|
||||||
"input": {Name: "input", Fn: Input},
|
"input": {Name: "input", Fn: Input},
|
||||||
"print": {Name: "print", Fn: Print},
|
"print": {Name: "print", Fn: Print},
|
||||||
"first": {Name: "first", Fn: First},
|
"first": {Name: "first", Fn: First},
|
||||||
"last": {Name: "last", Fn: Last},
|
"last": {Name: "last", Fn: Last},
|
||||||
"rest": {Name: "rest", Fn: Rest},
|
"rest": {Name: "rest", Fn: Rest},
|
||||||
"push": {Name: "push", Fn: Push},
|
"push": {Name: "push", Fn: Push},
|
||||||
"pop": {Name: "pop", Fn: Pop},
|
"pop": {Name: "pop", Fn: Pop},
|
||||||
"exit": {Name: "exit", Fn: Exit},
|
"exit": {Name: "exit", Fn: Exit},
|
||||||
|
"assert": {Name: "assert", Fn: Assert},
|
||||||
}
|
}
|
||||||
|
|
||||||
// BuiltinsIndex ...
|
// BuiltinsIndex ...
|
||||||
@@ -213,3 +214,26 @@ func Exit(args ...Object) Object {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Assert ...
|
||||||
|
func Assert(args ...Object) Object {
|
||||||
|
if len(args) != 2 {
|
||||||
|
return newError("wrong number of arguments. got=%d, want=2",
|
||||||
|
len(args))
|
||||||
|
}
|
||||||
|
if args[0].Type() != BOOLEAN_OBJ {
|
||||||
|
return newError("argument #1 to `assert` must be BOOLEAN, got %s",
|
||||||
|
args[0].Type())
|
||||||
|
}
|
||||||
|
if args[1].Type() != STRING_OBJ {
|
||||||
|
return newError("argument #2 to `assert` must be STRING, got %s",
|
||||||
|
args[0].Type())
|
||||||
|
}
|
||||||
|
|
||||||
|
if !args[0].(*Boolean).Value {
|
||||||
|
fmt.Printf("Assertion Error: %s", args[1].(*String).Value)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
6
vm/vm.go
6
vm/vm.go
@@ -119,11 +119,7 @@ func (vm *VM) Run() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case code.OpPop:
|
case code.OpPop:
|
||||||
// This makes things like this work:
|
vm.pop()
|
||||||
// >> let x = 1; if (x == 1) { x = 2 }
|
|
||||||
if vm.sp > 0 {
|
|
||||||
vm.pop()
|
|
||||||
}
|
|
||||||
|
|
||||||
case code.OpTrue:
|
case code.OpTrue:
|
||||||
err := vm.push(True)
|
err := vm.push(True)
|
||||||
|
|||||||
107
vm/vm_test.go
107
vm/vm_test.go
@@ -259,7 +259,12 @@ func TestConditionals(t *testing.T) {
|
|||||||
{"if (1 > 2) { 10 } else { 20 }", 20},
|
{"if (1 > 2) { 10 } else { 20 }", 20},
|
||||||
{"if (1 > 2) { 10 }", Null},
|
{"if (1 > 2) { 10 }", Null},
|
||||||
{"if (false) { 10 }", Null},
|
{"if (false) { 10 }", Null},
|
||||||
//{"if ((if (false) { 10 })) { 10 } else { 20 }", 20},
|
{"if ((if (false) { 10 })) { 10 } else { 20 }", 20},
|
||||||
|
{"if (true) { let a = 5; }", Null},
|
||||||
|
{"if (true) { 10; let a = 5; }", Null},
|
||||||
|
{"if (false) { 10 } else { let b = 5; }", Null},
|
||||||
|
{"if (false) { 10 } else { 10; let b = 5; }", Null},
|
||||||
|
{"if (true) { let a = 5; } else { 10 }", Null},
|
||||||
{"let x = 0; if (true) { x = 1; }; if (false) { x = 2; }; x", 1},
|
{"let x = 0; if (true) { x = 1; }; if (false) { x = 2; }; x", 1},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -346,24 +351,24 @@ func TestCallingFunctionsWithoutArguments(t *testing.T) {
|
|||||||
tests := []vmTestCase{
|
tests := []vmTestCase{
|
||||||
{
|
{
|
||||||
input: `
|
input: `
|
||||||
let fivePlusTen = fn() { 5 + 10; };
|
let fivePlusTen = fn() { return 5 + 10; };
|
||||||
fivePlusTen();
|
fivePlusTen();
|
||||||
`,
|
`,
|
||||||
expected: 15,
|
expected: 15,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: `
|
input: `
|
||||||
let one = fn() { 1; };
|
let one = fn() { return 1; };
|
||||||
let two = fn() { 2; };
|
let two = fn() { return 2; };
|
||||||
one() + two()
|
one() + two()
|
||||||
`,
|
`,
|
||||||
expected: 3,
|
expected: 3,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: `
|
input: `
|
||||||
let a = fn() { 1 };
|
let a = fn() { return 1 };
|
||||||
let b = fn() { a() + 1 };
|
let b = fn() { return a() + 1 };
|
||||||
let c = fn() { b() + 1 };
|
let c = fn() { return b() + 1 };
|
||||||
c();
|
c();
|
||||||
`,
|
`,
|
||||||
expected: 3,
|
expected: 3,
|
||||||
@@ -421,8 +426,8 @@ func TestFirstClassFunctions(t *testing.T) {
|
|||||||
tests := []vmTestCase{
|
tests := []vmTestCase{
|
||||||
{
|
{
|
||||||
input: `
|
input: `
|
||||||
let returnsOne = fn() { 1; };
|
let returnsOne = fn() { return 1; };
|
||||||
let returnsOneReturner = fn() { returnsOne; };
|
let returnsOneReturner = fn() { return returnsOne; };
|
||||||
returnsOneReturner()();
|
returnsOneReturner()();
|
||||||
`,
|
`,
|
||||||
expected: 1,
|
expected: 1,
|
||||||
@@ -430,7 +435,7 @@ func TestFirstClassFunctions(t *testing.T) {
|
|||||||
{
|
{
|
||||||
input: `
|
input: `
|
||||||
let returnsOneReturner = fn() {
|
let returnsOneReturner = fn() {
|
||||||
let returnsOne = fn() { 1; };
|
let returnsOne = fn() { return 1; };
|
||||||
returnsOne;
|
returnsOne;
|
||||||
};
|
};
|
||||||
returnsOneReturner()();
|
returnsOneReturner()();
|
||||||
@@ -444,32 +449,32 @@ func TestFirstClassFunctions(t *testing.T) {
|
|||||||
|
|
||||||
func TestCallingFunctionsWithBindings(t *testing.T) {
|
func TestCallingFunctionsWithBindings(t *testing.T) {
|
||||||
tests := []vmTestCase{
|
tests := []vmTestCase{
|
||||||
//{
|
|
||||||
// input: `
|
|
||||||
//let one = fn() { let one = 1; one };
|
|
||||||
//one();
|
|
||||||
//`,
|
|
||||||
// expected: 1,
|
|
||||||
//},
|
|
||||||
{
|
{
|
||||||
input: `
|
input: `
|
||||||
let oneAndTwo = fn() { let one = 1; let two = 2; one + two; };
|
let one = fn() { let one = 1; return one };
|
||||||
|
one();
|
||||||
|
`,
|
||||||
|
expected: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: `
|
||||||
|
let oneAndTwo = fn() { let one = 1; let two = 2; return one + two; };
|
||||||
oneAndTwo();
|
oneAndTwo();
|
||||||
`,
|
`,
|
||||||
expected: 3,
|
expected: 3,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: `
|
input: `
|
||||||
let oneAndTwo = fn() { let one = 1; let two = 2; one + two; };
|
let oneAndTwo = fn() { let one = 1; let two = 2; return one + two; };
|
||||||
let threeAndFour = fn() { let three = 3; let four = 4; three + four; };
|
let threeAndFour = fn() { let three = 3; let four = 4; return three + four; };
|
||||||
oneAndTwo() + threeAndFour();
|
oneAndTwo() + threeAndFour();
|
||||||
`,
|
`,
|
||||||
expected: 10,
|
expected: 10,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: `
|
input: `
|
||||||
let firstFoobar = fn() { let foobar = 50; foobar; };
|
let firstFoobar = fn() { let foobar = 50; return foobar; };
|
||||||
let secondFoobar = fn() { let foobar = 100; foobar; };
|
let secondFoobar = fn() { let foobar = 100; return foobar; };
|
||||||
firstFoobar() + secondFoobar();
|
firstFoobar() + secondFoobar();
|
||||||
`,
|
`,
|
||||||
expected: 150,
|
expected: 150,
|
||||||
@@ -479,11 +484,11 @@ func TestCallingFunctionsWithBindings(t *testing.T) {
|
|||||||
let globalSeed = 50;
|
let globalSeed = 50;
|
||||||
let minusOne = fn() {
|
let minusOne = fn() {
|
||||||
let num = 1;
|
let num = 1;
|
||||||
globalSeed - num;
|
return globalSeed - num;
|
||||||
}
|
}
|
||||||
let minusTwo = fn() {
|
let minusTwo = fn() {
|
||||||
let num = 2;
|
let num = 2;
|
||||||
globalSeed - num;
|
return globalSeed - num;
|
||||||
}
|
}
|
||||||
minusOne() + minusTwo();
|
minusOne() + minusTwo();
|
||||||
`,
|
`,
|
||||||
@@ -498,14 +503,14 @@ func TestCallingFunctionsWithArgumentsAndBindings(t *testing.T) {
|
|||||||
tests := []vmTestCase{
|
tests := []vmTestCase{
|
||||||
{
|
{
|
||||||
input: `
|
input: `
|
||||||
let identity = fn(a) { a; };
|
let identity = fn(a) { return a; };
|
||||||
identity(4);
|
identity(4);
|
||||||
`,
|
`,
|
||||||
expected: 4,
|
expected: 4,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: `
|
input: `
|
||||||
let sum = fn(a, b) { a + b; };
|
let sum = fn(a, b) { return a + b; };
|
||||||
sum(1, 2);
|
sum(1, 2);
|
||||||
`,
|
`,
|
||||||
expected: 3,
|
expected: 3,
|
||||||
@@ -514,7 +519,7 @@ func TestCallingFunctionsWithArgumentsAndBindings(t *testing.T) {
|
|||||||
input: `
|
input: `
|
||||||
let sum = fn(a, b) {
|
let sum = fn(a, b) {
|
||||||
let c = a + b;
|
let c = a + b;
|
||||||
c;
|
return c;
|
||||||
};
|
};
|
||||||
sum(1, 2);
|
sum(1, 2);
|
||||||
`,
|
`,
|
||||||
@@ -524,7 +529,7 @@ func TestCallingFunctionsWithArgumentsAndBindings(t *testing.T) {
|
|||||||
input: `
|
input: `
|
||||||
let sum = fn(a, b) {
|
let sum = fn(a, b) {
|
||||||
let c = a + b;
|
let c = a + b;
|
||||||
c;
|
return c;
|
||||||
};
|
};
|
||||||
sum(1, 2) + sum(3, 4);`,
|
sum(1, 2) + sum(3, 4);`,
|
||||||
expected: 10,
|
expected: 10,
|
||||||
@@ -533,10 +538,10 @@ func TestCallingFunctionsWithArgumentsAndBindings(t *testing.T) {
|
|||||||
input: `
|
input: `
|
||||||
let sum = fn(a, b) {
|
let sum = fn(a, b) {
|
||||||
let c = a + b;
|
let c = a + b;
|
||||||
c;
|
return c;
|
||||||
};
|
};
|
||||||
let outer = fn() {
|
let outer = fn() {
|
||||||
sum(1, 2) + sum(3, 4);
|
return sum(1, 2) + sum(3, 4);
|
||||||
};
|
};
|
||||||
outer();
|
outer();
|
||||||
`,
|
`,
|
||||||
@@ -548,11 +553,11 @@ func TestCallingFunctionsWithArgumentsAndBindings(t *testing.T) {
|
|||||||
|
|
||||||
let sum = fn(a, b) {
|
let sum = fn(a, b) {
|
||||||
let c = a + b;
|
let c = a + b;
|
||||||
c + globalNum;
|
return c + globalNum;
|
||||||
};
|
};
|
||||||
|
|
||||||
let outer = fn() {
|
let outer = fn() {
|
||||||
sum(1, 2) + sum(3, 4) + globalNum;
|
return sum(1, 2) + sum(3, 4) + globalNum;
|
||||||
};
|
};
|
||||||
|
|
||||||
outer() + globalNum;
|
outer() + globalNum;
|
||||||
@@ -567,15 +572,15 @@ func TestCallingFunctionsWithArgumentsAndBindings(t *testing.T) {
|
|||||||
func TestCallingFunctionsWithWrongArguments(t *testing.T) {
|
func TestCallingFunctionsWithWrongArguments(t *testing.T) {
|
||||||
tests := []vmTestCase{
|
tests := []vmTestCase{
|
||||||
{
|
{
|
||||||
input: `fn() { 1; }(1);`,
|
input: `fn() { return 1; }(1);`,
|
||||||
expected: `wrong number of arguments: want=0, got=1`,
|
expected: `wrong number of arguments: want=0, got=1`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: `fn(a) { a; }();`,
|
input: `fn(a) { return a; }();`,
|
||||||
expected: `wrong number of arguments: want=1, got=0`,
|
expected: `wrong number of arguments: want=1, got=0`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: `fn(a, b) { a + b; }(1);`,
|
input: `fn(a, b) { return a + b; }(1);`,
|
||||||
expected: `wrong number of arguments: want=2, got=1`,
|
expected: `wrong number of arguments: want=2, got=1`,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -658,7 +663,7 @@ func TestClosures(t *testing.T) {
|
|||||||
{
|
{
|
||||||
input: `
|
input: `
|
||||||
let newClosure = fn(a) {
|
let newClosure = fn(a) {
|
||||||
fn() { a; };
|
fn() { return a; };
|
||||||
};
|
};
|
||||||
let closure = newClosure(99);
|
let closure = newClosure(99);
|
||||||
closure();
|
closure();
|
||||||
@@ -668,7 +673,7 @@ func TestClosures(t *testing.T) {
|
|||||||
{
|
{
|
||||||
input: `
|
input: `
|
||||||
let newAdder = fn(a, b) {
|
let newAdder = fn(a, b) {
|
||||||
fn(c) { a + b + c };
|
fn(c) { return a + b + c };
|
||||||
};
|
};
|
||||||
let adder = newAdder(1, 2);
|
let adder = newAdder(1, 2);
|
||||||
adder(8);
|
adder(8);
|
||||||
@@ -679,7 +684,7 @@ func TestClosures(t *testing.T) {
|
|||||||
input: `
|
input: `
|
||||||
let newAdder = fn(a, b) {
|
let newAdder = fn(a, b) {
|
||||||
let c = a + b;
|
let c = a + b;
|
||||||
fn(d) { c + d };
|
fn(d) { return c + d };
|
||||||
};
|
};
|
||||||
let adder = newAdder(1, 2);
|
let adder = newAdder(1, 2);
|
||||||
adder(8);
|
adder(8);
|
||||||
@@ -690,9 +695,9 @@ func TestClosures(t *testing.T) {
|
|||||||
input: `
|
input: `
|
||||||
let newAdderOuter = fn(a, b) {
|
let newAdderOuter = fn(a, b) {
|
||||||
let c = a + b;
|
let c = a + b;
|
||||||
fn(d) {
|
return fn(d) {
|
||||||
let e = d + c;
|
let e = d + c;
|
||||||
fn(f) { e + f; };
|
return fn(f) { return e + f; };
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
let newAdderInner = newAdderOuter(1, 2)
|
let newAdderInner = newAdderOuter(1, 2)
|
||||||
@@ -705,8 +710,8 @@ func TestClosures(t *testing.T) {
|
|||||||
input: `
|
input: `
|
||||||
let a = 1;
|
let a = 1;
|
||||||
let newAdderOuter = fn(b) {
|
let newAdderOuter = fn(b) {
|
||||||
fn(c) {
|
return fn(c) {
|
||||||
fn(d) { a + b + c + d };
|
return fn(d) { return a + b + c + d };
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
let newAdderInner = newAdderOuter(2)
|
let newAdderInner = newAdderOuter(2)
|
||||||
@@ -718,9 +723,9 @@ func TestClosures(t *testing.T) {
|
|||||||
{
|
{
|
||||||
input: `
|
input: `
|
||||||
let newClosure = fn(a, b) {
|
let newClosure = fn(a, b) {
|
||||||
let one = fn() { a; };
|
let one = fn() { return a; };
|
||||||
let two = fn() { b; };
|
let two = fn() { return b; };
|
||||||
fn() { one() + two(); };
|
return fn() { return one() + two(); };
|
||||||
};
|
};
|
||||||
let closure = newClosure(9, 90);
|
let closure = newClosure(9, 90);
|
||||||
closure();
|
closure();
|
||||||
@@ -740,7 +745,7 @@ func TestRecursiveFunctions(t *testing.T) {
|
|||||||
if (x == 0) {
|
if (x == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
countDown(x - 1);
|
return countDown(x - 1);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
countDown(1);
|
countDown(1);
|
||||||
@@ -753,11 +758,11 @@ func TestRecursiveFunctions(t *testing.T) {
|
|||||||
if (x == 0) {
|
if (x == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
countDown(x - 1);
|
return countDown(x - 1);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let wrapper = fn() {
|
let wrapper = fn() {
|
||||||
countDown(1);
|
return countDown(1);
|
||||||
};
|
};
|
||||||
wrapper();
|
wrapper();
|
||||||
`,
|
`,
|
||||||
@@ -770,10 +775,10 @@ func TestRecursiveFunctions(t *testing.T) {
|
|||||||
if (x == 0) {
|
if (x == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
countDown(x - 1);
|
return countDown(x - 1);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
countDown(1);
|
return countDown(1);
|
||||||
};
|
};
|
||||||
wrapper();
|
wrapper();
|
||||||
`,
|
`,
|
||||||
@@ -795,7 +800,7 @@ func TestRecursiveFibonacci(t *testing.T) {
|
|||||||
if (x == 1) {
|
if (x == 1) {
|
||||||
return 1;
|
return 1;
|
||||||
} else {
|
} else {
|
||||||
fibonacci(x - 1) + fibonacci(x - 2);
|
return fibonacci(x - 1) + fibonacci(x - 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user