148 lines
3.1 KiB
Go
148 lines
3.1 KiB
Go
package compiler
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
"testing"
|
|
|
|
"c65gm/internal/preproc"
|
|
"c65gm/internal/utils"
|
|
)
|
|
|
|
// TestBreakCommand is a simple command implementation for testing
|
|
type TestBreakCommand struct {
|
|
line preproc.Line
|
|
}
|
|
|
|
func (c *TestBreakCommand) WillHandle(line preproc.Line) bool {
|
|
params, err := utils.ParseParams(line.Text)
|
|
if err != nil || len(params) == 0 {
|
|
return false
|
|
}
|
|
return strings.ToUpper(params[0]) == "BREAK"
|
|
}
|
|
|
|
func (c *TestBreakCommand) Interpret(line preproc.Line, ctx *CompilerContext) error {
|
|
c.line = line
|
|
|
|
params, err := utils.ParseParams(line.Text)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if len(params) != 1 {
|
|
return fmt.Errorf("BREAK does not expect parameters")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (c *TestBreakCommand) Generate(ctx *CompilerContext) ([]string, error) {
|
|
// BREAK jumps to end of WHILE loop
|
|
label, err := ctx.WhileStack.Peek()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("BREAK outside of WHILE loop")
|
|
}
|
|
|
|
return []string{
|
|
fmt.Sprintf(" jmp %s_end", label),
|
|
}, nil
|
|
}
|
|
|
|
func TestCompilerArchitecture(t *testing.T) {
|
|
// Create pragma
|
|
pragma := preproc.NewPragma()
|
|
|
|
// Create compiler
|
|
comp := NewCompiler(pragma)
|
|
|
|
// Register BREAK command
|
|
comp.Registry().Register(&TestBreakCommand{})
|
|
|
|
// Create test input - BREAK inside a simulated WHILE
|
|
lines := []preproc.Line{
|
|
{
|
|
Text: "BREAK",
|
|
Filename: "test.c65",
|
|
LineNo: 1,
|
|
Kind: preproc.Source,
|
|
PragmaSetIndex: 0,
|
|
},
|
|
}
|
|
|
|
// Manually push a WHILE label so BREAK has something to reference
|
|
comp.Context().WhileStack.Push()
|
|
|
|
// Compile
|
|
output, err := comp.Compile(lines)
|
|
|
|
// Should fail because BREAK needs proper WHILE context
|
|
// But this tests the basic flow: WillHandle -> Interpret -> Generate
|
|
if err != nil {
|
|
t.Logf("Expected controlled error: %v", err)
|
|
}
|
|
|
|
// Check we got some output structure
|
|
if len(output) == 0 {
|
|
t.Logf("Got output lines: %d", len(output))
|
|
}
|
|
|
|
t.Logf("Output:\n%s", strings.Join(output, "\n"))
|
|
}
|
|
|
|
func TestCommandRegistry(t *testing.T) {
|
|
registry := NewCommandRegistry()
|
|
|
|
breakCmd := &TestBreakCommand{}
|
|
registry.Register(breakCmd)
|
|
|
|
line := preproc.Line{
|
|
Text: "BREAK",
|
|
Filename: "test.c65",
|
|
LineNo: 1,
|
|
Kind: preproc.Source,
|
|
}
|
|
|
|
cmd, found := registry.FindHandler(line)
|
|
if !found {
|
|
t.Fatal("Expected to find BREAK handler")
|
|
}
|
|
|
|
if cmd != breakCmd {
|
|
t.Fatal("Expected to get same command instance")
|
|
}
|
|
}
|
|
|
|
func TestCompilerContext(t *testing.T) {
|
|
pragma := preproc.NewPragma()
|
|
ctx := NewCompilerContext(pragma)
|
|
|
|
// Test that all resources are initialized
|
|
if ctx.SymbolTable == nil {
|
|
t.Error("SymbolTable not initialized")
|
|
}
|
|
if ctx.FunctionHandler == nil {
|
|
t.Error("FunctionHandler not initialized")
|
|
}
|
|
if ctx.ConstStrHandler == nil {
|
|
t.Error("ConstStrHandler not initialized")
|
|
}
|
|
if ctx.WhileStack == nil {
|
|
t.Error("WhileStack not initialized")
|
|
}
|
|
if ctx.IfStack == nil {
|
|
t.Error("IfStack not initialized")
|
|
}
|
|
if ctx.GeneralStack == nil {
|
|
t.Error("GeneralStack not initialized")
|
|
}
|
|
if ctx.Pragma == nil {
|
|
t.Error("Pragma not initialized")
|
|
}
|
|
|
|
// Test CurrentScope
|
|
scope := ctx.CurrentScope()
|
|
if scope != nil {
|
|
t.Errorf("Expected nil scope in global context, got %v", scope)
|
|
}
|
|
}
|