Merge pull request 'unused_variable_warnings' (#3) from unused_variable_warnings into main
Reviewed-on: #3
This commit is contained in:
commit
90caee5439
51 changed files with 1304 additions and 770 deletions
5
.gitignore
vendored
5
.gitignore
vendored
|
|
@ -33,3 +33,8 @@ c65gm
|
|||
*.sym
|
||||
*.prg
|
||||
*.s
|
||||
|
||||
.cache/
|
||||
.env
|
||||
.local/
|
||||
opencode-config/package-lock.json
|
||||
|
|
|
|||
167
AGENTS.md
Normal file
167
AGENTS.md
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
# c65gm Agent Instructions
|
||||
|
||||
## Project Overview
|
||||
c65gm is a high-level 6502 cross-compiler targeting the ACME Cross-Assembler for Commodore 64 and similar 6502-based platforms. It provides a more expressive language for writing 6502 assembly programs with modern programming constructs.
|
||||
|
||||
## Key Documentation Locations
|
||||
|
||||
### Primary Documentation
|
||||
1. **README.md** - Project overview, building, usage, and requirements
|
||||
2. **language.md** - Complete language reference with examples (1091 lines)
|
||||
3. **syntax.md** - Syntax rules and preprocessor directives (646 lines)
|
||||
4. **commands.md** - Complete command reference (776 lines)
|
||||
|
||||
### Code Structure
|
||||
- **main.go** - Entry point and command-line interface
|
||||
- **internal/compiler/** - Core compiler implementation
|
||||
- **internal/preproc/** - Preprocessor implementation
|
||||
- **internal/commands/** - Individual command implementations
|
||||
- **internal/utils/** - Utility functions
|
||||
- **lib/** - Standard library files for C64 development
|
||||
- **examples/** - Example programs demonstrating language features
|
||||
|
||||
### Standard Library (lib/)
|
||||
- **c64start.c65** - Required for C64 executables (BASIC loader setup)
|
||||
- **c64defs.c65** - C64 hardware definitions (colors, addresses, etc.)
|
||||
- **c64kernal.c65** - Kernal routine wrappers
|
||||
- **c64scr.c65** - Screen manipulation functions
|
||||
- **string.c65** - String handling functions
|
||||
- **memlib.c65** - Memory management functions
|
||||
- **fat16/** - FAT16 filesystem support
|
||||
- **koalalib.c65** - Koala graphics support
|
||||
|
||||
## Language Features to Note
|
||||
|
||||
### Key Concepts
|
||||
1. **Type system**: BYTE (8-bit) and WORD (16-bit) variables with scope resolution
|
||||
2. **Functions**: Named functions with parameters and call graph analysis
|
||||
3. **Control flow**: IF/ENDIF, WHILE/WEND, FOR loops, SWITCH/CASE
|
||||
4. **Memory operations**: PEEK/POKE/PEEKW/POKEW with zero-page optimization
|
||||
5. **Preprocessor**: File inclusion, macros, conditional compilation, Starlark scripting
|
||||
6. **Optimizations**: Constant folding, self-assignment detection
|
||||
7. **Safety features**: Compile-time detection of overlapping absolute addresses
|
||||
|
||||
### Important Syntax Rules
|
||||
1. **No operator precedence**: Expressions evaluate strictly left-to-right
|
||||
2. **Memory-mapped variables**: Use `@` to place variables at specific addresses
|
||||
3. **Constants**: Prefer `BYTE CONST`/`WORD CONST` over `#DEFINE`
|
||||
4. **Zero-page optimization**: Place frequently accessed pointers in zero page ($00-$FF)
|
||||
5. **Include guards**: Always use `#IFNDEF` in library files
|
||||
|
||||
### Special Blocks
|
||||
1. **ASM blocks**: Inline assembly code
|
||||
2. **SCRIPT blocks**: Starlark code for compile-time code generation
|
||||
3. **SCRIPT LIBRARY blocks**: Reusable Starlark functions
|
||||
4. **SCRIPT MACRO blocks**: Parameterized macros for inline expansion
|
||||
|
||||
## Common Patterns
|
||||
|
||||
### Program Structure
|
||||
```c65
|
||||
#INCLUDE <c64start.c65>
|
||||
#INCLUDE <c64defs.c65>
|
||||
|
||||
GOTO start // Jump over function definitions
|
||||
|
||||
// Variables and functions here
|
||||
|
||||
LABEL start // Program entry point
|
||||
main()
|
||||
```
|
||||
|
||||
### Library Structure
|
||||
```c65
|
||||
#IFNDEF __MY_LIBRARY
|
||||
#DEFINE __MY_LIBRARY = 1
|
||||
|
||||
GOTO lib_mylib_skip
|
||||
|
||||
// Library code here
|
||||
|
||||
LABEL lib_mylib_skip
|
||||
#IFEND
|
||||
```
|
||||
|
||||
### Memory Operations
|
||||
- Use `PEEK`/`POKE` for byte access
|
||||
- Use `PEEKW`/`POKEW` for word (16-bit) access
|
||||
- For indexed access, address must be a WORD variable in zero page
|
||||
|
||||
## Development Guidelines
|
||||
|
||||
### Environment Constraints
|
||||
**IMPORTANT**: The agent runs in a Docker container without access to compilers, testing tools, or external build systems. All compilation and testing must be performed by the user. The agent can only:
|
||||
1. Read and analyze source code
|
||||
2. Make code changes
|
||||
3. Provide instructions for the user to compile and test
|
||||
|
||||
### File Access Restrictions
|
||||
**CRITICAL**: The agent must only access normal project files within the current working directory. The agent must NEVER:
|
||||
1. Look at files outside the project directory (e.g., `/tmp/`, `/etc/`, `/home/`, etc.)
|
||||
2. Read or attempt to access system files, environment files (`.env`), or configuration files outside the project
|
||||
3. Search for or read files containing secrets, credentials, or sensitive information
|
||||
4. Attempt to access files in parent directories or unrelated paths
|
||||
|
||||
All file operations must be restricted to the project's source code and documentation files only.
|
||||
|
||||
### When Modifying the Compiler
|
||||
1. Check `internal/commands/` for command implementations
|
||||
2. Check `internal/compiler/` for core compiler logic
|
||||
3. Check `internal/preproc/` for preprocessor functionality
|
||||
4. **DO NOT run tests** - provide instructions for the user to run tests
|
||||
|
||||
### When Adding New Features
|
||||
1. Follow existing patterns in command implementations
|
||||
2. Add comprehensive tests
|
||||
3. Update documentation in appropriate .md files
|
||||
4. Consider adding examples in `examples/` directory
|
||||
|
||||
### Testing
|
||||
**IMPORTANT**: The agent cannot run tests. Provide these instructions to the user:
|
||||
- Run all tests: `go test ./...`
|
||||
- Run specific package tests: `go test ./internal/compiler`
|
||||
- Test with verbose output: `go test -v ./...`
|
||||
|
||||
## Common Pitfalls
|
||||
|
||||
1. **Expression evaluation**: Remember no operator precedence
|
||||
2. **Zero-page requirements**: Indexed memory operations require zero-page addresses
|
||||
3. **Include guards**: Essential for library files to prevent multiple inclusion
|
||||
4. **Program structure**: Always use `GOTO start` to jump over function definitions
|
||||
5. **String handling**: Strings are passed as pointers to WORD parameters
|
||||
|
||||
## Quick Reference
|
||||
|
||||
### Compilation
|
||||
**IMPORTANT**: The agent cannot compile code. Provide these instructions to the user:
|
||||
```bash
|
||||
./c65gm -in input.c65 -out output.asm
|
||||
acme -f cbm -o output.prg output.asm
|
||||
```
|
||||
|
||||
### Environment Variables
|
||||
- `C65LIBPATH`: Library search path for `#INCLUDE <file>`
|
||||
|
||||
### Editor Support
|
||||
- Kate syntax: `editor_syntaxes/kate/`
|
||||
- Sublime syntax: `editor_syntaxes/sublime/`
|
||||
|
||||
## Where to Look for Specifics
|
||||
|
||||
### Language Syntax
|
||||
- `language.md`: Sections 1-10 cover all language features
|
||||
- `syntax.md`: Detailed syntax rules and preprocessor directives
|
||||
- `commands.md`: Complete command reference with examples
|
||||
|
||||
### Implementation Details
|
||||
- `internal/compiler/compiler.go`: Main compiler logic
|
||||
- `internal/commands/*.go`: Individual command implementations
|
||||
- `internal/preproc/preproc.go`: Preprocessor implementation
|
||||
|
||||
### Examples
|
||||
- `examples/`: Working example programs
|
||||
- `lib/`: Standard library usage examples
|
||||
|
||||
### Testing
|
||||
- `*_test.go` files throughout the codebase
|
||||
- `examples/`: Functional test programs
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
FROM node:18-alpine
|
||||
WORKDIR /app
|
||||
RUN apk add --no-cache bash
|
||||
ENV SHELL=/bin/bash
|
||||
RUN npm install -g @anthropic-ai/claude-code
|
||||
CMD ["claude"]
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
#!/bin/bash
|
||||
export DOCKER_UID=$(id -u)
|
||||
export DOCKER_GID=$(id -g)
|
||||
docker compose run --rm claude-c65gm
|
||||
|
|
@ -1,13 +1,15 @@
|
|||
services:
|
||||
claude-c65gm:
|
||||
build: .
|
||||
opencode-deepseek-c65gm:
|
||||
#image: ghcr.io/anomalyco/opencode:0.0.0-beta-202604081541
|
||||
image: ghcr.io/anomalyco/opencode:latest
|
||||
user: "${DOCKER_UID}:${DOCKER_GID}"
|
||||
working_dir: /app
|
||||
volumes:
|
||||
- .:/app
|
||||
- ./opencode-config:/app/.config/opencode
|
||||
- ./opencode-data:/home/opencode/.local/share/opencode
|
||||
environment:
|
||||
- ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
|
||||
- CLAUDE_CONFIG_DIR=/app/.claude
|
||||
- DEEPSEEK_API_KEY=${DEEPSEEK_API_KEY}
|
||||
- HOME=/app
|
||||
- DISABLE_AUTOUPDATER=1
|
||||
stdin_open: true
|
||||
tty: true
|
||||
|
|
|
|||
|
|
@ -68,13 +68,7 @@ func (c *AddCommand) Interpret(line preproc.Line, ctx *compiler.CompilerContext)
|
|||
scope := ctx.CurrentScope()
|
||||
|
||||
// Create constant lookup function
|
||||
constLookup := func(name string) (int64, bool) {
|
||||
sym := ctx.SymbolTable.Lookup(name, scope)
|
||||
if sym != nil && sym.IsConst() {
|
||||
return int64(sym.Value), true
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
constLookup := ctx.SymbolTable.ConstantLookupFunc(scope)
|
||||
|
||||
// Determine syntax and parse accordingly
|
||||
if strings.ToUpper(params[0]) == "ADD" {
|
||||
|
|
|
|||
|
|
@ -54,9 +54,9 @@ func TestAddCommand_Interpret_OldSyntax(t *testing.T) {
|
|||
{
|
||||
name: "byte + byte -> byte",
|
||||
setup: func(ctx *compiler.CompilerContext) {
|
||||
ctx.SymbolTable.AddVar("a", "", compiler.KindByte, 10)
|
||||
ctx.SymbolTable.AddVar("b", "", compiler.KindByte, 20)
|
||||
ctx.SymbolTable.AddVar("c", "", compiler.KindByte, 0)
|
||||
ctx.SymbolTable.AddVar("a", "", compiler.KindByte, 10, "test.c65", 1)
|
||||
ctx.SymbolTable.AddVar("b", "", compiler.KindByte, 20, "test.c65", 1)
|
||||
ctx.SymbolTable.AddVar("c", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
text: "ADD a TO b GIVING c",
|
||||
wantErr: false,
|
||||
|
|
@ -75,9 +75,9 @@ func TestAddCommand_Interpret_OldSyntax(t *testing.T) {
|
|||
{
|
||||
name: "word + word -> word",
|
||||
setup: func(ctx *compiler.CompilerContext) {
|
||||
ctx.SymbolTable.AddVar("x", "", compiler.KindWord, 1000)
|
||||
ctx.SymbolTable.AddVar("y", "", compiler.KindWord, 2000)
|
||||
ctx.SymbolTable.AddVar("z", "", compiler.KindWord, 0)
|
||||
ctx.SymbolTable.AddVar("x", "", compiler.KindWord, 1000, "test.c65", 1)
|
||||
ctx.SymbolTable.AddVar("y", "", compiler.KindWord, 2000, "test.c65", 1)
|
||||
ctx.SymbolTable.AddVar("z", "", compiler.KindWord, 0, "test.c65", 1)
|
||||
},
|
||||
text: "ADD x TO y GIVING z",
|
||||
wantErr: false,
|
||||
|
|
@ -90,9 +90,9 @@ func TestAddCommand_Interpret_OldSyntax(t *testing.T) {
|
|||
{
|
||||
name: "byte + word -> word",
|
||||
setup: func(ctx *compiler.CompilerContext) {
|
||||
ctx.SymbolTable.AddVar("a", "", compiler.KindByte, 10)
|
||||
ctx.SymbolTable.AddVar("b", "", compiler.KindWord, 1000)
|
||||
ctx.SymbolTable.AddVar("c", "", compiler.KindWord, 0)
|
||||
ctx.SymbolTable.AddVar("a", "", compiler.KindByte, 10, "test.c65", 1)
|
||||
ctx.SymbolTable.AddVar("b", "", compiler.KindWord, 1000, "test.c65", 1)
|
||||
ctx.SymbolTable.AddVar("c", "", compiler.KindWord, 0, "test.c65", 1)
|
||||
},
|
||||
text: "ADD a TO b GIVING c",
|
||||
wantErr: false,
|
||||
|
|
@ -111,8 +111,8 @@ func TestAddCommand_Interpret_OldSyntax(t *testing.T) {
|
|||
{
|
||||
name: "literal + var -> var",
|
||||
setup: func(ctx *compiler.CompilerContext) {
|
||||
ctx.SymbolTable.AddVar("b", "", compiler.KindByte, 20)
|
||||
ctx.SymbolTable.AddVar("c", "", compiler.KindByte, 0)
|
||||
ctx.SymbolTable.AddVar("b", "", compiler.KindByte, 20, "test.c65", 1)
|
||||
ctx.SymbolTable.AddVar("c", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
text: "ADD 10 TO b GIVING c",
|
||||
wantErr: false,
|
||||
|
|
@ -128,8 +128,8 @@ func TestAddCommand_Interpret_OldSyntax(t *testing.T) {
|
|||
{
|
||||
name: "var + literal -> var",
|
||||
setup: func(ctx *compiler.CompilerContext) {
|
||||
ctx.SymbolTable.AddVar("a", "", compiler.KindByte, 10)
|
||||
ctx.SymbolTable.AddVar("c", "", compiler.KindByte, 0)
|
||||
ctx.SymbolTable.AddVar("a", "", compiler.KindByte, 10, "test.c65", 1)
|
||||
ctx.SymbolTable.AddVar("c", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
text: "ADD a TO 20 GIVING c",
|
||||
wantErr: false,
|
||||
|
|
@ -145,7 +145,7 @@ func TestAddCommand_Interpret_OldSyntax(t *testing.T) {
|
|||
{
|
||||
name: "literal + literal -> var",
|
||||
setup: func(ctx *compiler.CompilerContext) {
|
||||
ctx.SymbolTable.AddVar("c", "", compiler.KindByte, 0)
|
||||
ctx.SymbolTable.AddVar("c", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
text: "ADD 15 TO 25 GIVING c",
|
||||
wantErr: false,
|
||||
|
|
@ -161,7 +161,7 @@ func TestAddCommand_Interpret_OldSyntax(t *testing.T) {
|
|||
{
|
||||
name: "hex literal",
|
||||
setup: func(ctx *compiler.CompilerContext) {
|
||||
ctx.SymbolTable.AddVar("c", "", compiler.KindByte, 0)
|
||||
ctx.SymbolTable.AddVar("c", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
text: "ADD $10 TO $20 GIVING c",
|
||||
wantErr: false,
|
||||
|
|
@ -174,9 +174,9 @@ func TestAddCommand_Interpret_OldSyntax(t *testing.T) {
|
|||
{
|
||||
name: "constant usage",
|
||||
setup: func(ctx *compiler.CompilerContext) {
|
||||
ctx.SymbolTable.AddConst("MAX", "", compiler.KindByte, 100)
|
||||
ctx.SymbolTable.AddVar("a", "", compiler.KindByte, 10)
|
||||
ctx.SymbolTable.AddVar("c", "", compiler.KindByte, 0)
|
||||
ctx.SymbolTable.AddConst("MAX", "", compiler.KindByte, 100, "test.c65", 1)
|
||||
ctx.SymbolTable.AddVar("a", "", compiler.KindByte, 10, "test.c65", 1)
|
||||
ctx.SymbolTable.AddVar("c", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
text: "ADD MAX TO a GIVING c",
|
||||
wantErr: false,
|
||||
|
|
@ -192,9 +192,9 @@ func TestAddCommand_Interpret_OldSyntax(t *testing.T) {
|
|||
{
|
||||
name: "alternative syntax +/->",
|
||||
setup: func(ctx *compiler.CompilerContext) {
|
||||
ctx.SymbolTable.AddVar("a", "", compiler.KindByte, 10)
|
||||
ctx.SymbolTable.AddVar("b", "", compiler.KindByte, 20)
|
||||
ctx.SymbolTable.AddVar("c", "", compiler.KindByte, 0)
|
||||
ctx.SymbolTable.AddVar("a", "", compiler.KindByte, 10, "test.c65", 1)
|
||||
ctx.SymbolTable.AddVar("b", "", compiler.KindByte, 20, "test.c65", 1)
|
||||
ctx.SymbolTable.AddVar("c", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
text: "ADD a + b -> c",
|
||||
wantErr: false,
|
||||
|
|
@ -207,7 +207,7 @@ func TestAddCommand_Interpret_OldSyntax(t *testing.T) {
|
|||
{
|
||||
name: "unknown variable",
|
||||
setup: func(ctx *compiler.CompilerContext) {
|
||||
ctx.SymbolTable.AddVar("a", "", compiler.KindByte, 10)
|
||||
ctx.SymbolTable.AddVar("a", "", compiler.KindByte, 10, "test.c65", 1)
|
||||
},
|
||||
text: "ADD a TO b GIVING c",
|
||||
wantErr: true,
|
||||
|
|
@ -215,9 +215,9 @@ func TestAddCommand_Interpret_OldSyntax(t *testing.T) {
|
|||
{
|
||||
name: "assign to constant",
|
||||
setup: func(ctx *compiler.CompilerContext) {
|
||||
ctx.SymbolTable.AddVar("a", "", compiler.KindByte, 10)
|
||||
ctx.SymbolTable.AddVar("b", "", compiler.KindByte, 20)
|
||||
ctx.SymbolTable.AddConst("MAX", "", compiler.KindByte, 100)
|
||||
ctx.SymbolTable.AddVar("a", "", compiler.KindByte, 10, "test.c65", 1)
|
||||
ctx.SymbolTable.AddVar("b", "", compiler.KindByte, 20, "test.c65", 1)
|
||||
ctx.SymbolTable.AddConst("MAX", "", compiler.KindByte, 100, "test.c65", 1)
|
||||
},
|
||||
text: "ADD a TO b GIVING MAX",
|
||||
wantErr: true,
|
||||
|
|
@ -225,7 +225,7 @@ func TestAddCommand_Interpret_OldSyntax(t *testing.T) {
|
|||
{
|
||||
name: "wrong parameter count",
|
||||
setup: func(ctx *compiler.CompilerContext) {
|
||||
ctx.SymbolTable.AddVar("a", "", compiler.KindByte, 10)
|
||||
ctx.SymbolTable.AddVar("a", "", compiler.KindByte, 10, "test.c65", 1)
|
||||
},
|
||||
text: "ADD a TO b",
|
||||
wantErr: true,
|
||||
|
|
@ -233,9 +233,9 @@ func TestAddCommand_Interpret_OldSyntax(t *testing.T) {
|
|||
{
|
||||
name: "wrong separator #3",
|
||||
setup: func(ctx *compiler.CompilerContext) {
|
||||
ctx.SymbolTable.AddVar("a", "", compiler.KindByte, 10)
|
||||
ctx.SymbolTable.AddVar("b", "", compiler.KindByte, 20)
|
||||
ctx.SymbolTable.AddVar("c", "", compiler.KindByte, 0)
|
||||
ctx.SymbolTable.AddVar("a", "", compiler.KindByte, 10, "test.c65", 1)
|
||||
ctx.SymbolTable.AddVar("b", "", compiler.KindByte, 20, "test.c65", 1)
|
||||
ctx.SymbolTable.AddVar("c", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
text: "ADD a AND b GIVING c",
|
||||
wantErr: true,
|
||||
|
|
@ -243,9 +243,9 @@ func TestAddCommand_Interpret_OldSyntax(t *testing.T) {
|
|||
{
|
||||
name: "wrong separator #5",
|
||||
setup: func(ctx *compiler.CompilerContext) {
|
||||
ctx.SymbolTable.AddVar("a", "", compiler.KindByte, 10)
|
||||
ctx.SymbolTable.AddVar("b", "", compiler.KindByte, 20)
|
||||
ctx.SymbolTable.AddVar("c", "", compiler.KindByte, 0)
|
||||
ctx.SymbolTable.AddVar("a", "", compiler.KindByte, 10, "test.c65", 1)
|
||||
ctx.SymbolTable.AddVar("b", "", compiler.KindByte, 20, "test.c65", 1)
|
||||
ctx.SymbolTable.AddVar("c", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
text: "ADD a TO b INTO c",
|
||||
wantErr: true,
|
||||
|
|
@ -253,7 +253,7 @@ func TestAddCommand_Interpret_OldSyntax(t *testing.T) {
|
|||
{
|
||||
name: "invalid expression",
|
||||
setup: func(ctx *compiler.CompilerContext) {
|
||||
ctx.SymbolTable.AddVar("c", "", compiler.KindByte, 0)
|
||||
ctx.SymbolTable.AddVar("c", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
text: "ADD @#$% TO 10 GIVING c",
|
||||
wantErr: true,
|
||||
|
|
@ -295,9 +295,9 @@ func TestAddCommand_Interpret_NewSyntax(t *testing.T) {
|
|||
{
|
||||
name: "dest = var1 + var2",
|
||||
setup: func(ctx *compiler.CompilerContext) {
|
||||
ctx.SymbolTable.AddVar("a", "", compiler.KindByte, 10)
|
||||
ctx.SymbolTable.AddVar("b", "", compiler.KindByte, 20)
|
||||
ctx.SymbolTable.AddVar("result", "", compiler.KindByte, 0)
|
||||
ctx.SymbolTable.AddVar("a", "", compiler.KindByte, 10, "test.c65", 1)
|
||||
ctx.SymbolTable.AddVar("b", "", compiler.KindByte, 20, "test.c65", 1)
|
||||
ctx.SymbolTable.AddVar("result", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
text: "result = a + b",
|
||||
wantErr: false,
|
||||
|
|
@ -316,8 +316,8 @@ func TestAddCommand_Interpret_NewSyntax(t *testing.T) {
|
|||
{
|
||||
name: "dest = literal + var",
|
||||
setup: func(ctx *compiler.CompilerContext) {
|
||||
ctx.SymbolTable.AddVar("x", "", compiler.KindByte, 5)
|
||||
ctx.SymbolTable.AddVar("result", "", compiler.KindByte, 0)
|
||||
ctx.SymbolTable.AddVar("x", "", compiler.KindByte, 5, "test.c65", 1)
|
||||
ctx.SymbolTable.AddVar("result", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
text: "result = 100 + x",
|
||||
wantErr: false,
|
||||
|
|
@ -333,8 +333,8 @@ func TestAddCommand_Interpret_NewSyntax(t *testing.T) {
|
|||
{
|
||||
name: "dest = var + literal",
|
||||
setup: func(ctx *compiler.CompilerContext) {
|
||||
ctx.SymbolTable.AddVar("x", "", compiler.KindByte, 5)
|
||||
ctx.SymbolTable.AddVar("result", "", compiler.KindByte, 0)
|
||||
ctx.SymbolTable.AddVar("x", "", compiler.KindByte, 5, "test.c65", 1)
|
||||
ctx.SymbolTable.AddVar("result", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
text: "result = x + 50",
|
||||
wantErr: false,
|
||||
|
|
@ -350,7 +350,7 @@ func TestAddCommand_Interpret_NewSyntax(t *testing.T) {
|
|||
{
|
||||
name: "dest = literal + literal",
|
||||
setup: func(ctx *compiler.CompilerContext) {
|
||||
ctx.SymbolTable.AddVar("result", "", compiler.KindByte, 0)
|
||||
ctx.SymbolTable.AddVar("result", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
text: "result = 30 + 70",
|
||||
wantErr: false,
|
||||
|
|
@ -363,9 +363,9 @@ func TestAddCommand_Interpret_NewSyntax(t *testing.T) {
|
|||
{
|
||||
name: "word destination",
|
||||
setup: func(ctx *compiler.CompilerContext) {
|
||||
ctx.SymbolTable.AddVar("a", "", compiler.KindWord, 1000)
|
||||
ctx.SymbolTable.AddVar("b", "", compiler.KindWord, 2000)
|
||||
ctx.SymbolTable.AddVar("result", "", compiler.KindWord, 0)
|
||||
ctx.SymbolTable.AddVar("a", "", compiler.KindWord, 1000, "test.c65", 1)
|
||||
ctx.SymbolTable.AddVar("b", "", compiler.KindWord, 2000, "test.c65", 1)
|
||||
ctx.SymbolTable.AddVar("result", "", compiler.KindWord, 0, "test.c65", 1)
|
||||
},
|
||||
text: "result = a + b",
|
||||
wantErr: false,
|
||||
|
|
@ -378,8 +378,8 @@ func TestAddCommand_Interpret_NewSyntax(t *testing.T) {
|
|||
{
|
||||
name: "unknown dest variable",
|
||||
setup: func(ctx *compiler.CompilerContext) {
|
||||
ctx.SymbolTable.AddVar("a", "", compiler.KindByte, 10)
|
||||
ctx.SymbolTable.AddVar("b", "", compiler.KindByte, 20)
|
||||
ctx.SymbolTable.AddVar("a", "", compiler.KindByte, 10, "test.c65", 1)
|
||||
ctx.SymbolTable.AddVar("b", "", compiler.KindByte, 20, "test.c65", 1)
|
||||
},
|
||||
text: "result = a + b",
|
||||
wantErr: true,
|
||||
|
|
@ -387,9 +387,9 @@ func TestAddCommand_Interpret_NewSyntax(t *testing.T) {
|
|||
{
|
||||
name: "assign to constant",
|
||||
setup: func(ctx *compiler.CompilerContext) {
|
||||
ctx.SymbolTable.AddVar("a", "", compiler.KindByte, 10)
|
||||
ctx.SymbolTable.AddVar("b", "", compiler.KindByte, 20)
|
||||
ctx.SymbolTable.AddConst("MAX", "", compiler.KindByte, 100)
|
||||
ctx.SymbolTable.AddVar("a", "", compiler.KindByte, 10, "test.c65", 1)
|
||||
ctx.SymbolTable.AddVar("b", "", compiler.KindByte, 20, "test.c65", 1)
|
||||
ctx.SymbolTable.AddConst("MAX", "", compiler.KindByte, 100, "test.c65", 1)
|
||||
},
|
||||
text: "MAX = a + b",
|
||||
wantErr: true,
|
||||
|
|
@ -397,9 +397,9 @@ func TestAddCommand_Interpret_NewSyntax(t *testing.T) {
|
|||
{
|
||||
name: "wrong operator (not +)",
|
||||
setup: func(ctx *compiler.CompilerContext) {
|
||||
ctx.SymbolTable.AddVar("a", "", compiler.KindByte, 10)
|
||||
ctx.SymbolTable.AddVar("b", "", compiler.KindByte, 20)
|
||||
ctx.SymbolTable.AddVar("result", "", compiler.KindByte, 0)
|
||||
ctx.SymbolTable.AddVar("a", "", compiler.KindByte, 10, "test.c65", 1)
|
||||
ctx.SymbolTable.AddVar("b", "", compiler.KindByte, 20, "test.c65", 1)
|
||||
ctx.SymbolTable.AddVar("result", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
text: "result = a - b",
|
||||
wantErr: true,
|
||||
|
|
@ -439,7 +439,7 @@ func TestAddCommand_Generate(t *testing.T) {
|
|||
{
|
||||
name: "constant folding - both literals to byte",
|
||||
setup: func(ctx *compiler.CompilerContext) *AddCommand {
|
||||
ctx.SymbolTable.AddVar("result", "", compiler.KindByte, 0)
|
||||
ctx.SymbolTable.AddVar("result", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
return &AddCommand{
|
||||
param1IsVar: false,
|
||||
param1Value: 10,
|
||||
|
|
@ -457,7 +457,7 @@ func TestAddCommand_Generate(t *testing.T) {
|
|||
{
|
||||
name: "constant folding - both literals to word",
|
||||
setup: func(ctx *compiler.CompilerContext) *AddCommand {
|
||||
ctx.SymbolTable.AddVar("result", "", compiler.KindWord, 0)
|
||||
ctx.SymbolTable.AddVar("result", "", compiler.KindWord, 0, "test.c65", 1)
|
||||
return &AddCommand{
|
||||
param1IsVar: false,
|
||||
param1Value: 100,
|
||||
|
|
@ -477,7 +477,7 @@ func TestAddCommand_Generate(t *testing.T) {
|
|||
{
|
||||
name: "constant folding with overflow",
|
||||
setup: func(ctx *compiler.CompilerContext) *AddCommand {
|
||||
ctx.SymbolTable.AddVar("result", "", compiler.KindWord, 0)
|
||||
ctx.SymbolTable.AddVar("result", "", compiler.KindWord, 0, "test.c65", 1)
|
||||
return &AddCommand{
|
||||
param1IsVar: false,
|
||||
param1Value: 200,
|
||||
|
|
@ -497,9 +497,9 @@ func TestAddCommand_Generate(t *testing.T) {
|
|||
{
|
||||
name: "byte + byte -> byte",
|
||||
setup: func(ctx *compiler.CompilerContext) *AddCommand {
|
||||
ctx.SymbolTable.AddVar("a", "", compiler.KindByte, 10)
|
||||
ctx.SymbolTable.AddVar("b", "", compiler.KindByte, 20)
|
||||
ctx.SymbolTable.AddVar("result", "", compiler.KindByte, 0)
|
||||
ctx.SymbolTable.AddVar("a", "", compiler.KindByte, 10, "test.c65", 1)
|
||||
ctx.SymbolTable.AddVar("b", "", compiler.KindByte, 20, "test.c65", 1)
|
||||
ctx.SymbolTable.AddVar("result", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
return &AddCommand{
|
||||
param1IsVar: true,
|
||||
param1VarName: "a",
|
||||
|
|
@ -521,9 +521,9 @@ func TestAddCommand_Generate(t *testing.T) {
|
|||
{
|
||||
name: "word + word -> word",
|
||||
setup: func(ctx *compiler.CompilerContext) *AddCommand {
|
||||
ctx.SymbolTable.AddVar("x", "", compiler.KindWord, 1000)
|
||||
ctx.SymbolTable.AddVar("y", "", compiler.KindWord, 2000)
|
||||
ctx.SymbolTable.AddVar("z", "", compiler.KindWord, 0)
|
||||
ctx.SymbolTable.AddVar("x", "", compiler.KindWord, 1000, "test.c65", 1)
|
||||
ctx.SymbolTable.AddVar("y", "", compiler.KindWord, 2000, "test.c65", 1)
|
||||
ctx.SymbolTable.AddVar("z", "", compiler.KindWord, 0, "test.c65", 1)
|
||||
return &AddCommand{
|
||||
param1IsVar: true,
|
||||
param1VarName: "x",
|
||||
|
|
@ -548,9 +548,9 @@ func TestAddCommand_Generate(t *testing.T) {
|
|||
{
|
||||
name: "byte + word -> word",
|
||||
setup: func(ctx *compiler.CompilerContext) *AddCommand {
|
||||
ctx.SymbolTable.AddVar("a", "", compiler.KindByte, 10)
|
||||
ctx.SymbolTable.AddVar("w", "", compiler.KindWord, 1000)
|
||||
ctx.SymbolTable.AddVar("result", "", compiler.KindWord, 0)
|
||||
ctx.SymbolTable.AddVar("a", "", compiler.KindByte, 10, "test.c65", 1)
|
||||
ctx.SymbolTable.AddVar("w", "", compiler.KindWord, 1000, "test.c65", 1)
|
||||
ctx.SymbolTable.AddVar("result", "", compiler.KindWord, 0, "test.c65", 1)
|
||||
return &AddCommand{
|
||||
param1IsVar: true,
|
||||
param1VarName: "a",
|
||||
|
|
@ -575,8 +575,8 @@ func TestAddCommand_Generate(t *testing.T) {
|
|||
{
|
||||
name: "literal + var -> byte",
|
||||
setup: func(ctx *compiler.CompilerContext) *AddCommand {
|
||||
ctx.SymbolTable.AddVar("a", "", compiler.KindByte, 10)
|
||||
ctx.SymbolTable.AddVar("result", "", compiler.KindByte, 0)
|
||||
ctx.SymbolTable.AddVar("a", "", compiler.KindByte, 10, "test.c65", 1)
|
||||
ctx.SymbolTable.AddVar("result", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
return &AddCommand{
|
||||
param1IsVar: false,
|
||||
param1Value: 5,
|
||||
|
|
@ -597,8 +597,8 @@ func TestAddCommand_Generate(t *testing.T) {
|
|||
{
|
||||
name: "var + literal -> word",
|
||||
setup: func(ctx *compiler.CompilerContext) *AddCommand {
|
||||
ctx.SymbolTable.AddVar("w", "", compiler.KindWord, 1000)
|
||||
ctx.SymbolTable.AddVar("result", "", compiler.KindWord, 0)
|
||||
ctx.SymbolTable.AddVar("w", "", compiler.KindWord, 1000, "test.c65", 1)
|
||||
ctx.SymbolTable.AddVar("result", "", compiler.KindWord, 0, "test.c65", 1)
|
||||
return &AddCommand{
|
||||
param1IsVar: true,
|
||||
param1VarName: "w",
|
||||
|
|
@ -622,9 +622,9 @@ func TestAddCommand_Generate(t *testing.T) {
|
|||
{
|
||||
name: "byte + byte -> word (promotion)",
|
||||
setup: func(ctx *compiler.CompilerContext) *AddCommand {
|
||||
ctx.SymbolTable.AddVar("a", "", compiler.KindByte, 10)
|
||||
ctx.SymbolTable.AddVar("b", "", compiler.KindByte, 20)
|
||||
ctx.SymbolTable.AddVar("result", "", compiler.KindWord, 0)
|
||||
ctx.SymbolTable.AddVar("a", "", compiler.KindByte, 10, "test.c65", 1)
|
||||
ctx.SymbolTable.AddVar("b", "", compiler.KindByte, 20, "test.c65", 1)
|
||||
ctx.SymbolTable.AddVar("result", "", compiler.KindWord, 0, "test.c65", 1)
|
||||
return &AddCommand{
|
||||
param1IsVar: true,
|
||||
param1VarName: "a",
|
||||
|
|
@ -678,9 +678,9 @@ func TestAddCommand_Scopes(t *testing.T) {
|
|||
ctx := compiler.NewCompilerContext(preproc.NewPragma())
|
||||
|
||||
// Global variables
|
||||
ctx.SymbolTable.AddVar("globalA", "", compiler.KindByte, 10)
|
||||
ctx.SymbolTable.AddVar("globalB", "", compiler.KindByte, 20)
|
||||
ctx.SymbolTable.AddVar("result", "", compiler.KindByte, 0)
|
||||
ctx.SymbolTable.AddVar("globalA", "", compiler.KindByte, 10, "test.c65", 1)
|
||||
ctx.SymbolTable.AddVar("globalB", "", compiler.KindByte, 20, "test.c65", 1)
|
||||
ctx.SymbolTable.AddVar("result", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
|
||||
// Simulate function declaration to enter scope
|
||||
line := preproc.Line{Text: "FUNC myFunc"}
|
||||
|
|
@ -690,8 +690,8 @@ func TestAddCommand_Scopes(t *testing.T) {
|
|||
}
|
||||
|
||||
// Function scope variables
|
||||
ctx.SymbolTable.AddVar("localA", "myFunc", compiler.KindByte, 5)
|
||||
ctx.SymbolTable.AddVar("localB", "myFunc", compiler.KindByte, 15)
|
||||
ctx.SymbolTable.AddVar("localA", "myFunc", compiler.KindByte, 5, "test.c65", 1)
|
||||
ctx.SymbolTable.AddVar("localB", "myFunc", compiler.KindByte, 15, "test.c65", 1)
|
||||
|
||||
// Test local variables
|
||||
cmd := &AddCommand{}
|
||||
|
|
|
|||
|
|
@ -68,13 +68,7 @@ func (c *AndCommand) Interpret(line preproc.Line, ctx *compiler.CompilerContext)
|
|||
scope := ctx.CurrentScope()
|
||||
|
||||
// Create constant lookup function
|
||||
constLookup := func(name string) (int64, bool) {
|
||||
sym := ctx.SymbolTable.Lookup(name, scope)
|
||||
if sym != nil && sym.IsConst() {
|
||||
return int64(sym.Value), true
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
constLookup := ctx.SymbolTable.ConstantLookupFunc(scope)
|
||||
|
||||
// Determine syntax and parse accordingly
|
||||
if strings.ToUpper(params[0]) == "AND" {
|
||||
|
|
|
|||
|
|
@ -48,9 +48,9 @@ func TestAndCommand_OldSyntax(t *testing.T) {
|
|||
name: "byte AND byte -> byte (variables)",
|
||||
line: "AND a WITH b GIVING result",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("a", "", compiler.KindByte, 0xFF)
|
||||
st.AddVar("b", "", compiler.KindByte, 0x0F)
|
||||
st.AddVar("result", "", compiler.KindByte, 0)
|
||||
st.AddVar("a", "", compiler.KindByte, 0xFF, "test.c65", 1)
|
||||
st.AddVar("b", "", compiler.KindByte, 0x0F, "test.c65", 1)
|
||||
st.AddVar("result", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda a",
|
||||
|
|
@ -62,9 +62,9 @@ func TestAndCommand_OldSyntax(t *testing.T) {
|
|||
name: "byte AND byte -> word",
|
||||
line: "AND a WITH b GIVING result",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("a", "", compiler.KindByte, 0xFF)
|
||||
st.AddVar("b", "", compiler.KindByte, 0x0F)
|
||||
st.AddVar("result", "", compiler.KindWord, 0)
|
||||
st.AddVar("a", "", compiler.KindByte, 0xFF, "test.c65", 1)
|
||||
st.AddVar("b", "", compiler.KindByte, 0x0F, "test.c65", 1)
|
||||
st.AddVar("result", "", compiler.KindWord, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda a",
|
||||
|
|
@ -79,9 +79,9 @@ func TestAndCommand_OldSyntax(t *testing.T) {
|
|||
name: "word AND word -> word",
|
||||
line: "AND x WITH y GIVING result",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("x", "", compiler.KindWord, 0x1234)
|
||||
st.AddVar("y", "", compiler.KindWord, 0x0F0F)
|
||||
st.AddVar("result", "", compiler.KindWord, 0)
|
||||
st.AddVar("x", "", compiler.KindWord, 0x1234, "test.c65", 1)
|
||||
st.AddVar("y", "", compiler.KindWord, 0x0F0F, "test.c65", 1)
|
||||
st.AddVar("result", "", compiler.KindWord, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda x",
|
||||
|
|
@ -96,8 +96,8 @@ func TestAndCommand_OldSyntax(t *testing.T) {
|
|||
name: "byte AND literal -> byte",
|
||||
line: "AND a WITH $F0 GIVING result",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("a", "", compiler.KindByte, 0xFF)
|
||||
st.AddVar("result", "", compiler.KindByte, 0)
|
||||
st.AddVar("a", "", compiler.KindByte, 0xFF, "test.c65", 1)
|
||||
st.AddVar("result", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda a",
|
||||
|
|
@ -109,8 +109,8 @@ func TestAndCommand_OldSyntax(t *testing.T) {
|
|||
name: "literal AND byte -> byte",
|
||||
line: "AND 255 WITH b GIVING result",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("b", "", compiler.KindByte, 0x0F)
|
||||
st.AddVar("result", "", compiler.KindByte, 0)
|
||||
st.AddVar("b", "", compiler.KindByte, 0x0F, "test.c65", 1)
|
||||
st.AddVar("result", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda #$ff",
|
||||
|
|
@ -122,7 +122,7 @@ func TestAndCommand_OldSyntax(t *testing.T) {
|
|||
name: "constant folding: 255 AND 15 -> byte",
|
||||
line: "AND 255 WITH 15 GIVING result",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("result", "", compiler.KindByte, 0)
|
||||
st.AddVar("result", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda #$0f",
|
||||
|
|
@ -133,7 +133,7 @@ func TestAndCommand_OldSyntax(t *testing.T) {
|
|||
name: "constant folding: $FFFF AND $0F0F -> word",
|
||||
line: "AND $FFFF WITH $0F0F GIVING result",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("result", "", compiler.KindWord, 0)
|
||||
st.AddVar("result", "", compiler.KindWord, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda #$0f",
|
||||
|
|
@ -146,9 +146,9 @@ func TestAndCommand_OldSyntax(t *testing.T) {
|
|||
name: "arrow syntax",
|
||||
line: "AND a WITH b -> result",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("a", "", compiler.KindByte, 0)
|
||||
st.AddVar("b", "", compiler.KindByte, 0)
|
||||
st.AddVar("result", "", compiler.KindByte, 0)
|
||||
st.AddVar("a", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
st.AddVar("b", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
st.AddVar("result", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda a",
|
||||
|
|
@ -160,9 +160,9 @@ func TestAndCommand_OldSyntax(t *testing.T) {
|
|||
name: "word AND byte -> byte",
|
||||
line: "AND wval WITH bval GIVING result",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("wval", "", compiler.KindWord, 0x1234)
|
||||
st.AddVar("bval", "", compiler.KindByte, 0xFF)
|
||||
st.AddVar("result", "", compiler.KindByte, 0)
|
||||
st.AddVar("wval", "", compiler.KindWord, 0x1234, "test.c65", 1)
|
||||
st.AddVar("bval", "", compiler.KindByte, 0xFF, "test.c65", 1)
|
||||
st.AddVar("result", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda wval",
|
||||
|
|
@ -174,9 +174,9 @@ func TestAndCommand_OldSyntax(t *testing.T) {
|
|||
name: "word AND byte -> word",
|
||||
line: "AND wval WITH bval GIVING result",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("wval", "", compiler.KindWord, 0x1234)
|
||||
st.AddVar("bval", "", compiler.KindByte, 0xFF)
|
||||
st.AddVar("result", "", compiler.KindWord, 0)
|
||||
st.AddVar("wval", "", compiler.KindWord, 0x1234, "test.c65", 1)
|
||||
st.AddVar("bval", "", compiler.KindByte, 0xFF, "test.c65", 1)
|
||||
st.AddVar("result", "", compiler.KindWord, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda wval",
|
||||
|
|
@ -191,8 +191,8 @@ func TestAndCommand_OldSyntax(t *testing.T) {
|
|||
name: "error: unknown destination variable",
|
||||
line: "AND a WITH b GIVING unknown",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("a", "", compiler.KindByte, 0)
|
||||
st.AddVar("b", "", compiler.KindByte, 0)
|
||||
st.AddVar("a", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
st.AddVar("b", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
|
|
@ -200,9 +200,9 @@ func TestAndCommand_OldSyntax(t *testing.T) {
|
|||
name: "error: wrong separator",
|
||||
line: "AND a TO b GIVING result",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("a", "", compiler.KindByte, 0)
|
||||
st.AddVar("b", "", compiler.KindByte, 0)
|
||||
st.AddVar("result", "", compiler.KindByte, 0)
|
||||
st.AddVar("a", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
st.AddVar("b", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
st.AddVar("result", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
|
|
@ -210,9 +210,9 @@ func TestAndCommand_OldSyntax(t *testing.T) {
|
|||
name: "error: cannot assign to constant",
|
||||
line: "AND a WITH b GIVING MAXVAL",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("a", "", compiler.KindByte, 0)
|
||||
st.AddVar("b", "", compiler.KindByte, 0)
|
||||
st.AddConst("MAXVAL", "", compiler.KindByte, 255)
|
||||
st.AddVar("a", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
st.AddVar("b", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
st.AddConst("MAXVAL", "", compiler.KindByte, 255, "test.c65", 1)
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
|
|
@ -263,9 +263,9 @@ func TestAndCommand_NewSyntax(t *testing.T) {
|
|||
name: "byte & byte -> byte",
|
||||
line: "result = a & b",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("a", "", compiler.KindByte, 0xFF)
|
||||
st.AddVar("b", "", compiler.KindByte, 0x0F)
|
||||
st.AddVar("result", "", compiler.KindByte, 0)
|
||||
st.AddVar("a", "", compiler.KindByte, 0xFF, "test.c65", 1)
|
||||
st.AddVar("b", "", compiler.KindByte, 0x0F, "test.c65", 1)
|
||||
st.AddVar("result", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda a",
|
||||
|
|
@ -277,9 +277,9 @@ func TestAndCommand_NewSyntax(t *testing.T) {
|
|||
name: "byte & byte -> word",
|
||||
line: "result = a & b",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("a", "", compiler.KindByte, 0xFF)
|
||||
st.AddVar("b", "", compiler.KindByte, 0x0F)
|
||||
st.AddVar("result", "", compiler.KindWord, 0)
|
||||
st.AddVar("a", "", compiler.KindByte, 0xFF, "test.c65", 1)
|
||||
st.AddVar("b", "", compiler.KindByte, 0x0F, "test.c65", 1)
|
||||
st.AddVar("result", "", compiler.KindWord, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda a",
|
||||
|
|
@ -294,9 +294,9 @@ func TestAndCommand_NewSyntax(t *testing.T) {
|
|||
name: "word & word -> word",
|
||||
line: "result = x & y",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("x", "", compiler.KindWord, 0x1234)
|
||||
st.AddVar("y", "", compiler.KindWord, 0x0F0F)
|
||||
st.AddVar("result", "", compiler.KindWord, 0)
|
||||
st.AddVar("x", "", compiler.KindWord, 0x1234, "test.c65", 1)
|
||||
st.AddVar("y", "", compiler.KindWord, 0x0F0F, "test.c65", 1)
|
||||
st.AddVar("result", "", compiler.KindWord, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda x",
|
||||
|
|
@ -311,8 +311,8 @@ func TestAndCommand_NewSyntax(t *testing.T) {
|
|||
name: "variable & literal",
|
||||
line: "result = a & $F0",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("a", "", compiler.KindByte, 0xFF)
|
||||
st.AddVar("result", "", compiler.KindByte, 0)
|
||||
st.AddVar("a", "", compiler.KindByte, 0xFF, "test.c65", 1)
|
||||
st.AddVar("result", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda a",
|
||||
|
|
@ -324,7 +324,7 @@ func TestAndCommand_NewSyntax(t *testing.T) {
|
|||
name: "constant folding",
|
||||
line: "result = 255 & 15",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("result", "", compiler.KindByte, 0)
|
||||
st.AddVar("result", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda #$0f",
|
||||
|
|
@ -335,7 +335,7 @@ func TestAndCommand_NewSyntax(t *testing.T) {
|
|||
name: "constant folding word",
|
||||
line: "result = $FFFF & $1234",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("result", "", compiler.KindWord, 0)
|
||||
st.AddVar("result", "", compiler.KindWord, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda #$34",
|
||||
|
|
@ -348,9 +348,9 @@ func TestAndCommand_NewSyntax(t *testing.T) {
|
|||
name: "using constant in expression",
|
||||
line: "result = a & MASK",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("a", "", compiler.KindByte, 0xFF)
|
||||
st.AddConst("MASK", "", compiler.KindByte, 0xF0)
|
||||
st.AddVar("result", "", compiler.KindByte, 0)
|
||||
st.AddVar("a", "", compiler.KindByte, 0xFF, "test.c65", 1)
|
||||
st.AddConst("MASK", "", compiler.KindByte, 0xF0, "test.c65", 1)
|
||||
st.AddVar("result", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda a",
|
||||
|
|
@ -362,8 +362,8 @@ func TestAndCommand_NewSyntax(t *testing.T) {
|
|||
name: "error: unknown destination",
|
||||
line: "unknown = a & b",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("a", "", compiler.KindByte, 0)
|
||||
st.AddVar("b", "", compiler.KindByte, 0)
|
||||
st.AddVar("a", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
st.AddVar("b", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
|
|
@ -371,9 +371,9 @@ func TestAndCommand_NewSyntax(t *testing.T) {
|
|||
name: "error: wrong operator",
|
||||
line: "result = a + b",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("a", "", compiler.KindByte, 0)
|
||||
st.AddVar("b", "", compiler.KindByte, 0)
|
||||
st.AddVar("result", "", compiler.KindByte, 0)
|
||||
st.AddVar("a", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
st.AddVar("b", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
st.AddVar("result", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -55,13 +55,7 @@ func (c *ByteCommand) Interpret(line preproc.Line, ctx *compiler.CompilerContext
|
|||
scope := ctx.FunctionHandler.CurrentFunction()
|
||||
|
||||
// Create constant lookup function
|
||||
constLookup := func(name string) (int64, bool) {
|
||||
sym := ctx.SymbolTable.Lookup(name, ctx.CurrentScope())
|
||||
if sym != nil && sym.IsConst() {
|
||||
return int64(sym.Value), true
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
constLookup := ctx.SymbolTable.ConstantLookupFunc(ctx.CurrentScope())
|
||||
|
||||
switch paramCount {
|
||||
case 2:
|
||||
|
|
@ -73,7 +67,7 @@ func (c *ByteCommand) Interpret(line preproc.Line, ctx *compiler.CompilerContext
|
|||
return fmt.Errorf("BYTE: invalid identifier %q", varName)
|
||||
}
|
||||
|
||||
err = ctx.SymbolTable.AddVar(varName, scope, compiler.KindByte, uint16(value))
|
||||
err = ctx.SymbolTable.AddVar(varName, scope, compiler.KindByte, uint16(value), line.Filename, line.LineNo)
|
||||
|
||||
case 4:
|
||||
// BYTE varname = value OR BYTE varname @ address
|
||||
|
|
@ -95,7 +89,7 @@ func (c *ByteCommand) Interpret(line preproc.Line, ctx *compiler.CompilerContext
|
|||
if value < 0 || value > 255 {
|
||||
return fmt.Errorf("BYTE: init value %d out of range (0-255)", value)
|
||||
}
|
||||
err = ctx.SymbolTable.AddVar(varName, scope, compiler.KindByte, uint16(value))
|
||||
err = ctx.SymbolTable.AddVar(varName, scope, compiler.KindByte, uint16(value), line.Filename, line.LineNo)
|
||||
|
||||
} else if operator == "@" {
|
||||
// BYTE varname @ address
|
||||
|
|
@ -103,7 +97,7 @@ func (c *ByteCommand) Interpret(line preproc.Line, ctx *compiler.CompilerContext
|
|||
return fmt.Errorf("BYTE: absolute address $%X out of range", value)
|
||||
}
|
||||
c.isAbs = true
|
||||
err = ctx.SymbolTable.AddAbsolute(varName, scope, compiler.KindByte, uint16(value))
|
||||
err = ctx.SymbolTable.AddAbsolute(varName, scope, compiler.KindByte, uint16(value), line.Filename, line.LineNo)
|
||||
|
||||
} else {
|
||||
return fmt.Errorf("BYTE: expected '=' or '@', got %q", operator)
|
||||
|
|
@ -138,7 +132,7 @@ func (c *ByteCommand) Interpret(line preproc.Line, ctx *compiler.CompilerContext
|
|||
}
|
||||
|
||||
c.isConst = true
|
||||
err = ctx.SymbolTable.AddConst(varName, scope, compiler.KindByte, uint16(value))
|
||||
err = ctx.SymbolTable.AddConst(varName, scope, compiler.KindByte, uint16(value), line.Filename, line.LineNo)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -302,7 +302,7 @@ func TestByteCommand_Interpret(t *testing.T) {
|
|||
|
||||
// For duplicate test, pre-declare the variable
|
||||
if tt.name == "duplicate declaration" {
|
||||
ctx.SymbolTable.AddVar("x", "", compiler.KindByte, 0)
|
||||
ctx.SymbolTable.AddVar("x", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
}
|
||||
|
||||
cmd := &ByteCommand{}
|
||||
|
|
@ -370,7 +370,7 @@ func TestByteCommand_InFunctionScope(t *testing.T) {
|
|||
// Simulate being inside a function
|
||||
// We'd need to push function context, but for now we can test the scoping manually
|
||||
scope := "myFunc"
|
||||
ctx.SymbolTable.AddVar("localVar", scope, compiler.KindByte, 5)
|
||||
ctx.SymbolTable.AddVar("localVar", scope, compiler.KindByte, 5, "test.c65", 1)
|
||||
|
||||
// Check it was added with correct scope
|
||||
sym := ctx.SymbolTable.Lookup("localVar", []string{scope})
|
||||
|
|
@ -390,8 +390,8 @@ func TestByteCommand_WithConstantExpression(t *testing.T) {
|
|||
ctx := compiler.NewCompilerContext(pragma)
|
||||
|
||||
// First, declare a constant
|
||||
ctx.SymbolTable.AddConst("MAXVAL", "", compiler.KindByte, 200)
|
||||
ctx.SymbolTable.AddConst("OFFSET", "", compiler.KindByte, 10)
|
||||
ctx.SymbolTable.AddConst("MAXVAL", "", compiler.KindByte, 200, "test.c65", 1)
|
||||
ctx.SymbolTable.AddConst("OFFSET", "", compiler.KindByte, 10, "test.c65", 1)
|
||||
|
||||
// Now declare a byte using the constant in an expression
|
||||
cmd := &ByteCommand{}
|
||||
|
|
|
|||
|
|
@ -39,13 +39,7 @@ func (c *CaseCommand) Interpret(line preproc.Line, ctx *compiler.CompilerContext
|
|||
}
|
||||
|
||||
scope := ctx.CurrentScope()
|
||||
constLookup := func(name string) (int64, bool) {
|
||||
sym := ctx.SymbolTable.Lookup(name, scope)
|
||||
if sym != nil && sym.IsConst() {
|
||||
return int64(sym.Value), true
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
constLookup := ctx.SymbolTable.ConstantLookupFunc(scope)
|
||||
|
||||
// Parse the case value
|
||||
varName, varKind, value, isVar, err := compiler.ParseOperandParam(
|
||||
|
|
|
|||
|
|
@ -97,13 +97,7 @@ func (c *DecrCommand) Interpret(line preproc.Line, ctx *compiler.CompilerContext
|
|||
}
|
||||
|
||||
// Old syntax allows absolute addresses
|
||||
constLookup := func(name string) (int64, bool) {
|
||||
s := ctx.SymbolTable.Lookup(name, scope)
|
||||
if s != nil && s.IsConst() {
|
||||
return int64(s.Value), true
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
constLookup := ctx.SymbolTable.ConstantLookupFunc(scope)
|
||||
|
||||
val, evalErr := utils.EvaluateExpression(targetParam, constLookup)
|
||||
if evalErr != nil {
|
||||
|
|
|
|||
|
|
@ -48,13 +48,7 @@ func (c *ForCommand) Interpret(line preproc.Line, ctx *compiler.CompilerContext)
|
|||
}
|
||||
|
||||
scope := ctx.CurrentScope()
|
||||
constLookup := func(name string) (int64, bool) {
|
||||
sym := ctx.SymbolTable.Lookup(name, scope)
|
||||
if sym != nil && sym.IsConst() {
|
||||
return int64(sym.Value), true
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
constLookup := ctx.SymbolTable.ConstantLookupFunc(scope)
|
||||
|
||||
// Parse variable
|
||||
varName := params[1]
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ func TestForBasicTO(t *testing.T) {
|
|||
name: "byte var TO byte literal",
|
||||
forLine: "FOR i = 0 TO 10",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("i", "", compiler.KindByte, 0)
|
||||
st.AddVar("i", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
// Do-while style: initial guard (constant folded - 0<=10 is true, no code)
|
||||
// then loop label
|
||||
|
|
@ -43,7 +43,7 @@ func TestForBasicTO(t *testing.T) {
|
|||
name: "word var TO word literal",
|
||||
forLine: "FOR counter = 0 TO 1000",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("counter", "", compiler.KindWord, 0)
|
||||
st.AddVar("counter", "", compiler.KindWord, 0, "test.c65", 1)
|
||||
},
|
||||
// Do-while style: initial guard (constant folded - 0<=1000 is true, no code)
|
||||
wantFor: []string{
|
||||
|
|
@ -126,7 +126,7 @@ func TestForBasicTO(t *testing.T) {
|
|||
func TestForBreak(t *testing.T) {
|
||||
pragma := preproc.NewPragma()
|
||||
ctx := compiler.NewCompilerContext(pragma)
|
||||
ctx.SymbolTable.AddVar("i", "", compiler.KindByte, 0)
|
||||
ctx.SymbolTable.AddVar("i", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
|
||||
forCmd := &ForCommand{}
|
||||
breakCmd := &BreakCommand{}
|
||||
|
|
@ -166,8 +166,8 @@ func TestForBreak(t *testing.T) {
|
|||
func TestForNested(t *testing.T) {
|
||||
pragma := preproc.NewPragma()
|
||||
ctx := compiler.NewCompilerContext(pragma)
|
||||
ctx.SymbolTable.AddVar("i", "", compiler.KindByte, 0)
|
||||
ctx.SymbolTable.AddVar("j", "", compiler.KindByte, 0)
|
||||
ctx.SymbolTable.AddVar("i", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
ctx.SymbolTable.AddVar("j", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
|
||||
pragmaIdx := pragma.GetCurrentPragmaSetIndex()
|
||||
|
||||
|
|
@ -226,8 +226,8 @@ func TestForNested(t *testing.T) {
|
|||
func TestForMixedWithWhile(t *testing.T) {
|
||||
pragma := preproc.NewPragma()
|
||||
ctx := compiler.NewCompilerContext(pragma)
|
||||
ctx.SymbolTable.AddVar("i", "", compiler.KindByte, 0)
|
||||
ctx.SymbolTable.AddVar("x", "", compiler.KindByte, 0)
|
||||
ctx.SymbolTable.AddVar("i", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
ctx.SymbolTable.AddVar("x", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
|
||||
pragmaIdx := pragma.GetCurrentPragmaSetIndex()
|
||||
|
||||
|
|
@ -263,8 +263,8 @@ func TestForMixedWithWhile(t *testing.T) {
|
|||
func TestForIllegalNesting(t *testing.T) {
|
||||
pragma := preproc.NewPragma()
|
||||
ctx := compiler.NewCompilerContext(pragma)
|
||||
ctx.SymbolTable.AddVar("i", "", compiler.KindByte, 0)
|
||||
ctx.SymbolTable.AddVar("x", "", compiler.KindByte, 0)
|
||||
ctx.SymbolTable.AddVar("i", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
ctx.SymbolTable.AddVar("x", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
|
||||
pragmaIdx := pragma.GetCurrentPragmaSetIndex()
|
||||
|
||||
|
|
@ -320,7 +320,7 @@ func TestNextWithoutFor(t *testing.T) {
|
|||
func TestForWrongParamCount(t *testing.T) {
|
||||
pragma := preproc.NewPragma()
|
||||
ctx := compiler.NewCompilerContext(pragma)
|
||||
ctx.SymbolTable.AddVar("i", "", compiler.KindByte, 0)
|
||||
ctx.SymbolTable.AddVar("i", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
|
||||
tests := []string{
|
||||
"FOR i",
|
||||
|
|
@ -348,7 +348,7 @@ func TestForWrongParamCount(t *testing.T) {
|
|||
func TestForInvalidDirection(t *testing.T) {
|
||||
pragma := preproc.NewPragma()
|
||||
ctx := compiler.NewCompilerContext(pragma)
|
||||
ctx.SymbolTable.AddVar("i", "", compiler.KindByte, 0)
|
||||
ctx.SymbolTable.AddVar("i", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
|
||||
cmd := &ForCommand{}
|
||||
line := preproc.Line{
|
||||
|
|
@ -369,7 +369,7 @@ func TestForInvalidDirection(t *testing.T) {
|
|||
func TestForDOWNTORejected(t *testing.T) {
|
||||
pragma := preproc.NewPragma()
|
||||
ctx := compiler.NewCompilerContext(pragma)
|
||||
ctx.SymbolTable.AddVar("i", "", compiler.KindByte, 0)
|
||||
ctx.SymbolTable.AddVar("i", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
|
||||
cmd := &ForCommand{}
|
||||
line := preproc.Line{
|
||||
|
|
@ -390,7 +390,7 @@ func TestForDOWNTORejected(t *testing.T) {
|
|||
func TestForConstVariable(t *testing.T) {
|
||||
pragma := preproc.NewPragma()
|
||||
ctx := compiler.NewCompilerContext(pragma)
|
||||
ctx.SymbolTable.AddConst("LIMIT", "", compiler.KindByte, 10)
|
||||
ctx.SymbolTable.AddConst("LIMIT", "", compiler.KindByte, 10, "test.c65", 1)
|
||||
|
||||
cmd := &ForCommand{}
|
||||
line := preproc.Line{
|
||||
|
|
@ -431,8 +431,8 @@ func TestForUnknownVariable(t *testing.T) {
|
|||
func TestForConstantEnd(t *testing.T) {
|
||||
pragma := preproc.NewPragma()
|
||||
ctx := compiler.NewCompilerContext(pragma)
|
||||
ctx.SymbolTable.AddVar("i", "", compiler.KindByte, 0)
|
||||
ctx.SymbolTable.AddConst("MAX", "", compiler.KindByte, 100)
|
||||
ctx.SymbolTable.AddVar("i", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
ctx.SymbolTable.AddConst("MAX", "", compiler.KindByte, 100, "test.c65", 1)
|
||||
|
||||
forCmd := &ForCommand{}
|
||||
nextCmd := &NextCommand{}
|
||||
|
|
@ -484,7 +484,7 @@ func TestForByteMaxEndValue(t *testing.T) {
|
|||
// This naturally handles the max value case (255) without overflow.
|
||||
pragma := preproc.NewPragma()
|
||||
ctx := compiler.NewCompilerContext(pragma)
|
||||
ctx.SymbolTable.AddVar("b", "", compiler.KindByte, 0)
|
||||
ctx.SymbolTable.AddVar("b", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
|
||||
forCmd := &ForCommand{}
|
||||
nextCmd := &NextCommand{}
|
||||
|
|
@ -543,7 +543,7 @@ func TestForWordMaxEndValue(t *testing.T) {
|
|||
// Naturally handles the max value case (65535) without overflow.
|
||||
pragma := preproc.NewPragma()
|
||||
ctx := compiler.NewCompilerContext(pragma)
|
||||
ctx.SymbolTable.AddVar("w", "", compiler.KindWord, 0)
|
||||
ctx.SymbolTable.AddVar("w", "", compiler.KindWord, 0, "test.c65", 1)
|
||||
|
||||
forCmd := &ForCommand{}
|
||||
nextCmd := &NextCommand{}
|
||||
|
|
|
|||
|
|
@ -70,13 +70,7 @@ func (c *GosubCommand) Interpret(line preproc.Line, ctx *compiler.CompilerContex
|
|||
|
||||
scope := ctx.CurrentScope()
|
||||
|
||||
constLookup := func(name string) (int64, bool) {
|
||||
sym := ctx.SymbolTable.Lookup(name, scope)
|
||||
if sym != nil && sym.IsConst() {
|
||||
return int64(sym.Value), true
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
constLookup := ctx.SymbolTable.ConstantLookupFunc(scope)
|
||||
|
||||
// Parse target (param 2)
|
||||
targetParam := params[1]
|
||||
|
|
|
|||
|
|
@ -52,13 +52,7 @@ func (c *GotoCommand) Interpret(line preproc.Line, ctx *compiler.CompilerContext
|
|||
targetParam := params[1]
|
||||
scope := ctx.CurrentScope()
|
||||
|
||||
constLookup := func(name string) (int64, bool) {
|
||||
sym := ctx.SymbolTable.Lookup(name, scope)
|
||||
if sym != nil && sym.IsConst() {
|
||||
return int64(sym.Value), true
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
constLookup := ctx.SymbolTable.ConstantLookupFunc(scope)
|
||||
|
||||
// Try ParseOperandParam - handles variables, constants, expressions
|
||||
varName, varKind, value, isVar, err := compiler.ParseOperandParam(
|
||||
|
|
|
|||
|
|
@ -40,13 +40,7 @@ func (c *IfCommand) Interpret(line preproc.Line, ctx *compiler.CompilerContext)
|
|||
}
|
||||
|
||||
scope := ctx.CurrentScope()
|
||||
constLookup := func(name string) (int64, bool) {
|
||||
sym := ctx.SymbolTable.Lookup(name, scope)
|
||||
if sym != nil && sym.IsConst() {
|
||||
return int64(sym.Value), true
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
constLookup := ctx.SymbolTable.ConstantLookupFunc(scope)
|
||||
|
||||
// Parse param1
|
||||
varName, varKind, value, isVar, err := compiler.ParseOperandParam(
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ func TestIfBasicEqual(t *testing.T) {
|
|||
name: "byte var == byte literal",
|
||||
ifLine: "IF x = 10",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("x", "", compiler.KindByte, 0)
|
||||
st.AddVar("x", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
wantIf: []string{
|
||||
"\tlda x",
|
||||
|
|
@ -35,7 +35,7 @@ func TestIfBasicEqual(t *testing.T) {
|
|||
name: "word var == word literal",
|
||||
ifLine: "IF x = 1000",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("x", "", compiler.KindWord, 0)
|
||||
st.AddVar("x", "", compiler.KindWord, 0, "test.c65", 1)
|
||||
},
|
||||
wantIf: []string{
|
||||
"\tlda x",
|
||||
|
|
@ -116,7 +116,7 @@ func TestIfElseEndif(t *testing.T) {
|
|||
name: "byte var with else",
|
||||
ifLine: "IF x = 10",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("x", "", compiler.KindByte, 0)
|
||||
st.AddVar("x", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
wantIf: []string{
|
||||
"\tlda x",
|
||||
|
|
@ -209,7 +209,7 @@ func TestIfAllOperators(t *testing.T) {
|
|||
t.Run(tt.name, func(t *testing.T) {
|
||||
pragma := preproc.NewPragma()
|
||||
ctx := compiler.NewCompilerContext(pragma)
|
||||
ctx.SymbolTable.AddVar("x", "", compiler.KindByte, 0)
|
||||
ctx.SymbolTable.AddVar("x", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
|
||||
cmd := &IfCommand{}
|
||||
line := preproc.Line{
|
||||
|
|
@ -244,8 +244,8 @@ func TestIfAllOperators(t *testing.T) {
|
|||
func TestIfMixedTypes(t *testing.T) {
|
||||
pragma := preproc.NewPragma()
|
||||
ctx := compiler.NewCompilerContext(pragma)
|
||||
ctx.SymbolTable.AddVar("x", "", compiler.KindByte, 0)
|
||||
ctx.SymbolTable.AddVar("y", "", compiler.KindWord, 0)
|
||||
ctx.SymbolTable.AddVar("x", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
ctx.SymbolTable.AddVar("y", "", compiler.KindWord, 0, "test.c65", 1)
|
||||
|
||||
cmd := &IfCommand{}
|
||||
line := preproc.Line{
|
||||
|
|
@ -318,8 +318,8 @@ func TestElseWithoutIf(t *testing.T) {
|
|||
func TestIfNested(t *testing.T) {
|
||||
pragma := preproc.NewPragma()
|
||||
ctx := compiler.NewCompilerContext(pragma)
|
||||
ctx.SymbolTable.AddVar("x", "", compiler.KindByte, 0)
|
||||
ctx.SymbolTable.AddVar("y", "", compiler.KindByte, 0)
|
||||
ctx.SymbolTable.AddVar("x", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
ctx.SymbolTable.AddVar("y", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
|
||||
pragmaIdx := pragma.GetCurrentPragmaSetIndex()
|
||||
|
||||
|
|
@ -366,8 +366,8 @@ func TestIfNested(t *testing.T) {
|
|||
func TestIfNestedWithElse(t *testing.T) {
|
||||
pragma := preproc.NewPragma()
|
||||
ctx := compiler.NewCompilerContext(pragma)
|
||||
ctx.SymbolTable.AddVar("x", "", compiler.KindByte, 0)
|
||||
ctx.SymbolTable.AddVar("y", "", compiler.KindByte, 0)
|
||||
ctx.SymbolTable.AddVar("x", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
ctx.SymbolTable.AddVar("y", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
|
||||
pragmaIdx := pragma.GetCurrentPragmaSetIndex()
|
||||
|
||||
|
|
@ -407,7 +407,7 @@ func TestIfLongJump(t *testing.T) {
|
|||
pragma := preproc.NewPragma()
|
||||
pragma.AddPragma("_P_USE_LONG_JUMP", "1")
|
||||
ctx := compiler.NewCompilerContext(pragma)
|
||||
ctx.SymbolTable.AddVar("x", "", compiler.KindByte, 0)
|
||||
ctx.SymbolTable.AddVar("x", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
|
||||
cmd := &IfCommand{}
|
||||
line := preproc.Line{
|
||||
|
|
@ -440,8 +440,8 @@ func TestIfLongJump(t *testing.T) {
|
|||
func TestIfConstant(t *testing.T) {
|
||||
pragma := preproc.NewPragma()
|
||||
ctx := compiler.NewCompilerContext(pragma)
|
||||
ctx.SymbolTable.AddConst("MAX", "", compiler.KindByte, 100)
|
||||
ctx.SymbolTable.AddVar("x", "", compiler.KindByte, 0)
|
||||
ctx.SymbolTable.AddConst("MAX", "", compiler.KindByte, 100, "test.c65", 1)
|
||||
ctx.SymbolTable.AddVar("x", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
|
||||
cmd := &IfCommand{}
|
||||
line := preproc.Line{
|
||||
|
|
@ -499,7 +499,7 @@ func TestIfWrongParamCount(t *testing.T) {
|
|||
func TestElseWrongParamCount(t *testing.T) {
|
||||
pragma := preproc.NewPragma()
|
||||
ctx := compiler.NewCompilerContext(pragma)
|
||||
ctx.SymbolTable.AddVar("x", "", compiler.KindByte, 0)
|
||||
ctx.SymbolTable.AddVar("x", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
|
||||
// Setup IF first
|
||||
ifCmd := &IfCommand{}
|
||||
|
|
@ -525,7 +525,7 @@ func TestElseWrongParamCount(t *testing.T) {
|
|||
func TestEndifWrongParamCount(t *testing.T) {
|
||||
pragma := preproc.NewPragma()
|
||||
ctx := compiler.NewCompilerContext(pragma)
|
||||
ctx.SymbolTable.AddVar("x", "", compiler.KindByte, 0)
|
||||
ctx.SymbolTable.AddVar("x", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
|
||||
// Setup IF first
|
||||
ifCmd := &IfCommand{}
|
||||
|
|
|
|||
|
|
@ -97,13 +97,7 @@ func (c *IncrCommand) Interpret(line preproc.Line, ctx *compiler.CompilerContext
|
|||
}
|
||||
|
||||
// Old syntax allows absolute addresses
|
||||
constLookup := func(name string) (int64, bool) {
|
||||
s := ctx.SymbolTable.Lookup(name, scope)
|
||||
if s != nil && s.IsConst() {
|
||||
return int64(s.Value), true
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
constLookup := ctx.SymbolTable.ConstantLookupFunc(scope)
|
||||
|
||||
val, evalErr := utils.EvaluateExpression(targetParam, constLookup)
|
||||
if evalErr != nil {
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ func TestIncrCommand_InterpretAndGenerate(t *testing.T) {
|
|||
{
|
||||
name: "INC byte variable old syntax",
|
||||
setup: func(ctx *compiler.CompilerContext) {
|
||||
ctx.SymbolTable.AddVar("counter", "", compiler.KindByte, 0)
|
||||
ctx.SymbolTable.AddVar("counter", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
line: "INC counter",
|
||||
expectError: false,
|
||||
|
|
@ -94,7 +94,7 @@ func TestIncrCommand_InterpretAndGenerate(t *testing.T) {
|
|||
{
|
||||
name: "INC byte variable new syntax",
|
||||
setup: func(ctx *compiler.CompilerContext) {
|
||||
ctx.SymbolTable.AddVar("counter", "", compiler.KindByte, 0)
|
||||
ctx.SymbolTable.AddVar("counter", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
line: "counter++",
|
||||
expectError: false,
|
||||
|
|
@ -111,7 +111,7 @@ func TestIncrCommand_InterpretAndGenerate(t *testing.T) {
|
|||
{
|
||||
name: "INC word variable old syntax",
|
||||
setup: func(ctx *compiler.CompilerContext) {
|
||||
ctx.SymbolTable.AddVar("pointer", "", compiler.KindWord, 0)
|
||||
ctx.SymbolTable.AddVar("pointer", "", compiler.KindWord, 0, "test.c65", 1)
|
||||
},
|
||||
line: "INCREMENT pointer",
|
||||
expectError: false,
|
||||
|
|
@ -135,7 +135,7 @@ func TestIncrCommand_InterpretAndGenerate(t *testing.T) {
|
|||
{
|
||||
name: "INC word variable new syntax",
|
||||
setup: func(ctx *compiler.CompilerContext) {
|
||||
ctx.SymbolTable.AddVar("pointer", "", compiler.KindWord, 0)
|
||||
ctx.SymbolTable.AddVar("pointer", "", compiler.KindWord, 0, "test.c65", 1)
|
||||
},
|
||||
line: "pointer++",
|
||||
expectError: false,
|
||||
|
|
@ -174,7 +174,7 @@ func TestIncrCommand_InterpretAndGenerate(t *testing.T) {
|
|||
{
|
||||
name: "Error: INC constant variable",
|
||||
setup: func(ctx *compiler.CompilerContext) {
|
||||
ctx.SymbolTable.AddConst("MAX", "", compiler.KindByte, 100)
|
||||
ctx.SymbolTable.AddConst("MAX", "", compiler.KindByte, 100, "test.c65", 1)
|
||||
},
|
||||
line: "INC MAX",
|
||||
expectError: true,
|
||||
|
|
@ -233,7 +233,7 @@ func TestDecrCommand_InterpretAndGenerate(t *testing.T) {
|
|||
{
|
||||
name: "DEC byte variable old syntax",
|
||||
setup: func(ctx *compiler.CompilerContext) {
|
||||
ctx.SymbolTable.AddVar("counter", "", compiler.KindByte, 0)
|
||||
ctx.SymbolTable.AddVar("counter", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
line: "DEC counter",
|
||||
expectError: false,
|
||||
|
|
@ -250,7 +250,7 @@ func TestDecrCommand_InterpretAndGenerate(t *testing.T) {
|
|||
{
|
||||
name: "DEC byte variable new syntax",
|
||||
setup: func(ctx *compiler.CompilerContext) {
|
||||
ctx.SymbolTable.AddVar("counter", "", compiler.KindByte, 0)
|
||||
ctx.SymbolTable.AddVar("counter", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
line: "counter--",
|
||||
expectError: false,
|
||||
|
|
@ -267,7 +267,7 @@ func TestDecrCommand_InterpretAndGenerate(t *testing.T) {
|
|||
{
|
||||
name: "DEC word variable old syntax",
|
||||
setup: func(ctx *compiler.CompilerContext) {
|
||||
ctx.SymbolTable.AddVar("pointer", "", compiler.KindWord, 0)
|
||||
ctx.SymbolTable.AddVar("pointer", "", compiler.KindWord, 0, "test.c65", 1)
|
||||
},
|
||||
line: "DECREMENT pointer",
|
||||
expectError: false,
|
||||
|
|
@ -294,7 +294,7 @@ func TestDecrCommand_InterpretAndGenerate(t *testing.T) {
|
|||
{
|
||||
name: "DEC word variable new syntax",
|
||||
setup: func(ctx *compiler.CompilerContext) {
|
||||
ctx.SymbolTable.AddVar("pointer", "", compiler.KindWord, 0)
|
||||
ctx.SymbolTable.AddVar("pointer", "", compiler.KindWord, 0, "test.c65", 1)
|
||||
},
|
||||
line: "pointer--",
|
||||
expectError: false,
|
||||
|
|
@ -332,7 +332,7 @@ func TestDecrCommand_InterpretAndGenerate(t *testing.T) {
|
|||
{
|
||||
name: "Error: DEC constant variable",
|
||||
setup: func(ctx *compiler.CompilerContext) {
|
||||
ctx.SymbolTable.AddConst("MAX", "", compiler.KindByte, 100)
|
||||
ctx.SymbolTable.AddConst("MAX", "", compiler.KindByte, 100, "test.c65", 1)
|
||||
},
|
||||
line: "DEC MAX",
|
||||
expectError: true,
|
||||
|
|
@ -385,7 +385,7 @@ func TestIncrDecrCommand_FullNameResolution(t *testing.T) {
|
|||
ctx := compiler.NewCompilerContext(preproc.NewPragma())
|
||||
|
||||
// Add a variable with scoped name directly
|
||||
ctx.SymbolTable.AddVar("counter", "myfunc", compiler.KindWord, 0)
|
||||
ctx.SymbolTable.AddVar("counter", "myfunc", compiler.KindWord, 0, "test.c65", 1)
|
||||
|
||||
// Note: CurrentScope will return nil (global) since we're not in a function context
|
||||
// The symbol table lookup will try scoped search and fall back to global
|
||||
|
|
|
|||
|
|
@ -62,13 +62,7 @@ func (c *LetCommand) Interpret(line preproc.Line, ctx *compiler.CompilerContext)
|
|||
scope := ctx.CurrentScope()
|
||||
|
||||
// Create constant lookup function
|
||||
constLookup := func(name string) (int64, bool) {
|
||||
sym := ctx.SymbolTable.Lookup(name, scope)
|
||||
if sym != nil && sym.IsConst() {
|
||||
return int64(sym.Value), true
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
constLookup := ctx.SymbolTable.ConstantLookupFunc(scope)
|
||||
|
||||
// Determine syntax and parse accordingly
|
||||
if strings.ToUpper(params[0]) == "LET" {
|
||||
|
|
|
|||
|
|
@ -48,8 +48,8 @@ func TestLetCommand_OldSyntax(t *testing.T) {
|
|||
name: "LET byte GET byte",
|
||||
line: "LET a GET b",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("a", "", compiler.KindByte, 0)
|
||||
st.AddVar("b", "", compiler.KindByte, 10)
|
||||
st.AddVar("a", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
st.AddVar("b", "", compiler.KindByte, 10, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda b",
|
||||
|
|
@ -60,7 +60,7 @@ func TestLetCommand_OldSyntax(t *testing.T) {
|
|||
name: "LET byte = literal",
|
||||
line: "LET a = 100",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("a", "", compiler.KindByte, 0)
|
||||
st.AddVar("a", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda #$64",
|
||||
|
|
@ -71,8 +71,8 @@ func TestLetCommand_OldSyntax(t *testing.T) {
|
|||
name: "LET word GET word",
|
||||
line: "LET x GET y",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("x", "", compiler.KindWord, 0)
|
||||
st.AddVar("y", "", compiler.KindWord, 0x1234)
|
||||
st.AddVar("x", "", compiler.KindWord, 0, "test.c65", 1)
|
||||
st.AddVar("y", "", compiler.KindWord, 0x1234, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda y",
|
||||
|
|
@ -85,7 +85,7 @@ func TestLetCommand_OldSyntax(t *testing.T) {
|
|||
name: "LET word = literal",
|
||||
line: "LET x = $1234",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("x", "", compiler.KindWord, 0)
|
||||
st.AddVar("x", "", compiler.KindWord, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda #$34",
|
||||
|
|
@ -98,8 +98,8 @@ func TestLetCommand_OldSyntax(t *testing.T) {
|
|||
name: "LET word GET byte (zero-extend)",
|
||||
line: "LET x GET b",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("x", "", compiler.KindWord, 0)
|
||||
st.AddVar("b", "", compiler.KindByte, 100)
|
||||
st.AddVar("x", "", compiler.KindWord, 0, "test.c65", 1)
|
||||
st.AddVar("b", "", compiler.KindByte, 100, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda b",
|
||||
|
|
@ -112,8 +112,8 @@ func TestLetCommand_OldSyntax(t *testing.T) {
|
|||
name: "LET byte GET word (take low byte)",
|
||||
line: "LET b GET x",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("b", "", compiler.KindByte, 0)
|
||||
st.AddVar("x", "", compiler.KindWord, 0x1234)
|
||||
st.AddVar("b", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
st.AddVar("x", "", compiler.KindWord, 0x1234, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda x",
|
||||
|
|
@ -124,7 +124,7 @@ func TestLetCommand_OldSyntax(t *testing.T) {
|
|||
name: "LET word = $0000 (optimization)",
|
||||
line: "LET x = 0",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("x", "", compiler.KindWord, 0)
|
||||
st.AddVar("x", "", compiler.KindWord, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda #$00",
|
||||
|
|
@ -136,7 +136,7 @@ func TestLetCommand_OldSyntax(t *testing.T) {
|
|||
name: "LET word = $FFFF (optimization)",
|
||||
line: "LET x = $FFFF",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("x", "", compiler.KindWord, 0)
|
||||
st.AddVar("x", "", compiler.KindWord, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda #$ff",
|
||||
|
|
@ -148,8 +148,8 @@ func TestLetCommand_OldSyntax(t *testing.T) {
|
|||
name: "LET with constant",
|
||||
line: "LET a = MAXVAL",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("a", "", compiler.KindByte, 0)
|
||||
st.AddConst("MAXVAL", "", compiler.KindByte, 255)
|
||||
st.AddVar("a", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
st.AddConst("MAXVAL", "", compiler.KindByte, 255, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda #$ff",
|
||||
|
|
@ -160,7 +160,7 @@ func TestLetCommand_OldSyntax(t *testing.T) {
|
|||
name: "error: unknown destination",
|
||||
line: "LET unknown GET a",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("a", "", compiler.KindByte, 0)
|
||||
st.AddVar("a", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
|
|
@ -168,8 +168,8 @@ func TestLetCommand_OldSyntax(t *testing.T) {
|
|||
name: "error: wrong separator",
|
||||
line: "LET a TO b",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("a", "", compiler.KindByte, 0)
|
||||
st.AddVar("b", "", compiler.KindByte, 0)
|
||||
st.AddVar("a", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
st.AddVar("b", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
|
|
@ -177,7 +177,7 @@ func TestLetCommand_OldSyntax(t *testing.T) {
|
|||
name: "error: cannot assign to constant",
|
||||
line: "LET MAXVAL = 100",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddConst("MAXVAL", "", compiler.KindByte, 255)
|
||||
st.AddConst("MAXVAL", "", compiler.KindByte, 255, "test.c65", 1)
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
|
|
@ -228,8 +228,8 @@ func TestLetCommand_NewSyntax(t *testing.T) {
|
|||
name: "byte = byte",
|
||||
line: "a = b",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("a", "", compiler.KindByte, 0)
|
||||
st.AddVar("b", "", compiler.KindByte, 10)
|
||||
st.AddVar("a", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
st.AddVar("b", "", compiler.KindByte, 10, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda b",
|
||||
|
|
@ -240,7 +240,7 @@ func TestLetCommand_NewSyntax(t *testing.T) {
|
|||
name: "byte = literal",
|
||||
line: "a = 100",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("a", "", compiler.KindByte, 0)
|
||||
st.AddVar("a", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda #$64",
|
||||
|
|
@ -251,8 +251,8 @@ func TestLetCommand_NewSyntax(t *testing.T) {
|
|||
name: "word = word",
|
||||
line: "x = y",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("x", "", compiler.KindWord, 0)
|
||||
st.AddVar("y", "", compiler.KindWord, 0x1234)
|
||||
st.AddVar("x", "", compiler.KindWord, 0, "test.c65", 1)
|
||||
st.AddVar("y", "", compiler.KindWord, 0x1234, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda y",
|
||||
|
|
@ -265,7 +265,7 @@ func TestLetCommand_NewSyntax(t *testing.T) {
|
|||
name: "word = literal",
|
||||
line: "x = $1234",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("x", "", compiler.KindWord, 0)
|
||||
st.AddVar("x", "", compiler.KindWord, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda #$34",
|
||||
|
|
@ -278,8 +278,8 @@ func TestLetCommand_NewSyntax(t *testing.T) {
|
|||
name: "word = byte (zero-extend)",
|
||||
line: "x = b",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("x", "", compiler.KindWord, 0)
|
||||
st.AddVar("b", "", compiler.KindByte, 100)
|
||||
st.AddVar("x", "", compiler.KindWord, 0, "test.c65", 1)
|
||||
st.AddVar("b", "", compiler.KindByte, 100, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda b",
|
||||
|
|
@ -292,8 +292,8 @@ func TestLetCommand_NewSyntax(t *testing.T) {
|
|||
name: "byte = word (take low byte)",
|
||||
line: "b = x",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("b", "", compiler.KindByte, 0)
|
||||
st.AddVar("x", "", compiler.KindWord, 0x1234)
|
||||
st.AddVar("b", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
st.AddVar("x", "", compiler.KindWord, 0x1234, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda x",
|
||||
|
|
@ -304,7 +304,7 @@ func TestLetCommand_NewSyntax(t *testing.T) {
|
|||
name: "word = 0 (optimization)",
|
||||
line: "x = 0",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("x", "", compiler.KindWord, 0)
|
||||
st.AddVar("x", "", compiler.KindWord, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda #$00",
|
||||
|
|
@ -316,7 +316,7 @@ func TestLetCommand_NewSyntax(t *testing.T) {
|
|||
name: "word = $FFFF (optimization)",
|
||||
line: "x = 65535",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("x", "", compiler.KindWord, 0)
|
||||
st.AddVar("x", "", compiler.KindWord, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda #$ff",
|
||||
|
|
@ -328,7 +328,7 @@ func TestLetCommand_NewSyntax(t *testing.T) {
|
|||
name: "word = $0102 (different bytes, no optimization)",
|
||||
line: "x = $0102",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("x", "", compiler.KindWord, 0)
|
||||
st.AddVar("x", "", compiler.KindWord, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda #$02",
|
||||
|
|
@ -341,8 +341,8 @@ func TestLetCommand_NewSyntax(t *testing.T) {
|
|||
name: "using constant",
|
||||
line: "a = MAXVAL",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("a", "", compiler.KindByte, 0)
|
||||
st.AddConst("MAXVAL", "", compiler.KindByte, 255)
|
||||
st.AddVar("a", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
st.AddConst("MAXVAL", "", compiler.KindByte, 255, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda #$ff",
|
||||
|
|
@ -353,7 +353,7 @@ func TestLetCommand_NewSyntax(t *testing.T) {
|
|||
name: "expression with constant",
|
||||
line: "a = 10+5",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("a", "", compiler.KindByte, 0)
|
||||
st.AddVar("a", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda #$0f",
|
||||
|
|
@ -364,7 +364,7 @@ func TestLetCommand_NewSyntax(t *testing.T) {
|
|||
name: "error: unknown destination",
|
||||
line: "unknown = a",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("a", "", compiler.KindByte, 0)
|
||||
st.AddVar("a", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
|
|
@ -372,7 +372,7 @@ func TestLetCommand_NewSyntax(t *testing.T) {
|
|||
name: "error: cannot assign to constant",
|
||||
line: "MAXVAL = 100",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddConst("MAXVAL", "", compiler.KindByte, 255)
|
||||
st.AddConst("MAXVAL", "", compiler.KindByte, 255, "test.c65", 1)
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -68,13 +68,7 @@ func (c *OrCommand) Interpret(line preproc.Line, ctx *compiler.CompilerContext)
|
|||
scope := ctx.CurrentScope()
|
||||
|
||||
// Create constant lookup function
|
||||
constLookup := func(name string) (int64, bool) {
|
||||
sym := ctx.SymbolTable.Lookup(name, scope)
|
||||
if sym != nil && sym.IsConst() {
|
||||
return int64(sym.Value), true
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
constLookup := ctx.SymbolTable.ConstantLookupFunc(scope)
|
||||
|
||||
// Determine syntax and parse accordingly
|
||||
if strings.ToUpper(params[0]) == "OR" {
|
||||
|
|
|
|||
|
|
@ -48,9 +48,9 @@ func TestOrCommand_OldSyntax(t *testing.T) {
|
|||
name: "byte OR byte -> byte (variables)",
|
||||
line: "OR a WITH b GIVING result",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("a", "", compiler.KindByte, 0xF0)
|
||||
st.AddVar("b", "", compiler.KindByte, 0x0F)
|
||||
st.AddVar("result", "", compiler.KindByte, 0)
|
||||
st.AddVar("a", "", compiler.KindByte, 0xF0, "test.c65", 1)
|
||||
st.AddVar("b", "", compiler.KindByte, 0x0F, "test.c65", 1)
|
||||
st.AddVar("result", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda a",
|
||||
|
|
@ -62,9 +62,9 @@ func TestOrCommand_OldSyntax(t *testing.T) {
|
|||
name: "byte OR byte -> word",
|
||||
line: "OR a WITH b GIVING result",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("a", "", compiler.KindByte, 0xF0)
|
||||
st.AddVar("b", "", compiler.KindByte, 0x0F)
|
||||
st.AddVar("result", "", compiler.KindWord, 0)
|
||||
st.AddVar("a", "", compiler.KindByte, 0xF0, "test.c65", 1)
|
||||
st.AddVar("b", "", compiler.KindByte, 0x0F, "test.c65", 1)
|
||||
st.AddVar("result", "", compiler.KindWord, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda a",
|
||||
|
|
@ -79,9 +79,9 @@ func TestOrCommand_OldSyntax(t *testing.T) {
|
|||
name: "word OR word -> word",
|
||||
line: "OR x WITH y GIVING result",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("x", "", compiler.KindWord, 0x1234)
|
||||
st.AddVar("y", "", compiler.KindWord, 0x0F0F)
|
||||
st.AddVar("result", "", compiler.KindWord, 0)
|
||||
st.AddVar("x", "", compiler.KindWord, 0x1234, "test.c65", 1)
|
||||
st.AddVar("y", "", compiler.KindWord, 0x0F0F, "test.c65", 1)
|
||||
st.AddVar("result", "", compiler.KindWord, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda x",
|
||||
|
|
@ -96,8 +96,8 @@ func TestOrCommand_OldSyntax(t *testing.T) {
|
|||
name: "byte OR literal -> byte",
|
||||
line: "OR a WITH $0F GIVING result",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("a", "", compiler.KindByte, 0xF0)
|
||||
st.AddVar("result", "", compiler.KindByte, 0)
|
||||
st.AddVar("a", "", compiler.KindByte, 0xF0, "test.c65", 1)
|
||||
st.AddVar("result", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda a",
|
||||
|
|
@ -109,8 +109,8 @@ func TestOrCommand_OldSyntax(t *testing.T) {
|
|||
name: "literal OR byte -> byte",
|
||||
line: "OR 15 WITH b GIVING result",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("b", "", compiler.KindByte, 0xF0)
|
||||
st.AddVar("result", "", compiler.KindByte, 0)
|
||||
st.AddVar("b", "", compiler.KindByte, 0xF0, "test.c65", 1)
|
||||
st.AddVar("result", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda #$0f",
|
||||
|
|
@ -122,7 +122,7 @@ func TestOrCommand_OldSyntax(t *testing.T) {
|
|||
name: "constant folding: 15 OR 240 -> byte",
|
||||
line: "OR 15 WITH 240 GIVING result",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("result", "", compiler.KindByte, 0)
|
||||
st.AddVar("result", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda #$ff",
|
||||
|
|
@ -133,7 +133,7 @@ func TestOrCommand_OldSyntax(t *testing.T) {
|
|||
name: "constant folding: $00F0 OR $0F00 -> word",
|
||||
line: "OR $00F0 WITH $0F00 GIVING result",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("result", "", compiler.KindWord, 0)
|
||||
st.AddVar("result", "", compiler.KindWord, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda #$f0",
|
||||
|
|
@ -146,9 +146,9 @@ func TestOrCommand_OldSyntax(t *testing.T) {
|
|||
name: "arrow syntax",
|
||||
line: "OR a WITH b -> result",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("a", "", compiler.KindByte, 0)
|
||||
st.AddVar("b", "", compiler.KindByte, 0)
|
||||
st.AddVar("result", "", compiler.KindByte, 0)
|
||||
st.AddVar("a", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
st.AddVar("b", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
st.AddVar("result", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda a",
|
||||
|
|
@ -160,9 +160,9 @@ func TestOrCommand_OldSyntax(t *testing.T) {
|
|||
name: "word OR byte -> byte",
|
||||
line: "OR wval WITH bval GIVING result",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("wval", "", compiler.KindWord, 0x1234)
|
||||
st.AddVar("bval", "", compiler.KindByte, 0x0F)
|
||||
st.AddVar("result", "", compiler.KindByte, 0)
|
||||
st.AddVar("wval", "", compiler.KindWord, 0x1234, "test.c65", 1)
|
||||
st.AddVar("bval", "", compiler.KindByte, 0x0F, "test.c65", 1)
|
||||
st.AddVar("result", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda wval",
|
||||
|
|
@ -174,9 +174,9 @@ func TestOrCommand_OldSyntax(t *testing.T) {
|
|||
name: "word OR byte -> word",
|
||||
line: "OR wval WITH bval GIVING result",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("wval", "", compiler.KindWord, 0x1234)
|
||||
st.AddVar("bval", "", compiler.KindByte, 0x0F)
|
||||
st.AddVar("result", "", compiler.KindWord, 0)
|
||||
st.AddVar("wval", "", compiler.KindWord, 0x1234, "test.c65", 1)
|
||||
st.AddVar("bval", "", compiler.KindByte, 0x0F, "test.c65", 1)
|
||||
st.AddVar("result", "", compiler.KindWord, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda wval",
|
||||
|
|
@ -191,8 +191,8 @@ func TestOrCommand_OldSyntax(t *testing.T) {
|
|||
name: "error: unknown destination variable",
|
||||
line: "OR a WITH b GIVING unknown",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("a", "", compiler.KindByte, 0)
|
||||
st.AddVar("b", "", compiler.KindByte, 0)
|
||||
st.AddVar("a", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
st.AddVar("b", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
|
|
@ -200,9 +200,9 @@ func TestOrCommand_OldSyntax(t *testing.T) {
|
|||
name: "error: wrong separator",
|
||||
line: "OR a TO b GIVING result",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("a", "", compiler.KindByte, 0)
|
||||
st.AddVar("b", "", compiler.KindByte, 0)
|
||||
st.AddVar("result", "", compiler.KindByte, 0)
|
||||
st.AddVar("a", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
st.AddVar("b", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
st.AddVar("result", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
|
|
@ -210,9 +210,9 @@ func TestOrCommand_OldSyntax(t *testing.T) {
|
|||
name: "error: cannot assign to constant",
|
||||
line: "OR a WITH b GIVING MAXVAL",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("a", "", compiler.KindByte, 0)
|
||||
st.AddVar("b", "", compiler.KindByte, 0)
|
||||
st.AddConst("MAXVAL", "", compiler.KindByte, 255)
|
||||
st.AddVar("a", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
st.AddVar("b", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
st.AddConst("MAXVAL", "", compiler.KindByte, 255, "test.c65", 1)
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
|
|
@ -263,9 +263,9 @@ func TestOrCommand_NewSyntax(t *testing.T) {
|
|||
name: "byte | byte -> byte",
|
||||
line: "result = a | b",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("a", "", compiler.KindByte, 0xF0)
|
||||
st.AddVar("b", "", compiler.KindByte, 0x0F)
|
||||
st.AddVar("result", "", compiler.KindByte, 0)
|
||||
st.AddVar("a", "", compiler.KindByte, 0xF0, "test.c65", 1)
|
||||
st.AddVar("b", "", compiler.KindByte, 0x0F, "test.c65", 1)
|
||||
st.AddVar("result", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda a",
|
||||
|
|
@ -277,9 +277,9 @@ func TestOrCommand_NewSyntax(t *testing.T) {
|
|||
name: "byte | byte -> word",
|
||||
line: "result = a | b",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("a", "", compiler.KindByte, 0xF0)
|
||||
st.AddVar("b", "", compiler.KindByte, 0x0F)
|
||||
st.AddVar("result", "", compiler.KindWord, 0)
|
||||
st.AddVar("a", "", compiler.KindByte, 0xF0, "test.c65", 1)
|
||||
st.AddVar("b", "", compiler.KindByte, 0x0F, "test.c65", 1)
|
||||
st.AddVar("result", "", compiler.KindWord, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda a",
|
||||
|
|
@ -294,9 +294,9 @@ func TestOrCommand_NewSyntax(t *testing.T) {
|
|||
name: "word | word -> word",
|
||||
line: "result = x | y",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("x", "", compiler.KindWord, 0x1234)
|
||||
st.AddVar("y", "", compiler.KindWord, 0x0F0F)
|
||||
st.AddVar("result", "", compiler.KindWord, 0)
|
||||
st.AddVar("x", "", compiler.KindWord, 0x1234, "test.c65", 1)
|
||||
st.AddVar("y", "", compiler.KindWord, 0x0F0F, "test.c65", 1)
|
||||
st.AddVar("result", "", compiler.KindWord, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda x",
|
||||
|
|
@ -311,8 +311,8 @@ func TestOrCommand_NewSyntax(t *testing.T) {
|
|||
name: "variable | literal",
|
||||
line: "result = a | $0F",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("a", "", compiler.KindByte, 0xF0)
|
||||
st.AddVar("result", "", compiler.KindByte, 0)
|
||||
st.AddVar("a", "", compiler.KindByte, 0xF0, "test.c65", 1)
|
||||
st.AddVar("result", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda a",
|
||||
|
|
@ -324,7 +324,7 @@ func TestOrCommand_NewSyntax(t *testing.T) {
|
|||
name: "constant folding",
|
||||
line: "result = 15 | 240",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("result", "", compiler.KindByte, 0)
|
||||
st.AddVar("result", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda #$ff",
|
||||
|
|
@ -335,7 +335,7 @@ func TestOrCommand_NewSyntax(t *testing.T) {
|
|||
name: "constant folding word",
|
||||
line: "result = $00F0 | $0F00",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("result", "", compiler.KindWord, 0)
|
||||
st.AddVar("result", "", compiler.KindWord, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda #$f0",
|
||||
|
|
@ -348,9 +348,9 @@ func TestOrCommand_NewSyntax(t *testing.T) {
|
|||
name: "using constant in expression",
|
||||
line: "result = a | BITS",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("a", "", compiler.KindByte, 0xF0)
|
||||
st.AddConst("BITS", "", compiler.KindByte, 0x0F)
|
||||
st.AddVar("result", "", compiler.KindByte, 0)
|
||||
st.AddVar("a", "", compiler.KindByte, 0xF0, "test.c65", 1)
|
||||
st.AddConst("BITS", "", compiler.KindByte, 0x0F, "test.c65", 1)
|
||||
st.AddVar("result", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda a",
|
||||
|
|
@ -362,8 +362,8 @@ func TestOrCommand_NewSyntax(t *testing.T) {
|
|||
name: "error: unknown destination",
|
||||
line: "unknown = a | b",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("a", "", compiler.KindByte, 0)
|
||||
st.AddVar("b", "", compiler.KindByte, 0)
|
||||
st.AddVar("a", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
st.AddVar("b", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
|
|
@ -371,9 +371,9 @@ func TestOrCommand_NewSyntax(t *testing.T) {
|
|||
name: "error: wrong operator",
|
||||
line: "result = a + b",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("a", "", compiler.KindByte, 0)
|
||||
st.AddVar("b", "", compiler.KindByte, 0)
|
||||
st.AddVar("result", "", compiler.KindByte, 0)
|
||||
st.AddVar("a", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
st.AddVar("b", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
st.AddVar("result", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -36,13 +36,7 @@ func (c *OriginCommand) Interpret(line preproc.Line, ctx *compiler.CompilerConte
|
|||
}
|
||||
|
||||
scope := ctx.CurrentScope()
|
||||
constLookup := func(name string) (int64, bool) {
|
||||
sym := ctx.SymbolTable.Lookup(name, scope)
|
||||
if sym != nil && sym.IsConst() {
|
||||
return int64(sym.Value), true
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
constLookup := ctx.SymbolTable.ConstantLookupFunc(scope)
|
||||
|
||||
val, err := utils.EvaluateExpression(params[1], constLookup)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -115,13 +115,7 @@ func (c *PeekCommand) Interpret(line preproc.Line, ctx *compiler.CompilerContext
|
|||
// Parse address - may have [offset]
|
||||
baseAddr, offsetParam := parseOffset(addrParam)
|
||||
|
||||
constLookup := func(name string) (int64, bool) {
|
||||
sym := ctx.SymbolTable.Lookup(name, scope)
|
||||
if sym != nil && sym.IsConst() {
|
||||
return int64(sym.Value), true
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
constLookup := ctx.SymbolTable.ConstantLookupFunc(scope)
|
||||
|
||||
// Try to parse base address
|
||||
varName, varKind, value, isVar, err := compiler.ParseOperandParam(
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ func TestPeekOldSyntax(t *testing.T) {
|
|||
name: "peek constant address to byte",
|
||||
line: "PEEK 1024 GIVING result",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("result", "", compiler.KindByte, 0)
|
||||
st.AddVar("result", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda 1024",
|
||||
|
|
@ -30,8 +30,8 @@ func TestPeekOldSyntax(t *testing.T) {
|
|||
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)
|
||||
st.AddAbsolute("ptr", "", compiler.KindWord, 0x80, "test.c65", 1)
|
||||
st.AddVar("result", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tldy #0",
|
||||
|
|
@ -43,8 +43,8 @@ func TestPeekOldSyntax(t *testing.T) {
|
|||
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)
|
||||
st.AddAbsolute("ptr", "", compiler.KindWord, 0x80, "test.c65", 1)
|
||||
st.AddVar("result", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tldy #5",
|
||||
|
|
@ -56,7 +56,7 @@ func TestPeekOldSyntax(t *testing.T) {
|
|||
name: "peek with -> separator",
|
||||
line: "PEEK 2048 -> result",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("result", "", compiler.KindByte, 0)
|
||||
st.AddVar("result", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda 2048",
|
||||
|
|
@ -107,7 +107,7 @@ func TestPeekNewSyntax(t *testing.T) {
|
|||
name: "new syntax constant address to byte",
|
||||
line: "result = PEEK 1024",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("result", "", compiler.KindByte, 0)
|
||||
st.AddVar("result", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda 1024",
|
||||
|
|
@ -118,8 +118,8 @@ func TestPeekNewSyntax(t *testing.T) {
|
|||
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)
|
||||
st.AddAbsolute("ptr", "", compiler.KindWord, 0x80, "test.c65", 1)
|
||||
st.AddVar("result", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tldy #0",
|
||||
|
|
@ -131,8 +131,8 @@ func TestPeekNewSyntax(t *testing.T) {
|
|||
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)
|
||||
st.AddAbsolute("ptr", "", compiler.KindWord, 0x80, "test.c65", 1)
|
||||
st.AddVar("result", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tldy #10",
|
||||
|
|
@ -144,9 +144,9 @@ func TestPeekNewSyntax(t *testing.T) {
|
|||
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)
|
||||
st.AddAbsolute("ptr", "", compiler.KindWord, 0x80, "test.c65", 1)
|
||||
st.AddVar("idx", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
st.AddVar("result", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tldy idx",
|
||||
|
|
@ -158,7 +158,7 @@ func TestPeekNewSyntax(t *testing.T) {
|
|||
name: "new syntax to word destination",
|
||||
line: "result = PEEK 2048",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("result", "", compiler.KindWord, 0)
|
||||
st.AddVar("result", "", compiler.KindWord, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda 2048",
|
||||
|
|
@ -211,7 +211,7 @@ func TestPeekWNewSyntax(t *testing.T) {
|
|||
name: "new syntax constant address",
|
||||
line: "result = PEEKW 1024",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("result", "", compiler.KindWord, 0)
|
||||
st.AddVar("result", "", compiler.KindWord, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda 1024",
|
||||
|
|
@ -224,8 +224,8 @@ func TestPeekWNewSyntax(t *testing.T) {
|
|||
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)
|
||||
st.AddAbsolute("ptr", "", compiler.KindWord, 0x80, "test.c65", 1)
|
||||
st.AddVar("result", "", compiler.KindWord, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tldy #0",
|
||||
|
|
@ -240,8 +240,8 @@ func TestPeekWNewSyntax(t *testing.T) {
|
|||
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)
|
||||
st.AddAbsolute("ptr", "", compiler.KindWord, 0x80, "test.c65", 1)
|
||||
st.AddVar("result", "", compiler.KindWord, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tldy #8",
|
||||
|
|
@ -303,7 +303,7 @@ func TestPeekErrors(t *testing.T) {
|
|||
name: "constant destination",
|
||||
line: "PEEK 1024 GIVING CONST",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddConst("CONST", "", compiler.KindByte, 100)
|
||||
st.AddConst("CONST", "", compiler.KindByte, 100, "test.c65", 1)
|
||||
},
|
||||
wantError: "cannot PEEK into constant",
|
||||
},
|
||||
|
|
@ -318,7 +318,7 @@ func TestPeekErrors(t *testing.T) {
|
|||
name: "new syntax constant destination",
|
||||
line: "CONST = PEEK 1024",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddConst("CONST", "", compiler.KindByte, 100)
|
||||
st.AddConst("CONST", "", compiler.KindByte, 100, "test.c65", 1)
|
||||
},
|
||||
wantError: "cannot PEEK into constant",
|
||||
},
|
||||
|
|
@ -326,8 +326,8 @@ func TestPeekErrors(t *testing.T) {
|
|||
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)
|
||||
st.AddVar("addr", "", compiler.KindWord, 0, "test.c65", 1)
|
||||
st.AddVar("result", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
wantError: "offset",
|
||||
},
|
||||
|
|
@ -335,8 +335,8 @@ func TestPeekErrors(t *testing.T) {
|
|||
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)
|
||||
st.AddVar("addr", "", compiler.KindWord, 0, "test.c65", 1)
|
||||
st.AddVar("result", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
wantError: "offset",
|
||||
},
|
||||
|
|
@ -377,7 +377,7 @@ func TestPeekWErrors(t *testing.T) {
|
|||
name: "byte destination",
|
||||
line: "PEEKW 1024 GIVING result",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("result", "", compiler.KindByte, 0)
|
||||
st.AddVar("result", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
wantError: "must be word type",
|
||||
},
|
||||
|
|
@ -385,7 +385,7 @@ func TestPeekWErrors(t *testing.T) {
|
|||
name: "new syntax byte destination",
|
||||
line: "result = PEEKW 1024",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("result", "", compiler.KindByte, 0)
|
||||
st.AddVar("result", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
wantError: "must be word type",
|
||||
},
|
||||
|
|
|
|||
|
|
@ -116,13 +116,7 @@ func (c *PeekWCommand) Interpret(line preproc.Line, ctx *compiler.CompilerContex
|
|||
// Parse address - may have [offset]
|
||||
baseAddr, offsetParam := parseOffsetW(addrParam)
|
||||
|
||||
constLookup := func(name string) (int64, bool) {
|
||||
sym := ctx.SymbolTable.Lookup(name, scope)
|
||||
if sym != nil && sym.IsConst() {
|
||||
return int64(sym.Value), true
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
constLookup := ctx.SymbolTable.ConstantLookupFunc(scope)
|
||||
|
||||
// Try to parse base address
|
||||
varName, varKind, value, isVar, err := compiler.ParseOperandParam(
|
||||
|
|
|
|||
|
|
@ -74,13 +74,7 @@ func (c *PointerCommand) Interpret(line preproc.Line, ctx *compiler.CompilerCont
|
|||
// Parse target (param 4)
|
||||
targetParam := params[3]
|
||||
|
||||
constLookup := func(name string) (int64, bool) {
|
||||
sym := ctx.SymbolTable.Lookup(name, scope)
|
||||
if sym != nil && sym.IsConst() {
|
||||
return int64(sym.Value), true
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
constLookup := ctx.SymbolTable.ConstantLookupFunc(scope)
|
||||
|
||||
// Try ParseOperandParam - handles variables, constants, expressions
|
||||
varName, _, value, isVar, err := compiler.ParseOperandParam(
|
||||
|
|
|
|||
|
|
@ -83,13 +83,7 @@ func (c *PokeCommand) Interpret(line preproc.Line, ctx *compiler.CompilerContext
|
|||
addrParam := params[1]
|
||||
baseAddr, offsetParam := parsePOKEOffset(addrParam)
|
||||
|
||||
constLookup := func(name string) (int64, bool) {
|
||||
sym := ctx.SymbolTable.Lookup(name, scope)
|
||||
if sym != nil && sym.IsConst() {
|
||||
return int64(sym.Value), true
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
constLookup := ctx.SymbolTable.ConstantLookupFunc(scope)
|
||||
|
||||
// Try to parse base address
|
||||
varName, varKind, value, isVar, err := compiler.ParseOperandParam(
|
||||
|
|
|
|||
|
|
@ -82,13 +82,7 @@ func (c *PokeWCommand) Interpret(line preproc.Line, ctx *compiler.CompilerContex
|
|||
addrParam := params[1]
|
||||
baseAddr, offsetParam := parsePOKEWOffset(addrParam)
|
||||
|
||||
constLookup := func(name string) (int64, bool) {
|
||||
sym := ctx.SymbolTable.Lookup(name, scope)
|
||||
if sym != nil && sym.IsConst() {
|
||||
return int64(sym.Value), true
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
constLookup := ctx.SymbolTable.ConstantLookupFunc(scope)
|
||||
|
||||
// Try to parse base address
|
||||
varName, varKind, value, isVar, err := compiler.ParseOperandParam(
|
||||
|
|
|
|||
|
|
@ -71,13 +71,7 @@ func (c *SubtractCommand) Interpret(line preproc.Line, ctx *compiler.CompilerCon
|
|||
scope := ctx.CurrentScope()
|
||||
|
||||
// Create constant lookup function
|
||||
constLookup := func(name string) (int64, bool) {
|
||||
sym := ctx.SymbolTable.Lookup(name, scope)
|
||||
if sym != nil && sym.IsConst() {
|
||||
return int64(sym.Value), true
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
constLookup := ctx.SymbolTable.ConstantLookupFunc(scope)
|
||||
|
||||
// Determine syntax and parse accordingly
|
||||
kw := strings.ToUpper(params[0])
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ func TestSubtractCommand_OldSyntax_FROM(t *testing.T) {
|
|||
name: "SUBTRACT a FROM b (means b-a)",
|
||||
line: "SUBTRACT 5 FROM 10 GIVING result",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("result", "", compiler.KindByte, 0)
|
||||
st.AddVar("result", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda #$05",
|
||||
|
|
@ -61,9 +61,9 @@ func TestSubtractCommand_OldSyntax_FROM(t *testing.T) {
|
|||
name: "SUBTRACT byte FROM byte -> byte (variables)",
|
||||
line: "SUBTRACT a FROM b GIVING result",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("a", "", compiler.KindByte, 10)
|
||||
st.AddVar("b", "", compiler.KindByte, 20)
|
||||
st.AddVar("result", "", compiler.KindByte, 0)
|
||||
st.AddVar("a", "", compiler.KindByte, 10, "test.c65", 1)
|
||||
st.AddVar("b", "", compiler.KindByte, 20, "test.c65", 1)
|
||||
st.AddVar("result", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tsec",
|
||||
|
|
@ -76,9 +76,9 @@ func TestSubtractCommand_OldSyntax_FROM(t *testing.T) {
|
|||
name: "SUBT a FROM b -> c with arrow",
|
||||
line: "SUBT a FROM b -> result",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("a", "", compiler.KindByte, 10)
|
||||
st.AddVar("b", "", compiler.KindByte, 20)
|
||||
st.AddVar("result", "", compiler.KindByte, 0)
|
||||
st.AddVar("a", "", compiler.KindByte, 10, "test.c65", 1)
|
||||
st.AddVar("b", "", compiler.KindByte, 20, "test.c65", 1)
|
||||
st.AddVar("result", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tsec",
|
||||
|
|
@ -91,8 +91,8 @@ func TestSubtractCommand_OldSyntax_FROM(t *testing.T) {
|
|||
name: "SUBTRACT literal FROM variable",
|
||||
line: "SUBTRACT 10 FROM a GIVING result",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("a", "", compiler.KindByte, 20)
|
||||
st.AddVar("result", "", compiler.KindByte, 0)
|
||||
st.AddVar("a", "", compiler.KindByte, 20, "test.c65", 1)
|
||||
st.AddVar("result", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tsec",
|
||||
|
|
@ -105,9 +105,9 @@ func TestSubtractCommand_OldSyntax_FROM(t *testing.T) {
|
|||
name: "word FROM word -> word",
|
||||
line: "SUBTRACT x FROM y GIVING result",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("x", "", compiler.KindWord, 0x1000)
|
||||
st.AddVar("y", "", compiler.KindWord, 0x2000)
|
||||
st.AddVar("result", "", compiler.KindWord, 0)
|
||||
st.AddVar("x", "", compiler.KindWord, 0x1000, "test.c65", 1)
|
||||
st.AddVar("y", "", compiler.KindWord, 0x2000, "test.c65", 1)
|
||||
st.AddVar("result", "", compiler.KindWord, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tsec",
|
||||
|
|
@ -166,7 +166,7 @@ func TestSubtractCommand_OldSyntax_Minus(t *testing.T) {
|
|||
name: "SUBT a - b (means a-b, no swap)",
|
||||
line: "SUBT 10 - 5 GIVING result",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("result", "", compiler.KindByte, 0)
|
||||
st.AddVar("result", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda #$05",
|
||||
|
|
@ -177,9 +177,9 @@ func TestSubtractCommand_OldSyntax_Minus(t *testing.T) {
|
|||
name: "SUBT byte - byte -> byte (variables)",
|
||||
line: "SUBT a - b -> result",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("a", "", compiler.KindByte, 20)
|
||||
st.AddVar("b", "", compiler.KindByte, 10)
|
||||
st.AddVar("result", "", compiler.KindByte, 0)
|
||||
st.AddVar("a", "", compiler.KindByte, 20, "test.c65", 1)
|
||||
st.AddVar("b", "", compiler.KindByte, 10, "test.c65", 1)
|
||||
st.AddVar("result", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tsec",
|
||||
|
|
@ -192,9 +192,9 @@ func TestSubtractCommand_OldSyntax_Minus(t *testing.T) {
|
|||
name: "SUBTRACT a - b GIVING c",
|
||||
line: "SUBTRACT a - b GIVING result",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("a", "", compiler.KindByte, 20)
|
||||
st.AddVar("b", "", compiler.KindByte, 10)
|
||||
st.AddVar("result", "", compiler.KindByte, 0)
|
||||
st.AddVar("a", "", compiler.KindByte, 20, "test.c65", 1)
|
||||
st.AddVar("b", "", compiler.KindByte, 10, "test.c65", 1)
|
||||
st.AddVar("result", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tsec",
|
||||
|
|
@ -207,8 +207,8 @@ func TestSubtractCommand_OldSyntax_Minus(t *testing.T) {
|
|||
name: "SUBT variable - literal",
|
||||
line: "SUBT a - 10 -> result",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("a", "", compiler.KindByte, 20)
|
||||
st.AddVar("result", "", compiler.KindByte, 0)
|
||||
st.AddVar("a", "", compiler.KindByte, 20, "test.c65", 1)
|
||||
st.AddVar("result", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tsec",
|
||||
|
|
@ -221,9 +221,9 @@ func TestSubtractCommand_OldSyntax_Minus(t *testing.T) {
|
|||
name: "word - word -> word",
|
||||
line: "SUBT x - y -> result",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("x", "", compiler.KindWord, 0x2000)
|
||||
st.AddVar("y", "", compiler.KindWord, 0x1000)
|
||||
st.AddVar("result", "", compiler.KindWord, 0)
|
||||
st.AddVar("x", "", compiler.KindWord, 0x2000, "test.c65", 1)
|
||||
st.AddVar("y", "", compiler.KindWord, 0x1000, "test.c65", 1)
|
||||
st.AddVar("result", "", compiler.KindWord, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tsec",
|
||||
|
|
@ -239,9 +239,9 @@ func TestSubtractCommand_OldSyntax_Minus(t *testing.T) {
|
|||
name: "byte - byte -> word",
|
||||
line: "SUBT a - b GIVING result",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("a", "", compiler.KindByte, 20)
|
||||
st.AddVar("b", "", compiler.KindByte, 10)
|
||||
st.AddVar("result", "", compiler.KindWord, 0)
|
||||
st.AddVar("a", "", compiler.KindByte, 20, "test.c65", 1)
|
||||
st.AddVar("b", "", compiler.KindByte, 10, "test.c65", 1)
|
||||
st.AddVar("result", "", compiler.KindWord, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tsec",
|
||||
|
|
@ -300,9 +300,9 @@ func TestSubtractCommand_NewSyntax(t *testing.T) {
|
|||
name: "byte - byte -> byte",
|
||||
line: "result = a - b",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("a", "", compiler.KindByte, 20)
|
||||
st.AddVar("b", "", compiler.KindByte, 10)
|
||||
st.AddVar("result", "", compiler.KindByte, 0)
|
||||
st.AddVar("a", "", compiler.KindByte, 20, "test.c65", 1)
|
||||
st.AddVar("b", "", compiler.KindByte, 10, "test.c65", 1)
|
||||
st.AddVar("result", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tsec",
|
||||
|
|
@ -315,9 +315,9 @@ func TestSubtractCommand_NewSyntax(t *testing.T) {
|
|||
name: "byte - byte -> word",
|
||||
line: "result = a - b",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("a", "", compiler.KindByte, 20)
|
||||
st.AddVar("b", "", compiler.KindByte, 10)
|
||||
st.AddVar("result", "", compiler.KindWord, 0)
|
||||
st.AddVar("a", "", compiler.KindByte, 20, "test.c65", 1)
|
||||
st.AddVar("b", "", compiler.KindByte, 10, "test.c65", 1)
|
||||
st.AddVar("result", "", compiler.KindWord, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tsec",
|
||||
|
|
@ -333,9 +333,9 @@ func TestSubtractCommand_NewSyntax(t *testing.T) {
|
|||
name: "word - word -> word",
|
||||
line: "result = x - y",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("x", "", compiler.KindWord, 0x2000)
|
||||
st.AddVar("y", "", compiler.KindWord, 0x1000)
|
||||
st.AddVar("result", "", compiler.KindWord, 0)
|
||||
st.AddVar("x", "", compiler.KindWord, 0x2000, "test.c65", 1)
|
||||
st.AddVar("y", "", compiler.KindWord, 0x1000, "test.c65", 1)
|
||||
st.AddVar("result", "", compiler.KindWord, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tsec",
|
||||
|
|
@ -351,8 +351,8 @@ func TestSubtractCommand_NewSyntax(t *testing.T) {
|
|||
name: "variable - literal",
|
||||
line: "result = a - 10",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("a", "", compiler.KindByte, 20)
|
||||
st.AddVar("result", "", compiler.KindByte, 0)
|
||||
st.AddVar("a", "", compiler.KindByte, 20, "test.c65", 1)
|
||||
st.AddVar("result", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tsec",
|
||||
|
|
@ -365,8 +365,8 @@ func TestSubtractCommand_NewSyntax(t *testing.T) {
|
|||
name: "literal - variable",
|
||||
line: "result = 20 - b",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("b", "", compiler.KindByte, 10)
|
||||
st.AddVar("result", "", compiler.KindByte, 0)
|
||||
st.AddVar("b", "", compiler.KindByte, 10, "test.c65", 1)
|
||||
st.AddVar("result", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tsec",
|
||||
|
|
@ -379,7 +379,7 @@ func TestSubtractCommand_NewSyntax(t *testing.T) {
|
|||
name: "constant folding",
|
||||
line: "result = 100 - 25",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("result", "", compiler.KindByte, 0)
|
||||
st.AddVar("result", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda #$4b",
|
||||
|
|
@ -390,7 +390,7 @@ func TestSubtractCommand_NewSyntax(t *testing.T) {
|
|||
name: "constant folding word",
|
||||
line: "result = $2000 - $1000",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("result", "", compiler.KindWord, 0)
|
||||
st.AddVar("result", "", compiler.KindWord, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda #$00",
|
||||
|
|
@ -403,9 +403,9 @@ func TestSubtractCommand_NewSyntax(t *testing.T) {
|
|||
name: "using constant in expression",
|
||||
line: "result = a - OFFSET",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("a", "", compiler.KindByte, 100)
|
||||
st.AddConst("OFFSET", "", compiler.KindByte, 10)
|
||||
st.AddVar("result", "", compiler.KindByte, 0)
|
||||
st.AddVar("a", "", compiler.KindByte, 100, "test.c65", 1)
|
||||
st.AddConst("OFFSET", "", compiler.KindByte, 10, "test.c65", 1)
|
||||
st.AddVar("result", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tsec",
|
||||
|
|
@ -418,9 +418,9 @@ func TestSubtractCommand_NewSyntax(t *testing.T) {
|
|||
name: "word - byte -> word",
|
||||
line: "result = wval - bval",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("wval", "", compiler.KindWord, 0x1234)
|
||||
st.AddVar("bval", "", compiler.KindByte, 0x10)
|
||||
st.AddVar("result", "", compiler.KindWord, 0)
|
||||
st.AddVar("wval", "", compiler.KindWord, 0x1234, "test.c65", 1)
|
||||
st.AddVar("bval", "", compiler.KindByte, 0x10, "test.c65", 1)
|
||||
st.AddVar("result", "", compiler.KindWord, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tsec",
|
||||
|
|
@ -436,8 +436,8 @@ func TestSubtractCommand_NewSyntax(t *testing.T) {
|
|||
name: "error: unknown destination",
|
||||
line: "unknown = a - b",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("a", "", compiler.KindByte, 0)
|
||||
st.AddVar("b", "", compiler.KindByte, 0)
|
||||
st.AddVar("a", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
st.AddVar("b", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
|
|
@ -445,9 +445,9 @@ func TestSubtractCommand_NewSyntax(t *testing.T) {
|
|||
name: "error: wrong operator",
|
||||
line: "result = a + b",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("a", "", compiler.KindByte, 0)
|
||||
st.AddVar("b", "", compiler.KindByte, 0)
|
||||
st.AddVar("result", "", compiler.KindByte, 0)
|
||||
st.AddVar("a", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
st.AddVar("b", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
st.AddVar("result", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
|
|
@ -455,9 +455,9 @@ func TestSubtractCommand_NewSyntax(t *testing.T) {
|
|||
name: "error: cannot assign to constant",
|
||||
line: "MAXVAL = a - b",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("a", "", compiler.KindByte, 0)
|
||||
st.AddVar("b", "", compiler.KindByte, 0)
|
||||
st.AddConst("MAXVAL", "", compiler.KindByte, 255)
|
||||
st.AddVar("a", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
st.AddVar("b", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
st.AddConst("MAXVAL", "", compiler.KindByte, 255, "test.c65", 1)
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -33,13 +33,7 @@ func (c *SwitchCommand) Interpret(line preproc.Line, ctx *compiler.CompilerConte
|
|||
}
|
||||
|
||||
scope := ctx.CurrentScope()
|
||||
constLookup := func(name string) (int64, bool) {
|
||||
sym := ctx.SymbolTable.Lookup(name, scope)
|
||||
if sym != nil && sym.IsConst() {
|
||||
return int64(sym.Value), true
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
constLookup := ctx.SymbolTable.ConstantLookupFunc(scope)
|
||||
|
||||
// Parse the switch variable/expression
|
||||
varName, varKind, value, isVar, err := compiler.ParseOperandParam(
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ func TestSwitchBasicByte(t *testing.T) {
|
|||
{
|
||||
name: "byte var with byte literal case",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("x", "", compiler.KindByte, 0)
|
||||
st.AddVar("x", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
caseValue: "10",
|
||||
wantSwitch: []string{},
|
||||
|
|
@ -96,7 +96,7 @@ func TestSwitchBasicByte(t *testing.T) {
|
|||
func TestSwitchMultipleCases(t *testing.T) {
|
||||
pragma := preproc.NewPragma()
|
||||
ctx := compiler.NewCompilerContext(pragma)
|
||||
ctx.SymbolTable.AddVar("x", "", compiler.KindByte, 0)
|
||||
ctx.SymbolTable.AddVar("x", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
|
||||
pragmaIdx := pragma.GetCurrentPragmaSetIndex()
|
||||
|
||||
|
|
@ -157,7 +157,7 @@ func TestSwitchMultipleCases(t *testing.T) {
|
|||
func TestSwitchWithDefault(t *testing.T) {
|
||||
pragma := preproc.NewPragma()
|
||||
ctx := compiler.NewCompilerContext(pragma)
|
||||
ctx.SymbolTable.AddVar("x", "", compiler.KindByte, 0)
|
||||
ctx.SymbolTable.AddVar("x", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
|
||||
pragmaIdx := pragma.GetCurrentPragmaSetIndex()
|
||||
|
||||
|
|
@ -198,7 +198,7 @@ func TestSwitchWithDefault(t *testing.T) {
|
|||
func TestSwitchCaseAfterDefault(t *testing.T) {
|
||||
pragma := preproc.NewPragma()
|
||||
ctx := compiler.NewCompilerContext(pragma)
|
||||
ctx.SymbolTable.AddVar("x", "", compiler.KindByte, 0)
|
||||
ctx.SymbolTable.AddVar("x", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
|
||||
pragmaIdx := pragma.GetCurrentPragmaSetIndex()
|
||||
|
||||
|
|
@ -234,7 +234,7 @@ func TestSwitchCaseAfterDefault(t *testing.T) {
|
|||
func TestSwitchMultipleDefaults(t *testing.T) {
|
||||
pragma := preproc.NewPragma()
|
||||
ctx := compiler.NewCompilerContext(pragma)
|
||||
ctx.SymbolTable.AddVar("x", "", compiler.KindByte, 0)
|
||||
ctx.SymbolTable.AddVar("x", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
|
||||
pragmaIdx := pragma.GetCurrentPragmaSetIndex()
|
||||
|
||||
|
|
@ -333,7 +333,7 @@ func TestSwitchWrongParamCount(t *testing.T) {
|
|||
func TestCaseWrongParamCount(t *testing.T) {
|
||||
pragma := preproc.NewPragma()
|
||||
ctx := compiler.NewCompilerContext(pragma)
|
||||
ctx.SymbolTable.AddVar("x", "", compiler.KindByte, 0)
|
||||
ctx.SymbolTable.AddVar("x", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
|
||||
pragmaIdx := pragma.GetCurrentPragmaSetIndex()
|
||||
|
||||
|
|
@ -358,7 +358,7 @@ func TestCaseWrongParamCount(t *testing.T) {
|
|||
func TestDefaultWrongParamCount(t *testing.T) {
|
||||
pragma := preproc.NewPragma()
|
||||
ctx := compiler.NewCompilerContext(pragma)
|
||||
ctx.SymbolTable.AddVar("x", "", compiler.KindByte, 0)
|
||||
ctx.SymbolTable.AddVar("x", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
|
||||
pragmaIdx := pragma.GetCurrentPragmaSetIndex()
|
||||
|
||||
|
|
@ -376,7 +376,7 @@ func TestDefaultWrongParamCount(t *testing.T) {
|
|||
func TestEndswitchWrongParamCount(t *testing.T) {
|
||||
pragma := preproc.NewPragma()
|
||||
ctx := compiler.NewCompilerContext(pragma)
|
||||
ctx.SymbolTable.AddVar("x", "", compiler.KindByte, 0)
|
||||
ctx.SymbolTable.AddVar("x", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
|
||||
pragmaIdx := pragma.GetCurrentPragmaSetIndex()
|
||||
|
||||
|
|
@ -394,7 +394,7 @@ func TestEndswitchWrongParamCount(t *testing.T) {
|
|||
func TestSwitchWordType(t *testing.T) {
|
||||
pragma := preproc.NewPragma()
|
||||
ctx := compiler.NewCompilerContext(pragma)
|
||||
ctx.SymbolTable.AddVar("big_val", "", compiler.KindWord, 0)
|
||||
ctx.SymbolTable.AddVar("big_val", "", compiler.KindWord, 0, "test.c65", 1)
|
||||
|
||||
pragmaIdx := pragma.GetCurrentPragmaSetIndex()
|
||||
|
||||
|
|
@ -434,8 +434,8 @@ func TestSwitchWordType(t *testing.T) {
|
|||
func TestSwitchWithConstant(t *testing.T) {
|
||||
pragma := preproc.NewPragma()
|
||||
ctx := compiler.NewCompilerContext(pragma)
|
||||
ctx.SymbolTable.AddConst("MAX_VAL", "", compiler.KindByte, 100)
|
||||
ctx.SymbolTable.AddVar("x", "", compiler.KindByte, 0)
|
||||
ctx.SymbolTable.AddConst("MAX_VAL", "", compiler.KindByte, 100, "test.c65", 1)
|
||||
ctx.SymbolTable.AddVar("x", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
|
||||
pragmaIdx := pragma.GetCurrentPragmaSetIndex()
|
||||
|
||||
|
|
@ -475,8 +475,8 @@ func TestSwitchWithConstant(t *testing.T) {
|
|||
func TestSwitchNested(t *testing.T) {
|
||||
pragma := preproc.NewPragma()
|
||||
ctx := compiler.NewCompilerContext(pragma)
|
||||
ctx.SymbolTable.AddVar("outer", "", compiler.KindByte, 0)
|
||||
ctx.SymbolTable.AddVar("inner", "", compiler.KindByte, 0)
|
||||
ctx.SymbolTable.AddVar("outer", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
ctx.SymbolTable.AddVar("inner", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
|
||||
pragmaIdx := pragma.GetCurrentPragmaSetIndex()
|
||||
|
||||
|
|
@ -546,7 +546,7 @@ func TestSwitchLongJump(t *testing.T) {
|
|||
pragma := preproc.NewPragma()
|
||||
pragma.AddPragma("_P_USE_LONG_JUMP", "1")
|
||||
ctx := compiler.NewCompilerContext(pragma)
|
||||
ctx.SymbolTable.AddVar("x", "", compiler.KindByte, 0)
|
||||
ctx.SymbolTable.AddVar("x", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
|
||||
pragmaIdx := pragma.GetCurrentPragmaSetIndex()
|
||||
|
||||
|
|
@ -600,7 +600,7 @@ func TestSwitchLongJump(t *testing.T) {
|
|||
// Verify the pattern is different from normal mode
|
||||
pragmaNormal := preproc.NewPragma()
|
||||
ctxNormal := compiler.NewCompilerContext(pragmaNormal)
|
||||
ctxNormal.SymbolTable.AddVar("x", "", compiler.KindByte, 0)
|
||||
ctxNormal.SymbolTable.AddVar("x", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
|
||||
pragmaIdxNormal := pragmaNormal.GetCurrentPragmaSetIndex()
|
||||
|
||||
|
|
@ -629,7 +629,7 @@ func TestSwitchLongJump(t *testing.T) {
|
|||
func TestSwitchOnConstant(t *testing.T) {
|
||||
pragma := preproc.NewPragma()
|
||||
ctx := compiler.NewCompilerContext(pragma)
|
||||
ctx.SymbolTable.AddConst("VALUE", "", compiler.KindByte, 5)
|
||||
ctx.SymbolTable.AddConst("VALUE", "", compiler.KindByte, 5, "test.c65", 1)
|
||||
|
||||
pragmaIdx := pragma.GetCurrentPragmaSetIndex()
|
||||
|
||||
|
|
@ -688,7 +688,7 @@ func TestSwitchOnConstant(t *testing.T) {
|
|||
func TestSwitchEmptyWithOnlyDefault(t *testing.T) {
|
||||
pragma := preproc.NewPragma()
|
||||
ctx := compiler.NewCompilerContext(pragma)
|
||||
ctx.SymbolTable.AddVar("x", "", compiler.KindByte, 0)
|
||||
ctx.SymbolTable.AddVar("x", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
|
||||
pragmaIdx := pragma.GetCurrentPragmaSetIndex()
|
||||
|
||||
|
|
@ -752,7 +752,7 @@ func TestSwitchComparisonTypes(t *testing.T) {
|
|||
t.Run(tt.name, func(t *testing.T) {
|
||||
pragma := preproc.NewPragma()
|
||||
ctx := compiler.NewCompilerContext(pragma)
|
||||
ctx.SymbolTable.AddVar("x", "", tt.varType, 0)
|
||||
ctx.SymbolTable.AddVar("x", "", tt.varType, 0, "test.c65", 1)
|
||||
|
||||
pragmaIdx := pragma.GetCurrentPragmaSetIndex()
|
||||
|
||||
|
|
@ -801,8 +801,8 @@ func TestSwitchWithVariableCase(t *testing.T) {
|
|||
t.Run(tt.name, func(t *testing.T) {
|
||||
pragma := preproc.NewPragma()
|
||||
ctx := compiler.NewCompilerContext(pragma)
|
||||
ctx.SymbolTable.AddVar("switch_var", "", tt.switchType, 0)
|
||||
ctx.SymbolTable.AddVar("case_var", "", tt.caseType, 0)
|
||||
ctx.SymbolTable.AddVar("switch_var", "", tt.switchType, 0, "test.c65", 1)
|
||||
ctx.SymbolTable.AddVar("case_var", "", tt.caseType, 0, "test.c65", 1)
|
||||
|
||||
pragmaIdx := pragma.GetCurrentPragmaSetIndex()
|
||||
|
||||
|
|
@ -859,7 +859,7 @@ func TestSwitchByteRangeValidation(t *testing.T) {
|
|||
t.Run(tt.name, func(t *testing.T) {
|
||||
pragma := preproc.NewPragma()
|
||||
ctx := compiler.NewCompilerContext(pragma)
|
||||
ctx.SymbolTable.AddVar("x", "", compiler.KindByte, 0)
|
||||
ctx.SymbolTable.AddVar("x", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
|
||||
pragmaIdx := pragma.GetCurrentPragmaSetIndex()
|
||||
|
||||
|
|
|
|||
|
|
@ -41,13 +41,7 @@ func (c *WhileCommand) Interpret(line preproc.Line, ctx *compiler.CompilerContex
|
|||
}
|
||||
|
||||
scope := ctx.CurrentScope()
|
||||
constLookup := func(name string) (int64, bool) {
|
||||
sym := ctx.SymbolTable.Lookup(name, scope)
|
||||
if sym != nil && sym.IsConst() {
|
||||
return int64(sym.Value), true
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
constLookup := ctx.SymbolTable.ConstantLookupFunc(scope)
|
||||
|
||||
// Parse param1
|
||||
varName, varKind, value, isVar, err := compiler.ParseOperandParam(
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ func TestWhileBasicEqual(t *testing.T) {
|
|||
name: "byte var == byte literal",
|
||||
whileLine: "WHILE x = 10",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("x", "", compiler.KindByte, 0)
|
||||
st.AddVar("x", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
wantWhile: []string{
|
||||
"_LOOPSTART1",
|
||||
|
|
@ -37,7 +37,7 @@ func TestWhileBasicEqual(t *testing.T) {
|
|||
name: "word var == word literal",
|
||||
whileLine: "WHILE x = 1000",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("x", "", compiler.KindWord, 0)
|
||||
st.AddVar("x", "", compiler.KindWord, 0, "test.c65", 1)
|
||||
},
|
||||
wantWhile: []string{
|
||||
"_LOOPSTART1",
|
||||
|
|
@ -125,7 +125,7 @@ func TestWhileAllOperators(t *testing.T) {
|
|||
t.Run(tt.name, func(t *testing.T) {
|
||||
pragma := preproc.NewPragma()
|
||||
ctx := compiler.NewCompilerContext(pragma)
|
||||
ctx.SymbolTable.AddVar("x", "", compiler.KindByte, 0)
|
||||
ctx.SymbolTable.AddVar("x", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
|
||||
cmd := &WhileCommand{}
|
||||
line := preproc.Line{
|
||||
|
|
@ -160,8 +160,8 @@ func TestWhileAllOperators(t *testing.T) {
|
|||
func TestWhileMixedTypes(t *testing.T) {
|
||||
pragma := preproc.NewPragma()
|
||||
ctx := compiler.NewCompilerContext(pragma)
|
||||
ctx.SymbolTable.AddVar("x", "", compiler.KindByte, 0)
|
||||
ctx.SymbolTable.AddVar("y", "", compiler.KindWord, 0)
|
||||
ctx.SymbolTable.AddVar("x", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
ctx.SymbolTable.AddVar("y", "", compiler.KindWord, 0, "test.c65", 1)
|
||||
|
||||
cmd := &WhileCommand{}
|
||||
line := preproc.Line{
|
||||
|
|
@ -194,7 +194,7 @@ func TestWhileMixedTypes(t *testing.T) {
|
|||
func TestWhileBreak(t *testing.T) {
|
||||
pragma := preproc.NewPragma()
|
||||
ctx := compiler.NewCompilerContext(pragma)
|
||||
ctx.SymbolTable.AddVar("x", "", compiler.KindByte, 0)
|
||||
ctx.SymbolTable.AddVar("x", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
|
||||
whileCmd := &WhileCommand{}
|
||||
breakCmd := &BreakCommand{}
|
||||
|
|
@ -274,8 +274,8 @@ func TestWendWithoutWhile(t *testing.T) {
|
|||
func TestWhileNested(t *testing.T) {
|
||||
pragma := preproc.NewPragma()
|
||||
ctx := compiler.NewCompilerContext(pragma)
|
||||
ctx.SymbolTable.AddVar("i", "", compiler.KindByte, 0)
|
||||
ctx.SymbolTable.AddVar("j", "", compiler.KindByte, 0)
|
||||
ctx.SymbolTable.AddVar("i", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
ctx.SymbolTable.AddVar("j", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
|
||||
pragmaIdx := pragma.GetCurrentPragmaSetIndex()
|
||||
|
||||
|
|
@ -316,7 +316,7 @@ func TestWhileLongJump(t *testing.T) {
|
|||
pragma := preproc.NewPragma()
|
||||
pragma.AddPragma("_P_USE_LONG_JUMP", "1")
|
||||
ctx := compiler.NewCompilerContext(pragma)
|
||||
ctx.SymbolTable.AddVar("x", "", compiler.KindByte, 0)
|
||||
ctx.SymbolTable.AddVar("x", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
|
||||
cmd := &WhileCommand{}
|
||||
line := preproc.Line{
|
||||
|
|
@ -349,8 +349,8 @@ func TestWhileLongJump(t *testing.T) {
|
|||
func TestWhileConstant(t *testing.T) {
|
||||
pragma := preproc.NewPragma()
|
||||
ctx := compiler.NewCompilerContext(pragma)
|
||||
ctx.SymbolTable.AddConst("MAX", "", compiler.KindByte, 100)
|
||||
ctx.SymbolTable.AddVar("x", "", compiler.KindByte, 0)
|
||||
ctx.SymbolTable.AddConst("MAX", "", compiler.KindByte, 100, "test.c65", 1)
|
||||
ctx.SymbolTable.AddVar("x", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
|
||||
cmd := &WhileCommand{}
|
||||
line := preproc.Line{
|
||||
|
|
|
|||
|
|
@ -57,13 +57,7 @@ func (c *WordCommand) Interpret(line preproc.Line, ctx *compiler.CompilerContext
|
|||
scope := ctx.FunctionHandler.CurrentFunction()
|
||||
|
||||
// Create constant lookup function
|
||||
constLookup := func(name string) (int64, bool) {
|
||||
sym := ctx.SymbolTable.Lookup(name, ctx.CurrentScope())
|
||||
if sym != nil && sym.IsConst() {
|
||||
return int64(sym.Value), true
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
constLookup := ctx.SymbolTable.ConstantLookupFunc(ctx.CurrentScope())
|
||||
|
||||
switch paramCount {
|
||||
case 2:
|
||||
|
|
@ -75,7 +69,7 @@ func (c *WordCommand) Interpret(line preproc.Line, ctx *compiler.CompilerContext
|
|||
return fmt.Errorf("WORD: invalid identifier %q", varName)
|
||||
}
|
||||
|
||||
err = ctx.SymbolTable.AddVar(varName, scope, compiler.KindWord, uint16(value))
|
||||
err = ctx.SymbolTable.AddVar(varName, scope, compiler.KindWord, uint16(value), line.Filename, line.LineNo)
|
||||
|
||||
case 4:
|
||||
// WORD varname = value OR WORD varname @ address OR WORD varname = "string"
|
||||
|
|
@ -102,7 +96,7 @@ func (c *WordCommand) Interpret(line preproc.Line, ctx *compiler.CompilerContext
|
|||
// Add string to constant string handler
|
||||
ctx.ConstStrHandler.AddConstStr(label, valueStr, false, pragmaSet)
|
||||
|
||||
err = ctx.SymbolTable.AddLabel(varName, scope, label)
|
||||
err = ctx.SymbolTable.AddLabel(varName, scope, label, line.Filename, line.LineNo)
|
||||
if err != nil {
|
||||
return fmt.Errorf("WORD: %w", err)
|
||||
}
|
||||
|
|
@ -129,7 +123,7 @@ func (c *WordCommand) Interpret(line preproc.Line, ctx *compiler.CompilerContext
|
|||
labelRef = sym.FullName()
|
||||
}
|
||||
|
||||
err = ctx.SymbolTable.AddLabel(varName, scope, labelRef)
|
||||
err = ctx.SymbolTable.AddLabel(varName, scope, labelRef, line.Filename, line.LineNo)
|
||||
if err != nil {
|
||||
return fmt.Errorf("WORD: %w", err)
|
||||
}
|
||||
|
|
@ -150,7 +144,7 @@ func (c *WordCommand) Interpret(line preproc.Line, ctx *compiler.CompilerContext
|
|||
if value < 0 || value > 65535 {
|
||||
return fmt.Errorf("WORD: init value %d out of range (0-65535)", value)
|
||||
}
|
||||
err = ctx.SymbolTable.AddVar(varName, scope, compiler.KindWord, uint16(value))
|
||||
err = ctx.SymbolTable.AddVar(varName, scope, compiler.KindWord, uint16(value), line.Filename, line.LineNo)
|
||||
|
||||
} else if operator == "@" {
|
||||
// WORD varname @ address
|
||||
|
|
@ -158,7 +152,7 @@ func (c *WordCommand) Interpret(line preproc.Line, ctx *compiler.CompilerContext
|
|||
return fmt.Errorf("WORD: absolute address $%X out of range", value)
|
||||
}
|
||||
c.isAbs = true
|
||||
err = ctx.SymbolTable.AddAbsolute(varName, scope, compiler.KindWord, uint16(value))
|
||||
err = ctx.SymbolTable.AddAbsolute(varName, scope, compiler.KindWord, uint16(value), line.Filename, line.LineNo)
|
||||
|
||||
} else {
|
||||
return fmt.Errorf("WORD: expected '=' or '@', got %q", operator)
|
||||
|
|
@ -193,7 +187,7 @@ func (c *WordCommand) Interpret(line preproc.Line, ctx *compiler.CompilerContext
|
|||
}
|
||||
|
||||
c.isConst = true
|
||||
err = ctx.SymbolTable.AddConst(varName, scope, compiler.KindWord, uint16(value))
|
||||
err = ctx.SymbolTable.AddConst(varName, scope, compiler.KindWord, uint16(value), line.Filename, line.LineNo)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -330,7 +330,7 @@ func TestWordCommand_Interpret(t *testing.T) {
|
|||
|
||||
// For duplicate test, pre-declare the variable
|
||||
if tt.name == "duplicate declaration" {
|
||||
ctx.SymbolTable.AddVar("x", "", compiler.KindWord, 0)
|
||||
ctx.SymbolTable.AddVar("x", "", compiler.KindWord, 0, "test.c65", 1)
|
||||
}
|
||||
|
||||
cmd := &WordCommand{}
|
||||
|
|
@ -396,8 +396,8 @@ func TestWordCommand_WithConstantExpression(t *testing.T) {
|
|||
ctx := compiler.NewCompilerContext(pragma)
|
||||
|
||||
// First, declare a constant
|
||||
ctx.SymbolTable.AddConst("MAXVAL", "", compiler.KindWord, 1000)
|
||||
ctx.SymbolTable.AddConst("OFFSET", "", compiler.KindWord, 500)
|
||||
ctx.SymbolTable.AddConst("MAXVAL", "", compiler.KindWord, 1000, "test.c65", 1)
|
||||
ctx.SymbolTable.AddConst("OFFSET", "", compiler.KindWord, 500, "test.c65", 1)
|
||||
|
||||
// Now declare a word using the constant in an expression
|
||||
cmd := &WordCommand{}
|
||||
|
|
@ -474,7 +474,7 @@ func TestWordCommand_LabelReference(t *testing.T) {
|
|||
|
||||
// Pre-declare existingVar for the reference test
|
||||
if tt.name == "word referencing another variable" {
|
||||
ctx.SymbolTable.AddVar("existingVar", "", compiler.KindWord, 0)
|
||||
ctx.SymbolTable.AddVar("existingVar", "", compiler.KindWord, 0, "test.c65", 1)
|
||||
}
|
||||
|
||||
cmd := &WordCommand{}
|
||||
|
|
@ -525,7 +525,7 @@ func TestWordCommand_LabelReferenceLocalExpansion(t *testing.T) {
|
|||
}
|
||||
|
||||
// Declare a local variable in function scope
|
||||
ctx.SymbolTable.AddVar("localBuffer", "myFunc", compiler.KindWord, 0)
|
||||
ctx.SymbolTable.AddVar("localBuffer", "myFunc", compiler.KindWord, 0, "test.c65", 1)
|
||||
|
||||
// Now declare another variable referencing the local
|
||||
cmd := &WordCommand{}
|
||||
|
|
|
|||
|
|
@ -68,13 +68,7 @@ func (c *XorCommand) Interpret(line preproc.Line, ctx *compiler.CompilerContext)
|
|||
scope := ctx.CurrentScope()
|
||||
|
||||
// Create constant lookup function
|
||||
constLookup := func(name string) (int64, bool) {
|
||||
sym := ctx.SymbolTable.Lookup(name, scope)
|
||||
if sym != nil && sym.IsConst() {
|
||||
return int64(sym.Value), true
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
constLookup := ctx.SymbolTable.ConstantLookupFunc(scope)
|
||||
|
||||
// Determine syntax and parse accordingly
|
||||
if strings.ToUpper(params[0]) == "XOR" {
|
||||
|
|
|
|||
|
|
@ -48,9 +48,9 @@ func TestXorCommand_OldSyntax(t *testing.T) {
|
|||
name: "byte XOR byte -> byte (variables)",
|
||||
line: "XOR a WITH b GIVING result",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("a", "", compiler.KindByte, 0xFF)
|
||||
st.AddVar("b", "", compiler.KindByte, 0xAA)
|
||||
st.AddVar("result", "", compiler.KindByte, 0)
|
||||
st.AddVar("a", "", compiler.KindByte, 0xFF, "test.c65", 1)
|
||||
st.AddVar("b", "", compiler.KindByte, 0xAA, "test.c65", 1)
|
||||
st.AddVar("result", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda a",
|
||||
|
|
@ -62,9 +62,9 @@ func TestXorCommand_OldSyntax(t *testing.T) {
|
|||
name: "byte XOR byte -> word",
|
||||
line: "XOR a WITH b GIVING result",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("a", "", compiler.KindByte, 0xFF)
|
||||
st.AddVar("b", "", compiler.KindByte, 0xAA)
|
||||
st.AddVar("result", "", compiler.KindWord, 0)
|
||||
st.AddVar("a", "", compiler.KindByte, 0xFF, "test.c65", 1)
|
||||
st.AddVar("b", "", compiler.KindByte, 0xAA, "test.c65", 1)
|
||||
st.AddVar("result", "", compiler.KindWord, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda a",
|
||||
|
|
@ -78,9 +78,9 @@ func TestXorCommand_OldSyntax(t *testing.T) {
|
|||
name: "word XOR word -> word",
|
||||
line: "XOR x WITH y GIVING result",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("x", "", compiler.KindWord, 0x1234)
|
||||
st.AddVar("y", "", compiler.KindWord, 0x5678)
|
||||
st.AddVar("result", "", compiler.KindWord, 0)
|
||||
st.AddVar("x", "", compiler.KindWord, 0x1234, "test.c65", 1)
|
||||
st.AddVar("y", "", compiler.KindWord, 0x5678, "test.c65", 1)
|
||||
st.AddVar("result", "", compiler.KindWord, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda x",
|
||||
|
|
@ -95,8 +95,8 @@ func TestXorCommand_OldSyntax(t *testing.T) {
|
|||
name: "byte XOR literal -> byte",
|
||||
line: "XOR a WITH $AA GIVING result",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("a", "", compiler.KindByte, 0xFF)
|
||||
st.AddVar("result", "", compiler.KindByte, 0)
|
||||
st.AddVar("a", "", compiler.KindByte, 0xFF, "test.c65", 1)
|
||||
st.AddVar("result", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda a",
|
||||
|
|
@ -108,8 +108,8 @@ func TestXorCommand_OldSyntax(t *testing.T) {
|
|||
name: "literal XOR byte -> byte",
|
||||
line: "XOR 255 WITH b GIVING result",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("b", "", compiler.KindByte, 0xAA)
|
||||
st.AddVar("result", "", compiler.KindByte, 0)
|
||||
st.AddVar("b", "", compiler.KindByte, 0xAA, "test.c65", 1)
|
||||
st.AddVar("result", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda #$ff",
|
||||
|
|
@ -121,7 +121,7 @@ func TestXorCommand_OldSyntax(t *testing.T) {
|
|||
name: "constant folding: 255 XOR 170 -> byte",
|
||||
line: "XOR 255 WITH 170 GIVING result",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("result", "", compiler.KindByte, 0)
|
||||
st.AddVar("result", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda #$55",
|
||||
|
|
@ -132,7 +132,7 @@ func TestXorCommand_OldSyntax(t *testing.T) {
|
|||
name: "constant folding: $FFFF XOR $AAAA -> word",
|
||||
line: "XOR $FFFF WITH $AAAA GIVING result",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("result", "", compiler.KindWord, 0)
|
||||
st.AddVar("result", "", compiler.KindWord, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda #$55",
|
||||
|
|
@ -145,9 +145,9 @@ func TestXorCommand_OldSyntax(t *testing.T) {
|
|||
name: "arrow syntax",
|
||||
line: "XOR a WITH b -> result",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("a", "", compiler.KindByte, 0)
|
||||
st.AddVar("b", "", compiler.KindByte, 0)
|
||||
st.AddVar("result", "", compiler.KindByte, 0)
|
||||
st.AddVar("a", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
st.AddVar("b", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
st.AddVar("result", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda a",
|
||||
|
|
@ -159,9 +159,9 @@ func TestXorCommand_OldSyntax(t *testing.T) {
|
|||
name: "word XOR byte -> byte",
|
||||
line: "XOR wval WITH bval GIVING result",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("wval", "", compiler.KindWord, 0x1234)
|
||||
st.AddVar("bval", "", compiler.KindByte, 0xFF)
|
||||
st.AddVar("result", "", compiler.KindByte, 0)
|
||||
st.AddVar("wval", "", compiler.KindWord, 0x1234, "test.c65", 1)
|
||||
st.AddVar("bval", "", compiler.KindByte, 0xFF, "test.c65", 1)
|
||||
st.AddVar("result", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda wval",
|
||||
|
|
@ -173,9 +173,9 @@ func TestXorCommand_OldSyntax(t *testing.T) {
|
|||
name: "word XOR byte -> word",
|
||||
line: "XOR wval WITH bval GIVING result",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("wval", "", compiler.KindWord, 0x1234)
|
||||
st.AddVar("bval", "", compiler.KindByte, 0xFF)
|
||||
st.AddVar("result", "", compiler.KindWord, 0)
|
||||
st.AddVar("wval", "", compiler.KindWord, 0x1234, "test.c65", 1)
|
||||
st.AddVar("bval", "", compiler.KindByte, 0xFF, "test.c65", 1)
|
||||
st.AddVar("result", "", compiler.KindWord, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda wval",
|
||||
|
|
@ -189,8 +189,8 @@ func TestXorCommand_OldSyntax(t *testing.T) {
|
|||
name: "error: unknown destination variable",
|
||||
line: "XOR a WITH b GIVING unknown",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("a", "", compiler.KindByte, 0)
|
||||
st.AddVar("b", "", compiler.KindByte, 0)
|
||||
st.AddVar("a", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
st.AddVar("b", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
|
|
@ -198,9 +198,9 @@ func TestXorCommand_OldSyntax(t *testing.T) {
|
|||
name: "error: wrong separator",
|
||||
line: "XOR a TO b GIVING result",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("a", "", compiler.KindByte, 0)
|
||||
st.AddVar("b", "", compiler.KindByte, 0)
|
||||
st.AddVar("result", "", compiler.KindByte, 0)
|
||||
st.AddVar("a", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
st.AddVar("b", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
st.AddVar("result", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
|
|
@ -208,9 +208,9 @@ func TestXorCommand_OldSyntax(t *testing.T) {
|
|||
name: "error: cannot assign to constant",
|
||||
line: "XOR a WITH b GIVING MAXVAL",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("a", "", compiler.KindByte, 0)
|
||||
st.AddVar("b", "", compiler.KindByte, 0)
|
||||
st.AddConst("MAXVAL", "", compiler.KindByte, 255)
|
||||
st.AddVar("a", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
st.AddVar("b", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
st.AddConst("MAXVAL", "", compiler.KindByte, 255, "test.c65", 1)
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
|
|
@ -261,9 +261,9 @@ func TestXorCommand_NewSyntax(t *testing.T) {
|
|||
name: "byte ^ byte -> byte",
|
||||
line: "result = a ^ b",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("a", "", compiler.KindByte, 0xFF)
|
||||
st.AddVar("b", "", compiler.KindByte, 0xAA)
|
||||
st.AddVar("result", "", compiler.KindByte, 0)
|
||||
st.AddVar("a", "", compiler.KindByte, 0xFF, "test.c65", 1)
|
||||
st.AddVar("b", "", compiler.KindByte, 0xAA, "test.c65", 1)
|
||||
st.AddVar("result", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda a",
|
||||
|
|
@ -275,9 +275,9 @@ func TestXorCommand_NewSyntax(t *testing.T) {
|
|||
name: "byte ^ byte -> word",
|
||||
line: "result = a ^ b",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("a", "", compiler.KindByte, 0xFF)
|
||||
st.AddVar("b", "", compiler.KindByte, 0xAA)
|
||||
st.AddVar("result", "", compiler.KindWord, 0)
|
||||
st.AddVar("a", "", compiler.KindByte, 0xFF, "test.c65", 1)
|
||||
st.AddVar("b", "", compiler.KindByte, 0xAA, "test.c65", 1)
|
||||
st.AddVar("result", "", compiler.KindWord, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda a",
|
||||
|
|
@ -291,9 +291,9 @@ func TestXorCommand_NewSyntax(t *testing.T) {
|
|||
name: "word ^ word -> word",
|
||||
line: "result = x ^ y",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("x", "", compiler.KindWord, 0x1234)
|
||||
st.AddVar("y", "", compiler.KindWord, 0x5678)
|
||||
st.AddVar("result", "", compiler.KindWord, 0)
|
||||
st.AddVar("x", "", compiler.KindWord, 0x1234, "test.c65", 1)
|
||||
st.AddVar("y", "", compiler.KindWord, 0x5678, "test.c65", 1)
|
||||
st.AddVar("result", "", compiler.KindWord, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda x",
|
||||
|
|
@ -308,8 +308,8 @@ func TestXorCommand_NewSyntax(t *testing.T) {
|
|||
name: "byte ^ byte_const -> word (optimization: skip eor #0)",
|
||||
line: "result = b ^ 5",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("b", "", compiler.KindByte, 0xFF)
|
||||
st.AddVar("result", "", compiler.KindWord, 0)
|
||||
st.AddVar("b", "", compiler.KindByte, 0xFF, "test.c65", 1)
|
||||
st.AddVar("result", "", compiler.KindWord, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda b",
|
||||
|
|
@ -323,9 +323,9 @@ func TestXorCommand_NewSyntax(t *testing.T) {
|
|||
name: "byte ^ word -> word (swapped to word ^ byte)",
|
||||
line: "result = bval ^ wval",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("bval", "", compiler.KindByte, 0xFF)
|
||||
st.AddVar("wval", "", compiler.KindWord, 0x1234)
|
||||
st.AddVar("result", "", compiler.KindWord, 0)
|
||||
st.AddVar("bval", "", compiler.KindByte, 0xFF, "test.c65", 1)
|
||||
st.AddVar("wval", "", compiler.KindWord, 0x1234, "test.c65", 1)
|
||||
st.AddVar("result", "", compiler.KindWord, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda wval",
|
||||
|
|
@ -339,8 +339,8 @@ func TestXorCommand_NewSyntax(t *testing.T) {
|
|||
name: "byte_const ^ byte -> word (optimization: skip eor #0)",
|
||||
line: "result = 5 ^ b",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("b", "", compiler.KindByte, 0xFF)
|
||||
st.AddVar("result", "", compiler.KindWord, 0)
|
||||
st.AddVar("b", "", compiler.KindByte, 0xFF, "test.c65", 1)
|
||||
st.AddVar("result", "", compiler.KindWord, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda #$05",
|
||||
|
|
@ -354,8 +354,8 @@ func TestXorCommand_NewSyntax(t *testing.T) {
|
|||
name: "byte ^ word_const -> word (no optimization)",
|
||||
line: "result = b ^ 300",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("b", "", compiler.KindByte, 0xFF)
|
||||
st.AddVar("result", "", compiler.KindWord, 0)
|
||||
st.AddVar("b", "", compiler.KindByte, 0xFF, "test.c65", 1)
|
||||
st.AddVar("result", "", compiler.KindWord, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda b",
|
||||
|
|
@ -370,8 +370,8 @@ func TestXorCommand_NewSyntax(t *testing.T) {
|
|||
name: "word_const ^ byte -> word (optimization: skip eor #0)",
|
||||
line: "result = 300 ^ b",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("b", "", compiler.KindByte, 0xFF)
|
||||
st.AddVar("result", "", compiler.KindWord, 0)
|
||||
st.AddVar("b", "", compiler.KindByte, 0xFF, "test.c65", 1)
|
||||
st.AddVar("result", "", compiler.KindWord, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda #$2c",
|
||||
|
|
@ -385,8 +385,8 @@ func TestXorCommand_NewSyntax(t *testing.T) {
|
|||
name: "self-assignment: word ^= byte (optimization: skip high byte entirely)",
|
||||
line: "wval = wval ^ bval",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("wval", "", compiler.KindWord, 0x1234)
|
||||
st.AddVar("bval", "", compiler.KindByte, 0xFF)
|
||||
st.AddVar("wval", "", compiler.KindWord, 0x1234, "test.c65", 1)
|
||||
st.AddVar("bval", "", compiler.KindByte, 0xFF, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda wval",
|
||||
|
|
@ -398,8 +398,8 @@ func TestXorCommand_NewSyntax(t *testing.T) {
|
|||
name: "self-assignment reversed: word ^= byte (optimization via swap)",
|
||||
line: "wval = bval ^ wval",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("wval", "", compiler.KindWord, 0x1234)
|
||||
st.AddVar("bval", "", compiler.KindByte, 0xFF)
|
||||
st.AddVar("wval", "", compiler.KindWord, 0x1234, "test.c65", 1)
|
||||
st.AddVar("bval", "", compiler.KindByte, 0xFF, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda wval",
|
||||
|
|
@ -411,7 +411,7 @@ func TestXorCommand_NewSyntax(t *testing.T) {
|
|||
name: "self-assignment: word ^= byte_const (optimization: skip high byte entirely)",
|
||||
line: "wval = wval ^ 42",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("wval", "", compiler.KindWord, 0x1234)
|
||||
st.AddVar("wval", "", compiler.KindWord, 0x1234, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda wval",
|
||||
|
|
@ -423,7 +423,7 @@ func TestXorCommand_NewSyntax(t *testing.T) {
|
|||
name: "self-assignment: word ^= word_const (no optimization: high byte needed)",
|
||||
line: "wval = wval ^ 300",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("wval", "", compiler.KindWord, 0x1234)
|
||||
st.AddVar("wval", "", compiler.KindWord, 0x1234, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda wval",
|
||||
|
|
@ -438,8 +438,8 @@ func TestXorCommand_NewSyntax(t *testing.T) {
|
|||
name: "self-assignment: word ^= word (no optimization: both high bytes needed)",
|
||||
line: "wval = wval ^ wval2",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("wval", "", compiler.KindWord, 0x1234)
|
||||
st.AddVar("wval2", "", compiler.KindWord, 0x5678)
|
||||
st.AddVar("wval", "", compiler.KindWord, 0x1234, "test.c65", 1)
|
||||
st.AddVar("wval2", "", compiler.KindWord, 0x5678, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda wval",
|
||||
|
|
@ -454,8 +454,8 @@ func TestXorCommand_NewSyntax(t *testing.T) {
|
|||
name: "variable ^ literal",
|
||||
line: "result = a ^ $AA",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("a", "", compiler.KindByte, 0xFF)
|
||||
st.AddVar("result", "", compiler.KindByte, 0)
|
||||
st.AddVar("a", "", compiler.KindByte, 0xFF, "test.c65", 1)
|
||||
st.AddVar("result", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda a",
|
||||
|
|
@ -467,7 +467,7 @@ func TestXorCommand_NewSyntax(t *testing.T) {
|
|||
name: "constant folding",
|
||||
line: "result = 255 ^ 170",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("result", "", compiler.KindByte, 0)
|
||||
st.AddVar("result", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda #$55",
|
||||
|
|
@ -478,7 +478,7 @@ func TestXorCommand_NewSyntax(t *testing.T) {
|
|||
name: "constant folding word",
|
||||
line: "result = $FFFF ^ $AAAA",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("result", "", compiler.KindWord, 0)
|
||||
st.AddVar("result", "", compiler.KindWord, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda #$55",
|
||||
|
|
@ -491,9 +491,9 @@ func TestXorCommand_NewSyntax(t *testing.T) {
|
|||
name: "using constant in expression",
|
||||
line: "result = a ^ MASK",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("a", "", compiler.KindByte, 0xFF)
|
||||
st.AddConst("MASK", "", compiler.KindByte, 0xAA)
|
||||
st.AddVar("result", "", compiler.KindByte, 0)
|
||||
st.AddVar("a", "", compiler.KindByte, 0xFF, "test.c65", 1)
|
||||
st.AddConst("MASK", "", compiler.KindByte, 0xAA, "test.c65", 1)
|
||||
st.AddVar("result", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
wantAsm: []string{
|
||||
"\tlda a",
|
||||
|
|
@ -505,8 +505,8 @@ func TestXorCommand_NewSyntax(t *testing.T) {
|
|||
name: "error: unknown destination",
|
||||
line: "unknown = a ^ b",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("a", "", compiler.KindByte, 0)
|
||||
st.AddVar("b", "", compiler.KindByte, 0)
|
||||
st.AddVar("a", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
st.AddVar("b", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
|
|
@ -514,9 +514,9 @@ func TestXorCommand_NewSyntax(t *testing.T) {
|
|||
name: "error: wrong operator",
|
||||
line: "result = a + b",
|
||||
setupVars: func(st *compiler.SymbolTable) {
|
||||
st.AddVar("a", "", compiler.KindByte, 0)
|
||||
st.AddVar("b", "", compiler.KindByte, 0)
|
||||
st.AddVar("result", "", compiler.KindByte, 0)
|
||||
st.AddVar("a", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
st.AddVar("b", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
st.AddVar("result", "", compiler.KindByte, 0, "test.c65", 1)
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -222,6 +222,12 @@ func (c *Compiler) Compile(lines []preproc.Line) ([]string, error) {
|
|||
// Analyze for overlapping absolute addresses in function call chains
|
||||
c.checkAbsoluteOverlaps()
|
||||
|
||||
// Check for unused variables and print warnings
|
||||
warnings := c.ctx.SymbolTable.CheckUnused()
|
||||
for _, warning := range warnings {
|
||||
_, _ = fmt.Fprintf(os.Stderr, "%s\n", warning)
|
||||
}
|
||||
|
||||
// Assemble final output with headers and footers
|
||||
return c.assembleOutput(codeOutput), nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -428,7 +428,7 @@ func TestExecuteMacro_LocalVariableExpansion(t *testing.T) {
|
|||
ctx := NewCompilerContext(pragma)
|
||||
|
||||
// Add a local variable in function scope "testfunc"
|
||||
ctx.SymbolTable.AddVar("myvar", "testfunc", KindByte, 0)
|
||||
ctx.SymbolTable.AddVar("myvar", "testfunc", KindByte, 0, "test.c65", 1)
|
||||
|
||||
// Enter the function scope by declaring the function
|
||||
_, err := ctx.FunctionHandler.HandleFuncDecl(makeLine("FUNC testfunc"))
|
||||
|
|
@ -468,11 +468,11 @@ func TestExecuteMacro_LocalVariableExpansion_MultipleVars(t *testing.T) {
|
|||
ctx := NewCompilerContext(pragma)
|
||||
|
||||
// Add local variables in function scope
|
||||
ctx.SymbolTable.AddVar("color_index", "myfunc", KindByte, 0)
|
||||
ctx.SymbolTable.AddVar("row_color", "myfunc", KindWord, 0)
|
||||
ctx.SymbolTable.AddVar("color_index", "myfunc", KindByte, 0, "test.c65", 1)
|
||||
ctx.SymbolTable.AddVar("row_color", "myfunc", KindWord, 0, "test.c65", 1)
|
||||
|
||||
// Add a global table (no function scope)
|
||||
ctx.SymbolTable.AddVar("scroll_color_table", "", KindWord, 0)
|
||||
ctx.SymbolTable.AddVar("scroll_color_table", "", KindWord, 0, "test.c65", 1)
|
||||
|
||||
// Enter the function scope
|
||||
_, err := ctx.FunctionHandler.HandleFuncDecl(makeLine("FUNC myfunc"))
|
||||
|
|
@ -524,7 +524,7 @@ func TestExecuteScript_LocalVariableExpansion(t *testing.T) {
|
|||
ctx := NewCompilerContext(pragma)
|
||||
|
||||
// Add a local variable in function scope
|
||||
ctx.SymbolTable.AddVar("counter", "loopfunc", KindByte, 0)
|
||||
ctx.SymbolTable.AddVar("counter", "loopfunc", KindByte, 0, "test.c65", 1)
|
||||
|
||||
// Enter the function scope
|
||||
_, err := ctx.FunctionHandler.HandleFuncDecl(makeLine("FUNC loopfunc"))
|
||||
|
|
@ -557,7 +557,7 @@ func TestExecuteScript_Library_GlobalVariableExpansion(t *testing.T) {
|
|||
ctx := NewCompilerContext(pragma)
|
||||
|
||||
// Add a global variable
|
||||
ctx.SymbolTable.AddVar("global_counter", "", KindByte, 0)
|
||||
ctx.SymbolTable.AddVar("global_counter", "", KindByte, 0, "test.c65", 1)
|
||||
|
||||
// Library script that uses |varname| syntax at global scope
|
||||
// Should expand to the global name (unchanged since it's already global)
|
||||
|
|
@ -597,7 +597,7 @@ func TestExecuteScript_Library_VariableExpansionAtDefinitionTime(t *testing.T) {
|
|||
ctx := NewCompilerContext(pragma)
|
||||
|
||||
// Add a local variable in a function scope
|
||||
ctx.SymbolTable.AddVar("local_var", "caller", KindByte, 0)
|
||||
ctx.SymbolTable.AddVar("local_var", "caller", KindByte, 0, "test.c65", 1)
|
||||
|
||||
// Library is defined at GLOBAL scope (not inside any function)
|
||||
// So |varname| expansion happens at global scope during library definition
|
||||
|
|
@ -728,7 +728,7 @@ func TestAsmBlock_VariableExpansion_IgnoresComments(t *testing.T) {
|
|||
comp := NewCompiler(pragma)
|
||||
|
||||
// Add a variable to the symbol table so expansion can work
|
||||
comp.Context().SymbolTable.AddVar("myvar", "", KindByte, 0)
|
||||
comp.Context().SymbolTable.AddVar("myvar", "", KindByte, 0, "test.c65", 1)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
|
|
@ -771,7 +771,7 @@ func TestAsmBlock_VariableExpansion_IgnoresComments(t *testing.T) {
|
|||
t.Run(tt.name, func(t *testing.T) {
|
||||
// Create fresh compiler for each test
|
||||
comp := NewCompiler(pragma)
|
||||
comp.Context().SymbolTable.AddVar("myvar", "", KindByte, 0)
|
||||
comp.Context().SymbolTable.AddVar("myvar", "", KindByte, 0, "test.c65", 1)
|
||||
|
||||
lines := []preproc.Line{
|
||||
{
|
||||
|
|
|
|||
|
|
@ -124,14 +124,14 @@ func (fh *FunctionHandler) HandleFuncDecl(line preproc.Line) ([]string, error) {
|
|||
if isImplicit {
|
||||
// Parse and add implicit variable declaration
|
||||
// Format: {BYTE varname} or {WORD varname}
|
||||
if err := fh.parseImplicitDecl(implicitDecl, funcName); err != nil {
|
||||
if err := fh.parseImplicitDecl(implicitDecl, funcName, line.Filename, line.LineNo); err != nil {
|
||||
fh.currentFuncs = fh.currentFuncs[:len(fh.currentFuncs)-1]
|
||||
return nil, fmt.Errorf("%s:%d: FUNC %s: implicit declaration: %w", line.Filename, line.LineNo, funcName, err)
|
||||
}
|
||||
}
|
||||
|
||||
// Look up variable in symbol table
|
||||
sym := fh.symTable.Lookup(varName, []string{funcName})
|
||||
// Look up variable in symbol table (validation only, not usage)
|
||||
sym := fh.symTable.LookupWithoutUsage(varName, []string{funcName})
|
||||
if sym == nil {
|
||||
fh.currentFuncs = fh.currentFuncs[:len(fh.currentFuncs)-1]
|
||||
return nil, fmt.Errorf("%s:%d: FUNC %s: parameter %q not declared", line.Filename, line.LineNo, funcName, varName)
|
||||
|
|
@ -343,12 +343,7 @@ func (fh *FunctionHandler) HandleFuncCall(line preproc.Line) ([]string, error) {
|
|||
}
|
||||
|
||||
// Use ParseOperandParam for variables, constants, and expressions
|
||||
constLookup := func(name string) (int64, bool) {
|
||||
if sym := fh.symTable.Lookup(name, fh.currentFuncs); sym != nil && sym.IsConst() {
|
||||
return int64(sym.Value), true
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
constLookup := fh.symTable.ConstantLookupFunc(fh.currentFuncs)
|
||||
|
||||
_, _, value, isVar, err := ParseOperandParam(
|
||||
arg, fh.symTable, fh.currentFuncs, constLookup)
|
||||
|
|
@ -599,7 +594,7 @@ func (fh *FunctionHandler) processConstValue(value uint16, param *FuncParam, fun
|
|||
}
|
||||
|
||||
// parseImplicitDecl parses {BYTE varname} or {WORD varname} or {BYTE varname @ address} and adds to symbol table
|
||||
func (fh *FunctionHandler) parseImplicitDecl(decl string, funcName string) error {
|
||||
func (fh *FunctionHandler) parseImplicitDecl(decl string, funcName string, filename string, lineNo int) error {
|
||||
parts := strings.Fields(decl)
|
||||
if len(parts) != 2 && len(parts) != 4 {
|
||||
return fmt.Errorf("implicit declaration must be 'TYPE name' or 'TYPE name @ addr', got: %q", decl)
|
||||
|
|
@ -620,7 +615,7 @@ func (fh *FunctionHandler) parseImplicitDecl(decl string, funcName string) error
|
|||
|
||||
if len(parts) == 2 {
|
||||
// Simple: BYTE name or WORD name
|
||||
return fh.symTable.AddVar(varName, funcName, kind, 0)
|
||||
return fh.symTable.AddVar(varName, funcName, kind, 0, filename, lineNo)
|
||||
}
|
||||
|
||||
// Extended: BYTE name @ address or WORD name @ address
|
||||
|
|
@ -632,13 +627,7 @@ func (fh *FunctionHandler) parseImplicitDecl(decl string, funcName string) error
|
|||
}
|
||||
|
||||
// Create constant lookup function for address evaluation
|
||||
constLookup := func(name string) (int64, bool) {
|
||||
sym := fh.symTable.Lookup(name, []string{funcName})
|
||||
if sym != nil && sym.IsConst() {
|
||||
return int64(sym.Value), true
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
constLookup := fh.symTable.ConstantLookupFunc([]string{funcName})
|
||||
|
||||
// Parse address (supports $hex and decimal) using EvaluateExpression
|
||||
addr, err := utils.EvaluateExpression(addrStr, constLookup)
|
||||
|
|
@ -650,7 +639,7 @@ func (fh *FunctionHandler) parseImplicitDecl(decl string, funcName string) error
|
|||
return fmt.Errorf("absolute address $%X out of range", addr)
|
||||
}
|
||||
|
||||
return fh.symTable.AddAbsolute(varName, funcName, kind, uint16(addr))
|
||||
return fh.symTable.AddAbsolute(varName, funcName, kind, uint16(addr), filename, lineNo)
|
||||
}
|
||||
|
||||
// EndFunction pops all functions from the stack (called by FEND)
|
||||
|
|
|
|||
|
|
@ -231,8 +231,8 @@ func TestHandleFuncDecl_WithExistingParams(t *testing.T) {
|
|||
fh := NewFunctionHandler(st, ls, csh, pragma)
|
||||
|
||||
// Pre-declare parameters
|
||||
st.AddVar("x", "test_func", KindByte, 0)
|
||||
st.AddVar("y", "test_func", KindWord, 0)
|
||||
st.AddVar("x", "test_func", KindByte, 0, "test.c65", 1)
|
||||
st.AddVar("y", "test_func", KindWord, 0, "test.c65", 1)
|
||||
|
||||
asm, err := fh.HandleFuncDecl(makeLine("FUNC test_func ( x y )"))
|
||||
if err != nil {
|
||||
|
|
@ -340,7 +340,7 @@ func TestHandleFuncDecl_Errors(t *testing.T) {
|
|||
name: "const param",
|
||||
line: "FUNC test ( constval )",
|
||||
preDecl: func(st *SymbolTable) {
|
||||
st.AddConst("constval", "test", KindByte, 42)
|
||||
st.AddConst("constval", "test", KindByte, 42, "test.c65", 1)
|
||||
},
|
||||
wantErr: "cannot be a constant",
|
||||
},
|
||||
|
|
@ -387,13 +387,13 @@ func TestHandleFuncCall_VarArgs(t *testing.T) {
|
|||
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)
|
||||
st.AddVar("param_a", "test_func", KindByte, 0, "test.c65", 1)
|
||||
st.AddVar("param_b", "test_func", KindWord, 0, "test.c65", 1)
|
||||
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)
|
||||
st.AddVar("var_a", "", KindByte, 0, "test.c65", 1)
|
||||
st.AddVar("var_b", "", KindWord, 0, "test.c65", 1)
|
||||
|
||||
asm, err := fh.HandleFuncCall(makeLine("CALL test_func ( var_a var_b )"))
|
||||
if err != nil {
|
||||
|
|
@ -430,11 +430,11 @@ func TestHandleFuncCall_OutParams(t *testing.T) {
|
|||
fh := NewFunctionHandler(st, ls, csh, pragma)
|
||||
|
||||
// Declare function with out param
|
||||
st.AddVar("result", "get_result", KindByte, 0)
|
||||
st.AddVar("result", "get_result", KindByte, 0, "test.c65", 1)
|
||||
fh.HandleFuncDecl(makeLine("FUNC get_result ( out:result )"))
|
||||
|
||||
// Declare caller variable
|
||||
st.AddVar("output", "", KindByte, 0)
|
||||
st.AddVar("output", "", KindByte, 0, "test.c65", 1)
|
||||
|
||||
asm, err := fh.HandleFuncCall(makeLine("CALL get_result ( output )"))
|
||||
if err != nil {
|
||||
|
|
@ -469,8 +469,8 @@ func TestHandleFuncCall_ConstArgs(t *testing.T) {
|
|||
fh := NewFunctionHandler(st, ls, csh, pragma)
|
||||
|
||||
// Declare function
|
||||
st.AddVar("x", "test_const", KindByte, 0)
|
||||
st.AddVar("y", "test_const", KindWord, 0)
|
||||
st.AddVar("x", "test_const", KindByte, 0, "test.c65", 1)
|
||||
st.AddVar("y", "test_const", KindWord, 0, "test.c65", 1)
|
||||
fh.HandleFuncDecl(makeLine("FUNC test_const ( x y )"))
|
||||
|
||||
asm, err := fh.HandleFuncCall(makeLine("CALL test_const ( 42 $1234 )"))
|
||||
|
|
@ -506,7 +506,7 @@ func TestHandleFuncCall_LabelArg(t *testing.T) {
|
|||
fh := NewFunctionHandler(st, ls, csh, pragma)
|
||||
|
||||
// Declare function
|
||||
st.AddVar("ptr", "test_label", KindWord, 0)
|
||||
st.AddVar("ptr", "test_label", KindWord, 0, "test.c65", 1)
|
||||
fh.HandleFuncDecl(makeLine("FUNC test_label ( ptr )"))
|
||||
|
||||
asm, err := fh.HandleFuncCall(makeLine("CALL test_label ( @my_label )"))
|
||||
|
|
@ -539,7 +539,7 @@ func TestHandleFuncCall_StringArg(t *testing.T) {
|
|||
fh := NewFunctionHandler(st, ls, csh, pragma)
|
||||
|
||||
// Declare function
|
||||
st.AddVar("str_ptr", "print", KindWord, 0)
|
||||
st.AddVar("str_ptr", "print", KindWord, 0, "test.c65", 1)
|
||||
fh.HandleFuncDecl(makeLine("FUNC print ( str_ptr )"))
|
||||
|
||||
asm, err := fh.HandleFuncCall(makeLine(`CALL print ( "hello" )`))
|
||||
|
|
@ -582,7 +582,7 @@ func TestHandleFuncCall_Errors(t *testing.T) {
|
|||
{
|
||||
name: "wrong arg count",
|
||||
setup: func(fh *FunctionHandler, st *SymbolTable) {
|
||||
st.AddVar("x", "test", KindByte, 0)
|
||||
st.AddVar("x", "test", KindByte, 0, "test.c65", 1)
|
||||
fh.HandleFuncDecl(makeLine("FUNC test ( x )"))
|
||||
},
|
||||
line: "CALL test ( 1 2 )",
|
||||
|
|
@ -593,9 +593,9 @@ func TestHandleFuncCall_Errors(t *testing.T) {
|
|||
{
|
||||
name: "type mismatch",
|
||||
setup: func(fh *FunctionHandler, st *SymbolTable) {
|
||||
st.AddVar("param", "test", KindByte, 0)
|
||||
st.AddVar("param", "test", KindByte, 0, "test.c65", 1)
|
||||
fh.HandleFuncDecl(makeLine("FUNC test ( param )"))
|
||||
st.AddVar("wvar", "", KindWord, 0)
|
||||
st.AddVar("wvar", "", KindWord, 0, "test.c65", 1)
|
||||
},
|
||||
line: "CALL test ( wvar )",
|
||||
wantErr: "type mismatch",
|
||||
|
|
@ -603,7 +603,7 @@ func TestHandleFuncCall_Errors(t *testing.T) {
|
|||
{
|
||||
name: "const to out param",
|
||||
setup: func(fh *FunctionHandler, st *SymbolTable) {
|
||||
st.AddVar("result", "test", KindByte, 0)
|
||||
st.AddVar("result", "test", KindByte, 0, "test.c65", 1)
|
||||
fh.HandleFuncDecl(makeLine("FUNC test ( out:result )"))
|
||||
},
|
||||
line: "CALL test ( 42 )",
|
||||
|
|
@ -612,7 +612,7 @@ func TestHandleFuncCall_Errors(t *testing.T) {
|
|||
{
|
||||
name: "label to byte param",
|
||||
setup: func(fh *FunctionHandler, st *SymbolTable) {
|
||||
st.AddVar("x", "test", KindByte, 0)
|
||||
st.AddVar("x", "test", KindByte, 0, "test.c65", 1)
|
||||
fh.HandleFuncDecl(makeLine("FUNC test ( x )"))
|
||||
},
|
||||
line: "CALL test ( @label )",
|
||||
|
|
@ -921,8 +921,8 @@ func TestHandleFuncCall_AbsoluteParams(t *testing.T) {
|
|||
fh.HandleFuncDecl(makeLine("FUNC test_abs ( {BYTE param_a @ $fa} {WORD param_b @ $fb} )"))
|
||||
|
||||
// Declare caller variables
|
||||
st.AddVar("var_a", "", KindByte, 0)
|
||||
st.AddVar("var_b", "", KindWord, 0)
|
||||
st.AddVar("var_a", "", KindByte, 0, "test.c65", 1)
|
||||
st.AddVar("var_b", "", KindWord, 0, "test.c65", 1)
|
||||
|
||||
asm, err := fh.HandleFuncCall(makeLine("CALL test_abs ( var_a var_b )"))
|
||||
if err != nil {
|
||||
|
|
@ -962,7 +962,7 @@ func TestHandleFuncCall_AbsoluteOutParams(t *testing.T) {
|
|||
fh.HandleFuncDecl(makeLine("FUNC get_result ( out:{BYTE result @ $fa} )"))
|
||||
|
||||
// Declare caller variable
|
||||
st.AddVar("output", "", KindByte, 0)
|
||||
st.AddVar("output", "", KindByte, 0, "test.c65", 1)
|
||||
|
||||
asm, err := fh.HandleFuncCall(makeLine("CALL get_result ( output )"))
|
||||
if err != nil {
|
||||
|
|
@ -1059,7 +1059,7 @@ func TestParseImplicitDecl_Absolute(t *testing.T) {
|
|||
st = NewSymbolTable()
|
||||
fh.symTable = st
|
||||
|
||||
err := fh.parseImplicitDecl(tt.decl, tt.funcName)
|
||||
err := fh.parseImplicitDecl(tt.decl, tt.funcName, "test.c65", 1)
|
||||
if tt.wantErr {
|
||||
if err == nil {
|
||||
t.Fatal("expected error, got nil")
|
||||
|
|
@ -1167,7 +1167,7 @@ FEND
|
|||
if strings.ToUpper(parts[0]) == "WORD" {
|
||||
varKind = KindWord
|
||||
}
|
||||
st.AddVar(parts[1], "", varKind, 0)
|
||||
st.AddVar(parts[1], "", varKind, 0, "test.c65", 1)
|
||||
}
|
||||
} else if strings.HasPrefix(lineText, "FUNC ") {
|
||||
_, err := fh.HandleFuncDecl(pline)
|
||||
|
|
@ -1276,7 +1276,7 @@ FEND
|
|||
addrStr := strings.TrimPrefix(parts[3], "$")
|
||||
var addr uint16
|
||||
fmt.Sscanf(addrStr, "%x", &addr)
|
||||
st.AddAbsolute(parts[1], currentFunc, varKind, addr)
|
||||
st.AddAbsolute(parts[1], currentFunc, varKind, addr, "test.c65", 1)
|
||||
}
|
||||
} else if strings.HasPrefix(lineText, "FUNC ") {
|
||||
_, err := fh.HandleFuncDecl(pline)
|
||||
|
|
@ -1386,7 +1386,7 @@ FEND
|
|||
if strings.ToUpper(parts[0]) == "WORD" {
|
||||
varKind = KindWord
|
||||
}
|
||||
st.AddVar(parts[1], "", varKind, 0)
|
||||
st.AddVar(parts[1], "", varKind, 0, "test.c65", 1)
|
||||
}
|
||||
} else if strings.HasPrefix(lineText, "FUNC ") {
|
||||
_, err := fh.HandleFuncDecl(pline)
|
||||
|
|
|
|||
|
|
@ -177,13 +177,7 @@ func evaluateMacroArg(arg string, ctx *CompilerContext) (starlark.Value, error)
|
|||
arg = strings.TrimSpace(arg)
|
||||
|
||||
// Create lookup function for constants
|
||||
lookup := func(name string) (int64, bool) {
|
||||
sym := ctx.SymbolTable.Lookup(name, nil)
|
||||
if sym != nil && sym.IsConst() {
|
||||
return int64(sym.Value), true
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
lookup := ctx.SymbolTable.ConstantLookupFunc(nil)
|
||||
|
||||
// Try to evaluate as expression (number, constant, arithmetic)
|
||||
val, err := utils.EvaluateExpression(arg, lookup)
|
||||
|
|
|
|||
|
|
@ -26,14 +26,37 @@ const (
|
|||
FlagLabelRef
|
||||
)
|
||||
|
||||
// Symbol represents a variable or constant declaration
|
||||
// Symbol represents a variable, constant, or label reference
|
||||
type Symbol struct {
|
||||
Name string
|
||||
Scope string // empty string = global, otherwise function name
|
||||
Flags SymbolFlags
|
||||
Value uint16 // init value or const value
|
||||
AbsAddr uint16 // if FlagAbsolute set
|
||||
LabelRef string // if FlagLabelRef set
|
||||
Name string // Variable name
|
||||
Scope string // Function scope (empty for global)
|
||||
Flags SymbolFlags // Type and properties
|
||||
Value uint16 // Initial value for variables, constant value for constants
|
||||
AbsAddr uint16 // Absolute address (for @ variables)
|
||||
LabelRef string // Label reference (for label variables)
|
||||
Usage uint8 // Usage tracking
|
||||
Filename string // Source file where declared
|
||||
LineNo int // Line number in source file
|
||||
}
|
||||
|
||||
// Usage tracking for variables
|
||||
const (
|
||||
UsageNone uint8 = 0
|
||||
UsageUsed uint8 = 1 << 0
|
||||
// Future flags can be added:
|
||||
// UsageRead = 1 << 1
|
||||
// UsageWritten = 1 << 2
|
||||
// UsageAddress = 1 << 3
|
||||
)
|
||||
|
||||
// MarkUsed marks the symbol as used (should not be called for constants or absolutes)
|
||||
func (s *Symbol) MarkUsed() {
|
||||
s.Usage |= UsageUsed
|
||||
}
|
||||
|
||||
// IsUsed returns true if the symbol has been marked as used
|
||||
func (s *Symbol) IsUsed() bool {
|
||||
return s.Usage&UsageUsed != 0
|
||||
}
|
||||
|
||||
// Helper methods for Symbol
|
||||
|
|
@ -89,7 +112,7 @@ func (st *SymbolTable) SetFunctionHandler(fh FunctionHandlerInterface) {
|
|||
}
|
||||
|
||||
// AddVar adds a regular variable (byte or word)
|
||||
func (st *SymbolTable) AddVar(name, scope string, kind VarKind, initValue uint16) error {
|
||||
func (st *SymbolTable) AddVar(name, scope string, kind VarKind, initValue uint16, filename string, lineNo int) error {
|
||||
var flags SymbolFlags
|
||||
|
||||
switch kind {
|
||||
|
|
@ -109,11 +132,13 @@ func (st *SymbolTable) AddVar(name, scope string, kind VarKind, initValue uint16
|
|||
Scope: scope,
|
||||
Flags: flags,
|
||||
Value: initValue,
|
||||
Filename: filename,
|
||||
LineNo: lineNo,
|
||||
})
|
||||
}
|
||||
|
||||
// AddConst adds a constant (byte or word)
|
||||
func (st *SymbolTable) AddConst(name, scope string, kind VarKind, value uint16) error {
|
||||
func (st *SymbolTable) AddConst(name, scope string, kind VarKind, value uint16, filename string, lineNo int) error {
|
||||
var flags SymbolFlags
|
||||
|
||||
switch kind {
|
||||
|
|
@ -133,11 +158,13 @@ func (st *SymbolTable) AddConst(name, scope string, kind VarKind, value uint16)
|
|||
Scope: scope,
|
||||
Flags: flags,
|
||||
Value: value,
|
||||
Filename: filename,
|
||||
LineNo: lineNo,
|
||||
})
|
||||
}
|
||||
|
||||
// AddAbsolute adds a variable at a fixed memory address
|
||||
func (st *SymbolTable) AddAbsolute(name, scope string, kind VarKind, addr uint16) error {
|
||||
func (st *SymbolTable) AddAbsolute(name, scope string, kind VarKind, addr uint16, filename string, lineNo int) error {
|
||||
if addr > 0xFFFF {
|
||||
return fmt.Errorf("absolute address %d exceeds 16-bit range", addr)
|
||||
}
|
||||
|
|
@ -171,16 +198,20 @@ func (st *SymbolTable) AddAbsolute(name, scope string, kind VarKind, addr uint16
|
|||
Scope: scope,
|
||||
Flags: flags,
|
||||
AbsAddr: addr,
|
||||
Filename: filename,
|
||||
LineNo: lineNo,
|
||||
})
|
||||
}
|
||||
|
||||
// AddLabel adds a word variable that references a label
|
||||
func (st *SymbolTable) AddLabel(name, scope string, labelRef string) error {
|
||||
func (st *SymbolTable) AddLabel(name, scope string, labelRef string, filename string, lineNo int) error {
|
||||
return st.add(&Symbol{
|
||||
Name: name,
|
||||
Scope: scope,
|
||||
Flags: FlagWord | FlagLabelRef,
|
||||
LabelRef: labelRef,
|
||||
Filename: filename,
|
||||
LineNo: lineNo,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -208,12 +239,17 @@ func (st *SymbolTable) add(sym *Symbol) error {
|
|||
|
||||
// Lookup finds a symbol by name, resolving scope
|
||||
// Searches local scope first (if currentScopes provided), then global
|
||||
// Marks non-constant, non-absolute variables as used
|
||||
func (st *SymbolTable) Lookup(name string, currentScopes []string) *Symbol {
|
||||
// Try local scopes first (innermost to outermost)
|
||||
for i := len(currentScopes) - 1; i >= 0; i-- {
|
||||
scope := currentScopes[i]
|
||||
if scopeMap, ok := st.byScope[scope]; ok {
|
||||
if sym, ok := scopeMap[name]; ok {
|
||||
// Mark as used if it's a regular variable (not constant, not absolute)
|
||||
if !sym.IsConst() && !sym.IsAbsolute() {
|
||||
sym.MarkUsed()
|
||||
}
|
||||
return sym
|
||||
}
|
||||
}
|
||||
|
|
@ -222,6 +258,10 @@ func (st *SymbolTable) Lookup(name string, currentScopes []string) *Symbol {
|
|||
// Try global scope
|
||||
if scopeMap, ok := st.byScope[""]; ok {
|
||||
if sym, ok := scopeMap[name]; ok {
|
||||
// Mark as used if it's a regular variable (not constant, not absolute)
|
||||
if !sym.IsConst() && !sym.IsAbsolute() {
|
||||
sym.MarkUsed()
|
||||
}
|
||||
return sym
|
||||
}
|
||||
}
|
||||
|
|
@ -253,6 +293,77 @@ func (st *SymbolTable) ExpandName(name string, currentScopes []string) string {
|
|||
return name
|
||||
}
|
||||
|
||||
// LookupWithoutUsage finds a symbol by name without marking it as used
|
||||
// Used for validation-only lookups (e.g., checking if variable exists)
|
||||
func (st *SymbolTable) LookupWithoutUsage(name string, currentScopes []string) *Symbol {
|
||||
// Try local scopes first (innermost to outermost)
|
||||
for i := len(currentScopes) - 1; i >= 0; i-- {
|
||||
scope := currentScopes[i]
|
||||
if scopeMap, ok := st.byScope[scope]; ok {
|
||||
if sym, ok := scopeMap[name]; ok {
|
||||
return sym
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Try global scope
|
||||
if scopeMap, ok := st.byScope[""]; ok {
|
||||
if sym, ok := scopeMap[name]; ok {
|
||||
return sym
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// LookupConstant looks up a constant by name and returns its value if found
|
||||
// Returns (value, true) if symbol exists and is a constant, (0, false) otherwise
|
||||
func (st *SymbolTable) LookupConstant(name string, currentScopes []string) (int64, bool) {
|
||||
sym := st.LookupWithoutUsage(name, currentScopes)
|
||||
if sym != nil && sym.IsConst() {
|
||||
return int64(sym.Value), true
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
|
||||
// ConstantLookupFunc returns a ConstantLookup function that captures the current scopes
|
||||
// This can be used directly with utils.EvaluateExpression
|
||||
func (st *SymbolTable) ConstantLookupFunc(currentScopes []string) func(string) (int64, bool) {
|
||||
return func(name string) (int64, bool) {
|
||||
return st.LookupConstant(name, currentScopes)
|
||||
}
|
||||
}
|
||||
|
||||
// CheckUnused returns warnings for unused variables
|
||||
// Returns slice of warning messages for regular variables (not constants, not absolutes) that were never used
|
||||
func (st *SymbolTable) CheckUnused() []string {
|
||||
var warnings []string
|
||||
for _, sym := range st.symbols {
|
||||
// Skip constants and absolute variables (they shouldn't track usage)
|
||||
if sym.IsConst() || sym.IsAbsolute() {
|
||||
// Sanity check: constants and absolutes should never be marked as used
|
||||
// If they are, it's a bug in the compiler
|
||||
if sym.IsUsed() {
|
||||
// This would be an internal error, but we'll just skip it
|
||||
continue
|
||||
}
|
||||
continue
|
||||
}
|
||||
// Check if variable was never used
|
||||
if !sym.IsUsed() {
|
||||
// Format warning message with file and line info
|
||||
var scopeInfo string
|
||||
if sym.Scope != "" {
|
||||
scopeInfo = fmt.Sprintf(" in function '%s'", sym.Scope)
|
||||
}
|
||||
warning := fmt.Sprintf("%s:%d: warning: variable '%s'%s declared but never used",
|
||||
sym.Filename, sym.LineNo, sym.Name, scopeInfo)
|
||||
warnings = append(warnings, warning)
|
||||
}
|
||||
}
|
||||
return warnings
|
||||
}
|
||||
|
||||
// String representation for debugging
|
||||
func (s *Symbol) String() string {
|
||||
var parts []string
|
||||
|
|
@ -277,6 +388,11 @@ func (s *Symbol) String() string {
|
|||
parts = append(parts, fmt.Sprintf("=%d", s.Value))
|
||||
}
|
||||
|
||||
// Add location info if available
|
||||
if s.Filename != "" {
|
||||
parts = append(parts, fmt.Sprintf("@%s:%d", s.Filename, s.LineNo))
|
||||
}
|
||||
|
||||
return strings.Join(parts, " ")
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@ func TestAddVar(t *testing.T) {
|
|||
st := NewSymbolTable()
|
||||
|
||||
// Add byte var
|
||||
err := st.AddVar("counter", "", KindByte, 0)
|
||||
err := st.AddVar("counter", "", KindByte, 0, "test.c65", 1)
|
||||
if err != nil {
|
||||
t.Fatalf("AddVar() error = %v", err)
|
||||
}
|
||||
|
|
@ -123,7 +123,7 @@ func TestAddVar(t *testing.T) {
|
|||
}
|
||||
|
||||
// Add word var
|
||||
err = st.AddVar("ptr", "", KindWord, 0x1234)
|
||||
err = st.AddVar("ptr", "", KindWord, 0x1234, "test.c65", 1)
|
||||
if err != nil {
|
||||
t.Fatalf("AddVar() error = %v", err)
|
||||
}
|
||||
|
|
@ -137,7 +137,7 @@ func TestAddVar(t *testing.T) {
|
|||
}
|
||||
|
||||
// Test byte value range check
|
||||
err = st.AddVar("bad", "", KindByte, 256)
|
||||
err = st.AddVar("bad", "", KindByte, 256, "test.c65", 1)
|
||||
if err == nil {
|
||||
t.Error("expected error for byte value > 255")
|
||||
}
|
||||
|
|
@ -146,7 +146,7 @@ func TestAddVar(t *testing.T) {
|
|||
func TestAddConst(t *testing.T) {
|
||||
st := NewSymbolTable()
|
||||
|
||||
err := st.AddConst("MAX", "", KindByte, 255)
|
||||
err := st.AddConst("MAX", "", KindByte, 255, "test.c65", 1)
|
||||
if err != nil {
|
||||
t.Fatalf("AddConst() error = %v", err)
|
||||
}
|
||||
|
|
@ -166,7 +166,7 @@ func TestAddConst(t *testing.T) {
|
|||
}
|
||||
|
||||
// Test byte range check
|
||||
err = st.AddConst("BAD", "", KindByte, 300)
|
||||
err = st.AddConst("BAD", "", KindByte, 300, "test.c65", 1)
|
||||
if err == nil {
|
||||
t.Error("expected error for byte const > 255")
|
||||
}
|
||||
|
|
@ -176,7 +176,7 @@ func TestAddAbsolute(t *testing.T) {
|
|||
st := NewSymbolTable()
|
||||
|
||||
// Zero-page byte
|
||||
err := st.AddAbsolute("ZP_VAR", "", KindByte, 0x80)
|
||||
err := st.AddAbsolute("ZP_VAR", "", KindByte, 0x80, "test.c65", 1)
|
||||
if err != nil {
|
||||
t.Fatalf("AddAbsolute() error = %v", err)
|
||||
}
|
||||
|
|
@ -193,7 +193,7 @@ func TestAddAbsolute(t *testing.T) {
|
|||
}
|
||||
|
||||
// Zero-page word pointer
|
||||
err = st.AddAbsolute("ZP_PTR", "", KindWord, 0xFE)
|
||||
err = st.AddAbsolute("ZP_PTR", "", KindWord, 0xFE, "test.c65", 1)
|
||||
if err != nil {
|
||||
t.Fatalf("AddAbsolute() error = %v", err)
|
||||
}
|
||||
|
|
@ -204,7 +204,7 @@ func TestAddAbsolute(t *testing.T) {
|
|||
}
|
||||
|
||||
// Non-zero-page
|
||||
err = st.AddAbsolute("VIC", "", KindWord, 0xD000)
|
||||
err = st.AddAbsolute("VIC", "", KindWord, 0xD000, "test.c65", 1)
|
||||
if err != nil {
|
||||
t.Fatalf("AddAbsolute() error = %v", err)
|
||||
}
|
||||
|
|
@ -224,7 +224,7 @@ func TestAddAbsolute(t *testing.T) {
|
|||
func TestAddLabel(t *testing.T) {
|
||||
st := NewSymbolTable()
|
||||
|
||||
err := st.AddLabel("handler", "", "irq_vector")
|
||||
err := st.AddLabel("handler", "", "irq_vector", "test.c65", 1)
|
||||
if err != nil {
|
||||
t.Fatalf("AddLabel() error = %v", err)
|
||||
}
|
||||
|
|
@ -247,19 +247,19 @@ func TestAddLabel(t *testing.T) {
|
|||
func TestRedeclaration(t *testing.T) {
|
||||
st := NewSymbolTable()
|
||||
|
||||
err := st.AddVar("test", "", KindByte, 0)
|
||||
err := st.AddVar("test", "", KindByte, 0, "test.c65", 1)
|
||||
if err != nil {
|
||||
t.Fatalf("first AddVar() error = %v", err)
|
||||
}
|
||||
|
||||
// Attempt redeclaration
|
||||
err = st.AddVar("test", "", KindByte, 0)
|
||||
err = st.AddVar("test", "", KindByte, 0, "test.c65", 1)
|
||||
if err == nil {
|
||||
t.Error("expected error on redeclaration")
|
||||
}
|
||||
|
||||
// Different scope should be OK
|
||||
err = st.AddVar("test", "main", KindByte, 0)
|
||||
err = st.AddVar("test", "main", KindByte, 0, "test.c65", 1)
|
||||
if err != nil {
|
||||
t.Errorf("AddVar() with different scope error = %v", err)
|
||||
}
|
||||
|
|
@ -269,13 +269,13 @@ func TestLookup(t *testing.T) {
|
|||
st := NewSymbolTable()
|
||||
|
||||
// Global variable
|
||||
st.AddVar("global", "", KindByte, 0)
|
||||
st.AddVar("global", "", KindByte, 0, "test.c65", 1)
|
||||
|
||||
// Local in main
|
||||
st.AddVar("local", "main", KindByte, 0)
|
||||
st.AddVar("local", "main", KindByte, 0, "test.c65", 1)
|
||||
|
||||
// Local in nested function
|
||||
st.AddVar("inner", "main_helper", KindByte, 0)
|
||||
st.AddVar("inner", "main_helper", KindByte, 0, "test.c65", 1)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
|
|
@ -350,8 +350,8 @@ func TestLookup(t *testing.T) {
|
|||
func TestExpandName(t *testing.T) {
|
||||
st := NewSymbolTable()
|
||||
|
||||
st.AddVar("global", "", KindByte, 0)
|
||||
st.AddVar("local", "main", KindByte, 0)
|
||||
st.AddVar("global", "", KindByte, 0, "test.c65", 1)
|
||||
st.AddVar("local", "main", KindByte, 0, "test.c65", 1)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
|
|
@ -379,7 +379,7 @@ func TestInsertionOrder(t *testing.T) {
|
|||
|
||||
names := []string{"first", "second", "third"}
|
||||
for _, name := range names {
|
||||
st.AddVar(name, "", KindByte, 0)
|
||||
st.AddVar(name, "", KindByte, 0, "test.c65", 1)
|
||||
}
|
||||
|
||||
symbols := st.Symbols()
|
||||
|
|
@ -401,8 +401,8 @@ func TestCount(t *testing.T) {
|
|||
t.Errorf("initial Count() = %d, want 0", st.Count())
|
||||
}
|
||||
|
||||
st.AddVar("a", "", KindByte, 0)
|
||||
st.AddVar("b", "", KindByte, 0)
|
||||
st.AddVar("a", "", KindByte, 0, "test.c65", 1)
|
||||
st.AddVar("b", "", KindByte, 0, "test.c65", 1)
|
||||
|
||||
if st.Count() != 2 {
|
||||
t.Errorf("Count() = %d, want 2", st.Count())
|
||||
|
|
@ -418,7 +418,7 @@ func TestSymbolString(t *testing.T) {
|
|||
{
|
||||
name: "byte variable",
|
||||
setup: func(st *SymbolTable) *Symbol {
|
||||
st.AddVar("test", "", KindByte, 0)
|
||||
st.AddVar("test", "", KindByte, 0, "test.c65", 1)
|
||||
return st.Get("test")
|
||||
},
|
||||
contains: []string{"Name=test", "BYTE"},
|
||||
|
|
@ -426,7 +426,7 @@ func TestSymbolString(t *testing.T) {
|
|||
{
|
||||
name: "word constant",
|
||||
setup: func(st *SymbolTable) *Symbol {
|
||||
st.AddConst("MAX", "", KindWord, 65535)
|
||||
st.AddConst("MAX", "", KindWord, 65535, "test.c65", 1)
|
||||
return st.Get("MAX")
|
||||
},
|
||||
contains: []string{"Name=MAX", "WORD", "CONST=65535"},
|
||||
|
|
@ -434,7 +434,7 @@ func TestSymbolString(t *testing.T) {
|
|||
{
|
||||
name: "zero-page pointer",
|
||||
setup: func(st *SymbolTable) *Symbol {
|
||||
st.AddAbsolute("ptr", "", KindWord, 0x80)
|
||||
st.AddAbsolute("ptr", "", KindWord, 0x80, "test.c65", 1)
|
||||
return st.Get("ptr")
|
||||
},
|
||||
contains: []string{"Name=ptr", "WORD", "@$0080", "ZP"},
|
||||
|
|
@ -442,7 +442,7 @@ func TestSymbolString(t *testing.T) {
|
|||
{
|
||||
name: "label reference",
|
||||
setup: func(st *SymbolTable) *Symbol {
|
||||
st.AddLabel("handler", "", "irq")
|
||||
st.AddLabel("handler", "", "irq", "test.c65", 1)
|
||||
return st.Get("handler")
|
||||
},
|
||||
contains: []string{"Name=handler", "->irq"},
|
||||
|
|
@ -484,9 +484,9 @@ func TestGenerateConstants(t *testing.T) {
|
|||
st := NewSymbolTable()
|
||||
|
||||
// Add some constants
|
||||
st.AddConst("MAX", "", KindByte, 255)
|
||||
st.AddConst("SIZE", "", KindWord, 0x1234)
|
||||
st.AddVar("notconst", "", KindByte, 0) // should be skipped
|
||||
st.AddConst("MAX", "", KindByte, 255, "test.c65", 1)
|
||||
st.AddConst("SIZE", "", KindWord, 0x1234, "test.c65", 1)
|
||||
st.AddVar("notconst", "", KindByte, 0, "test.c65", 1) // should be skipped
|
||||
|
||||
lines := GenerateConstants(st)
|
||||
|
||||
|
|
@ -520,14 +520,14 @@ func TestGenerateAbsolutes(t *testing.T) {
|
|||
st := NewSymbolTable()
|
||||
|
||||
// Zero-page
|
||||
st.AddAbsolute("ZP_VAR", "", KindByte, 0x80)
|
||||
st.AddAbsolute("ZP_PTR", "", KindWord, 0xFE)
|
||||
st.AddAbsolute("ZP_VAR", "", KindByte, 0x80, "test.c65", 1)
|
||||
st.AddAbsolute("ZP_PTR", "", KindWord, 0xFE, "test.c65", 1)
|
||||
|
||||
// Non-zero-page
|
||||
st.AddAbsolute("VIC", "", KindWord, 0xD000)
|
||||
st.AddAbsolute("VIC", "", KindWord, 0xD000, "test.c65", 1)
|
||||
|
||||
// Regular var (should be skipped)
|
||||
st.AddVar("regular", "", KindByte, 0)
|
||||
st.AddVar("regular", "", KindByte, 0, "test.c65", 1)
|
||||
|
||||
lines := GenerateAbsolutes(st)
|
||||
|
||||
|
|
@ -564,19 +564,19 @@ func TestGenerateVariables(t *testing.T) {
|
|||
st := NewSymbolTable()
|
||||
|
||||
// Byte variable
|
||||
st.AddVar("counter", "", KindByte, 42)
|
||||
st.AddVar("counter", "", KindByte, 42, "test.c65", 1)
|
||||
|
||||
// Word variable
|
||||
st.AddVar("ptr", "", KindWord, 0x1234)
|
||||
st.AddVar("ptr", "", KindWord, 0x1234, "test.c65", 1)
|
||||
|
||||
// Label reference
|
||||
st.AddLabel("handler", "", "irq_routine")
|
||||
st.AddLabel("handler", "", "irq_routine", "test.c65", 1)
|
||||
|
||||
// Const (should be skipped)
|
||||
st.AddConst("SKIP", "", KindByte, 99)
|
||||
st.AddConst("SKIP", "", KindByte, 99, "test.c65", 1)
|
||||
|
||||
// Absolute (should be skipped)
|
||||
st.AddAbsolute("SKIP2", "", KindByte, 0x80)
|
||||
st.AddAbsolute("SKIP2", "", KindByte, 0x80, "test.c65", 1)
|
||||
|
||||
lines := GenerateVariables(st)
|
||||
|
||||
|
|
@ -633,7 +633,7 @@ func TestGenerateEmpty(t *testing.T) {
|
|||
}
|
||||
|
||||
// Only variables (no constants/absolutes)
|
||||
st.AddVar("test", "", KindByte, 0)
|
||||
st.AddVar("test", "", KindByte, 0, "test.c65", 1)
|
||||
|
||||
if lines := GenerateConstants(st); lines != nil {
|
||||
t.Error("expected nil when no constants exist")
|
||||
|
|
@ -646,9 +646,9 @@ func TestGenerateEmpty(t *testing.T) {
|
|||
func TestGenerateScopedVariables(t *testing.T) {
|
||||
st := NewSymbolTable()
|
||||
|
||||
st.AddVar("global", "", KindByte, 0)
|
||||
st.AddVar("local", "main", KindByte, 0)
|
||||
st.AddVar("nested", "main_helper", KindByte, 0)
|
||||
st.AddVar("global", "", KindByte, 0, "test.c65", 1)
|
||||
st.AddVar("local", "main", KindByte, 0, "test.c65", 1)
|
||||
st.AddVar("nested", "main_helper", KindByte, 0, "test.c65", 1)
|
||||
|
||||
lines := GenerateVariables(st)
|
||||
output := strings.Join(lines, "\n")
|
||||
|
|
@ -668,9 +668,9 @@ func TestGenerateScopedVariables(t *testing.T) {
|
|||
func TestGenerateHexLowercase(t *testing.T) {
|
||||
st := NewSymbolTable()
|
||||
|
||||
st.AddConst("TEST", "", KindByte, 0xAB)
|
||||
st.AddAbsolute("ADDR", "", KindWord, 0xDEAD)
|
||||
st.AddVar("VAR", "", KindWord, 0xBEEF)
|
||||
st.AddConst("TEST", "", KindByte, 0xAB, "test.c65", 1)
|
||||
st.AddAbsolute("ADDR", "", KindWord, 0xDEAD, "test.c65", 1)
|
||||
st.AddVar("VAR", "", KindWord, 0xBEEF, "test.c65", 1)
|
||||
|
||||
constLines := GenerateConstants(st)
|
||||
absLines := GenerateAbsolutes(st)
|
||||
|
|
@ -693,3 +693,381 @@ func TestGenerateHexLowercase(t *testing.T) {
|
|||
t.Error("expected lowercase hex in variable")
|
||||
}
|
||||
}
|
||||
|
||||
func TestUsageTracking(t *testing.T) {
|
||||
t.Run("Unused variable generates warning", func(t *testing.T) {
|
||||
st := NewSymbolTable()
|
||||
|
||||
// Add an unused variable
|
||||
err := st.AddVar("unused", "", KindByte, 0, "test.c65", 10)
|
||||
if err != nil {
|
||||
t.Fatalf("AddVar() error = %v", err)
|
||||
}
|
||||
|
||||
// Check that it's marked as unused
|
||||
sym := st.Get("unused")
|
||||
if sym == nil {
|
||||
t.Fatal("symbol not found")
|
||||
}
|
||||
if sym.IsUsed() {
|
||||
t.Errorf("IsUsed() = true, want false")
|
||||
}
|
||||
|
||||
// Check that warning is generated
|
||||
warnings := st.CheckUnused()
|
||||
if len(warnings) != 1 {
|
||||
t.Fatalf("CheckUnused() returned %d warnings, want 1", len(warnings))
|
||||
}
|
||||
|
||||
expected := "test.c65:10: warning: variable 'unused' declared but never used"
|
||||
if warnings[0] != expected {
|
||||
t.Errorf("warning = %q, want %q", warnings[0], expected)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Used variable doesn't generate warning", func(t *testing.T) {
|
||||
st := NewSymbolTable()
|
||||
|
||||
// Add a variable
|
||||
err := st.AddVar("used", "", KindByte, 0, "test.c65", 20)
|
||||
if err != nil {
|
||||
t.Fatalf("AddVar() error = %v", err)
|
||||
}
|
||||
|
||||
// Mark it as used via Lookup (simulating actual usage)
|
||||
sym := st.Lookup("used", []string{})
|
||||
if sym == nil {
|
||||
t.Fatal("symbol not found")
|
||||
}
|
||||
|
||||
// Check that it's marked as used
|
||||
if !sym.IsUsed() {
|
||||
t.Errorf("IsUsed() = false, want true")
|
||||
}
|
||||
|
||||
// Check that no warning is generated
|
||||
warnings := st.CheckUnused()
|
||||
if len(warnings) != 0 {
|
||||
t.Errorf("CheckUnused() returned %d warnings, want 0: %v", len(warnings), warnings)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Constants are ignored", func(t *testing.T) {
|
||||
st := NewSymbolTable()
|
||||
|
||||
// Add a constant (should not generate warning)
|
||||
err := st.AddConst("MAX", "", KindByte, 100, "test.c65", 30)
|
||||
if err != nil {
|
||||
t.Fatalf("AddConst() error = %v", err)
|
||||
}
|
||||
|
||||
// Check that no warning is generated
|
||||
warnings := st.CheckUnused()
|
||||
if len(warnings) != 0 {
|
||||
t.Errorf("CheckUnused() returned %d warnings for constant, want 0: %v", len(warnings), warnings)
|
||||
}
|
||||
|
||||
// Verify constant is not marked as used (constants shouldn't track usage)
|
||||
sym := st.Get("MAX")
|
||||
if sym.IsUsed() {
|
||||
t.Errorf("Constant IsUsed() = true, want false")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Absolute variables are ignored", func(t *testing.T) {
|
||||
st := NewSymbolTable()
|
||||
|
||||
// Add an absolute variable (should not generate warning)
|
||||
err := st.AddAbsolute("SCREEN", "", KindWord, 0xD000, "test.c65", 40)
|
||||
if err != nil {
|
||||
t.Fatalf("AddAbsolute() error = %v", err)
|
||||
}
|
||||
|
||||
// Check that no warning is generated
|
||||
warnings := st.CheckUnused()
|
||||
if len(warnings) != 0 {
|
||||
t.Errorf("CheckUnused() returned %d warnings for absolute variable, want 0: %v", len(warnings), warnings)
|
||||
}
|
||||
|
||||
// Verify absolute variable is not marked as used (absolutes shouldn't track usage)
|
||||
sym := st.Get("SCREEN")
|
||||
if sym.IsUsed() {
|
||||
t.Errorf("Absolute variable IsUsed() = true, want false")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Function-scoped variables", func(t *testing.T) {
|
||||
st := NewSymbolTable()
|
||||
|
||||
// Add a global unused variable
|
||||
err := st.AddVar("global_unused", "", KindByte, 0, "test.c65", 50)
|
||||
if err != nil {
|
||||
t.Fatalf("AddVar() error = %v", err)
|
||||
}
|
||||
|
||||
// Add a function-scoped unused variable
|
||||
err = st.AddVar("local_unused", "myFunc", KindByte, 0, "test.c65", 60)
|
||||
if err != nil {
|
||||
t.Fatalf("AddVar() error = %v", err)
|
||||
}
|
||||
|
||||
// Add a function-scoped used variable
|
||||
err = st.AddVar("local_used", "myFunc", KindByte, 0, "test.c65", 70)
|
||||
if err != nil {
|
||||
t.Fatalf("AddVar() error = %v", err)
|
||||
}
|
||||
st.Lookup("local_used", []string{"myFunc"})
|
||||
|
||||
// Check warnings
|
||||
warnings := st.CheckUnused()
|
||||
if len(warnings) != 2 {
|
||||
t.Fatalf("CheckUnused() returned %d warnings, want 2: %v", len(warnings), warnings)
|
||||
}
|
||||
|
||||
// Check warning formats
|
||||
expectedGlobal := "test.c65:50: warning: variable 'global_unused' declared but never used"
|
||||
expectedLocal := "test.c65:60: warning: variable 'local_unused' in function 'myFunc' declared but never used"
|
||||
|
||||
foundGlobal := false
|
||||
foundLocal := false
|
||||
for _, w := range warnings {
|
||||
if w == expectedGlobal {
|
||||
foundGlobal = true
|
||||
}
|
||||
if w == expectedLocal {
|
||||
foundLocal = true
|
||||
}
|
||||
}
|
||||
|
||||
if !foundGlobal {
|
||||
t.Errorf("Missing warning for global variable: %q", expectedGlobal)
|
||||
}
|
||||
if !foundLocal {
|
||||
t.Errorf("Missing warning for local variable: %q", expectedLocal)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Multiple lookups don't affect usage flag", func(t *testing.T) {
|
||||
st := NewSymbolTable()
|
||||
|
||||
// Add a variable
|
||||
err := st.AddVar("counter", "", KindByte, 0, "test.c65", 80)
|
||||
if err != nil {
|
||||
t.Fatalf("AddVar() error = %v", err)
|
||||
}
|
||||
|
||||
// Lookup multiple times (should only mark as used once)
|
||||
sym1 := st.Lookup("counter", []string{})
|
||||
sym2 := st.Lookup("counter", []string{})
|
||||
sym3 := st.Lookup("counter", []string{})
|
||||
|
||||
if sym1 != sym2 || sym2 != sym3 {
|
||||
t.Error("Lookup should return same symbol instance")
|
||||
}
|
||||
|
||||
// Should still be marked as used (idempotent)
|
||||
if !sym1.IsUsed() {
|
||||
t.Errorf("IsUsed() after multiple lookups = false, want true")
|
||||
}
|
||||
|
||||
// No warnings should be generated
|
||||
warnings := st.CheckUnused()
|
||||
if len(warnings) != 0 {
|
||||
t.Errorf("CheckUnused() returned %d warnings for used variable, want 0", len(warnings))
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("LookupWithoutUsage doesn't mark as used", func(t *testing.T) {
|
||||
st := NewSymbolTable()
|
||||
|
||||
// Add a variable
|
||||
err := st.AddVar("temp", "", KindByte, 0, "test.c65", 90)
|
||||
if err != nil {
|
||||
t.Fatalf("AddVar() error = %v", err)
|
||||
}
|
||||
|
||||
// Use LookupWithoutUsage (validation only, not actual usage)
|
||||
sym := st.LookupWithoutUsage("temp", []string{})
|
||||
if sym == nil {
|
||||
t.Fatal("symbol not found")
|
||||
}
|
||||
|
||||
// Should NOT be marked as used
|
||||
if sym.IsUsed() {
|
||||
t.Errorf("IsUsed() after LookupWithoutUsage = true, want false")
|
||||
}
|
||||
|
||||
// Warning should be generated
|
||||
warnings := st.CheckUnused()
|
||||
if len(warnings) != 1 {
|
||||
t.Errorf("CheckUnused() returned %d warnings, want 1", len(warnings))
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Mixed variables with usage", func(t *testing.T) {
|
||||
st := NewSymbolTable()
|
||||
|
||||
// Add various types of variables
|
||||
st.AddVar("unused1", "", KindByte, 0, "test.c65", 100)
|
||||
st.AddVar("used1", "", KindByte, 0, "test.c65", 101)
|
||||
st.AddConst("CONST1", "", KindByte, 255, "test.c65", 102)
|
||||
st.AddAbsolute("ABS1", "", KindWord, 0xC000, "test.c65", 103)
|
||||
st.AddVar("unused2", "func1", KindWord, 0, "test.c65", 104)
|
||||
st.AddVar("used2", "func1", KindWord, 0, "test.c65", 105)
|
||||
|
||||
// Mark some as used
|
||||
st.Lookup("used1", []string{})
|
||||
st.Lookup("used2", []string{"func1"})
|
||||
|
||||
// Check warnings
|
||||
warnings := st.CheckUnused()
|
||||
if len(warnings) != 2 {
|
||||
t.Fatalf("CheckUnused() returned %d warnings, want 2: %v", len(warnings), warnings)
|
||||
}
|
||||
|
||||
// Verify correct warnings
|
||||
expected1 := "test.c65:100: warning: variable 'unused1' declared but never used"
|
||||
expected2 := "test.c65:104: warning: variable 'unused2' in function 'func1' declared but never used"
|
||||
|
||||
found1 := false
|
||||
found2 := false
|
||||
for _, w := range warnings {
|
||||
if w == expected1 {
|
||||
found1 = true
|
||||
}
|
||||
if w == expected2 {
|
||||
found2 = true
|
||||
}
|
||||
}
|
||||
|
||||
if !found1 {
|
||||
t.Errorf("Missing warning: %q", expected1)
|
||||
}
|
||||
if !found2 {
|
||||
t.Errorf("Missing warning: %q", expected2)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Label references", func(t *testing.T) {
|
||||
st := NewSymbolTable()
|
||||
|
||||
// Add a label reference variable
|
||||
err := st.AddLabel("handler", "", "irq_vector", "test.c65", 110)
|
||||
if err != nil {
|
||||
t.Fatalf("AddLabel() error = %v", err)
|
||||
}
|
||||
|
||||
// Label references are word variables that reference labels
|
||||
// They should be treated like regular variables for usage tracking
|
||||
sym := st.Get("handler")
|
||||
if !sym.Has(FlagLabelRef) {
|
||||
t.Error("Expected FlagLabelRef")
|
||||
}
|
||||
if !sym.IsWord() {
|
||||
t.Error("Label reference should be word")
|
||||
}
|
||||
|
||||
// Since we haven't used it, it should generate a warning
|
||||
warnings := st.CheckUnused()
|
||||
if len(warnings) != 1 {
|
||||
t.Errorf("CheckUnused() returned %d warnings for label reference, want 1", len(warnings))
|
||||
}
|
||||
|
||||
// Mark it as used
|
||||
st.Lookup("handler", []string{})
|
||||
|
||||
// Now no warning should be generated
|
||||
warnings = st.CheckUnused()
|
||||
if len(warnings) != 0 {
|
||||
t.Errorf("CheckUnused() returned %d warnings for used label reference, want 0", len(warnings))
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("LookupConstant doesn't mark as used", func(t *testing.T) {
|
||||
st := NewSymbolTable()
|
||||
|
||||
// Add a regular variable
|
||||
err := st.AddVar("var1", "", KindByte, 0, "test.c65", 120)
|
||||
if err != nil {
|
||||
t.Fatalf("AddVar() error = %v", err)
|
||||
}
|
||||
|
||||
// Add a constant
|
||||
err = st.AddConst("CONST1", "", KindByte, 100, "test.c65", 121)
|
||||
if err != nil {
|
||||
t.Fatalf("AddConst() error = %v", err)
|
||||
}
|
||||
|
||||
// Lookup constant (should not mark variable as used)
|
||||
val, found := st.LookupConstant("CONST1", []string{})
|
||||
if !found {
|
||||
t.Fatal("constant not found")
|
||||
}
|
||||
if val != 100 {
|
||||
t.Errorf("constant value = %d, want 100", val)
|
||||
}
|
||||
|
||||
// LookupConstant on non-constant variable (should not mark as used)
|
||||
val, found = st.LookupConstant("var1", []string{})
|
||||
if found {
|
||||
t.Error("LookupConstant should return false for non-constant")
|
||||
}
|
||||
|
||||
// Check that variable is still unused
|
||||
sym := st.Get("var1")
|
||||
if sym.IsUsed() {
|
||||
t.Errorf("IsUsed() after LookupConstant = true, want false")
|
||||
}
|
||||
|
||||
// Warning should be generated for the variable
|
||||
warnings := st.CheckUnused()
|
||||
if len(warnings) != 1 {
|
||||
t.Errorf("CheckUnused() returned %d warnings, want 1", len(warnings))
|
||||
}
|
||||
|
||||
expected := "test.c65:120: warning: variable 'var1' declared but never used"
|
||||
if warnings[0] != expected {
|
||||
t.Errorf("warning = %q, want %q", warnings[0], expected)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Lookup doesn't mark constants or absolutes as used", func(t *testing.T) {
|
||||
st := NewSymbolTable()
|
||||
|
||||
// Add a constant
|
||||
err := st.AddConst("MAX", "", KindByte, 255, "test.c65", 130)
|
||||
if err != nil {
|
||||
t.Fatalf("AddConst() error = %v", err)
|
||||
}
|
||||
|
||||
// Add an absolute variable
|
||||
err = st.AddAbsolute("VIC", "", KindWord, 0xD000, "test.c65", 131)
|
||||
if err != nil {
|
||||
t.Fatalf("AddAbsolute() error = %v", err)
|
||||
}
|
||||
|
||||
// Lookup constant (should not mark as used)
|
||||
symConst := st.Lookup("MAX", []string{})
|
||||
if symConst == nil {
|
||||
t.Fatal("constant not found")
|
||||
}
|
||||
if symConst.IsUsed() {
|
||||
t.Error("constant should not be marked as used after Lookup")
|
||||
}
|
||||
|
||||
// Lookup absolute variable (should not mark as used)
|
||||
symAbs := st.Lookup("VIC", []string{})
|
||||
if symAbs == nil {
|
||||
t.Fatal("absolute variable not found")
|
||||
}
|
||||
if symAbs.IsUsed() {
|
||||
t.Error("absolute variable should not be marked as used after Lookup")
|
||||
}
|
||||
|
||||
// No warnings should be generated
|
||||
warnings := st.CheckUnused()
|
||||
if len(warnings) != 0 {
|
||||
t.Errorf("CheckUnused() returned %d warnings for constants/absolutes, want 0", len(warnings))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
|||
13
opencode-config/opencode.json
Normal file
13
opencode-config/opencode.json
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"agent": {
|
||||
"plan": {
|
||||
"model": "deepseek/deepseek-reasoner",
|
||||
"description": "Planning and architecture analysis using DeepSeek Reasoner"
|
||||
},
|
||||
"build": {
|
||||
"model": "deepseek/deepseek-chat",
|
||||
"description": "Implementation and coding using DeepSeek Chat"
|
||||
}
|
||||
}
|
||||
}
|
||||
12
opencode-docker.sh
Normal file
12
opencode-docker.sh
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
export DOCKER_UID=$(id -u)
|
||||
export DOCKER_GID=$(id -g)
|
||||
|
||||
# Load from .env if it exists
|
||||
if [ -f .env ]; then
|
||||
export $(grep -v '^#' .env | xargs)
|
||||
fi
|
||||
|
||||
docker compose run --rm opencode-deepseek-c65gm
|
||||
Loading…
Reference in a new issue