Skip to content

Commit

Permalink
add support for specifying ranges for incbin, incbinstr, and `inc…
Browse files Browse the repository at this point in the history
…hexstr`
  • Loading branch information
MineRobber9000 authored and hlorenzi committed Dec 29, 2023
1 parent e7b43d5 commit 4c543f5
Show file tree
Hide file tree
Showing 25 changed files with 159 additions and 20 deletions.
130 changes: 122 additions & 8 deletions src/asm/resolver/eval_fn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ fn eval_builtin_incbin(
query: &mut expr::EvalFunctionQuery)
-> Result<expr::Value, ()>
{
query.ensure_arg_number(1)?;
query.ensure_min_max_arg_number(1, 3)?;

let relative_filename = query.args[0].value.expect_string(
query.report,
Expand All @@ -148,8 +148,59 @@ fn eval_builtin_incbin(
Some(query.args[0].span),
file_handle)?;

let start = {
if query.args.len() >= 2
{
query.args[1].value.expect_usize(
query.report,
query.args[1].span)?
}
else
{
0
}
};

let end = {
if query.args.len() >= 3
{
let size = query.args[2].value.expect_usize(
query.report,
query.args[2].span)?;

start + size
}
else
{
bytes.len()
}
};

if start >= bytes.len()
{
query.report.error_span(
format!(
"`incbin` range starts after EOF ({} >= {})",
start,
bytes.len()),
query.args[1].span);
return Err(());
}

if end > bytes.len()
{
query.report.error_span(
format!(
"`incbin` range ends after EOF ({} + {} > {})",
start,
end - start,
bytes.len()),
query.args[2].span);
return Err(());
}

Ok(expr::Value::make_integer(
util::BigInt::from_bytes_be(&bytes)))
util::BigInt::from_bytes_be(&bytes[start..end])))
}


Expand All @@ -167,7 +218,8 @@ fn eval_builtin_incbinstr(
decls,
defs,
ctx,
query)
query,
"incbinstr")
}


Expand All @@ -185,7 +237,8 @@ fn eval_builtin_inchexstr(
decls,
defs,
ctx,
query)
query,
"inchexstr")
}


Expand All @@ -195,10 +248,11 @@ fn eval_builtin_incstr(
_decls: &asm::ItemDecls,
_defs: &asm::ItemDefs,
ctx: &asm::ResolverContext,
query: &mut expr::EvalFunctionQuery)
query: &mut expr::EvalFunctionQuery,
funcname: &str)
-> Result<expr::Value, ()>
{
query.ensure_arg_number(1)?;
query.ensure_min_max_arg_number(1, 3)?;

let relative_filename = query.args[0].value.expect_string(
query.report,
Expand Down Expand Up @@ -258,5 +312,65 @@ fn eval_builtin_incstr(
}
}

Ok(expr::Value::make_integer(bitvec.to_bigint()))
}
let bigint = bitvec.to_bigint();

let bigint_size = bigint.size.unwrap();

let start = {
if query.args.len() >= 2
{
query.args[1].value.expect_usize(
query.report,
query.args[1].span)?
}
else
{
0
}
};

let end = {
if query.args.len() >= 3
{
let size = query.args[2].value.expect_usize(
query.report,
query.args[2].span)?;

start + size
}
else
{
bigint_size / bits_per_char
}
};

if (start * bits_per_char) >= bigint_size
{
query.report.error_span(
format!(
"`{}` range starts after EOF ({} >= {})",
funcname,
start,
bigint_size / bits_per_char),
query.args[1].span);
return Err(());
}

if (end * bits_per_char) > bigint_size
{
query.report.error_span(
format!(
"`{}` range ends after EOF ({} + {} > {})",
funcname,
start,
end - start,
bigint_size / bits_per_char),
query.args[2].span);
return Err(());
}

Ok(expr::Value::make_integer(
bigint.slice(
bigint_size - (start * bits_per_char),
bigint_size - (end * bits_per_char))))
}
6 changes: 3 additions & 3 deletions src/expr/expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,7 @@ impl Value
_ =>
{
report.error_span(
"expected integer",
"expected non-negative integer",
span);

Err(())
Expand Down Expand Up @@ -394,7 +394,7 @@ impl Value
_ =>
{
report.error_span(
"expected integer",
"expected non-negative integer",
span);

Err(())
Expand Down Expand Up @@ -430,7 +430,7 @@ impl Value
_ =>
{
report.error_span(
"expected integer",
"expected positive integer",
span);

Err(())
Expand Down
4 changes: 2 additions & 2 deletions src/test/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -275,8 +275,8 @@ fn test_ops_slice()
test("-1[1000:1000]", Pass(expr::Value::make_integer(util::BigInt::new(1, Some(1)))));

test("0x00[0:7]", Fail(("test", 1, "invalid")));
test("0x00`{}", Fail(("test", 1, "expected integer")));
test("0x00`(1 == 2)", Fail(("test", 1, "expected integer")));
test("0x00`{}", Fail(("test", 1, "expected non-negative integer")));
test("0x00`(1 == 2)", Fail(("test", 1, "expected non-negative integer")));
test("0x00`-1", Fail(("test", 1, "expected expression")));
test("0x00`(-1)", Fail(("test", 1, "out of supported range")));
test("0x00[7:-1]", Fail(("test", 1, "out of supported range")));
Expand Down
12 changes: 11 additions & 1 deletion src/util/bigint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -341,9 +341,19 @@ impl BigInt
panic!("invalid slice range");
}

if let Some(size) = self.size
{
if self.bigint.sign() != num_bigint::Sign::Minus &&
left == size &&
right == 0
{
return self.clone();
}
}

let mut result = BigInt::from(0);

for i in 0..(left - right)
for i in (0..(left - right)).rev()
{
result.set_bit(
i,
Expand Down
1 change: 1 addition & 0 deletions tests/incbin/err_end_after_eof.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
#d incbin("data1.bin",2,4) ; error: failed / error: ends after EOF (2 + 4 > 5)
1 change: 1 addition & 0 deletions tests/incbin/err_start_after_eof.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
#d incbin("data1.bin",5) ; error: failed / error: starts after EOF (5 >= 5)
2 changes: 1 addition & 1 deletion tests/incbin/err_too_few_arguments.asm
Original file line number Diff line number Diff line change
@@ -1 +1 @@
#d incbin() ; error: failed / error: expected 1 argument
#d incbin() ; error: failed / error: expected 1 to 3 arguments
2 changes: 1 addition & 1 deletion tests/incbin/err_too_many_args.asm
Original file line number Diff line number Diff line change
@@ -1 +1 @@
#d incbin("data1.bin", "data2.bin") ; error: failed / error: expected 1 argument
#d incbin("data1.bin", 1, 2, 3) ; error: failed / error: expected 1 to 3 arguments
1 change: 1 addition & 0 deletions tests/incbin/err_wrong_usage.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
#d incbin("data1.bin", "data2.bin") ; error: failed / error: expected non-negative integer
1 change: 1 addition & 0 deletions tests/incbin/ok_start.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
#d incbin("data1.bin",1) ; = 0x656c6c6f
1 change: 1 addition & 0 deletions tests/incbin/ok_start_size.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
#d incbin("data1.bin",2,2) ; = 0x6c6c
1 change: 1 addition & 0 deletions tests/incbinstr/err_end_after_eof.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
#d incbinstr("data1.txt",4,8) ; error: failed / error: ends after EOF (4 + 8 > 8)
1 change: 1 addition & 0 deletions tests/incbinstr/err_start_after_eof.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
#d incbinstr("data1.txt",8) ; error: failed / error: starts after EOF (8 >= 8)
2 changes: 1 addition & 1 deletion tests/incbinstr/err_too_few_args.asm
Original file line number Diff line number Diff line change
@@ -1 +1 @@
#d incbinstr() ; error: failed / error: expected 1 argument
#d incbinstr() ; error: failed / error: expected 1 to 3 arguments
2 changes: 1 addition & 1 deletion tests/incbinstr/err_too_many_args.asm
Original file line number Diff line number Diff line change
@@ -1 +1 @@
#d incbinstr("data1.txt", "data2.txt") ; error: failed / error: expected 1 argument
#d incbinstr("data1.txt",0,1,2) ; error: failed / error: expected 1 to 3 arguments
1 change: 1 addition & 0 deletions tests/incbinstr/err_wrong_usage.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
#d incbinstr("data1.txt", "data2.txt") ; error: failed / error: expected non-negative integer
1 change: 1 addition & 0 deletions tests/incbinstr/ok_start.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
#d incbinstr("data3.txt",4) ; =0xaf5a
1 change: 1 addition & 0 deletions tests/incbinstr/ok_start_size.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
#d incbinstr("data3.txt",8,8) ; =0xf5
1 change: 1 addition & 0 deletions tests/inchexstr/err_end_after_eof.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
#d inchexstr("data1.txt",2,4) ; error: failed / error: ends after EOF (2 + 4 > 4)
1 change: 1 addition & 0 deletions tests/inchexstr/err_start_after_eof.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
#d inchexstr("data1.txt",4) ; error: failed / error: starts after EOF (4 >= 4)
2 changes: 1 addition & 1 deletion tests/inchexstr/err_too_few_args.asm
Original file line number Diff line number Diff line change
@@ -1 +1 @@
#d inchexstr() ; error: failed / error: expected 1 argument
#d inchexstr() ; error: failed / error: expected 1 to 3 arguments
2 changes: 1 addition & 1 deletion tests/inchexstr/err_too_many_args.asm
Original file line number Diff line number Diff line change
@@ -1 +1 @@
#d inchexstr("data1.txt", "data2.txt") ; error: failed / error: expected 1 argument
#d inchexstr("data1.txt",0,1,2) ; error: failed / error: expected 1 to 3 arguments
1 change: 1 addition & 0 deletions tests/inchexstr/err_wrong_usage.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
#d inchexstr("data1.txt", "data2.txt") ; error: failed / error: expected non-negative integer
1 change: 1 addition & 0 deletions tests/inchexstr/ok_start.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
#d inchexstr("data3.txt",4) ; =0x5a5af5a5a0000
1 change: 1 addition & 0 deletions tests/inchexstr/ok_start_size.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
#d inchexstr("data3.txt",8,2) ; =0xf5

0 comments on commit 4c543f5

Please sign in to comment.