Skip to content

Commit

Permalink
parser: support more range expressions
Browse files Browse the repository at this point in the history
Previously, the parser required integer literals as the bounds for
range expressions. We now expand that to support normal expressions
there. Note the parser will parse any expression.

Signed-off-by: Reto Achermann <[email protected]>
  • Loading branch information
achreto committed Aug 31, 2023
1 parent b3257e8 commit 7afb2a5
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 28 deletions.
39 changes: 20 additions & 19 deletions src/parser/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,28 +182,24 @@ pub fn quantifier_expr(
///
/// # Grammar
///
/// `RANGE_EXPR := NUM_LIT_EXPR .. NUM_LIT_EXPR`
/// `RANGE_EXPR := EXPR .. EXPR`
///
/// # Examples
///
/// `0..10` corresponds to the mathematical interval `[0, 10)`
///
/// an arithmetic expression evalutes to a number a | b
/// an arithmetic expression evaluates to a number a | b
pub fn range_expr(
input: VelosiTokenStream,
) -> IResult<VelosiTokenStream, VelosiParseTreeRangeExpr> {
let mut loc = input.clone();
let (i, (s, _, e)) = tuple((num_lit_expr, dotdot, num_lit_expr))(input)?;

let (i, (s, _, e)) = tuple((expr, dotdot, expr))(input)?;

loc.span_until_start(&i);

match (s, e) {
(VelosiParseTreeExpr::NumLiteral(s), VelosiParseTreeExpr::NumLiteral(e)) => {
let range = VelosiParseTreeRangeExpr::with_loc(s.value, e.value, loc);
Ok((i, range))
//Ok((i, VelosiParseTreeExpr::Range(range)))
}
_ => unreachable!(),
}
let range = VelosiParseTreeRangeExpr::with_loc(s, e, loc);
Ok((i, range))
}

/// pares a function call expression
Expand Down Expand Up @@ -826,10 +822,10 @@ fn test_slice() {
test_parse_and_compare_ok!("foo[3..4]", expr);
test_parse_and_compare_ok!("foo.bar[0..3]", expr);
test_parse_and_compare_ok!("foo[1..2]", slice_expr);
test_parse_and_compare_ok!("foo[1 + 2..1 + 2]", slice_expr);
test_parse_and_compare_ok!("foo[a..b]", slice_expr);

// currently we don't support this
test_parse_and_check_fail!("foo[1+2..1+2]", slice_expr);
test_parse_and_check_fail!("foo[a..b]", slice_expr);
test_parse_and_check_fail!("foo.bar[a..(b..c)]", slice_expr);
}

#[test]
Expand Down Expand Up @@ -865,12 +861,17 @@ fn test_ifelse_fail() {

#[test]
fn test_range() {
// parse_equal!(range_expr, "a..b", "a..b");
test_parse_and_compare_ok!("1..2", range_expr);

// currently we don't support this
test_parse_and_check_fail!("a..b", range_expr);
test_parse_and_check_fail!("1+2..a+2", range_expr);
test_parse_and_compare_ok!("a..b", range_expr);
test_parse_and_compare_ok!("a..b", range_expr);
test_parse_and_compare_ok!("1 + 2..a + 2", range_expr);
test_parse_and_compare_ok!(
"1 + 2 + 3 .. a + 4 * 3",
range_expr,
"(1 + 2) + 3..a + (4 * 3)"
);
test_parse_and_compare_ok!("(1 + 2)..(a + 2)", range_expr, "1 + 2..a + 2");
test_parse_and_check_fail!("1 + 2 + 3 .. ( 1 .. 4)", range_expr);
}

#[test]
Expand Down
6 changes: 2 additions & 4 deletions src/parser/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -320,8 +320,7 @@ fn test_map_dest_fail() {
#[test]
fn test_map_src_ok() {
test_parse_and_check_ok!("0..0x1000 =>", map_src);
// TODO: should have support for this...
test_parse_and_check_fail!("i * 0x1000..(i+1) * 0x1000 =>", map_src);
test_parse_and_check_ok!("i * 0x1000..(i + 1) * 0x1000 =>", map_src);
}

#[test]
Expand All @@ -343,8 +342,7 @@ fn test_map_element_ok() {
test_parse_and_compare_ok!("0..4096 => UnitA() @ 4096", map_element);
test_parse_and_compare_ok!("0..4096 => UnitA() @ 4096 + (i * 4096)", map_element);

// TODO: should have support for this...
test_parse_and_check_fail!("i * 4096..(i+1) * 4096 => UnitA()", map_element);
test_parse_and_compare_ok!("i * 4096..(i + 1) * 4096 => UnitA()", map_element);
}

#[test]
Expand Down
26 changes: 21 additions & 5 deletions src/parsetree/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -543,23 +543,39 @@ impl Debug for VelosiParseTreeIfElseExpr {
#[derive(PartialEq, Eq, Clone)]
pub struct VelosiParseTreeRangeExpr {
/// start of the range (including)
pub start: u64,
pub start: Box<VelosiParseTreeExpr>,
/// end value of the range (not including)
pub end: u64,
pub end: Box<VelosiParseTreeExpr>,
/// location of the range expression in the source tree
pub loc: VelosiTokenStream,
}

impl VelosiParseTreeRangeExpr {
/// constructs a new range expression with default location
pub fn with_loc(start: u64, end: u64, loc: VelosiTokenStream) -> Self {
Self { start, end, loc }
pub fn with_loc(
start: VelosiParseTreeExpr,
end: VelosiParseTreeExpr,
loc: VelosiTokenStream,
) -> Self {
Self {
start: Box::new(start),
end: Box::new(end),
loc,
}
}

/// constructs a new range expression with default location
pub fn new(start: u64, end: u64) -> Self {
pub fn new(start: VelosiParseTreeExpr, end: VelosiParseTreeExpr) -> Self {
Self::with_loc(start, end, VelosiTokenStream::default())
}

pub fn new_fixed(start: u64, end: u64) -> Self {
Self::with_loc(
VelosiParseTreeExpr::NumLiteral(VelosiParseTreeNumLiteral::new(start)),
VelosiParseTreeExpr::NumLiteral(VelosiParseTreeNumLiteral::new(end)),
VelosiTokenStream::default(),
)
}
}

/// Implementation of [Display] for [VelosiParseTreeRangeExpr]
Expand Down

0 comments on commit 7afb2a5

Please sign in to comment.