move types to types
This commit is contained in:
parent
e536acb4c8
commit
6e5c35c9ee
@ -2,14 +2,14 @@ package compiler
|
||||
|
||||
import (
|
||||
"git.sharkk.net/Sharkk/Mako/parser"
|
||||
"git.sharkk.net/Sharkk/Mako/vm"
|
||||
"git.sharkk.net/Sharkk/Mako/types"
|
||||
)
|
||||
|
||||
// Compile converts AST to bytecode
|
||||
func Compile(program *parser.Program) *vm.Bytecode {
|
||||
func Compile(program *parser.Program) *types.Bytecode {
|
||||
c := &compiler{
|
||||
constants: []any{},
|
||||
instructions: []vm.Instruction{},
|
||||
instructions: []types.Instruction{},
|
||||
scopes: []scope{},
|
||||
}
|
||||
|
||||
@ -22,7 +22,7 @@ func Compile(program *parser.Program) *vm.Bytecode {
|
||||
|
||||
c.exitScope()
|
||||
|
||||
return &vm.Bytecode{
|
||||
return &types.Bytecode{
|
||||
Constants: c.constants,
|
||||
Instructions: c.instructions,
|
||||
}
|
||||
@ -34,7 +34,7 @@ type scope struct {
|
||||
|
||||
type compiler struct {
|
||||
constants []any
|
||||
instructions []vm.Instruction
|
||||
instructions []types.Instruction
|
||||
scopes []scope
|
||||
}
|
||||
|
||||
@ -42,12 +42,12 @@ func (c *compiler) enterScope() {
|
||||
c.scopes = append(c.scopes, scope{
|
||||
variables: make(map[string]bool),
|
||||
})
|
||||
c.emit(vm.OpEnterScope, 0)
|
||||
c.emit(types.OpEnterScope, 0)
|
||||
}
|
||||
|
||||
func (c *compiler) exitScope() {
|
||||
c.scopes = c.scopes[:len(c.scopes)-1]
|
||||
c.emit(vm.OpExitScope, 0)
|
||||
c.emit(types.OpExitScope, 0)
|
||||
}
|
||||
|
||||
func (c *compiler) declareVariable(name string) {
|
||||
@ -73,21 +73,21 @@ func (c *compiler) compileStatement(stmt parser.Statement) {
|
||||
|
||||
// Use SetGlobal for top-level variables to persist between REPL lines
|
||||
if len(c.scopes) <= 1 {
|
||||
c.emit(vm.OpSetGlobal, nameIndex)
|
||||
c.emit(types.OpSetGlobal, nameIndex)
|
||||
} else {
|
||||
c.declareVariable(s.Name.Value)
|
||||
c.emit(vm.OpSetLocal, nameIndex)
|
||||
c.emit(types.OpSetLocal, nameIndex)
|
||||
}
|
||||
|
||||
case *parser.IndexAssignmentStatement:
|
||||
c.compileExpression(s.Left)
|
||||
c.compileExpression(s.Index)
|
||||
c.compileExpression(s.Value)
|
||||
c.emit(vm.OpSetIndex, 0)
|
||||
c.emit(types.OpSetIndex, 0)
|
||||
|
||||
case *parser.EchoStatement:
|
||||
c.compileExpression(s.Value)
|
||||
c.emit(vm.OpEcho, 0)
|
||||
c.emit(types.OpEcho, 0)
|
||||
|
||||
case *parser.BlockStatement:
|
||||
c.enterScope()
|
||||
@ -102,48 +102,48 @@ func (c *compiler) compileExpression(expr parser.Expression) {
|
||||
switch e := expr.(type) {
|
||||
case *parser.StringLiteral:
|
||||
constIndex := c.addConstant(e.Value)
|
||||
c.emit(vm.OpConstant, constIndex)
|
||||
c.emit(types.OpConstant, constIndex)
|
||||
|
||||
case *parser.NumberLiteral:
|
||||
constIndex := c.addConstant(e.Value)
|
||||
c.emit(vm.OpConstant, constIndex)
|
||||
c.emit(types.OpConstant, constIndex)
|
||||
|
||||
case *parser.Identifier:
|
||||
nameIndex := c.addConstant(e.Value)
|
||||
|
||||
// Check if it's a local variable first
|
||||
if c.isLocalVariable(e.Value) {
|
||||
c.emit(vm.OpGetLocal, nameIndex)
|
||||
c.emit(types.OpGetLocal, nameIndex)
|
||||
} else {
|
||||
// Otherwise treat as global
|
||||
c.emit(vm.OpGetGlobal, nameIndex)
|
||||
c.emit(types.OpGetGlobal, nameIndex)
|
||||
}
|
||||
|
||||
case *parser.TableLiteral:
|
||||
c.emit(vm.OpNewTable, 0)
|
||||
c.emit(types.OpNewTable, 0)
|
||||
|
||||
for key, value := range e.Pairs {
|
||||
c.emit(vm.OpDup, 0)
|
||||
c.emit(types.OpDup, 0)
|
||||
|
||||
// Special handling for identifier keys in tables
|
||||
if ident, ok := key.(*parser.Identifier); ok {
|
||||
// Treat identifiers as string literals in table keys
|
||||
strIndex := c.addConstant(ident.Value)
|
||||
c.emit(vm.OpConstant, strIndex)
|
||||
c.emit(types.OpConstant, strIndex)
|
||||
} else {
|
||||
// For other expressions, compile normally
|
||||
c.compileExpression(key)
|
||||
}
|
||||
|
||||
c.compileExpression(value)
|
||||
c.emit(vm.OpSetIndex, 0)
|
||||
c.emit(vm.OpPop, 0)
|
||||
c.emit(types.OpSetIndex, 0)
|
||||
c.emit(types.OpPop, 0)
|
||||
}
|
||||
|
||||
case *parser.IndexExpression:
|
||||
c.compileExpression(e.Left)
|
||||
c.compileExpression(e.Index)
|
||||
c.emit(vm.OpGetIndex, 0)
|
||||
c.emit(types.OpGetIndex, 0)
|
||||
}
|
||||
}
|
||||
|
||||
@ -152,8 +152,8 @@ func (c *compiler) addConstant(value any) int {
|
||||
return len(c.constants) - 1
|
||||
}
|
||||
|
||||
func (c *compiler) emit(op vm.Opcode, operand int) {
|
||||
instruction := vm.Instruction{
|
||||
func (c *compiler) emit(op types.Opcode, operand int) {
|
||||
instruction := types.Instruction{
|
||||
Opcode: op,
|
||||
Operand: operand,
|
||||
}
|
||||
|
@ -7,9 +7,37 @@ const (
|
||||
TypeNumber
|
||||
TypeString
|
||||
TypeBoolean
|
||||
TypeTable // New type for tables
|
||||
TypeTable
|
||||
)
|
||||
|
||||
type Opcode byte
|
||||
|
||||
const (
|
||||
OpConstant Opcode = iota
|
||||
OpSetLocal
|
||||
OpGetLocal
|
||||
OpSetGlobal
|
||||
OpGetGlobal
|
||||
OpEcho
|
||||
OpNewTable
|
||||
OpSetIndex
|
||||
OpGetIndex
|
||||
OpDup
|
||||
OpPop
|
||||
OpEnterScope
|
||||
OpExitScope
|
||||
)
|
||||
|
||||
type Instruction struct {
|
||||
Opcode Opcode
|
||||
Operand int
|
||||
}
|
||||
|
||||
type Bytecode struct {
|
||||
Constants []any
|
||||
Instructions []Instruction
|
||||
}
|
||||
|
||||
type Value struct {
|
||||
Type ValueType
|
||||
Data any
|
||||
|
56
vm/vm.go
56
vm/vm.go
@ -6,34 +6,6 @@ import (
|
||||
"git.sharkk.net/Sharkk/Mako/types"
|
||||
)
|
||||
|
||||
type Opcode byte
|
||||
|
||||
const (
|
||||
OpConstant Opcode = iota
|
||||
OpSetLocal // Set local variable
|
||||
OpGetLocal // Get local variable
|
||||
OpSetGlobal // Set global variable
|
||||
OpGetGlobal // Get global variable
|
||||
OpEcho
|
||||
OpNewTable
|
||||
OpSetIndex
|
||||
OpGetIndex
|
||||
OpDup
|
||||
OpPop
|
||||
OpEnterScope // New opcode for entering a block
|
||||
OpExitScope // New opcode for exiting a block
|
||||
)
|
||||
|
||||
type Instruction struct {
|
||||
Opcode Opcode
|
||||
Operand int
|
||||
}
|
||||
|
||||
type Bytecode struct {
|
||||
Constants []any
|
||||
Instructions []Instruction
|
||||
}
|
||||
|
||||
// Scope represents a lexical scope
|
||||
type Scope struct {
|
||||
Variables map[string]types.Value
|
||||
@ -56,14 +28,14 @@ func New() *VM {
|
||||
}
|
||||
}
|
||||
|
||||
func (vm *VM) Run(bytecode *Bytecode) {
|
||||
func (vm *VM) Run(bytecode *types.Bytecode) {
|
||||
vm.constants = bytecode.Constants
|
||||
|
||||
for ip := 0; ip < len(bytecode.Instructions); ip++ {
|
||||
instruction := bytecode.Instructions[ip]
|
||||
|
||||
switch instruction.Opcode {
|
||||
case OpConstant:
|
||||
case types.OpConstant:
|
||||
constIndex := instruction.Operand
|
||||
constant := vm.constants[constIndex]
|
||||
|
||||
@ -74,7 +46,7 @@ func (vm *VM) Run(bytecode *Bytecode) {
|
||||
vm.push(types.NewNumber(v))
|
||||
}
|
||||
|
||||
case OpSetLocal:
|
||||
case types.OpSetLocal:
|
||||
constIndex := instruction.Operand
|
||||
name := vm.constants[constIndex].(string)
|
||||
value := vm.pop()
|
||||
@ -87,7 +59,7 @@ func (vm *VM) Run(bytecode *Bytecode) {
|
||||
vm.globals[name] = value
|
||||
}
|
||||
|
||||
case OpGetLocal:
|
||||
case types.OpGetLocal:
|
||||
constIndex := instruction.Operand
|
||||
name := vm.constants[constIndex].(string)
|
||||
|
||||
@ -110,13 +82,13 @@ func (vm *VM) Run(bytecode *Bytecode) {
|
||||
}
|
||||
}
|
||||
|
||||
case OpSetGlobal:
|
||||
case types.OpSetGlobal:
|
||||
constIndex := instruction.Operand
|
||||
name := vm.constants[constIndex].(string)
|
||||
value := vm.pop()
|
||||
vm.globals[name] = value
|
||||
|
||||
case OpGetGlobal:
|
||||
case types.OpGetGlobal:
|
||||
constIndex := instruction.Operand
|
||||
name := vm.constants[constIndex].(string)
|
||||
if val, ok := vm.globals[name]; ok {
|
||||
@ -125,22 +97,22 @@ func (vm *VM) Run(bytecode *Bytecode) {
|
||||
vm.push(types.NewNull())
|
||||
}
|
||||
|
||||
case OpEnterScope:
|
||||
case types.OpEnterScope:
|
||||
// Push a new scope
|
||||
vm.scopes = append(vm.scopes, Scope{
|
||||
Variables: make(map[string]types.Value),
|
||||
})
|
||||
|
||||
case OpExitScope:
|
||||
case types.OpExitScope:
|
||||
// Pop the current scope
|
||||
if len(vm.scopes) > 0 {
|
||||
vm.scopes = vm.scopes[:len(vm.scopes)-1]
|
||||
}
|
||||
|
||||
case OpNewTable:
|
||||
case types.OpNewTable:
|
||||
vm.push(types.NewTableValue())
|
||||
|
||||
case OpSetIndex:
|
||||
case types.OpSetIndex:
|
||||
value := vm.pop()
|
||||
key := vm.pop()
|
||||
tableVal := vm.pop()
|
||||
@ -155,7 +127,7 @@ func (vm *VM) Run(bytecode *Bytecode) {
|
||||
table.Set(key, value)
|
||||
vm.push(tableVal)
|
||||
|
||||
case OpGetIndex:
|
||||
case types.OpGetIndex:
|
||||
key := vm.pop()
|
||||
tableVal := vm.pop()
|
||||
|
||||
@ -169,15 +141,15 @@ func (vm *VM) Run(bytecode *Bytecode) {
|
||||
value := table.Get(key)
|
||||
vm.push(value)
|
||||
|
||||
case OpDup:
|
||||
case types.OpDup:
|
||||
if vm.sp > 0 {
|
||||
vm.push(vm.stack[vm.sp-1])
|
||||
}
|
||||
|
||||
case OpPop:
|
||||
case types.OpPop:
|
||||
vm.pop()
|
||||
|
||||
case OpEcho:
|
||||
case types.OpEcho:
|
||||
value := vm.pop()
|
||||
switch value.Type {
|
||||
case types.TypeString:
|
||||
|
Loading…
x
Reference in New Issue
Block a user