688 lines
17 KiB
Go
688 lines
17 KiB
Go
package compiler
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
|
|
"c65gm/internal/preproc"
|
|
)
|
|
|
|
// Helper to create a test Line
|
|
func makeLine(text string) preproc.Line {
|
|
return preproc.Line{
|
|
RawText: text,
|
|
Text: text,
|
|
Filename: "test.c65",
|
|
LineNo: 1,
|
|
Kind: preproc.Source,
|
|
PragmaSetIndex: 0,
|
|
}
|
|
}
|
|
|
|
func TestFixIntuitiveFuncs(t *testing.T) {
|
|
tests := []struct {
|
|
input string
|
|
expected string
|
|
}{
|
|
{"func(a,b)", "func ( a b )"},
|
|
{"func( a, b )", "func ( a b )"},
|
|
{"func(a,b,c)", "func ( a b c )"},
|
|
{"CALL func()", "CALL func ( )"},
|
|
{"func()", "func ( )"},
|
|
{`func("hello",x)`, `func ( "hello" x )`},
|
|
{`func("a,b",c)`, `func ( "a,b" c )`},
|
|
{"func ( a , b )", "func ( a b )"},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
result := fixIntuitiveFuncs(tt.input)
|
|
if result != tt.expected {
|
|
t.Errorf("fixIntuitiveFuncs(%q) = %q, want %q", tt.input, result, tt.expected)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestBuildComplexParams(t *testing.T) {
|
|
tests := []struct {
|
|
input []string
|
|
expected []string
|
|
wantErr bool
|
|
}{
|
|
{
|
|
input: []string{"a", "b", "c"},
|
|
expected: []string{"a", "b", "c"},
|
|
wantErr: false,
|
|
},
|
|
{
|
|
input: []string{"{BYTE", "x}"},
|
|
expected: []string{"{BYTE x}"},
|
|
wantErr: false,
|
|
},
|
|
{
|
|
input: []string{"{WORD", "ptr}"},
|
|
expected: []string{"{WORD ptr}"},
|
|
wantErr: false,
|
|
},
|
|
{
|
|
input: []string{"{BYTE", "a}", "{WORD", "b}"},
|
|
expected: []string{"{BYTE a}", "{WORD b}"},
|
|
wantErr: false,
|
|
},
|
|
{
|
|
input: []string{"x", "{BYTE", "a}", "y"},
|
|
expected: []string{"x", "{BYTE a}", "y"},
|
|
wantErr: false,
|
|
},
|
|
{
|
|
input: []string{"{BYTE", "x"},
|
|
expected: nil,
|
|
wantErr: true, // unclosed
|
|
},
|
|
{
|
|
input: []string{"x}"},
|
|
expected: nil,
|
|
wantErr: true, // unmatched close
|
|
},
|
|
{
|
|
input: []string{"{BYTE", "{WORD", "x}"},
|
|
expected: nil,
|
|
wantErr: true, // nested open
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
result, err := buildComplexParams(tt.input)
|
|
if tt.wantErr {
|
|
if err == nil {
|
|
t.Errorf("buildComplexParams(%v) expected error, got nil", tt.input)
|
|
}
|
|
continue
|
|
}
|
|
if err != nil {
|
|
t.Errorf("buildComplexParams(%v) unexpected error: %v", tt.input, err)
|
|
continue
|
|
}
|
|
if len(result) != len(tt.expected) {
|
|
t.Errorf("buildComplexParams(%v) = %v, want %v", tt.input, result, tt.expected)
|
|
continue
|
|
}
|
|
for i := range result {
|
|
if result[i] != tt.expected[i] {
|
|
t.Errorf("buildComplexParams(%v)[%d] = %q, want %q", tt.input, i, result[i], tt.expected[i])
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestParseParams(t *testing.T) {
|
|
tests := []struct {
|
|
input string
|
|
expected []string
|
|
wantErr bool
|
|
}{
|
|
{"FUNC test", []string{"FUNC", "test"}, false},
|
|
{"FUNC test ( a b )", []string{"FUNC", "test", "(", "a", "b", ")"}, false},
|
|
{`CALL print ( "hello world" )`, []string{"CALL", "print", "(", `"hello world"`, ")"}, false},
|
|
{" FUNC test ", []string{"FUNC", "test"}, false},
|
|
{`func("unterminated`, nil, true},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
result, err := parseParams(tt.input)
|
|
if tt.wantErr {
|
|
if err == nil {
|
|
t.Errorf("parseParams(%q) expected error, got nil", tt.input)
|
|
}
|
|
continue
|
|
}
|
|
if err != nil {
|
|
t.Errorf("parseParams(%q) unexpected error: %v", tt.input, err)
|
|
continue
|
|
}
|
|
if len(result) != len(tt.expected) {
|
|
t.Errorf("parseParams(%q) = %v, want %v", tt.input, result, tt.expected)
|
|
continue
|
|
}
|
|
for i := range result {
|
|
if result[i] != tt.expected[i] {
|
|
t.Errorf("parseParams(%q)[%d] = %q, want %q", tt.input, i, result[i], tt.expected[i])
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestParseParamSpec(t *testing.T) {
|
|
tests := []struct {
|
|
input string
|
|
wantDir ParamDirection
|
|
wantName string
|
|
wantImplicit bool
|
|
wantImplDecl string
|
|
wantErr bool
|
|
}{
|
|
{"varname", DirIn, "varname", false, "", false},
|
|
{"in:varname", DirIn, "varname", false, "", false},
|
|
{"out:varname", DirOut, "varname", false, "", false},
|
|
{"io:varname", DirIn | DirOut, "varname", false, "", false},
|
|
{"{BYTE temp}", DirIn, "temp", true, "BYTE temp", false},
|
|
{"{WORD result}", DirIn, "result", true, "WORD result", false},
|
|
{"out:{BYTE x}", DirOut, "x", true, "BYTE x", false},
|
|
{"io:{WORD ptr}", DirIn | DirOut, "ptr", true, "WORD ptr", false},
|
|
{"invalid:dir:x", 0, "", false, "", true},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
dir, name, isImpl, implDecl, err := parseParamSpec(tt.input)
|
|
if tt.wantErr {
|
|
if err == nil {
|
|
t.Errorf("parseParamSpec(%q) expected error, got nil", tt.input)
|
|
}
|
|
continue
|
|
}
|
|
if err != nil {
|
|
t.Errorf("parseParamSpec(%q) unexpected error: %v", tt.input, err)
|
|
continue
|
|
}
|
|
if dir != tt.wantDir {
|
|
t.Errorf("parseParamSpec(%q) direction = %v, want %v", tt.input, dir, tt.wantDir)
|
|
}
|
|
if name != tt.wantName {
|
|
t.Errorf("parseParamSpec(%q) name = %q, want %q", tt.input, name, tt.wantName)
|
|
}
|
|
if isImpl != tt.wantImplicit {
|
|
t.Errorf("parseParamSpec(%q) implicit = %v, want %v", tt.input, isImpl, tt.wantImplicit)
|
|
}
|
|
if implDecl != tt.wantImplDecl {
|
|
t.Errorf("parseParamSpec(%q) implDecl = %q, want %q", tt.input, implDecl, tt.wantImplDecl)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestHandleFuncDecl_VoidFunction(t *testing.T) {
|
|
st := NewSymbolTable()
|
|
ls := NewLabelStack("L")
|
|
csh := NewConstantStringHandler()
|
|
pragma := preproc.NewPragma()
|
|
fh := NewFunctionHandler(st, ls, csh, pragma)
|
|
|
|
asm, err := fh.HandleFuncDecl(makeLine("FUNC test_void"))
|
|
if err != nil {
|
|
t.Fatalf("HandleFuncDecl failed: %v", err)
|
|
}
|
|
|
|
if len(asm) != 1 {
|
|
t.Fatalf("expected 1 asm line, got %d", len(asm))
|
|
}
|
|
if asm[0] != "test_void" {
|
|
t.Errorf("expected label 'test_void', got %q", asm[0])
|
|
}
|
|
|
|
if !fh.FuncExists("test_void") {
|
|
t.Error("function should exist")
|
|
}
|
|
}
|
|
|
|
func TestHandleFuncDecl_WithExistingParams(t *testing.T) {
|
|
st := NewSymbolTable()
|
|
ls := NewLabelStack("L")
|
|
csh := NewConstantStringHandler()
|
|
pragma := preproc.NewPragma()
|
|
fh := NewFunctionHandler(st, ls, csh, pragma)
|
|
|
|
// Pre-declare parameters
|
|
st.AddVar("x", "test_func", KindByte, 0)
|
|
st.AddVar("y", "test_func", KindWord, 0)
|
|
|
|
asm, err := fh.HandleFuncDecl(makeLine("FUNC test_func ( x y )"))
|
|
if err != nil {
|
|
t.Fatalf("HandleFuncDecl failed: %v", err)
|
|
}
|
|
|
|
if len(asm) != 1 {
|
|
t.Fatalf("expected 1 asm line, got %d", len(asm))
|
|
}
|
|
|
|
funcDecl := fh.findFunc("test_func")
|
|
if funcDecl == nil {
|
|
t.Fatal("function not found")
|
|
}
|
|
if len(funcDecl.Params) != 2 {
|
|
t.Fatalf("expected 2 params, got %d", len(funcDecl.Params))
|
|
}
|
|
}
|
|
|
|
func TestHandleFuncDecl_ImplicitDeclarations(t *testing.T) {
|
|
st := NewSymbolTable()
|
|
ls := NewLabelStack("L")
|
|
csh := NewConstantStringHandler()
|
|
pragma := preproc.NewPragma()
|
|
fh := NewFunctionHandler(st, ls, csh, pragma)
|
|
|
|
asm, err := fh.HandleFuncDecl(makeLine("FUNC test_impl ( {BYTE a} {WORD b} )"))
|
|
if err != nil {
|
|
t.Fatalf("HandleFuncDecl failed: %v", err)
|
|
}
|
|
|
|
if len(asm) != 1 {
|
|
t.Fatalf("expected 1 asm line, got %d", len(asm))
|
|
}
|
|
|
|
// Check that variables were declared
|
|
symA := st.Lookup("a", []string{"test_impl"})
|
|
if symA == nil {
|
|
t.Fatal("parameter 'a' not declared")
|
|
}
|
|
if !symA.IsByte() {
|
|
t.Error("parameter 'a' should be byte")
|
|
}
|
|
|
|
symB := st.Lookup("b", []string{"test_impl"})
|
|
if symB == nil {
|
|
t.Fatal("parameter 'b' not declared")
|
|
}
|
|
if !symB.IsWord() {
|
|
t.Error("parameter 'b' should be word")
|
|
}
|
|
}
|
|
|
|
func TestHandleFuncDecl_WithDirections(t *testing.T) {
|
|
st := NewSymbolTable()
|
|
ls := NewLabelStack("L")
|
|
csh := NewConstantStringHandler()
|
|
pragma := preproc.NewPragma()
|
|
fh := NewFunctionHandler(st, ls, csh, pragma)
|
|
|
|
_, err := fh.HandleFuncDecl(makeLine("FUNC test_dir ( in:{BYTE a} out:{BYTE b} io:{WORD c} )"))
|
|
if err != nil {
|
|
t.Fatalf("HandleFuncDecl failed: %v", err)
|
|
}
|
|
|
|
funcDecl := fh.findFunc("test_dir")
|
|
if funcDecl == nil {
|
|
t.Fatal("function not found")
|
|
}
|
|
|
|
if len(funcDecl.Params) != 3 {
|
|
t.Fatalf("expected 3 params, got %d", len(funcDecl.Params))
|
|
}
|
|
|
|
if funcDecl.Params[0].Direction != DirIn {
|
|
t.Error("param 0 should be DirIn")
|
|
}
|
|
if funcDecl.Params[1].Direction != DirOut {
|
|
t.Error("param 1 should be DirOut")
|
|
}
|
|
if funcDecl.Params[2].Direction != (DirIn | DirOut) {
|
|
t.Error("param 2 should be DirIn|DirOut")
|
|
}
|
|
}
|
|
|
|
func TestHandleFuncDecl_Errors(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
line string
|
|
preDecl func(*SymbolTable)
|
|
wantErr string
|
|
}{
|
|
{
|
|
name: "redeclaration",
|
|
line: "FUNC duplicate ( {BYTE x} )",
|
|
preDecl: func(st *SymbolTable) {},
|
|
wantErr: "already declared",
|
|
},
|
|
{
|
|
name: "missing param",
|
|
line: "FUNC test ( missing )",
|
|
wantErr: "not declared",
|
|
},
|
|
{
|
|
name: "const param",
|
|
line: "FUNC test ( constval )",
|
|
preDecl: func(st *SymbolTable) {
|
|
st.AddConst("constval", "test", KindByte, 42)
|
|
},
|
|
wantErr: "cannot be a constant",
|
|
},
|
|
{
|
|
name: "invalid implicit",
|
|
line: "FUNC test ( {INVALID x} )",
|
|
wantErr: "must be BYTE or WORD",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
st := NewSymbolTable()
|
|
ls := NewLabelStack("L")
|
|
csh := NewConstantStringHandler()
|
|
pragma := preproc.NewPragma()
|
|
fh := NewFunctionHandler(st, ls, csh, pragma)
|
|
|
|
if tt.preDecl != nil {
|
|
tt.preDecl(st)
|
|
}
|
|
|
|
// Special case for redeclaration test
|
|
if tt.name == "redeclaration" {
|
|
fh.HandleFuncDecl(makeLine("FUNC duplicate ( {BYTE x} )"))
|
|
}
|
|
|
|
_, err := fh.HandleFuncDecl(makeLine(tt.line))
|
|
if err == nil {
|
|
t.Fatal("expected error, got nil")
|
|
}
|
|
if !strings.Contains(err.Error(), tt.wantErr) {
|
|
t.Errorf("error %q does not contain %q", err.Error(), tt.wantErr)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestHandleFuncCall_VarArgs(t *testing.T) {
|
|
st := NewSymbolTable()
|
|
ls := NewLabelStack("L")
|
|
csh := NewConstantStringHandler()
|
|
pragma := preproc.NewPragma()
|
|
fh := NewFunctionHandler(st, ls, csh, pragma)
|
|
|
|
// Declare function with params
|
|
st.AddVar("param_a", "test_func", KindByte, 0)
|
|
st.AddVar("param_b", "test_func", KindWord, 0)
|
|
fh.HandleFuncDecl(makeLine("FUNC test_func ( param_a param_b )"))
|
|
|
|
// Declare caller variables
|
|
st.AddVar("var_a", "", KindByte, 0)
|
|
st.AddVar("var_b", "", KindWord, 0)
|
|
|
|
asm, err := fh.HandleFuncCall(makeLine("CALL test_func ( var_a var_b )"))
|
|
if err != nil {
|
|
t.Fatalf("HandleFuncCall failed: %v", err)
|
|
}
|
|
|
|
// Check generated assembly
|
|
expectedLines := []string{
|
|
" lda var_a",
|
|
" sta test_func_param_a",
|
|
" lda var_b",
|
|
" sta test_func_param_b",
|
|
" lda var_b+1",
|
|
" sta test_func_param_b+1",
|
|
" jsr test_func",
|
|
}
|
|
|
|
if len(asm) != len(expectedLines) {
|
|
t.Fatalf("expected %d asm lines, got %d", len(expectedLines), len(asm))
|
|
}
|
|
|
|
for i, expected := range expectedLines {
|
|
if asm[i] != expected {
|
|
t.Errorf("asm[%d] = %q, want %q", i, asm[i], expected)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestHandleFuncCall_OutParams(t *testing.T) {
|
|
st := NewSymbolTable()
|
|
ls := NewLabelStack("L")
|
|
csh := NewConstantStringHandler()
|
|
pragma := preproc.NewPragma()
|
|
fh := NewFunctionHandler(st, ls, csh, pragma)
|
|
|
|
// Declare function with out param
|
|
st.AddVar("result", "get_result", KindByte, 0)
|
|
fh.HandleFuncDecl(makeLine("FUNC get_result ( out:result )"))
|
|
|
|
// Declare caller variable
|
|
st.AddVar("output", "", KindByte, 0)
|
|
|
|
asm, err := fh.HandleFuncCall(makeLine("CALL get_result ( output )"))
|
|
if err != nil {
|
|
t.Fatalf("HandleFuncCall failed: %v", err)
|
|
}
|
|
|
|
// Should have JSR and OUT assignment
|
|
found_jsr := false
|
|
found_out := false
|
|
for _, line := range asm {
|
|
if strings.Contains(line, "jsr get_result") {
|
|
found_jsr = true
|
|
}
|
|
if strings.Contains(line, "lda get_result_result") {
|
|
found_out = true
|
|
}
|
|
}
|
|
|
|
if !found_jsr {
|
|
t.Error("missing jsr instruction")
|
|
}
|
|
if !found_out {
|
|
t.Error("missing out assignment")
|
|
}
|
|
}
|
|
|
|
func TestHandleFuncCall_ConstArgs(t *testing.T) {
|
|
st := NewSymbolTable()
|
|
ls := NewLabelStack("L")
|
|
csh := NewConstantStringHandler()
|
|
pragma := preproc.NewPragma()
|
|
fh := NewFunctionHandler(st, ls, csh, pragma)
|
|
|
|
// Declare function
|
|
st.AddVar("x", "test_const", KindByte, 0)
|
|
st.AddVar("y", "test_const", KindWord, 0)
|
|
fh.HandleFuncDecl(makeLine("FUNC test_const ( x y )"))
|
|
|
|
asm, err := fh.HandleFuncCall(makeLine("CALL test_const ( 42 $1234 )"))
|
|
if err != nil {
|
|
t.Fatalf("HandleFuncCall failed: %v", err)
|
|
}
|
|
|
|
// Check for immediate loads
|
|
foundByte := false
|
|
foundWord := false
|
|
for _, line := range asm {
|
|
if strings.Contains(line, "lda #42") {
|
|
foundByte = true
|
|
}
|
|
if strings.Contains(line, "lda #18") { // 0x12
|
|
foundWord = true
|
|
}
|
|
}
|
|
|
|
if !foundByte {
|
|
t.Error("missing byte constant load")
|
|
}
|
|
if !foundWord {
|
|
t.Error("missing word constant load")
|
|
}
|
|
}
|
|
|
|
func TestHandleFuncCall_LabelArg(t *testing.T) {
|
|
st := NewSymbolTable()
|
|
ls := NewLabelStack("L")
|
|
csh := NewConstantStringHandler()
|
|
pragma := preproc.NewPragma()
|
|
fh := NewFunctionHandler(st, ls, csh, pragma)
|
|
|
|
// Declare function
|
|
st.AddVar("ptr", "test_label", KindWord, 0)
|
|
fh.HandleFuncDecl(makeLine("FUNC test_label ( ptr )"))
|
|
|
|
asm, err := fh.HandleFuncCall(makeLine("CALL test_label ( @my_label )"))
|
|
if err != nil {
|
|
t.Fatalf("HandleFuncCall failed: %v", err)
|
|
}
|
|
|
|
// Check for label reference
|
|
foundLow := false
|
|
foundHigh := false
|
|
for _, line := range asm {
|
|
if strings.Contains(line, "#<my_label") {
|
|
foundLow = true
|
|
}
|
|
if strings.Contains(line, "#>my_label") {
|
|
foundHigh = true
|
|
}
|
|
}
|
|
|
|
if !foundLow || !foundHigh {
|
|
t.Error("missing label reference code")
|
|
}
|
|
}
|
|
|
|
func TestHandleFuncCall_StringArg(t *testing.T) {
|
|
st := NewSymbolTable()
|
|
ls := NewLabelStack("L")
|
|
csh := NewConstantStringHandler()
|
|
pragma := preproc.NewPragma()
|
|
fh := NewFunctionHandler(st, ls, csh, pragma)
|
|
|
|
// Declare function
|
|
st.AddVar("str_ptr", "print", KindWord, 0)
|
|
fh.HandleFuncDecl(makeLine("FUNC print ( str_ptr )"))
|
|
|
|
asm, err := fh.HandleFuncCall(makeLine(`CALL print ( "hello" )`))
|
|
if err != nil {
|
|
t.Fatalf("HandleFuncCall failed: %v", err)
|
|
}
|
|
|
|
// Check that label was generated
|
|
if ls.Size() != 1 {
|
|
t.Errorf("expected 1 label generated, got %d", ls.Size())
|
|
}
|
|
|
|
// Check for label reference in asm
|
|
foundLabel := false
|
|
for _, line := range asm {
|
|
if strings.Contains(line, "#<L1") || strings.Contains(line, "#>L1") {
|
|
foundLabel = true
|
|
break
|
|
}
|
|
}
|
|
|
|
if !foundLabel {
|
|
t.Error("missing string label reference")
|
|
}
|
|
}
|
|
|
|
func TestHandleFuncCall_Errors(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
setup func(*FunctionHandler, *SymbolTable)
|
|
line string
|
|
wantErr string
|
|
}{
|
|
{
|
|
name: "function not declared",
|
|
setup: func(fh *FunctionHandler, st *SymbolTable) {},
|
|
line: "CALL undefined ( )",
|
|
wantErr: "not declared",
|
|
},
|
|
{
|
|
name: "wrong arg count",
|
|
setup: func(fh *FunctionHandler, st *SymbolTable) {
|
|
st.AddVar("x", "test", KindByte, 0)
|
|
fh.HandleFuncDecl(makeLine("FUNC test ( x )"))
|
|
},
|
|
line: "CALL test ( 1 2 )",
|
|
wantErr: "expected 1 arguments, got 2",
|
|
},
|
|
{
|
|
name: "type mismatch",
|
|
setup: func(fh *FunctionHandler, st *SymbolTable) {
|
|
st.AddVar("param", "test", KindByte, 0)
|
|
fh.HandleFuncDecl(makeLine("FUNC test ( param )"))
|
|
st.AddVar("wvar", "", KindWord, 0)
|
|
},
|
|
line: "CALL test ( wvar )",
|
|
wantErr: "type mismatch",
|
|
},
|
|
{
|
|
name: "const to out param",
|
|
setup: func(fh *FunctionHandler, st *SymbolTable) {
|
|
st.AddVar("result", "test", KindByte, 0)
|
|
fh.HandleFuncDecl(makeLine("FUNC test ( out:result )"))
|
|
},
|
|
line: "CALL test ( 42 )",
|
|
wantErr: "out/io parameter",
|
|
},
|
|
{
|
|
name: "label to byte param",
|
|
setup: func(fh *FunctionHandler, st *SymbolTable) {
|
|
st.AddVar("x", "test", KindByte, 0)
|
|
fh.HandleFuncDecl(makeLine("FUNC test ( x )"))
|
|
},
|
|
line: "CALL test ( @label )",
|
|
wantErr: "byte parameter",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
st := NewSymbolTable()
|
|
ls := NewLabelStack("L")
|
|
csh := NewConstantStringHandler()
|
|
pragma := preproc.NewPragma()
|
|
fh := NewFunctionHandler(st, ls, csh, pragma)
|
|
|
|
tt.setup(fh, st)
|
|
|
|
_, err := fh.HandleFuncCall(makeLine(tt.line))
|
|
if err == nil {
|
|
t.Fatal("expected error, got nil")
|
|
}
|
|
if !strings.Contains(err.Error(), tt.wantErr) {
|
|
t.Errorf("error %q does not contain %q", err.Error(), tt.wantErr)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestEndFunction(t *testing.T) {
|
|
st := NewSymbolTable()
|
|
ls := NewLabelStack("L")
|
|
csh := NewConstantStringHandler()
|
|
pragma := preproc.NewPragma()
|
|
fh := NewFunctionHandler(st, ls, csh, pragma)
|
|
|
|
// Declare function (pushes to stack)
|
|
fh.HandleFuncDecl(makeLine("FUNC test ( {BYTE x} )"))
|
|
|
|
if fh.CurrentFunction() != "test" {
|
|
t.Errorf("current function = %q, want 'test'", fh.CurrentFunction())
|
|
}
|
|
|
|
// End function
|
|
fh.EndFunction()
|
|
|
|
if fh.CurrentFunction() != "" {
|
|
t.Errorf("current function = %q, want ''", fh.CurrentFunction())
|
|
}
|
|
}
|
|
|
|
func TestCurrentFunction(t *testing.T) {
|
|
st := NewSymbolTable()
|
|
ls := NewLabelStack("L")
|
|
csh := NewConstantStringHandler()
|
|
pragma := preproc.NewPragma()
|
|
fh := NewFunctionHandler(st, ls, csh, pragma)
|
|
|
|
if fh.CurrentFunction() != "" {
|
|
t.Error("expected empty current function initially")
|
|
}
|
|
|
|
fh.HandleFuncDecl(makeLine("FUNC func1 ( {BYTE x} )"))
|
|
if fh.CurrentFunction() != "func1" {
|
|
t.Errorf("expected 'func1', got %q", fh.CurrentFunction())
|
|
}
|
|
|
|
fh.HandleFuncDecl(makeLine("FUNC func2 ( {BYTE y} )"))
|
|
if fh.CurrentFunction() != "func2" {
|
|
t.Errorf("expected 'func2', got %q", fh.CurrentFunction())
|
|
}
|
|
|
|
fh.EndFunction()
|
|
if fh.CurrentFunction() != "" {
|
|
t.Errorf("expected '', got %q", fh.CurrentFunction())
|
|
}
|
|
}
|