Merge pull request #727 from mir-protocol/fix_macro_vars_in_stack

Fix macro vars in `%stack` directives
This commit is contained in:
Daniel Lubarov 2022-09-21 09:22:16 -07:00 committed by GitHub
commit a84d3f5d44
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 50 additions and 8 deletions

View File

@ -195,12 +195,12 @@ fn expand_macro_call(
Item::StackManipulation(before, after) => {
let after = after
.iter()
.map(|replacement| {
if let StackReplacement::MacroLabel(label) = replacement {
.map(|replacement| match replacement {
StackReplacement::MacroLabel(label) => {
StackReplacement::Identifier(get_actual_label(label))
} else {
replacement.clone()
}
StackReplacement::MacroVar(var) => get_arg(var).into(),
_ => replacement.clone(),
})
.collect();
Item::StackManipulation(before.clone(), after)
@ -508,8 +508,8 @@ mod tests {
"%macro bar(y) PUSH $y %endmacro",
"%foo(42)",
]);
let push = get_push_opcode(1);
assert_eq!(kernel.code, vec![push, 42, push, 42]);
let push1 = get_push_opcode(1);
assert_eq!(kernel.code, vec![push1, 42, push1, 42]);
}
#[test]
@ -587,6 +587,34 @@ mod tests {
assert_eq!(kernel.code, vec![dup1]);
}
#[test]
fn stack_manipulation_in_macro() {
let pop = get_opcode("POP");
let push1 = get_push_opcode(1);
let kernel = parse_and_assemble(&[
"%macro set_top(x) %stack (a) -> ($x) %endmacro",
"%set_top(42)",
]);
assert_eq!(kernel.code, vec![pop, push1, 42]);
}
#[test]
fn stack_manipulation_in_macro_with_name_collision() {
let pop = get_opcode("POP");
let push_label = get_push_opcode(BYTES_PER_OFFSET);
// In the stack directive, there's a named item `foo`.
// But when we invoke `%foo(foo)`, the argument refers to the `foo` label.
// Thus the expanded macro is `%stack (foo) -> (label foo)` (not real syntax).
let kernel = parse_and_assemble(&[
"global foo:",
"%macro foo(x) %stack (foo) -> ($x) %endmacro",
"%foo(foo)",
]);
assert_eq!(kernel.code, vec![pop, push_label, 0, 0, 0]);
}
fn parse_and_assemble(files: &[&str]) -> Kernel {
parse_and_assemble_ext(files, HashMap::new(), true)
}

View File

@ -46,14 +46,27 @@ pub(crate) enum StackPlaceholder {
/// The right hand side of a %stack stack-manipulation macro.
#[derive(Eq, PartialEq, Clone, Debug)]
pub(crate) enum StackReplacement {
Literal(U256),
/// Can be either a named item or a label.
Identifier(String),
Literal(U256),
Label(String),
MacroLabel(String),
MacroVar(String),
Constant(String),
}
impl From<PushTarget> for StackReplacement {
fn from(target: PushTarget) -> Self {
match target {
PushTarget::Literal(x) => Self::Literal(x),
PushTarget::Label(l) => Self::Label(l),
PushTarget::MacroLabel(l) => Self::MacroLabel(l),
PushTarget::MacroVar(v) => Self::MacroVar(v),
PushTarget::Constant(c) => Self::Constant(c),
}
}
}
/// The target of a `PUSH` operation.
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub(crate) enum PushTarget {

View File

@ -52,6 +52,7 @@ fn expand(names: Vec<StackPlaceholder>, replacements: Vec<StackReplacement>) ->
let mut dst = replacements
.into_iter()
.flat_map(|item| match item {
StackReplacement::Literal(n) => vec![StackItem::PushTarget(PushTarget::Literal(n))],
StackReplacement::Identifier(name) => {
// May be either a named item or a label. Named items have precedence.
if stack_blocks.contains_key(&name) {
@ -68,7 +69,7 @@ fn expand(names: Vec<StackPlaceholder>, replacements: Vec<StackReplacement>) ->
vec![StackItem::PushTarget(PushTarget::Label(name))]
}
}
StackReplacement::Literal(n) => vec![StackItem::PushTarget(PushTarget::Literal(n))],
StackReplacement::Label(name) => vec![StackItem::PushTarget(PushTarget::Label(name))],
StackReplacement::MacroLabel(_)
| StackReplacement::MacroVar(_)
| StackReplacement::Constant(_) => {