builtins
This commit is contained in:
@@ -34,9 +34,16 @@ func New() *Compiler {
|
||||
lastInstruction: EmittedInstruction{},
|
||||
previousInstruction: EmittedInstruction{},
|
||||
}
|
||||
|
||||
symbolTable := NewSymbolTable()
|
||||
|
||||
for i, v := range object.Builtins {
|
||||
symbolTable.DefineBuiltin(i, v.Name)
|
||||
}
|
||||
|
||||
return &Compiler{
|
||||
constants: []object.Object{},
|
||||
symbolTable: NewSymbolTable(),
|
||||
symbolTable: symbolTable,
|
||||
scopes: []CompilationScope{mainScope},
|
||||
scopeIndex: 0,
|
||||
}
|
||||
@@ -207,11 +214,7 @@ func (c *Compiler) Compile(node ast.Node) error {
|
||||
return fmt.Errorf("undefined varible %s", node.Value)
|
||||
}
|
||||
|
||||
if symbol.Scope == GlobalScope {
|
||||
c.emit(code.OpGetGlobal, symbol.Index)
|
||||
} else {
|
||||
c.emit(code.OpGetLocal, symbol.Index)
|
||||
}
|
||||
c.loadSymbol(symbol)
|
||||
|
||||
case *ast.StringLiteral:
|
||||
str := &object.String{Value: node.Value}
|
||||
@@ -425,3 +428,14 @@ type Bytecode struct {
|
||||
Instructions code.Instructions
|
||||
Constants []object.Object
|
||||
}
|
||||
|
||||
func (c *Compiler) loadSymbol(s Symbol) {
|
||||
switch s.Scope {
|
||||
case GlobalScope:
|
||||
c.emit(code.OpGetGlobal, s.Index)
|
||||
case LocalScope:
|
||||
c.emit(code.OpGetLocal, s.Index)
|
||||
case BuiltinScope:
|
||||
c.emit(code.OpGetBuiltin, s.Index)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -832,3 +832,43 @@ func testStringObject(expected string, actual object.Object) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestBuiltins(t *testing.T) {
|
||||
tests := []compilerTestCase{
|
||||
{
|
||||
input: `
|
||||
len([]);
|
||||
push([], 1);
|
||||
`,
|
||||
expectedConstants: []interface{}{1},
|
||||
expectedInstructions: []code.Instructions{
|
||||
code.Make(code.OpGetBuiltin, 0),
|
||||
code.Make(code.OpArray, 0),
|
||||
code.Make(code.OpCall, 1),
|
||||
code.Make(code.OpPop),
|
||||
code.Make(code.OpGetBuiltin, 5),
|
||||
code.Make(code.OpArray, 0),
|
||||
code.Make(code.OpConstant, 0),
|
||||
code.Make(code.OpCall, 2),
|
||||
code.Make(code.OpPop),
|
||||
},
|
||||
},
|
||||
{
|
||||
input: `fn() { len([]) }`,
|
||||
expectedConstants: []interface{}{
|
||||
[]code.Instructions{
|
||||
code.Make(code.OpGetBuiltin, 0),
|
||||
code.Make(code.OpArray, 0),
|
||||
code.Make(code.OpCall, 1),
|
||||
code.Make(code.OpReturnValue),
|
||||
},
|
||||
},
|
||||
expectedInstructions: []code.Instructions{
|
||||
code.Make(code.OpConstant, 0),
|
||||
code.Make(code.OpPop),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
runCompilerTests(t, tests)
|
||||
}
|
||||
|
||||
@@ -3,8 +3,9 @@ package compiler
|
||||
type SymbolScope string
|
||||
|
||||
const (
|
||||
LocalScope SymbolScope = "LOCAL"
|
||||
GlobalScope SymbolScope = "GLOBAL"
|
||||
LocalScope SymbolScope = "LOCAL"
|
||||
GlobalScope SymbolScope = "GLOBAL"
|
||||
BuiltinScope SymbolScope = "BUILTIN"
|
||||
)
|
||||
|
||||
type Symbol struct {
|
||||
@@ -53,3 +54,9 @@ func (s *SymbolTable) Resolve(name string) (Symbol, bool) {
|
||||
|
||||
return obj, ok
|
||||
}
|
||||
|
||||
func (s *SymbolTable) DefineBuiltin(index int, name string) Symbol {
|
||||
symbol := Symbol{Name: name, Index: index, Scope: BuiltinScope}
|
||||
s.store[name] = symbol
|
||||
return symbol
|
||||
}
|
||||
|
||||
@@ -166,3 +166,34 @@ func TestResolveNestedLocal(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDefineResolveBuiltins(t *testing.T) {
|
||||
global := NewSymbolTable()
|
||||
firstLocal := NewEnclosedSymbolTable(global)
|
||||
secondLocal := NewEnclosedSymbolTable(firstLocal)
|
||||
|
||||
expected := []Symbol{
|
||||
Symbol{Name: "a", Scope: BuiltinScope, Index: 0},
|
||||
Symbol{Name: "c", Scope: BuiltinScope, Index: 1},
|
||||
Symbol{Name: "e", Scope: BuiltinScope, Index: 2},
|
||||
Symbol{Name: "f", Scope: BuiltinScope, Index: 3},
|
||||
}
|
||||
|
||||
for i, v := range expected {
|
||||
global.DefineBuiltin(i, v.Name)
|
||||
}
|
||||
|
||||
for _, table := range []*SymbolTable{global, firstLocal, secondLocal} {
|
||||
for _, sym := range expected {
|
||||
result, ok := table.Resolve(sym.Name)
|
||||
if !ok {
|
||||
t.Errorf("name %s not resolvable", sym.Name)
|
||||
continue
|
||||
}
|
||||
if result != sym {
|
||||
t.Errorf("expected %s to resolve to %+v, got=%+v",
|
||||
sym.Name, sym, result)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user