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