diff options
Diffstat (limited to 'pkg')
| -rw-r--r-- | pkg/lang/compiler/compiler.go | 9 | ||||
| -rw-r--r-- | pkg/lang/compiler/compiler_test.go | 1 | ||||
| -rw-r--r-- | pkg/lang/compiler/scope_chain.go | 3 | ||||
| -rw-r--r-- | pkg/lang/compiler/symbol.go | 1 | ||||
| -rw-r--r-- | pkg/lang/vm/code/op.go | 2 | ||||
| -rw-r--r-- | pkg/lang/vm/exec.go | 31 | ||||
| -rw-r--r-- | pkg/lang/vm/text/decompiler.go | 1 | ||||
| -rw-r--r-- | pkg/lang/vm/text/op.go | 1 | ||||
| -rw-r--r-- | pkg/lang/vm/value/data.go | 4 | ||||
| -rw-r--r-- | pkg/lang/vm/vm.go | 6 | ||||
| -rw-r--r-- | pkg/lang/vm/vm_test.go | 8 |
11 files changed, 54 insertions, 13 deletions
diff --git a/pkg/lang/compiler/compiler.go b/pkg/lang/compiler/compiler.go index ae2a71c..728dec1 100644 --- a/pkg/lang/compiler/compiler.go +++ b/pkg/lang/compiler/compiler.go @@ -50,7 +50,7 @@ func (comp *Compiler) Compile() (code.Code, error) { } func (comp *Compiler) preDeclareFunction(fnDeclStmt ast.StmtFnDecl) error { - if _, ok := comp.scopes.DeclareFunction(fnDeclStmt.Name.Value); !ok { + if _, ok := comp.scopes.DeclareFunction(fnDeclStmt.Name.Value, uint(len(fnDeclStmt.Args))); !ok { return fmt.Errorf("function %s already declared", fnDeclStmt.Name.Value) } @@ -103,7 +103,7 @@ func (comp *Compiler) compileStmt(t *code.Builder, stmt ast.Stmt) error { } func (comp *Compiler) compileFnDeclStmt(t *code.Builder, fnDeclStmt ast.StmtFnDecl) error { - marker, ok := comp.scopes.DeclareFunction(fnDeclStmt.Name.Value) + marker, ok := comp.scopes.DeclareFunction(fnDeclStmt.Name.Value, uint(len(fnDeclStmt.Args))) if !ok { // If we are in the root scope, the function was simply predeclared :) if comp.scopes.IsRootScope() { @@ -598,6 +598,11 @@ func (comp *Compiler) compileIdentExpr(t *code.Builder, expr ast.ExprIdent) erro t.AppendOp(code.OpPushFunction) t.AppendMarkerReference(symbol.data.marker) + + if symbol.data.args != 0 { + t.AppendOp(code.OpSetArgCount) + t.AppendInt(int64(symbol.data.args)) + } default: panic(fmt.Errorf("unknown symbol kind: %v", symbolId.symbolKind)) } diff --git a/pkg/lang/compiler/compiler_test.go b/pkg/lang/compiler/compiler_test.go index cd62088..bdbc375 100644 --- a/pkg/lang/compiler/compiler_test.go +++ b/pkg/lang/compiler/compiler_test.go @@ -383,6 +383,7 @@ func TestFunctionArgs(t *testing.T) { expected := ` push_function @add + set_arg_count 2 push_int 4 push_int 5 call 2 diff --git a/pkg/lang/compiler/scope_chain.go b/pkg/lang/compiler/scope_chain.go index 3a3b819..6705852 100644 --- a/pkg/lang/compiler/scope_chain.go +++ b/pkg/lang/compiler/scope_chain.go @@ -91,7 +91,7 @@ func (sc *ScopeChain) Declare(name string) (int, bool) { return indexInScope, true } -func (sc *ScopeChain) DeclareFunction(name string) (code.Marker, bool) { +func (sc *ScopeChain) DeclareFunction(name string, args uint) (code.Marker, bool) { if _, ok := sc.nameToSymbol[name]; ok { return "", false } @@ -111,6 +111,7 @@ func (sc *ScopeChain) DeclareFunction(name string) (code.Marker, bool) { name: name, data: SymbolFunction{ marker: unitName, + args: args, }, }) diff --git a/pkg/lang/compiler/symbol.go b/pkg/lang/compiler/symbol.go index d22cdc0..453cb2b 100644 --- a/pkg/lang/compiler/symbol.go +++ b/pkg/lang/compiler/symbol.go @@ -35,4 +35,5 @@ type SymbolVariable struct { type SymbolFunction struct { marker code.Marker + args uint } diff --git a/pkg/lang/vm/code/op.go b/pkg/lang/vm/code/op.go index 665742d..1ce08f7 100644 --- a/pkg/lang/vm/code/op.go +++ b/pkg/lang/vm/code/op.go @@ -30,6 +30,8 @@ const ( OpAddToEnv OpAnchorType + + OpSetArgCount OpAdd OpSub diff --git a/pkg/lang/vm/exec.go b/pkg/lang/vm/exec.go index 32b1013..f92e486 100644 --- a/pkg/lang/vm/exec.go +++ b/pkg/lang/vm/exec.go @@ -433,6 +433,28 @@ func (vm *VM) execAnchorType() error { return nil } +func (vm *VM) execSetArgCount(argCount uint) error { + f, err := vm.stack.Pop() + if err != nil { + return err + } + + if f.Type() != value.FunctionType { + return ErrInvalidOperandType{ + Op: code.OpSetArgCount, + X: f.Type(), + } + } + + fn := f.Data().(value.FunctionData) + + fn = fn.WithArgs(argCount) + f = f.WithData(fn) + + vm.stack.Push(f) + return nil +} + type binaryOperation = func(value.Value, value.Value) (value.Value, error) type typesToBinaryOperation = map[value.TypeKind]map[value.TypeKind]binaryOperation @@ -747,11 +769,10 @@ func (vm *VM) execCall(argCount uint) error { fn := f.Data().(value.FunctionData) if argCount != fn.Args() { - // TODO: Uncomment when push_function can set fn.Args() - // return ErrWrongNumberOfArguments{ - // Got: argCount, - // Needed: fn.Args(), - // } + return ErrWrongNumberOfArguments{ + Got: argCount, + Needed: fn.Args(), + } } if err = vm.stack.PushCall(fn.Pc(), vm.pc, fn.Env()); err != nil { diff --git a/pkg/lang/vm/text/decompiler.go b/pkg/lang/vm/text/decompiler.go index bef066b..aca024c 100644 --- a/pkg/lang/vm/text/decompiler.go +++ b/pkg/lang/vm/text/decompiler.go @@ -75,6 +75,7 @@ func (d *Decompiler) decompileInstruction(bc code.Raw) (string, code.Raw) { code.OpGetEnv, code.OpSetEnv, code.OpAddToEnv, + code.OpSetArgCount, code.OpCall: i, rest := d.decompileInt(bc[1:]) return fmt.Sprintf("%s %s", opString, i), rest diff --git a/pkg/lang/vm/text/op.go b/pkg/lang/vm/text/op.go index d438a25..ce53f50 100644 --- a/pkg/lang/vm/text/op.go +++ b/pkg/lang/vm/text/op.go @@ -26,6 +26,7 @@ var ( code.OpSetEnv: "set_env", code.OpAddToEnv: "add_to_env", code.OpAnchorType: "anchor_type", + code.OpSetArgCount: "set_arg_count", code.OpAdd: "add", code.OpSub: "sub", code.OpMul: "mul", diff --git a/pkg/lang/vm/value/data.go b/pkg/lang/vm/value/data.go index e51904e..18e1b3d 100644 --- a/pkg/lang/vm/value/data.go +++ b/pkg/lang/vm/value/data.go @@ -155,6 +155,10 @@ func (f FunctionData) WithEnv(env mem.Ptr) FunctionData { return FunctionData{pc: f.pc, args: f.args, env: env, native: f.native} } +func (f FunctionData) WithArgs(args uint) FunctionData { + return FunctionData{pc: f.pc, args: args, env: f.env, native: f.native} +} + func (f FunctionData) String(_ mem.Mem) (string, error) { if f.native != nil { return fmt.Sprintf("<fn(%d) native>", f.args), nil diff --git a/pkg/lang/vm/vm.go b/pkg/lang/vm/vm.go index 54fd8ee..ff9c28e 100644 --- a/pkg/lang/vm/vm.go +++ b/pkg/lang/vm/vm.go @@ -160,6 +160,12 @@ func (vm *VM) step(op code.Op) (stepDecision, error) { case code.OpAnchorType: err = vm.execAnchorType() + case code.OpSetArgCount: + argCount, advance := vm.code.GetUint(vm.pc) + vm.pc += advance + + err = vm.execSetArgCount(uint(argCount)) + case code.OpAdd: err = vm.execAdd() case code.OpSub: diff --git a/pkg/lang/vm/vm_test.go b/pkg/lang/vm/vm_test.go index fa43b02..7fe07dd 100644 --- a/pkg/lang/vm/vm_test.go +++ b/pkg/lang/vm/vm_test.go @@ -91,18 +91,15 @@ func TestFibonacci(t *testing.T) { } func TestFunction(t *testing.T) { - t.Skip("Reimplement arguments") - src := ` - push_int 44 push_function @subtract_two + set_arg_count 1 + push_int 44 call 1 halt @subtract_two: - shift 1 push_int 2 - get_local 0 sub ret ` @@ -255,6 +252,7 @@ func TestTypeConstruct(t *testing.T) { push_string "$init" push_function @Cat:$init + set_arg_count 2 call 2 |
