Skip to content
This repository has been archived by the owner on Dec 10, 2023. It is now read-only.

Commit

Permalink
fix hlorenzi#115: add unordered label support within asm blocks
Browse files Browse the repository at this point in the history
  • Loading branch information
Emmett81 authored and hlorenzi committed Nov 7, 2021
1 parent 71bacc1 commit cd58621
Show file tree
Hide file tree
Showing 7 changed files with 287 additions and 93 deletions.
239 changes: 146 additions & 93 deletions src/asm/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1331,128 +1331,181 @@ impl State
fileserver: &dyn util::FileServer)
-> Result<expr::Value, ()>
{
// Clone the context in order to advance the logical address
// between instructions.
let mut inner_ctx = ctx.clone();

let mut result = util::BigInt::new(0, Some(0));

let mut parser = syntax::Parser::new(Some(info.report.clone()), info.tokens);

//println!("asm block `{}`", fileserver.get_excerpt(&parser.get_full_span()));

while !parser.is_over()
let mut size_guess = 0;

// Parse the tokens twice, once to find the labels and guess
// size of result, then to assemble the output
for iterations in 0..2
{
// Substitute `{x}` occurrences with tokens from the argument
let mut subs_parser = parser.slice_until_linebreak_over_nested_braces();
let subparser_span = subs_parser.get_full_span();
// Clone the context in order to advance the logical address
// between instructions.
let mut inner_ctx = ctx.clone();

let mut parser = syntax::Parser::new(Some(info.report.clone()), info.tokens);

//println!("> instr `{}`", fileserver.get_excerpt(&subparser_span));
//println!("asm block `{}`", fileserver.get_excerpt(&parser.get_full_span()));

let mut subs_tokens: Vec<syntax::Token> = Vec::new();
while !subs_parser.is_over()
while !parser.is_over()
{
if let Some(open_token) = subs_parser.maybe_expect(syntax::TokenKind::BraceOpen)
{
let arg_name_token = subs_parser.expect(syntax::TokenKind::Identifier)?;
let arg_name = arg_name_token.excerpt.as_ref().unwrap();
// Substitute `{x}` occurrences with tokens from the argument
let mut subs_parser = parser.slice_until_linebreak_over_nested_braces();
let subparser_span = subs_parser.get_full_span();

let token_sub = match info.args.get_token_sub(&arg_name)
//println!("> instr `{}`", fileserver.get_excerpt(&subparser_span));

let mut subs_tokens: Vec<syntax::Token> = Vec::new();
while !subs_parser.is_over()
{
if let Some(open_token) = subs_parser.maybe_expect(syntax::TokenKind::BraceOpen)
{
None =>
let arg_name_token = subs_parser.expect(syntax::TokenKind::Identifier)?;
let arg_name = arg_name_token.excerpt.as_ref().unwrap();

let token_sub = match info.args.get_token_sub(&arg_name)
{
info.report.error_span("unknown argument", &arg_name_token.span);
return Err(());
}
Some(t) => t
};
None =>
{
info.report.error_span("unknown argument", &arg_name_token.span);
return Err(());
}
Some(t) => t
};

let close_token = subs_parser.expect(syntax::TokenKind::BraceClose)?;
let sub_span = open_token.span.join(&close_token.span);
let close_token = subs_parser.expect(syntax::TokenKind::BraceClose)?;
let sub_span = open_token.span.join(&close_token.span);

for token in token_sub
for token in token_sub
{
let mut sub_token = token.clone();
sub_token.span = sub_span.clone();
subs_tokens.push(sub_token);
}
}
else
{
let mut sub_token = token.clone();
sub_token.span = sub_span.clone();
subs_tokens.push(sub_token);
subs_tokens.push(subs_parser.advance());
}
}
else

let mut subparser = syntax::Parser::new(Some(info.report.clone()), &subs_tokens);
subparser.suppress_reports();

//println!("> after subs `{:?}`", subs_tokens);

if subparser.next_is(0, syntax::TokenKind::Identifier) && subparser.next_is(1, syntax::TokenKind::Colon)
{
subs_tokens.push(subs_parser.advance());
let label_tk = subparser.expect(syntax::TokenKind::Identifier)?;

let label_name = label_tk.excerpt.as_ref().unwrap();

info.args.set_local(
label_name,
expr::Value::make_integer(
self.get_addr(info.report.clone(), &inner_ctx, &subparser_span)?));

subparser.expect(syntax::TokenKind::Colon)?;
}
}
else
{
let matches = asm::parser::match_rule_invocation(
&self,
subparser,
inner_ctx.clone(),
fileserver,
info.report.clone())?;

let mut subparser = syntax::Parser::new(Some(info.report.clone()), &subs_tokens);
subparser.suppress_reports();
if iterations == 0
{
let value = self.resolve_rule_invocation(
info.report.clone(),
&matches,
fileserver,
false,
info.args).unwrap_or(expr::Value::make_integer(0));

//println!("> after subs `{:?}`", subs_tokens);

let matches = asm::parser::match_rule_invocation(
&self,
subparser,
inner_ctx.clone(),
fileserver,
info.report.clone())?;
if value.get_bigint().is_some() && value.get_bigint().unwrap().size.is_some()
{
let size = value.get_bigint().unwrap().size.unwrap();
size_guess += size;
inner_ctx.bit_offset += size;
}
}

let value = self.resolve_rule_invocation(
info.report.clone(),
&matches,
fileserver,
true,
info.args)?;
if iterations == 1
{
let value = self.resolve_rule_invocation(
info.report.clone(),
&matches,
fileserver,
true,
info.args)?;

//println!(" value = {:?}", value);

let (bigint, size) = match value.get_bigint()
{
Some(bigint) =>
{
match bigint.size
{
Some(size) => (bigint, size),
None =>
{
info.report.error_span(
"cannot infer size of instruction",
&subparser_span);

//println!(" value = {:?}", value);

let (bigint, size) = match value.get_bigint()
{
Some(bigint) =>
{
match bigint.size
{
Some(size) => (bigint, size),
None =>
return Err(());
}
}
}

_ =>
{
info.report.error_span(
"wrong type returned from instruction",
&subparser_span);

return Err(());
}
};

if size > 0
{
info.report.error_span(
"cannot infer size of instruction",
&subparser_span);
if result.size.unwrap() == 0
{
result = bigint;
}
else
{
result = result.concat(
(result.size.unwrap(), 0),
&bigint,
(size, 0));
}

return Err(());
inner_ctx.bit_offset += size;
}
}
}

_ =>
{
info.report.error_span(
"wrong type returned from instruction",
&subparser_span);

return Err(());
}
};

if size > 0
{
if result.size.unwrap() == 0
{
result = bigint;
}
else
{
result = result.concat(
(result.size.unwrap(), 0),
&bigint,
(size, 0));
}

inner_ctx.bit_offset += size;
parser.expect_linebreak()?;
}

parser.expect_linebreak()?;
}

//println!(" result size guess = {:?}", size_guess);
//println!(" result size = {:?}", result.size);

if size_guess != result.size.unwrap()
{
info.report.error_span(
"size of asm block did not converge after iterations",
&info.span);

return Err(());
}

Ok(expr::Value::make_integer(result))
}
}
29 changes: 29 additions & 0 deletions tests/issue115/3.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#ruledef {
emit {x: u8} => x

test => asm
{
label:
emit $
label2:
emit $
emit label
emit label2
emit $
}

nested_test => asm
{
label:
emit $
label2:
emit $
emit label
emit label2
emit $
test
}
}

test ; = 0x00_01_00_01_04
nested_test ; = 0x05_06_05_06_09_0a_0b_0a_0b_0e
26 changes: 26 additions & 0 deletions tests/issue115/4.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#ruledef {
emit {x: u8} => x

run => asm
{
test
emit 0x10
}

test => asm
{
test2 end
test2 end
end:
}

test2 {l: u32} => asm
{
emit l
emit end
end:
}
}

run ; = 0x04_02_04_04_10
emit $ ; = 0x05
24 changes: 24 additions & 0 deletions tests/issue115/5.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#ruledef test
{
ld {x} =>
{
assert(x <= 0x8)
0x11 @ x`16
}
ld {x} =>
{
assert(x > 0x8)
0x22 @ x`8
}

test => asm
{
label:
ld label
ld label
ld label
}
}

test ; = 0x110000_110000_110000
24 changes: 24 additions & 0 deletions tests/issue115/6.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#ruledef test
{
ld {x} =>
{
assert(x <= 0x8)
0x11 @ x`16
}
ld {x} =>
{
assert(x > 0x8)
0x22 @ x`8
}

test => asm
{
ld label
ld label
ld label
label:
}
}

test ; error: failed / error:_:15: converge
Loading

0 comments on commit cd58621

Please sign in to comment.