From 602919d237c9197b6b5f56edffeceaed67d5a7f7 Mon Sep 17 00:00:00 2001 From: hlorenzi Date: Mon, 7 Oct 2024 21:07:04 -0300 Subject: [PATCH] add the `assert` directive --- src/asm/mod.rs | 1 + src/asm/parser/directive.rs | 3 ++ src/asm/parser/directive_assert.rs | 26 ++++++++++++++++ src/asm/parser/mod.rs | 5 ++++ src/asm/resolver/assert.rs | 41 ++++++++++++++++++++++++++ src/asm/resolver/iter.rs | 17 ++++++++++- src/asm/resolver/mod.rs | 14 +++++++++ src/expr/expression.rs | 27 +++++++++++++++++ tests/assert/err_addr_convergence.asm | 27 +++++++++++++++++ tests/assert/err_constant.asm | 3 ++ tests/assert/err_constant_deferred.asm | 3 ++ tests/assert/err_expected_bool.asm | 2 ++ tests/assert/err_simple.asm | 2 ++ tests/assert/err_unknown_symbol.asm | 1 + tests/assert/ok_addr_convergence.asm | 27 +++++++++++++++++ tests/assert/ok_constant.asm | 3 ++ tests/assert/ok_constant_deferred.asm | 3 ++ tests/assert/ok_simple.asm | 2 ++ 18 files changed, 206 insertions(+), 1 deletion(-) create mode 100644 src/asm/parser/directive_assert.rs create mode 100644 src/asm/resolver/assert.rs create mode 100644 tests/assert/err_addr_convergence.asm create mode 100644 tests/assert/err_constant.asm create mode 100644 tests/assert/err_constant_deferred.asm create mode 100644 tests/assert/err_expected_bool.asm create mode 100644 tests/assert/err_simple.asm create mode 100644 tests/assert/err_unknown_symbol.asm create mode 100644 tests/assert/ok_addr_convergence.asm create mode 100644 tests/assert/ok_constant.asm create mode 100644 tests/assert/ok_constant_deferred.asm create mode 100644 tests/assert/ok_simple.asm diff --git a/src/asm/mod.rs b/src/asm/mod.rs index 269b0348..84feaa2b 100644 --- a/src/asm/mod.rs +++ b/src/asm/mod.rs @@ -6,6 +6,7 @@ pub use parser::{ AstAny, AstDirectiveAddr, AstDirectiveAlign, + AstDirectiveAssert, AstDirectiveBank, AstDirectiveBankdef, AstDirectiveBits, diff --git a/src/asm/parser/directive.rs b/src/asm/parser/directive.rs index a98d4448..1fd5757d 100644 --- a/src/asm/parser/directive.rs +++ b/src/asm/parser/directive.rs @@ -81,6 +81,9 @@ pub fn parse( "subruledef" => Ok(asm::AstAny::DirectiveRuledef( asm::parser::directive_ruledef::parse(report, walker, true, header_span)?)), + "assert" => Ok(asm::AstAny::DirectiveAssert( + asm::parser::directive_assert::parse(report, walker, header_span)?)), + _ => { report.error_span( diff --git a/src/asm/parser/directive_assert.rs b/src/asm/parser/directive_assert.rs new file mode 100644 index 00000000..8534552e --- /dev/null +++ b/src/asm/parser/directive_assert.rs @@ -0,0 +1,26 @@ +use crate::*; + + +#[derive(Clone, Debug)] +pub struct AstDirectiveAssert +{ + pub header_span: diagn::Span, + pub condition_expr: expr::Expr, +} + + +pub fn parse( + report: &mut diagn::Report, + walker: &mut syntax::Walker, + header_span: diagn::Span) + -> Result +{ + let expr = expr::parse(report, walker)?; + + walker.expect_linebreak(report)?; + + Ok(AstDirectiveAssert { + header_span, + condition_expr: expr, + }) +} \ No newline at end of file diff --git a/src/asm/parser/mod.rs b/src/asm/parser/mod.rs index b1687def..a26ee0bb 100644 --- a/src/asm/parser/mod.rs +++ b/src/asm/parser/mod.rs @@ -9,6 +9,9 @@ pub use directive_addr::AstDirectiveAddr; mod directive_align; pub use directive_align::AstDirectiveAlign; +mod directive_assert; +pub use directive_assert::AstDirectiveAssert; + mod directive_bank; pub use directive_bank::AstDirectiveBank; @@ -78,6 +81,7 @@ pub enum AstAny { DirectiveAddr(AstDirectiveAddr), DirectiveAlign(AstDirectiveAlign), + DirectiveAssert(AstDirectiveAssert), DirectiveBank(AstDirectiveBank), DirectiveBankdef(AstDirectiveBankdef), DirectiveBits(AstDirectiveBits), @@ -327,6 +331,7 @@ impl AstAny { AstAny::DirectiveAddr(node) => node.header_span, AstAny::DirectiveAlign(node) => node.header_span, + AstAny::DirectiveAssert(node) => node.header_span, AstAny::DirectiveBank(node) => node.header_span, AstAny::DirectiveBankdef(node) => node.header_span, AstAny::DirectiveBits(node) => node.header_span, diff --git a/src/asm/resolver/assert.rs b/src/asm/resolver/assert.rs new file mode 100644 index 00000000..64504e0e --- /dev/null +++ b/src/asm/resolver/assert.rs @@ -0,0 +1,41 @@ +use crate::*; + + +pub fn resolve_assert( + report: &mut diagn::Report, + opts: &asm::AssemblyOptions, + fileserver: &mut dyn util::FileServer, + ast_assert: &asm::AstDirectiveAssert, + decls: &asm::ItemDecls, + defs: &mut asm::ItemDefs, + ctx: &asm::ResolverContext) + -> Result +{ + if !ctx.is_last_iteration + { + return Ok(asm::ResolutionState::Unresolved); + } + + let value = asm::resolver::eval( + report, + opts, + fileserver, + decls, + defs, + ctx, + &mut expr::EvalContext::new(), + &ast_assert.condition_expr)?; + + let satisfied = value.expect_bool( + report, + ast_assert.condition_expr.span())?; + + if !satisfied + { + report.error_span( + "assertion failed", + ast_assert.condition_expr.span()); + } + + Ok(asm::ResolutionState::Resolved) +} \ No newline at end of file diff --git a/src/asm/resolver/iter.rs b/src/asm/resolver/iter.rs index 4e7e0a54..0d828f4d 100644 --- a/src/asm/resolver/iter.rs +++ b/src/asm/resolver/iter.rs @@ -43,6 +43,7 @@ pub enum ResolverNode<'ast> Res(&'ast asm::AstDirectiveRes), Align(&'ast asm::AstDirectiveAlign), Addr(&'ast asm::AstDirectiveAddr), + Assert(&'ast asm::AstDirectiveAssert), } @@ -205,7 +206,21 @@ impl<'ast, 'decls> ResolveIterator<'ast, 'decls> file_handle_ctx = Some(ast_addr.header_span.file_handle); } - _ => + asm::AstAny::DirectiveAssert(ast_assert) => + { + self.index += 1; + node = ResolverNode::Assert(ast_assert); + file_handle_ctx = Some(ast_assert.header_span.file_handle); + } + + asm::AstAny::DirectiveBits(..) | + asm::AstAny::DirectiveFn(..) | + asm::AstAny::DirectiveIf(..) | + asm::AstAny::DirectiveInclude(..) | + asm::AstAny::DirectiveLabelAlign(..) | + asm::AstAny::DirectiveNoEmit(..) | + asm::AstAny::DirectiveOnce(..) | + asm::AstAny::DirectiveRuledef(..) => { self.index += 1; node = ResolverNode::None; diff --git a/src/asm/resolver/mod.rs b/src/asm/resolver/mod.rs index 3d1368e8..b10cb4a1 100644 --- a/src/asm/resolver/mod.rs +++ b/src/asm/resolver/mod.rs @@ -21,6 +21,7 @@ mod data_block; mod res; mod align; mod addr; +mod assert; mod directive_if; pub use directive_if::{ @@ -263,6 +264,19 @@ pub fn resolve_once( defs, &ctx)?); } + + asm::ResolverNode::Assert(ast_assert) => + { + resolution_state.merge( + assert::resolve_assert( + report, + opts, + fileserver, + ast_assert, + decls, + defs, + &ctx)?); + } } } diff --git a/src/expr/expression.rs b/src/expr/expression.rs index 68ad474a..857a636f 100644 --- a/src/expr/expression.rs +++ b/src/expr/expression.rs @@ -324,6 +324,33 @@ impl Value } + pub fn expect_error_or_bool( + self, + report: &mut diagn::Report, + span: diagn::Span) + -> Result + { + match self.coallesce_to_integer().as_ref() + { + value @ expr::Value::Unknown | + value @ expr::Value::FailedConstraint(_) => + Ok(value.to_owned()), + + value @ expr::Value::Bool(_) => + Ok(value.to_owned()), + + _ => + { + report.error_span( + "expected boolean", + span); + + Err(()) + } + } + } + + pub fn as_usize(&self) -> Option { match self diff --git a/tests/assert/err_addr_convergence.asm b/tests/assert/err_addr_convergence.asm new file mode 100644 index 00000000..8b54218c --- /dev/null +++ b/tests/assert/err_addr_convergence.asm @@ -0,0 +1,27 @@ +#ruledef test +{ + ld {x} => + { + assert(x <= 0x8) + 0x11 @ x`16 + } + + ld {x} => + { + assert(x > 0x8) + 0x22 @ x`8 + } +} + +#assert $ == 0x0 + + ld label + ld label +label: + +#assert label == 0x4 ; error: assertion + + ld label + ld label + +#assert $ == 0x8 ; error: assertion \ No newline at end of file diff --git a/tests/assert/err_constant.asm b/tests/assert/err_constant.asm new file mode 100644 index 00000000..1c2c8790 --- /dev/null +++ b/tests/assert/err_constant.asm @@ -0,0 +1,3 @@ +x = 0xff +#d x +#assert x == 0xee ; error: assertion \ No newline at end of file diff --git a/tests/assert/err_constant_deferred.asm b/tests/assert/err_constant_deferred.asm new file mode 100644 index 00000000..d87cdda2 --- /dev/null +++ b/tests/assert/err_constant_deferred.asm @@ -0,0 +1,3 @@ +#d x +#assert x == 0xee ; error: assertion +x = 0xff \ No newline at end of file diff --git a/tests/assert/err_expected_bool.asm b/tests/assert/err_expected_bool.asm new file mode 100644 index 00000000..b7208fcc --- /dev/null +++ b/tests/assert/err_expected_bool.asm @@ -0,0 +1,2 @@ +#d 0xff +#assert 1 + 1 ; error: expected boolean \ No newline at end of file diff --git a/tests/assert/err_simple.asm b/tests/assert/err_simple.asm new file mode 100644 index 00000000..ad258ddc --- /dev/null +++ b/tests/assert/err_simple.asm @@ -0,0 +1,2 @@ +#d 0xff +#assert 1 + 1 == 5 ; error: assertion \ No newline at end of file diff --git a/tests/assert/err_unknown_symbol.asm b/tests/assert/err_unknown_symbol.asm new file mode 100644 index 00000000..3cf982df --- /dev/null +++ b/tests/assert/err_unknown_symbol.asm @@ -0,0 +1 @@ +#assert x ; error: unknown symbol \ No newline at end of file diff --git a/tests/assert/ok_addr_convergence.asm b/tests/assert/ok_addr_convergence.asm new file mode 100644 index 00000000..1906c339 --- /dev/null +++ b/tests/assert/ok_addr_convergence.asm @@ -0,0 +1,27 @@ +#ruledef test +{ + ld {x} => + { + assert(x <= 0x8) + 0x11 @ x`16 + } + + ld {x} => + { + assert(x > 0x8) + 0x22 @ x`8 + } +} + +#assert $ == 0x0 + + ld label ; = 0x110006 + ld label ; = 0x110006 +label: + +#assert label == 0x6 + + ld label ; = 0x110006 + ld label ; = 0x110006 + +#assert $ == 0xc \ No newline at end of file diff --git a/tests/assert/ok_constant.asm b/tests/assert/ok_constant.asm new file mode 100644 index 00000000..6d0281bf --- /dev/null +++ b/tests/assert/ok_constant.asm @@ -0,0 +1,3 @@ +x = 0xff +#d x ; = 0xff +#assert x == 0xff \ No newline at end of file diff --git a/tests/assert/ok_constant_deferred.asm b/tests/assert/ok_constant_deferred.asm new file mode 100644 index 00000000..ed40af30 --- /dev/null +++ b/tests/assert/ok_constant_deferred.asm @@ -0,0 +1,3 @@ +#d x ; = 0xff +#assert x == 0xff +x = 0xff \ No newline at end of file diff --git a/tests/assert/ok_simple.asm b/tests/assert/ok_simple.asm new file mode 100644 index 00000000..220a89dc --- /dev/null +++ b/tests/assert/ok_simple.asm @@ -0,0 +1,2 @@ +#d 0xff ; = 0xff +#assert 1 + 1 == 2 \ No newline at end of file