line counting in bytecode
This commit is contained in:
parent
aee29ac884
commit
2179a39e2c
@ -232,3 +232,18 @@ func GetOperandCount(op Opcode) int {
|
||||
func InstructionSize(op Opcode) int {
|
||||
return 1 + (GetOperandCount(op) * 2) // 1 byte opcode + 2 bytes per operand
|
||||
}
|
||||
|
||||
var opcodeNames = map[Opcode]string{
|
||||
OpLoadConst: "OP_LOAD_CONST",
|
||||
OpLoadLocal: "OP_LOAD_LOCAL",
|
||||
OpStoreLocal: "OP_STORE_LOCAL",
|
||||
OpAdd: "OP_ADD",
|
||||
OpSub: "OP_SUB",
|
||||
OpMul: "OP_MUL",
|
||||
OpDiv: "OP_DIV",
|
||||
OpJump: "OP_JUMP",
|
||||
OpJumpIfTrue: "OP_JUMP_TRUE",
|
||||
OpJumpIfFalse: "OP_JUMP_FALSE",
|
||||
OpReturn: "OP_RETURN",
|
||||
OpEcho: "OP_ECHO",
|
||||
}
|
||||
|
@ -38,6 +38,11 @@ func (c *Compiler) Compile(program *parser.Program) (*Chunk, []CompileError) {
|
||||
|
||||
// Statement compilation
|
||||
func (c *Compiler) compileStatement(stmt parser.Statement) {
|
||||
// Extract line from any statement that has position info
|
||||
if lineNode := c.getLineFromNode(stmt); lineNode != 0 {
|
||||
c.current.SetLine(lineNode)
|
||||
}
|
||||
|
||||
switch s := stmt.(type) {
|
||||
case *parser.StructStatement:
|
||||
c.compileStructStatement(s)
|
||||
@ -72,6 +77,10 @@ func (c *Compiler) compileStatement(stmt parser.Statement) {
|
||||
|
||||
// Expression compilation
|
||||
func (c *Compiler) compileExpression(expr parser.Expression) {
|
||||
if lineNode := c.getLineFromNode(expr); lineNode != 0 {
|
||||
c.current.SetLine(lineNode)
|
||||
}
|
||||
|
||||
switch e := expr.(type) {
|
||||
case *parser.Identifier:
|
||||
c.compileIdentifier(e)
|
||||
@ -836,14 +845,94 @@ func (c *Compiler) findStructFieldIndex(structID uint16, fieldName string) int {
|
||||
return -1
|
||||
}
|
||||
|
||||
// Enhanced error reporting
|
||||
func (c *Compiler) addError(message string) {
|
||||
c.errors = append(c.errors, CompileError{
|
||||
Message: message,
|
||||
Line: 0, // TODO: Add line tracking
|
||||
Column: 0, // TODO: Add column tracking
|
||||
Line: c.current.CurrentLine,
|
||||
Column: 0, // Column tracking would need more work
|
||||
})
|
||||
}
|
||||
|
||||
// Error reporting
|
||||
func (c *Compiler) Errors() []CompileError { return c.errors }
|
||||
func (c *Compiler) HasErrors() bool { return len(c.errors) > 0 }
|
||||
|
||||
// Helper to extract line info from AST nodes
|
||||
func (c *Compiler) getLineFromNode(node any) int {
|
||||
// Since AST nodes don't store position, we'd need to modify the parser
|
||||
// For now, track during compilation by passing line info through
|
||||
return 0 // Placeholder
|
||||
}
|
||||
|
||||
// Bytecode disassembler helper for debugging
|
||||
func DisassembleInstruction(chunk *Chunk, offset int) int {
|
||||
if offset >= len(chunk.Code) {
|
||||
return offset
|
||||
}
|
||||
|
||||
line := 0
|
||||
if offset < len(chunk.Lines) {
|
||||
line = chunk.Lines[offset]
|
||||
}
|
||||
|
||||
fmt.Printf("%04d ", offset)
|
||||
if offset > 0 && line == chunk.Lines[offset-1] {
|
||||
fmt.Print(" | ")
|
||||
} else {
|
||||
fmt.Printf("%4d ", line)
|
||||
}
|
||||
|
||||
op := Opcode(chunk.Code[offset])
|
||||
fmt.Printf("%-16s", opcodeNames[op])
|
||||
|
||||
switch op {
|
||||
case OpLoadConst, OpLoadLocal, OpStoreLocal:
|
||||
operand := uint16(chunk.Code[offset+1]) | (uint16(chunk.Code[offset+2]) << 8)
|
||||
fmt.Printf(" %4d", operand)
|
||||
if op == OpLoadConst && int(operand) < len(chunk.Constants) {
|
||||
fmt.Printf(" '")
|
||||
printValue(chunk.Constants[operand])
|
||||
fmt.Printf("'")
|
||||
}
|
||||
return offset + 3
|
||||
case OpJump, OpJumpIfTrue, OpJumpIfFalse:
|
||||
jump := uint16(chunk.Code[offset+1]) | (uint16(chunk.Code[offset+2]) << 8)
|
||||
fmt.Printf(" %4d -> %d", jump, offset+3+int(jump))
|
||||
return offset + 3
|
||||
default:
|
||||
return offset + 1
|
||||
}
|
||||
}
|
||||
|
||||
func printValue(value Value) {
|
||||
switch value.Type {
|
||||
case ValueNil:
|
||||
fmt.Print("nil")
|
||||
case ValueBool:
|
||||
fmt.Print(value.Data.(bool))
|
||||
case ValueNumber:
|
||||
fmt.Printf("%.2f", value.Data.(float64))
|
||||
case ValueString:
|
||||
fmt.Print(value.Data.(string))
|
||||
default:
|
||||
fmt.Printf("<%s>", valueTypeString(value.Type))
|
||||
}
|
||||
}
|
||||
|
||||
func valueTypeString(vt ValueType) string {
|
||||
switch vt {
|
||||
case ValueTable:
|
||||
return "table"
|
||||
case ValueFunction:
|
||||
return "function"
|
||||
case ValueStruct:
|
||||
return "struct"
|
||||
case ValueArray:
|
||||
return "array"
|
||||
case ValueUpvalue:
|
||||
return "upvalue"
|
||||
default:
|
||||
return "unknown"
|
||||
}
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ type CompilerState struct {
|
||||
LoopStart int // Start of current loop for continue
|
||||
LoopDepth int // Current loop nesting depth
|
||||
parent *CompilerState // Parent compiler state for nested functions
|
||||
CurrentLine int // Current source line being compiled
|
||||
}
|
||||
|
||||
// Local represents a local variable during compilation
|
||||
@ -216,7 +217,7 @@ func (cs *CompilerState) valueKey(value Value) string {
|
||||
// Bytecode emission methods
|
||||
func (cs *CompilerState) EmitByte(byte uint8) {
|
||||
cs.Chunk.Code = append(cs.Chunk.Code, byte)
|
||||
cs.Chunk.Lines = append(cs.Chunk.Lines, 0) // Line will be set by caller
|
||||
cs.Chunk.Lines = append(cs.Chunk.Lines, cs.CurrentLine)
|
||||
}
|
||||
|
||||
func (cs *CompilerState) EmitBytes(bytes ...uint8) {
|
||||
@ -290,3 +291,7 @@ func (cs *CompilerState) EmitContinue() {
|
||||
cs.ContinueJumps = append(cs.ContinueJumps, jumpOffset)
|
||||
}
|
||||
}
|
||||
|
||||
func (cs *CompilerState) SetLine(line int) {
|
||||
cs.CurrentLine = line
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user