compiler 2
This commit is contained in:
parent
07edd82c8b
commit
aee29ac884
@ -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,
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user