Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add support for unary not #29

Merged
merged 5 commits into from
Jun 3, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions src/generator/emitters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,10 @@ fn emit_expr(table: &mut SymbolTable, module_data: &mut ModuleData, expr: &mut E
metadata: &mut InsertionMetadata, index: &mut usize) -> Result<bool, WhammError> {
let mut is_success = true;
match expr {
Expr::UnOp{op, expr, ..} => {
is_success &= emit_expr(table, module_data, expr, instr_builder, metadata, index)?;
is_success &= emit_op(op, instr_builder, index);
}
Expr::BinOp {lhs, op, rhs, ..} => {
is_success &= emit_expr(table, module_data, lhs, instr_builder, metadata, index)?;
is_success &= emit_expr(table, module_data, rhs, instr_builder, metadata, index)?;
Expand Down Expand Up @@ -374,6 +378,14 @@ fn emit_op(op: &Op, instr_builder: &mut InstrSeqBuilder, index: &mut usize) -> b
*index += 1;
true
}
Op::Neg => {
instr_builder.instr_at( *index,walrus::ir::Unop {
op: walrus::ir::UnaryOp::I32Eqz // return 1 if 0, return 0 otherwise
});
// update index to point to what follows our insertions
*index += 1;
true
}
}
}

Expand Down
38 changes: 38 additions & 0 deletions src/generator/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ pub struct ExprFolder;
impl ExprFolder {
pub fn fold_expr(expr: &Expr, table: &SymbolTable) -> Expr {
match *expr {
Expr::UnOp { .. } => {
ExprFolder::fold_unop(expr, table)
}
Expr::BinOp { .. } => {
ExprFolder::fold_binop(expr, table)
}
Expand All @@ -24,6 +27,7 @@ impl ExprFolder {
}
}
}

fn fold_binop(binop: &Expr, table: &SymbolTable) -> Expr {
match &binop {
Expr::BinOp {lhs, op, rhs, ..} => {
Expand Down Expand Up @@ -187,6 +191,7 @@ impl ExprFolder {
return res;
}
}
_ => {}
ahuoguo marked this conversation as resolved.
Show resolved Hide resolved
}
},
_ => {}
Expand All @@ -196,6 +201,39 @@ impl ExprFolder {
binop.clone()
}

// similar to the logic of fold_binop
fn fold_unop(unop: &Expr, table: &SymbolTable) -> Expr {
match &unop {
Expr::UnOp {op, expr, ..} => {
let expr = ExprFolder::fold_expr(&expr, table);
match op {
Op::Neg => {
let expr_val = ExprFolder::get_single_bool(&expr);
return if let Some(expr_bool) = expr_val {
Expr::Primitive {
val: Value::Boolean {
ty: DataType::Boolean,
val: !expr_bool,
},
loc: None
}
} else {
Expr::UnOp {
op: Op::Neg,
expr: Box::new(expr),
loc: None
}
}
}
_ => {}
}
},
_ => {}
}

unop.clone()
ahuoguo marked this conversation as resolved.
Show resolved Hide resolved
}

fn fold_bools(lhs_val: &Option<bool>, rhs_val: &Option<bool>, op: &Op) -> Option<Expr> {
if let Some(lhs_bool) = lhs_val {
if let Some(rhs_bool) = rhs_val {
Expand Down
6 changes: 6 additions & 0 deletions src/parser/print_visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,11 @@ impl WhammVisitor<String> for AsStrVisitor {
Expr::Primitive {val, ..} => {
self.visit_value(val)
}
Expr::UnOp {op, expr, ..} => {
let mut s = "".to_string();
s += &format!("{}{}", self.visit_op(op), self.visit_expr(expr));
s
}
}
}

Expand All @@ -402,6 +407,7 @@ impl WhammVisitor<String> for AsStrVisitor {
Op::Multiply => "*",
Op::Divide => "/",
Op::Modulo => "%",
Op::Neg => "!",
}.parse().unwrap()
}

Expand Down
33 changes: 10 additions & 23 deletions src/parser/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,15 @@ const VALID_SCRIPTS: &'static [&'static str] = &[

// Predicates
"wasm:bytecode:br:before / i / { }",
"wasm:bytecode:br:before / \"i\" <= 1 / { }",
r#"wasm:bytecode:br:before / "i" <= 1 / { }"#, // Alex How is this a valid script
ahuoguo marked this conversation as resolved.
Show resolved Hide resolved
"wasm:bytecode:br:before / i54 < r77 / { }",
"wasm:bytecode:br:before / i54 < r77 / { }",
"wasm:bytecode:br:before / i != 7 / { }",
"wasm:bytecode:br:before / (i == \"1\") && (b == \"2\") / { }",
"wasm:bytecode:br:before / i == \"1\" && b == \"2\" / { }",
r#"wasm:bytecode:br:before / (i == "1") && (b == "2") / { }"#,
r#"wasm:bytecode:br:before / i == "1" && b == "2" / { }"#,
"wasm:bytecode:br:before / i == (1 + 3) / { count = 0; }",
"wasm:bytecode:br:before / !(a && b) / { count = 0; }",
"wasm:bytecode:br:before / !a / { count = 0; }",

// Function calls
r#"
Expand All @@ -63,7 +65,7 @@ wasm::call:alt /
}
"#,

// Statements
// Assignments
r#"
wasm:bytecode:br:before {
i = 0;
Expand Down Expand Up @@ -91,15 +93,14 @@ const INVALID_SCRIPTS: &'static [&'static str] = &[
// Variations of PROBE_SPEC
"wasm:bytecode:call:alt: { }",
"wasm:bytecode:call:alt",
"wasm:bytecode:call:alt: { }",
ahuoguo marked this conversation as resolved.
Show resolved Hide resolved
"wasm:bytecode:call:dne",

// Empty predicate
"wasm:bytecode:call:alt // { }",
"wasm:bytecode:call:alt / 5i < r77 / { }",
// "wasm:bytecode:call:alt / i < 1 < 2 / { }", // TODO -- make invalid on semantic pass
// "wasm:bytecode:call:alt / (1 + 3) / { i }", // TODO -- make invalid on type check
"wasm:bytecode:call:alt / i == \"\"\"\" / { }",
r#"wasm:bytecode:call:alt / i == """" / { }"#,

// bad statement
"wasm:bytecode:call:alt / i == 1 / { i; }",
Expand Down Expand Up @@ -143,25 +144,11 @@ pub fn get_test_scripts(subdir: &str) -> Vec<String> {

pub fn get_ast(script: &str, err: &mut ErrorGen) -> Option<Whamm> {
info!("Getting the AST");
match parse_script(&script.to_string(), err) {
Some(ast) => {
Some(ast)
},
None => {
None
}
}
parse_script(&script.to_string(), err)
ahuoguo marked this conversation as resolved.
Show resolved Hide resolved
}

fn is_valid_script(script: &str, err: &mut ErrorGen) -> bool {
match get_ast(script, err) {
Some(_ast) => {
true
},
None => {
false
}
}
get_ast(script, err).is_some()
}

pub fn run_test_on_valid_list(scripts: Vec<String>, err: &mut ErrorGen) {
Expand Down Expand Up @@ -295,7 +282,7 @@ wasm::call:alt /
pub fn test_implicit_probe_defs_dumper() {
setup_logger();
let mut err = ErrorGen::new("".to_string(), "".to_string(), 0);
let script = "wasm:::alt / (i == \"1\") && (b == \"2\") / { i = 0; }";
let script = r#"wasm:::alt / (i == "1") && (b == "2") / { i = 0; }"#;

match get_ast(script, &mut err) {
Some(ast) => {
Expand Down
19 changes: 12 additions & 7 deletions src/parser/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ lazy_static::lazy_static! {
| Op::infix(lt, Left)
).op(Op::infix(add, Left) | Op::infix(subtract, Left)) // SUMOP
.op(Op::infix(multiply, Left) | Op::infix(divide, Left) | Op::infix(modulo, Left)) // MULOP
.op(Op::prefix(neg))
};
}

Expand Down Expand Up @@ -66,15 +67,15 @@ impl Location {
pub fn span_between(loc0: &Location, loc1: &Location) -> LineColLocation {
let pos0 = match &loc0.line_col {
LineColLocation::Pos(pos0) |
LineColLocation::Span(pos0, ..) => pos0.clone()
LineColLocation::Span(pos0, ..) => *pos0
};

let pos1 = match &loc1.line_col {
LineColLocation::Pos(end1) |
LineColLocation::Span(.., end1) => end1.clone()
LineColLocation::Span(.., end1) => *end1
};

return LineColLocation::Span(pos0, pos1);
LineColLocation::Span(pos0, pos1)
}
}

Expand Down Expand Up @@ -178,10 +179,7 @@ impl Statement {
}
}
pub fn line_col(&self) -> Option<LineColLocation> {
return match self.loc() {
Some(loc) => Some(loc.line_col.clone()),
None => None
}
self.loc().as_ref().map(|loc| loc.line_col.clone())
}
pub fn dummy() -> Self {
Self::Expr {
Expand All @@ -199,6 +197,11 @@ impl Statement {

#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub enum Expr {
UnOp { // Type is based on the outermost `op`
op: Op,
expr: Box<Expr>,
loc: Option<Location>
},
BinOp { // Type is based on the outermost `op` (if arithmetic op, also based on types of lhs/rhs due to doubles)
lhs: Box<Expr>,
op: Op,
Expand All @@ -223,6 +226,7 @@ pub enum Expr {
impl Expr {
pub fn loc(&self) -> &Option<Location> {
match self {
Expr::UnOp {loc, ..} |
Expr::BinOp {loc, ..} |
Expr::Call {loc, ..} |
Expr::VarId {loc, ..} |
Expand Down Expand Up @@ -1637,6 +1641,7 @@ pub enum Op {
// Logical operators
And,
Or,
Neg,

// Relational operators
EQ,
Expand Down
5 changes: 3 additions & 2 deletions src/parser/whamm.pest
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,15 @@ statement = { ( ( fn_call | assignment ) ~ ";" )+ }
// ---- Expressions ----
// =====================

expr = { operand ~ (BINOP ~ operand)* }
expr = { prefix? ~ operand ~ (BINOP ~ prefix? ~ operand)* }

neg = { "!" }
ahuoguo marked this conversation as resolved.
Show resolved Hide resolved
prefix = _{ neg }
val = _{ BOOL | ID | INT | STRING }
operand = { fn_call | "(" ~ expr ~ ")" | val }

tuple = { "(" ~ (val) ~ ( "," ~ val )* ~ ")" }

// TODO -- add support for NOT (e.g. !(a == b)
BINOP = _{ LOGOP | RELOP | SUMOP | MULOP }
// Logical operators
and = { "&&" }
Expand Down
Loading