Mako/types/types.go
2025-05-06 12:09:17 -05:00

141 lines
2.4 KiB
Go

package types
type ValueType byte
const (
TypeNull ValueType = iota
TypeNumber
TypeString
TypeBoolean
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
}
func NewNull() Value {
return Value{Type: TypeNull, Data: nil}
}
func NewString(s string) Value {
return Value{Type: TypeString, Data: s}
}
func NewNumber(n float64) Value {
return Value{Type: TypeNumber, Data: n}
}
// TableEntry maintains insertion order
type TableEntry struct {
Key Value
Value Value
}
// Table with ordered entries
type Table struct {
Entries []TableEntry // Preserves insertion order
HashMap map[string]int // Fast lookups for string keys
NumMap map[float64]int // Fast lookups for number keys
BoolMap map[bool]int // Fast lookups for boolean keys
}
func NewTable() *Table {
return &Table{
Entries: []TableEntry{},
HashMap: make(map[string]int),
NumMap: make(map[float64]int),
BoolMap: make(map[bool]int),
}
}
func NewTableValue() Value {
return Value{Type: TypeTable, Data: NewTable()}
}
// TableSet preserves insertion order
func (t *Table) Set(key, value Value) {
idx := -1
switch key.Type {
case TypeString:
if i, ok := t.HashMap[key.Data.(string)]; ok {
idx = i
}
case TypeNumber:
if i, ok := t.NumMap[key.Data.(float64)]; ok {
idx = i
}
case TypeBoolean:
if i, ok := t.BoolMap[key.Data.(bool)]; ok {
idx = i
}
}
if idx >= 0 {
// Update existing entry
t.Entries[idx].Value = value
} else {
// Add new entry
t.Entries = append(t.Entries, TableEntry{Key: key, Value: value})
idx = len(t.Entries) - 1
// Update lookup maps
switch key.Type {
case TypeString:
t.HashMap[key.Data.(string)] = idx
case TypeNumber:
t.NumMap[key.Data.(float64)] = idx
case TypeBoolean:
t.BoolMap[key.Data.(bool)] = idx
}
}
}
func (t *Table) Get(key Value) Value {
switch key.Type {
case TypeString:
if i, ok := t.HashMap[key.Data.(string)]; ok {
return t.Entries[i].Value
}
case TypeNumber:
if i, ok := t.NumMap[key.Data.(float64)]; ok {
return t.Entries[i].Value
}
case TypeBoolean:
if i, ok := t.BoolMap[key.Data.(bool)]; ok {
return t.Entries[i].Value
}
}
return NewNull()
}