compiler 2

This commit is contained in:
Sky Johnson 2025-06-11 18:10:04 -05:00
parent 07edd82c8b
commit aee29ac884
2 changed files with 345 additions and 32 deletions

View File

@ -391,6 +391,313 @@ func (c *Compiler) compileWhileStatement(node *parser.WhileStatement) {
c.current.ExitLoop()
}
// For loop compilation
func (c *Compiler) compileForStatement(node *parser.ForStatement) {
c.current.BeginScope()
c.current.EnterLoop()
// Initialize loop variable
c.compileExpression(node.Start)
if err := c.current.AddLocal(node.Variable.Value); err != nil {
c.addError(err.Error())
return
}
c.current.MarkInitialized()
loopVar := len(c.current.Locals) - 1
// Compile end value
c.compileExpression(node.End)
endSlot := len(c.current.Locals)
if err := c.current.AddLocal("__end"); err != nil {
c.addError(err.Error())
return
}
c.current.MarkInitialized()
// Compile step value (default 1)
if node.Step != nil {
c.compileExpression(node.Step)
} else {
value := Value{Type: ValueNumber, Data: float64(1)}
index := c.current.AddConstant(value)
if index == -1 {
c.addError("too many constants")
return
}
c.current.EmitInstruction(OpLoadConst, uint16(index))
}
stepSlot := len(c.current.Locals)
if err := c.current.AddLocal("__step"); err != nil {
c.addError(err.Error())
return
}
c.current.MarkInitialized()
// Loop condition: check if loop variable <= end (for positive step)
conditionStart := len(c.current.Chunk.Code)
c.current.EmitInstruction(OpLoadLocal, uint16(loopVar)) // Load loop var
c.current.EmitInstruction(OpLoadLocal, uint16(endSlot)) // Load end
c.current.EmitInstruction(OpLte) // Compare
exitJump := c.current.EmitJump(OpJumpIfFalse)
c.current.EmitInstruction(OpPop)
// Loop body
for _, stmt := range node.Body {
c.compileStatement(stmt)
}
// Increment loop variable: var = var + step
c.current.EmitInstruction(OpLoadLocal, uint16(loopVar)) // Load current value
c.current.EmitInstruction(OpLoadLocal, uint16(stepSlot)) // Load step
c.current.EmitInstruction(OpAdd) // Add
c.current.EmitInstruction(OpStoreLocal, uint16(loopVar)) // Store back
// Jump back to condition
jumpBack := len(c.current.Chunk.Code) - conditionStart + 2
c.current.EmitInstruction(OpJump, uint16(jumpBack))
// Exit
c.current.PatchJump(exitJump)
c.current.EmitInstruction(OpPop)
c.current.ExitLoop()
c.current.EndScope()
}
// For-in loop compilation
func (c *Compiler) compileForInStatement(node *parser.ForInStatement) {
c.current.BeginScope()
c.current.EnterLoop()
// Compile iterable and set up iterator
c.compileExpression(node.Iterable)
// For simplicity, assume table iteration
// In a full implementation, we'd need to handle different iterator types
// Create iterator variables
if node.Key != nil {
if err := c.current.AddLocal(node.Key.Value); err != nil {
c.addError(err.Error())
return
}
c.current.MarkInitialized()
}
if err := c.current.AddLocal(node.Value.Value); err != nil {
c.addError(err.Error())
return
}
c.current.MarkInitialized()
// Loop condition (simplified - would need actual iterator logic)
conditionStart := len(c.current.Chunk.Code)
// For now, just emit a simple condition that will be false
// In real implementation, this would call iterator methods
nilValue := Value{Type: ValueNil, Data: nil}
index := c.current.AddConstant(nilValue)
if index == -1 {
c.addError("too many constants")
return
}
c.current.EmitInstruction(OpLoadConst, uint16(index))
c.current.EmitInstruction(OpNot) // Convert nil to true, everything else to false
exitJump := c.current.EmitJump(OpJumpIfFalse)
c.current.EmitInstruction(OpPop)
// Loop body
for _, stmt := range node.Body {
c.compileStatement(stmt)
}
// Jump back to condition
jumpBack := len(c.current.Chunk.Code) - conditionStart + 2
c.current.EmitInstruction(OpJump, uint16(jumpBack))
// Exit
c.current.PatchJump(exitJump)
c.current.EmitInstruction(OpPop)
c.current.ExitLoop()
c.current.EndScope()
}
// Function compilation
func (c *Compiler) compileFunctionLiteral(node *parser.FunctionLiteral) {
// Create new compiler state for function
enclosing := c.current
c.current = NewCompilerState(FunctionTypeFunction)
c.current.parent = enclosing
c.enclosing = enclosing
// Begin function scope
c.current.BeginScope()
// Add parameters as local variables
for _, param := range node.Parameters {
if err := c.current.AddLocal(param.Name); err != nil {
c.addError(err.Error())
return
}
c.current.MarkInitialized()
}
// Compile function body
for _, stmt := range node.Body {
c.compileStatement(stmt)
}
// Implicit return nil if no explicit return
c.current.EmitInstruction(OpReturnNil)
// Create function object
function := Function{
Name: "", // Anonymous function
Arity: len(node.Parameters),
Variadic: node.Variadic,
LocalCount: len(c.current.Locals),
UpvalCount: len(c.current.Upvalues),
Chunk: *c.current.Chunk,
Defaults: []Value{}, // TODO: Handle default parameters
}
// Add function to parent chunk
functionIndex := len(enclosing.Chunk.Functions)
enclosing.Chunk.Functions = append(enclosing.Chunk.Functions, function)
// Restore enclosing state
c.current = enclosing
c.enclosing = nil
// Emit closure instruction
c.current.EmitInstruction(OpClosure, uint16(functionIndex), uint16(function.UpvalCount))
}
// Struct compilation
func (c *Compiler) compileStructStatement(node *parser.StructStatement) {
// Convert parser fields to compiler fields
fields := make([]StructField, len(node.Fields))
for i, field := range node.Fields {
fields[i] = StructField{
Name: field.Name,
Type: c.typeInfoToValueType(field.TypeHint),
Offset: uint16(i),
}
}
// Create struct definition
structDef := Struct{
Name: node.Name,
Fields: fields,
Methods: make(map[string]uint16),
ID: node.ID,
}
// Add to chunk
c.current.Chunk.Structs = append(c.current.Chunk.Structs, structDef)
}
func (c *Compiler) compileMethodDefinition(node *parser.MethodDefinition) {
// Compile method as a function
enclosing := c.current
c.current = NewCompilerState(FunctionTypeMethod)
c.current.parent = enclosing
c.enclosing = enclosing
// Begin function scope
c.current.BeginScope()
// Add 'self' parameter
if err := c.current.AddLocal("self"); err != nil {
c.addError(err.Error())
return
}
c.current.MarkInitialized()
// Add method parameters
for _, param := range node.Function.Parameters {
if err := c.current.AddLocal(param.Name); err != nil {
c.addError(err.Error())
return
}
c.current.MarkInitialized()
}
// Compile method body
for _, stmt := range node.Function.Body {
c.compileStatement(stmt)
}
// Implicit return nil
c.current.EmitInstruction(OpReturnNil)
// Create function object
function := Function{
Name: node.MethodName,
Arity: len(node.Function.Parameters) + 1, // +1 for self
Variadic: node.Function.Variadic,
LocalCount: len(c.current.Locals),
UpvalCount: len(c.current.Upvalues),
Chunk: *c.current.Chunk,
Defaults: []Value{},
}
// Add to parent chunk
functionIndex := len(enclosing.Chunk.Functions)
enclosing.Chunk.Functions = append(enclosing.Chunk.Functions, function)
// Find struct and add method reference
for i := range enclosing.Chunk.Structs {
if enclosing.Chunk.Structs[i].ID == node.StructID {
enclosing.Chunk.Structs[i].Methods[node.MethodName] = uint16(functionIndex)
break
}
}
// Restore state
c.current = enclosing
c.enclosing = nil
}
func (c *Compiler) compileStructConstructor(node *parser.StructConstructor) {
// Create new struct instance
c.current.EmitInstruction(OpNewStruct, node.StructID)
// Initialize fields
for _, field := range node.Fields {
if field.Key != nil {
// Named field assignment
c.current.EmitInstruction(OpDup) // Duplicate struct reference
// Get field name
var fieldName string
if ident, ok := field.Key.(*parser.Identifier); ok {
fieldName = ident.Value
} else if str, ok := field.Key.(*parser.StringLiteral); ok {
fieldName = str.Value
} else {
c.addError("struct field names must be identifiers or strings")
continue
}
// Find field index in struct definition
fieldIndex := c.findStructFieldIndex(node.StructID, fieldName)
if fieldIndex == -1 {
c.addError(fmt.Sprintf("struct has no field '%s'", fieldName))
continue
}
c.compileExpression(field.Value)
c.current.EmitInstruction(OpSetProperty, uint16(fieldIndex))
} else {
// Positional field assignment (not typical for structs)
c.addError("struct constructors require named field assignments")
}
}
}
// Table operations
func (c *Compiler) compileTableLiteral(node *parser.TableLiteral) {
c.current.EmitInstruction(OpNewTable)
@ -427,7 +734,7 @@ func (c *Compiler) compileIndexExpression(node *parser.IndexExpression) {
c.current.EmitInstruction(OpGetIndex)
}
// Function compilation
// Function calls
func (c *Compiler) compileCallExpression(node *parser.CallExpression) {
c.compileExpression(node.Function)
@ -464,37 +771,6 @@ func (c *Compiler) compileExitStatement(node *parser.ExitStatement) {
c.current.EmitInstruction(OpExit)
}
// Placeholder implementations for complex features
func (c *Compiler) compileStructStatement(node *parser.StructStatement) {
// TODO: Implement struct compilation
c.addError("struct compilation not yet implemented")
}
func (c *Compiler) compileMethodDefinition(node *parser.MethodDefinition) {
// TODO: Implement method compilation
c.addError("method compilation not yet implemented")
}
func (c *Compiler) compileStructConstructor(node *parser.StructConstructor) {
// TODO: Implement struct constructor compilation
c.addError("struct constructor compilation not yet implemented")
}
func (c *Compiler) compileFunctionLiteral(node *parser.FunctionLiteral) {
// TODO: Implement function literal compilation
c.addError("function literal compilation not yet implemented")
}
func (c *Compiler) compileForStatement(node *parser.ForStatement) {
// TODO: Implement numeric for loop compilation
c.addError("for statement compilation not yet implemented")
}
func (c *Compiler) compileForInStatement(node *parser.ForInStatement) {
// TODO: Implement for-in loop compilation
c.addError("for-in statement compilation not yet implemented")
}
// Helper methods
func (c *Compiler) resolveUpvalue(name string) int {
if c.enclosing == nil {
@ -525,6 +801,41 @@ func (c *Compiler) resolveUpvalueInEnclosing(name string) int {
return -1
}
func (c *Compiler) typeInfoToValueType(typeInfo parser.TypeInfo) ValueType {
switch typeInfo.Type {
case parser.TypeNumber:
return ValueNumber
case parser.TypeString:
return ValueString
case parser.TypeBool:
return ValueBool
case parser.TypeNil:
return ValueNil
case parser.TypeTable:
return ValueTable
case parser.TypeFunction:
return ValueFunction
case parser.TypeStruct:
return ValueStruct
default:
return ValueNil
}
}
func (c *Compiler) findStructFieldIndex(structID uint16, fieldName string) int {
for _, structDef := range c.current.Chunk.Structs {
if structDef.ID == structID {
for i, field := range structDef.Fields {
if field.Name == fieldName {
return i
}
}
break
}
}
return -1
}
func (c *Compiler) addError(message string) {
c.errors = append(c.errors, CompileError{
Message: message,

View File

@ -23,6 +23,7 @@ type CompilerState struct {
ContinueJumps []int // Continue jump addresses for loops
LoopStart int // Start of current loop for continue
LoopDepth int // Current loop nesting depth
parent *CompilerState // Parent compiler state for nested functions
}
// Local represents a local variable during compilation
@ -74,6 +75,7 @@ func NewCompilerState(functionType FunctionType) *CompilerState {
ContinueJumps: make([]int, 0),
LoopStart: -1,
LoopDepth: 0,
parent: nil,
}
}