Skip to content

Commit

Permalink
fix(debugger): fix expression parser, now field op, index op and slic…
Browse files Browse the repository at this point in the history
…e op have the same priority and can be combined in any order (a previous version returned an error for valid expressions like "arr[0].some_field" and others)
  • Loading branch information
godzie44 committed Apr 1, 2024
1 parent 6ba9aae commit b06958f
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 19 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ All notable changes to this project will be documented in this file.
### Fixed
- console: now sub commands (like break remove or break info) don't clash with operation + argument
- debugger: updated `unwind` crate to 0.4.2, now it must support rcX releases of libunwind
- console: fix expression parser. Now field op, index op and slice op have the same priority and can be combined in any order

### Deprecated

Expand Down
90 changes: 71 additions & 19 deletions src/ui/command/parser/expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,24 +37,24 @@ pub fn parser<'a>() -> impl Parser<'a, &'a str, Expression, Err<'a>> {

let field = text::ascii::ident()
.or(text::int(10))
.map(|s: &str| s.to_string())
.labelled("field name or tuple index");
let field_expr = atom.clone().foldl(
op('.')
.to(Expression::Field as fn(_, _) -> _)
.then(field)
.repeated(),
|lhs, (op, rhs)| op(Box::new(lhs), rhs),
);

let field_op = op('.')
.ignore_then(field)
.map(|field: &str| -> Box<dyn Fn(Expression) -> Expression> {
Box::new(move |r| Expression::Field(Box::new(r), field.to_string()))
})
.boxed();

let index_op = text::int(10)
.padded()
.map(|v: &str| v.parse::<u64>().unwrap())
.labelled("index value")
.delimited_by(op('['), op(']'));
let index_expr = field_expr.clone().foldl(index_op.repeated(), |r, idx| {
Expression::Index(Box::new(r), idx)
});
.delimited_by(op('['), op(']'))
.map(|idx| -> Box<dyn Fn(Expression) -> Expression> {
Box::new(move |r: Expression| Expression::Index(Box::new(r), idx))
})
.boxed();

let mb_usize = text::int(10)
.or_not()
Expand All @@ -65,14 +65,18 @@ pub fn parser<'a>() -> impl Parser<'a, &'a str, Expression, Err<'a>> {
.then_ignore(just("..").padded())
.then(mb_usize)
.labelled("slice range (start..end)")
.delimited_by(op('['), op(']'));
let slice_expr = index_expr
.clone()
.foldl(slice_op.repeated(), |r, (from, to)| {
Expression::Slice(Box::new(r), from, to)
});
.delimited_by(op('['), op(']'))
.map(|(from, to)| -> Box<dyn Fn(Expression) -> Expression> {
Box::new(move |r: Expression| Expression::Slice(Box::new(r), from, to))
})
.boxed();

let expr = slice_expr.or(ptr_cast());
let expr = atom
.foldl(
field_op.or(index_op).or(slice_op).repeated(),
|r, expr_fn| expr_fn(r),
)
.or(ptr_cast());

op('*')
.repeated()
Expand Down Expand Up @@ -311,6 +315,54 @@ mod test {
Expression::PtrCast(0x7FFFFFFFDC94, "*const i32".to_string()).boxed(),
),
},
TestCase {
string: "var.arr[0].some_val",
expr: Expression::Field(
Expression::Index(
Expression::Field(
Expression::Variable(VariableSelector::Name {
var_name: "var".to_string(),
only_local: false,
})
.boxed(),
"arr".to_string(),
)
.boxed(),
0,
)
.boxed(),
"some_val".to_string(),
),
},
TestCase {
string: "arr[0][..][1..][0].some_val",
expr: Expression::Field(
Expression::Index(
Expression::Slice(
Expression::Slice(
Expression::Index(
Expression::Variable(VariableSelector::Name {
var_name: "arr".to_string(),
only_local: false,
})
.boxed(),
0,
)
.boxed(),
None,
None,
)
.boxed(),
Some(1),
None,
)
.boxed(),
0,
)
.boxed(),
"some_val".to_string(),
),
},
];

for tc in test_cases {
Expand Down

0 comments on commit b06958f

Please sign in to comment.