c65gm/internal/commands/peek_test.go

416 lines
9.7 KiB
Go

package commands
import (
"strings"
"testing"
"c65gm/internal/compiler"
"c65gm/internal/preproc"
)
func TestPeekOldSyntax(t *testing.T) {
tests := []struct {
name string
line string
setupVars func(*compiler.SymbolTable)
wantAsm []string
}{
{
name: "peek constant address to byte",
line: "PEEK 1024 GIVING result",
setupVars: func(st *compiler.SymbolTable) {
st.AddVar("result", "", compiler.KindByte, 0)
},
wantAsm: []string{
"\tlda 1024",
"\tsta result",
},
},
{
name: "peek ZP pointer to byte",
line: "PEEK ptr GIVING result",
setupVars: func(st *compiler.SymbolTable) {
st.AddAbsolute("ptr", "", compiler.KindWord, 0x80)
st.AddVar("result", "", compiler.KindByte, 0)
},
wantAsm: []string{
"\tldy #0",
"\tlda (ptr),y",
"\tsta result",
},
},
{
name: "peek ZP pointer with offset to byte",
line: "PEEK ptr[5] GIVING result",
setupVars: func(st *compiler.SymbolTable) {
st.AddAbsolute("ptr", "", compiler.KindWord, 0x80)
st.AddVar("result", "", compiler.KindByte, 0)
},
wantAsm: []string{
"\tldy #5",
"\tlda (ptr),y",
"\tsta result",
},
},
{
name: "peek with -> separator",
line: "PEEK 2048 -> result",
setupVars: func(st *compiler.SymbolTable) {
st.AddVar("result", "", compiler.KindByte, 0)
},
wantAsm: []string{
"\tlda 2048",
"\tsta result",
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
pragma := preproc.NewPragma()
ctx := compiler.NewCompilerContext(pragma)
tt.setupVars(ctx.SymbolTable)
cmd := &PeekCommand{}
line := preproc.Line{
Text: tt.line,
Kind: preproc.Source,
PragmaSetIndex: pragma.GetCurrentPragmaSetIndex(),
}
if err := cmd.Interpret(line, ctx); err != nil {
t.Fatalf("Interpret() error = %v", err)
}
asm, err := cmd.Generate(ctx)
if err != nil {
t.Fatalf("Generate() error = %v", err)
}
if !equalAsm(asm, tt.wantAsm) {
t.Errorf("Generate() mismatch\ngot:\n%s\nwant:\n%s",
strings.Join(asm, "\n"),
strings.Join(tt.wantAsm, "\n"))
}
})
}
}
func TestPeekNewSyntax(t *testing.T) {
tests := []struct {
name string
line string
setupVars func(*compiler.SymbolTable)
wantAsm []string
}{
{
name: "new syntax constant address to byte",
line: "result = PEEK 1024",
setupVars: func(st *compiler.SymbolTable) {
st.AddVar("result", "", compiler.KindByte, 0)
},
wantAsm: []string{
"\tlda 1024",
"\tsta result",
},
},
{
name: "new syntax ZP pointer to byte",
line: "result = PEEK ptr",
setupVars: func(st *compiler.SymbolTable) {
st.AddAbsolute("ptr", "", compiler.KindWord, 0x80)
st.AddVar("result", "", compiler.KindByte, 0)
},
wantAsm: []string{
"\tldy #0",
"\tlda (ptr),y",
"\tsta result",
},
},
{
name: "new syntax ZP pointer with offset",
line: "result = PEEK ptr[10]",
setupVars: func(st *compiler.SymbolTable) {
st.AddAbsolute("ptr", "", compiler.KindWord, 0x80)
st.AddVar("result", "", compiler.KindByte, 0)
},
wantAsm: []string{
"\tldy #10",
"\tlda (ptr),y",
"\tsta result",
},
},
{
name: "new syntax ZP pointer with variable offset",
line: "result = PEEK ptr[idx]",
setupVars: func(st *compiler.SymbolTable) {
st.AddAbsolute("ptr", "", compiler.KindWord, 0x80)
st.AddVar("idx", "", compiler.KindByte, 0)
st.AddVar("result", "", compiler.KindByte, 0)
},
wantAsm: []string{
"\tldy idx",
"\tlda (ptr),y",
"\tsta result",
},
},
{
name: "new syntax to word destination",
line: "result = PEEK 2048",
setupVars: func(st *compiler.SymbolTable) {
st.AddVar("result", "", compiler.KindWord, 0)
},
wantAsm: []string{
"\tlda 2048",
"\tsta result",
"\tlda #0",
"\tsta result+1",
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
pragma := preproc.NewPragma()
ctx := compiler.NewCompilerContext(pragma)
tt.setupVars(ctx.SymbolTable)
cmd := &PeekCommand{}
line := preproc.Line{
Text: tt.line,
Kind: preproc.Source,
PragmaSetIndex: pragma.GetCurrentPragmaSetIndex(),
}
if err := cmd.Interpret(line, ctx); err != nil {
t.Fatalf("Interpret() error = %v", err)
}
asm, err := cmd.Generate(ctx)
if err != nil {
t.Fatalf("Generate() error = %v", err)
}
if !equalAsm(asm, tt.wantAsm) {
t.Errorf("Generate() mismatch\ngot:\n%s\nwant:\n%s",
strings.Join(asm, "\n"),
strings.Join(tt.wantAsm, "\n"))
}
})
}
}
func TestPeekWNewSyntax(t *testing.T) {
tests := []struct {
name string
line string
setupVars func(*compiler.SymbolTable)
wantAsm []string
}{
{
name: "new syntax constant address",
line: "result = PEEKW 1024",
setupVars: func(st *compiler.SymbolTable) {
st.AddVar("result", "", compiler.KindWord, 0)
},
wantAsm: []string{
"\tlda 1024",
"\tsta result",
"\tlda 1025",
"\tsta result+1",
},
},
{
name: "new syntax ZP pointer",
line: "result = PEEKW ptr",
setupVars: func(st *compiler.SymbolTable) {
st.AddAbsolute("ptr", "", compiler.KindWord, 0x80)
st.AddVar("result", "", compiler.KindWord, 0)
},
wantAsm: []string{
"\tldy #0",
"\tlda (ptr),y",
"\tsta result",
"\tiny",
"\tlda (ptr),y",
"\tsta result+1",
},
},
{
name: "new syntax ZP pointer with offset",
line: "result = PEEKW ptr[8]",
setupVars: func(st *compiler.SymbolTable) {
st.AddAbsolute("ptr", "", compiler.KindWord, 0x80)
st.AddVar("result", "", compiler.KindWord, 0)
},
wantAsm: []string{
"\tldy #8",
"\tlda (ptr),y",
"\tsta result",
"\tiny",
"\tlda (ptr),y",
"\tsta result+1",
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
pragma := preproc.NewPragma()
ctx := compiler.NewCompilerContext(pragma)
tt.setupVars(ctx.SymbolTable)
cmd := &PeekWCommand{}
line := preproc.Line{
Text: tt.line,
Kind: preproc.Source,
PragmaSetIndex: pragma.GetCurrentPragmaSetIndex(),
}
if err := cmd.Interpret(line, ctx); err != nil {
t.Fatalf("Interpret() error = %v", err)
}
asm, err := cmd.Generate(ctx)
if err != nil {
t.Fatalf("Generate() error = %v", err)
}
if !equalAsm(asm, tt.wantAsm) {
t.Errorf("Generate() mismatch\ngot:\n%s\nwant:\n%s",
strings.Join(asm, "\n"),
strings.Join(tt.wantAsm, "\n"))
}
})
}
}
func TestPeekErrors(t *testing.T) {
tests := []struct {
name string
line string
setupVars func(*compiler.SymbolTable)
wantError string
}{
{
name: "unknown destination",
line: "PEEK 1024 GIVING unknown",
setupVars: func(st *compiler.SymbolTable) {
},
wantError: "unknown destination variable",
},
{
name: "constant destination",
line: "PEEK 1024 GIVING CONST",
setupVars: func(st *compiler.SymbolTable) {
st.AddConst("CONST", "", compiler.KindByte, 100)
},
wantError: "cannot PEEK into constant",
},
{
name: "new syntax unknown destination",
line: "unknown = PEEK 1024",
setupVars: func(st *compiler.SymbolTable) {
},
wantError: "unknown destination variable",
},
{
name: "new syntax constant destination",
line: "CONST = PEEK 1024",
setupVars: func(st *compiler.SymbolTable) {
st.AddConst("CONST", "", compiler.KindByte, 100)
},
wantError: "cannot PEEK into constant",
},
{
name: "offset without ZP pointer old syntax",
line: "PEEK addr[5] GIVING result",
setupVars: func(st *compiler.SymbolTable) {
st.AddVar("addr", "", compiler.KindWord, 0)
st.AddVar("result", "", compiler.KindByte, 0)
},
wantError: "offset",
},
{
name: "offset without ZP pointer new syntax",
line: "result = PEEK addr[5]",
setupVars: func(st *compiler.SymbolTable) {
st.AddVar("addr", "", compiler.KindWord, 0)
st.AddVar("result", "", compiler.KindByte, 0)
},
wantError: "offset",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
pragma := preproc.NewPragma()
ctx := compiler.NewCompilerContext(pragma)
tt.setupVars(ctx.SymbolTable)
cmd := &PeekCommand{}
line := preproc.Line{
Text: tt.line,
Kind: preproc.Source,
PragmaSetIndex: pragma.GetCurrentPragmaSetIndex(),
}
err := cmd.Interpret(line, ctx)
if err == nil {
t.Fatal("Expected error but got none")
}
if !strings.Contains(err.Error(), tt.wantError) {
t.Errorf("Error message mismatch\ngot: %v\nwant substring: %s", err, tt.wantError)
}
})
}
}
func TestPeekWErrors(t *testing.T) {
tests := []struct {
name string
line string
setupVars func(*compiler.SymbolTable)
wantError string
}{
{
name: "byte destination",
line: "PEEKW 1024 GIVING result",
setupVars: func(st *compiler.SymbolTable) {
st.AddVar("result", "", compiler.KindByte, 0)
},
wantError: "must be word type",
},
{
name: "new syntax byte destination",
line: "result = PEEKW 1024",
setupVars: func(st *compiler.SymbolTable) {
st.AddVar("result", "", compiler.KindByte, 0)
},
wantError: "must be word type",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
pragma := preproc.NewPragma()
ctx := compiler.NewCompilerContext(pragma)
tt.setupVars(ctx.SymbolTable)
cmd := &PeekWCommand{}
line := preproc.Line{
Text: tt.line,
Kind: preproc.Source,
PragmaSetIndex: pragma.GetCurrentPragmaSetIndex(),
}
err := cmd.Interpret(line, ctx)
if err == nil {
t.Fatal("Expected error but got none")
}
if !strings.Contains(err.Error(), tt.wantError) {
t.Errorf("Error message mismatch\ngot: %v\nwant substring: %s", err, tt.wantError)
}
})
}
}