416 lines
9.7 KiB
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)
|
|
}
|
|
})
|
|
}
|
|
}
|