Skip to content

Commit

Permalink
Merge branch 'main' into generic-parselets
Browse files Browse the repository at this point in the history
  • Loading branch information
phorward committed Feb 22, 2023
2 parents ae9a4b7 + d51ee23 commit 34e738e
Show file tree
Hide file tree
Showing 6 changed files with 397 additions and 279 deletions.
110 changes: 88 additions & 22 deletions src/compiler/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -864,6 +864,82 @@ fn traverse_node(compiler: &mut Compiler, node: &Dict) -> ImlOp {
ImlOp::from(Op::LoadFastCapture(index.to_usize().unwrap()))
}

// comparison -----------------------------------------------------
"comparison" => {
// comparison can be a chain of comparisons, allowing to compare e.g. `1 < 2 < 3`
let children = node["children"].borrow();
let mut children = children.object::<List>().unwrap().clone();

let first = children.remove(0);
let first = first.borrow();

let mut ops = Vec::new();

ops.push(traverse_node_rvalue(
compiler,
&first.object::<Dict>().unwrap(),
Rvalue::CallOrLoad,
));

let mut backpatch = Vec::new();

while !children.is_empty() {
let child = children.remove(0);
let child = child.borrow();
let child = child.object::<Dict>().unwrap();

let emit = child["emit"].borrow();
let emit = emit.object::<Str>().unwrap().as_str();

let next = child["children"].borrow();

ops.push(traverse_node_rvalue(
compiler,
&next.object::<Dict>().unwrap(),
Rvalue::CallOrLoad,
));

// Chained comparison requires forperand duplication
if !children.is_empty() {
ops.push(ImlOp::from(Op::Swap(2))); // Swap operands
ops.push(ImlOp::from(Op::Copy(2))); // Copy second operand
}

ops.push(ImlOp::from(match emit {
"cmp_eq" => Op::BinaryOp("eq"),
"cmp_neq" => Op::BinaryOp("neq"),
"cmp_lteq" => Op::BinaryOp("lteq"),
"cmp_gteq" => Op::BinaryOp("gteq"),
"cmp_lt" => Op::BinaryOp("lt"),
"cmp_gt" => Op::BinaryOp("gt"),
_ => unimplemented!("{}", emit),
}));

// Push and remember placeholder for later clean-up jump
if !children.is_empty() {
backpatch.push(ops.len());
ops.push(ImlOp::Nop); // Placeholder for condition
}
}

if backpatch.len() > 0 {
// Jump over clean-up part with last result
ops.push(ImlOp::from(Op::Forward(3)));

// Otherwise, remember clean-up start
let clean_up = ops.len();
ops.push(ImlOp::from(Op::Drop));
ops.push(ImlOp::from(Op::PushFalse));

// Backpatch all placeholders to relative jump to the clean-up part
for index in backpatch {
ops[index] = ImlOp::from(Op::ForwardIfFalse(clean_up - index + 1));
}
}

ImlOp::from(ops)
}

// constant -------------------------------------------------------
"constant" => {
let children = node["children"].borrow();
Expand Down Expand Up @@ -945,27 +1021,23 @@ fn traverse_node(compiler: &mut Compiler, node: &Dict) -> ImlOp {

match parts[1] {
"pre" => {
ops.push(
if parts[2] == "inc" {
Op::UnaryOp("iinc")
} else {
Op::UnaryOp("idec")
}
.into(),
);
ops.push(ImlOp::from(if parts[2] == "inc" {
Op::UnaryOp("iinc")
} else {
Op::UnaryOp("idec")
}));
ops.push(ImlOp::from(Op::Sep)); // Separate TOS
}
"post" => {
ops.extend(vec![
Op::Dup.into(),
Op::Rot2.into(),
if parts[2] == "inc" {
ImlOp::from(Op::Dup),
ImlOp::from(Op::Swap(2)),
ImlOp::from(if parts[2] == "inc" {
Op::UnaryOp("iinc")
} else {
Op::UnaryOp("idec")
}
.into(),
Op::Drop.into(),
}),
ImlOp::from(Op::Drop),
]);
}
_ => unreachable!(),
Expand Down Expand Up @@ -1055,12 +1127,12 @@ fn traverse_node(compiler: &mut Compiler, node: &Dict) -> ImlOp {
"not" => Op::UnaryOp("not"),
"neg" => Op::UnaryOp("neg"),
_ => {
unimplemented!("op_unary_{}", parts[2]);
unimplemented!("{}", emit);
}
})
}

"binary" | "compare" | "logical" => {
"binary" | "logical" => {
let children = node["children"].borrow();
let children = children.object::<List>().unwrap();
assert_eq!(children.len(), 2);
Expand Down Expand Up @@ -1127,12 +1199,6 @@ fn traverse_node(compiler: &mut Compiler, node: &Dict) -> ImlOp {
"div" => Op::BinaryOp("div"),
"divi" => Op::BinaryOp("divi"),
"mod" => Op::BinaryOp("mod"),
"eq" => Op::BinaryOp("eq"),
"neq" => Op::BinaryOp("neq"),
"lteq" => Op::BinaryOp("lteq"),
"gteq" => Op::BinaryOp("gteq"),
"lt" => Op::BinaryOp("lt"),
"gt" => Op::BinaryOp("gt"),
_ => {
unimplemented!("{}", emit);
}
Expand Down
4 changes: 2 additions & 2 deletions src/compiler/iml/op.rs
Original file line number Diff line number Diff line change
Expand Up @@ -519,9 +519,9 @@ impl ImlOp {
then: then_part,
else_: else_part,
} => {
// Clone on peek
// Copy on peek
if *peek {
ops.push(Op::Clone);
ops.push(Op::Copy(1));
}

let backpatch = ops.len();
Expand Down
Loading

0 comments on commit 34e738e

Please sign in to comment.