Skip to content

Commit

Permalink
asm: fix references to locals in global instruction macros
Browse files Browse the repository at this point in the history
This ensures references to local macros within instruction macros will be
resolved within the document where the macro is defined.
  • Loading branch information
fjl committed Sep 29, 2023
1 parent d61ac65 commit e7aa381
Show file tree
Hide file tree
Showing 4 changed files with 30 additions and 8 deletions.
7 changes: 6 additions & 1 deletion asm/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,18 @@ type document struct {
parent *document

// instruction macro parameters are passed through this map
instrMacroArgs map[string]astExpr
instrMacroArgs map[string]instrMacroArg

// for compiler
includes map[*includeInstruction]*document // filled by compiler
creation astStatement
}

type instrMacroArg struct {
calldoc *document // document of callsite
expr astExpr // the argument
}

func (doc *document) lookupLabel(lref *labelRefExpr) (*labelDefInstruction, *document) {
for doc != nil {
li, ok := doc.labels[lref.ident]
Expand Down
11 changes: 6 additions & 5 deletions asm/compiler.go
Original file line number Diff line number Diff line change
Expand Up @@ -329,10 +329,11 @@ func (inst *macroCallInstruction) expand(c *Compiler, doc *document, prog []*ins
name := inst.ident.text

var def *instructionMacroDef
var defdoc *document
if isGlobal(name) {
def, _ = c.globals.lookupInstrMacro(name)
def, defdoc = c.globals.lookupInstrMacro(name)
} else {
def, _ = doc.lookupInstrMacro(name)
def, defdoc = doc.lookupInstrMacro(name)
}
if def == nil {
return nil, fmt.Errorf("%w %%%s", ecUndefinedInstrMacro, name)
Expand All @@ -347,14 +348,14 @@ func (inst *macroCallInstruction) expand(c *Compiler, doc *document, prog []*ins
if len(inst.args) != len(def.params) {
return nil, fmt.Errorf("%w, macro %%%s needs %d", ecInvalidArgumentCount, name, len(def.params))
}
args := make(map[string]astExpr)
args := make(map[string]instrMacroArg)
for i, param := range def.params {
args[param] = inst.args[i]
args[param] = instrMacroArg{calldoc: doc, expr: inst.args[i]}
}

// Expand. Here we clone the macro document and then run it.
macroDoc := *def.body
macroDoc.parent = doc
macroDoc.parent = defdoc
macroDoc.creation = inst
macroDoc.instrMacroArgs = args

Expand Down
4 changes: 2 additions & 2 deletions asm/eval.go
Original file line number Diff line number Diff line change
Expand Up @@ -211,12 +211,12 @@ func (expr *variableExpr) eval(e *evaluator, env *evalEnvironment) (*big.Int, er
return v, nil
}
// Check for instruction macro args.
vexpr, ok := env.doc.instrMacroArgs[expr.ident]
arg, ok := env.doc.instrMacroArgs[expr.ident]
if !ok {
return nil, fmt.Errorf("%w $%s", ecUndefinedVariable, expr.ident)
}
// Evaluate it in the parent scope.
return vexpr.eval(e, newEvalEnvironment(env.doc.parent))
return arg.expr.eval(e, newEvalEnvironment(arg.calldoc))
}

func (expr *macroCallExpr) eval(e *evaluator, env *evalEnvironment) (*big.Int, error) {
Expand Down
16 changes: 16 additions & 0 deletions asm/testdata/compiler-tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,22 @@ instr-macro-outer-label:
output:
bytecode: "00 6006 56 6001 5b 00"

instr-macro-global-ref-local:
input:
code: |
%Gmac
#include "incfile.eas"
files:
incfile.eas: |
#define %Gmac {
%local
}
#define %local {
push 1
}
output:
bytecode: "6001"

instr-macro-recursion:
input:
code: |
Expand Down

0 comments on commit e7aa381

Please sign in to comment.