builtins
Some checks failed
Build / build (push) Failing after 1h2m55s
Test / build (push) Failing after 29m38s

This commit is contained in:
Chuck Smith
2024-03-12 16:35:24 -04:00
parent 1d2c7f0a51
commit e373e9f68a
11 changed files with 354 additions and 125 deletions

View File

@@ -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)
}
}

View File

@@ -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)
}

View File

@@ -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
}

View File

@@ -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)
}
}
}
}