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 {
|
func InstructionSize(op Opcode) int {
|
||||||
return 1 + (GetOperandCount(op) * 2) // 1 byte opcode + 2 bytes per operand
|
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
|
// Statement compilation
|
||||||
func (c *Compiler) compileStatement(stmt parser.Statement) {
|
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) {
|
switch s := stmt.(type) {
|
||||||
case *parser.StructStatement:
|
case *parser.StructStatement:
|
||||||
c.compileStructStatement(s)
|
c.compileStructStatement(s)
|
||||||
@ -72,6 +77,10 @@ func (c *Compiler) compileStatement(stmt parser.Statement) {
|
|||||||
|
|
||||||
// Expression compilation
|
// Expression compilation
|
||||||
func (c *Compiler) compileExpression(expr parser.Expression) {
|
func (c *Compiler) compileExpression(expr parser.Expression) {
|
||||||
|
if lineNode := c.getLineFromNode(expr); lineNode != 0 {
|
||||||
|
c.current.SetLine(lineNode)
|
||||||
|
}
|
||||||
|
|
||||||
switch e := expr.(type) {
|
switch e := expr.(type) {
|
||||||
case *parser.Identifier:
|
case *parser.Identifier:
|
||||||
c.compileIdentifier(e)
|
c.compileIdentifier(e)
|
||||||
@ -836,14 +845,94 @@ func (c *Compiler) findStructFieldIndex(structID uint16, fieldName string) int {
|
|||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Enhanced error reporting
|
||||||
func (c *Compiler) addError(message string) {
|
func (c *Compiler) addError(message string) {
|
||||||
c.errors = append(c.errors, CompileError{
|
c.errors = append(c.errors, CompileError{
|
||||||
Message: message,
|
Message: message,
|
||||||
Line: 0, // TODO: Add line tracking
|
Line: c.current.CurrentLine,
|
||||||
Column: 0, // TODO: Add column tracking
|
Column: 0, // Column tracking would need more work
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Error reporting
|
// Error reporting
|
||||||
func (c *Compiler) Errors() []CompileError { return c.errors }
|
func (c *Compiler) Errors() []CompileError { return c.errors }
|
||||||
func (c *Compiler) HasErrors() bool { return len(c.errors) > 0 }
|
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
|
LoopStart int // Start of current loop for continue
|
||||||
LoopDepth int // Current loop nesting depth
|
LoopDepth int // Current loop nesting depth
|
||||||
parent *CompilerState // Parent compiler state for nested functions
|
parent *CompilerState // Parent compiler state for nested functions
|
||||||
|
CurrentLine int // Current source line being compiled
|
||||||
}
|
}
|
||||||
|
|
||||||
// Local represents a local variable during compilation
|
// Local represents a local variable during compilation
|
||||||
@ -216,7 +217,7 @@ func (cs *CompilerState) valueKey(value Value) string {
|
|||||||
// Bytecode emission methods
|
// Bytecode emission methods
|
||||||
func (cs *CompilerState) EmitByte(byte uint8) {
|
func (cs *CompilerState) EmitByte(byte uint8) {
|
||||||
cs.Chunk.Code = append(cs.Chunk.Code, byte)
|
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) {
|
func (cs *CompilerState) EmitBytes(bytes ...uint8) {
|
||||||
@ -290,3 +291,7 @@ func (cs *CompilerState) EmitContinue() {
|
|||||||
cs.ContinueJumps = append(cs.ContinueJumps, jumpOffset)
|
cs.ContinueJumps = append(cs.ContinueJumps, jumpOffset)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (cs *CompilerState) SetLine(line int) {
|
||||||
|
cs.CurrentLine = line
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user