Refactored and decoupled BinOp
and CmpOp
This commit is contained in:
parent
e568baee1d
commit
d7df9fb5b4
@ -105,15 +105,11 @@ do
|
|||||||
end
|
end
|
||||||
|
|
||||||
do
|
do
|
||||||
local eqz = {}
|
|
||||||
local le = {}
|
local le = {}
|
||||||
local lt = {}
|
local lt = {}
|
||||||
local ge = {}
|
local ge = {}
|
||||||
local gt = {}
|
local gt = {}
|
||||||
|
|
||||||
function eqz.i32(lhs) return lhs == 0 end
|
|
||||||
function eqz.i64(lhs) return lhs == 0 end
|
|
||||||
|
|
||||||
function ge.u32(lhs, rhs) return u32(lhs) >= u32(rhs) end
|
function ge.u32(lhs, rhs) return u32(lhs) >= u32(rhs) end
|
||||||
function ge.u64(lhs, rhs) return u64(lhs) >= u64(rhs) end
|
function ge.u64(lhs, rhs) return u64(lhs) >= u64(rhs) end
|
||||||
|
|
||||||
@ -126,7 +122,6 @@ do
|
|||||||
function lt.u32(lhs, rhs) return u32(lhs) < u32(rhs) end
|
function lt.u32(lhs, rhs) return u32(lhs) < u32(rhs) end
|
||||||
function lt.u64(lhs, rhs) return u64(lhs) < u64(rhs) end
|
function lt.u64(lhs, rhs) return u64(lhs) < u64(rhs) end
|
||||||
|
|
||||||
module.eqz = eqz
|
|
||||||
module.le = le
|
module.le = le
|
||||||
module.lt = lt
|
module.lt = lt
|
||||||
module.ge = ge
|
module.ge = ge
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use std::collections::BTreeSet;
|
use std::collections::BTreeSet;
|
||||||
|
|
||||||
use crate::ast::node::{AnyBinOp, AnyLoad, AnyStore, AnyUnOp, Function};
|
use crate::ast::node::{AnyBinOp, AnyCmpOp, AnyLoad, AnyStore, AnyUnOp, Function};
|
||||||
|
|
||||||
use super::visit::{Driver, Visitor};
|
use super::visit::{Driver, Visitor};
|
||||||
|
|
||||||
@ -22,6 +22,12 @@ impl Visitor for Visit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn visit_any_unop(&mut self, v: &AnyUnOp) {
|
fn visit_any_unop(&mut self, v: &AnyUnOp) {
|
||||||
|
let name = v.op.as_name();
|
||||||
|
|
||||||
|
self.result.insert(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_any_binop(&mut self, v: &AnyBinOp) {
|
||||||
if v.op.as_operator().is_some() {
|
if v.op.as_operator().is_some() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -31,7 +37,7 @@ impl Visitor for Visit {
|
|||||||
self.result.insert(name);
|
self.result.insert(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_any_binop(&mut self, v: &AnyBinOp) {
|
fn visit_any_cmpop(&mut self, v: &AnyCmpOp) {
|
||||||
if v.op.as_operator().is_some() {
|
if v.op.as_operator().is_some() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use crate::ast::node::{
|
use crate::ast::node::{
|
||||||
AnyBinOp, AnyLoad, AnyStore, AnyUnOp, Backward, Br, BrIf, BrTable, Call, CallIndirect, Else,
|
AnyBinOp, AnyCmpOp, AnyLoad, AnyStore, AnyUnOp, Backward, Br, BrIf, BrTable, Call,
|
||||||
Expression, Forward, Function, GetGlobal, GetLocal, If, Memorize, MemoryGrow, MemorySize,
|
CallIndirect, Else, Expression, Forward, Function, GetGlobal, GetLocal, If, Memorize,
|
||||||
Recall, Return, Select, SetGlobal, SetLocal, Statement, Value,
|
MemoryGrow, MemorySize, Recall, Return, Select, SetGlobal, SetLocal, Statement, Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub trait Visitor {
|
pub trait Visitor {
|
||||||
@ -25,6 +25,8 @@ pub trait Visitor {
|
|||||||
|
|
||||||
fn visit_any_binop(&mut self, _: &AnyBinOp) {}
|
fn visit_any_binop(&mut self, _: &AnyBinOp) {}
|
||||||
|
|
||||||
|
fn visit_any_cmpop(&mut self, _: &AnyCmpOp) {}
|
||||||
|
|
||||||
fn visit_expression(&mut self, _: &Expression) {}
|
fn visit_expression(&mut self, _: &Expression) {}
|
||||||
|
|
||||||
fn visit_unreachable(&mut self) {}
|
fn visit_unreachable(&mut self) {}
|
||||||
@ -137,19 +139,29 @@ impl<T: Visitor> Driver<T> for AnyBinOp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T: Visitor> Driver<T> for AnyCmpOp {
|
||||||
|
fn accept(&self, visitor: &mut T) {
|
||||||
|
self.lhs.accept(visitor);
|
||||||
|
self.rhs.accept(visitor);
|
||||||
|
|
||||||
|
visitor.visit_any_cmpop(self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T: Visitor> Driver<T> for Expression {
|
impl<T: Visitor> Driver<T> for Expression {
|
||||||
fn accept(&self, visitor: &mut T) {
|
fn accept(&self, visitor: &mut T) {
|
||||||
match self {
|
match self {
|
||||||
Expression::Recall(v) => v.accept(visitor),
|
Self::Recall(v) => v.accept(visitor),
|
||||||
Expression::Select(v) => v.accept(visitor),
|
Self::Select(v) => v.accept(visitor),
|
||||||
Expression::GetLocal(v) => v.accept(visitor),
|
Self::GetLocal(v) => v.accept(visitor),
|
||||||
Expression::GetGlobal(v) => v.accept(visitor),
|
Self::GetGlobal(v) => v.accept(visitor),
|
||||||
Expression::AnyLoad(v) => v.accept(visitor),
|
Self::AnyLoad(v) => v.accept(visitor),
|
||||||
Expression::MemorySize(v) => v.accept(visitor),
|
Self::MemorySize(v) => v.accept(visitor),
|
||||||
Expression::MemoryGrow(v) => v.accept(visitor),
|
Self::MemoryGrow(v) => v.accept(visitor),
|
||||||
Expression::Value(v) => v.accept(visitor),
|
Self::Value(v) => v.accept(visitor),
|
||||||
Expression::AnyUnOp(v) => v.accept(visitor),
|
Self::AnyUnOp(v) => v.accept(visitor),
|
||||||
Expression::AnyBinOp(v) => v.accept(visitor),
|
Self::AnyBinOp(v) => v.accept(visitor),
|
||||||
|
Self::AnyCmpOp(v) => v.accept(visitor),
|
||||||
}
|
}
|
||||||
|
|
||||||
visitor.visit_expression(self);
|
visitor.visit_expression(self);
|
||||||
@ -292,20 +304,20 @@ impl<T: Visitor> Driver<T> for AnyStore {
|
|||||||
impl<T: Visitor> Driver<T> for Statement {
|
impl<T: Visitor> Driver<T> for Statement {
|
||||||
fn accept(&self, visitor: &mut T) {
|
fn accept(&self, visitor: &mut T) {
|
||||||
match self {
|
match self {
|
||||||
Statement::Unreachable => visitor.visit_unreachable(),
|
Self::Unreachable => visitor.visit_unreachable(),
|
||||||
Statement::Memorize(v) => v.accept(visitor),
|
Self::Memorize(v) => v.accept(visitor),
|
||||||
Statement::Forward(v) => v.accept(visitor),
|
Self::Forward(v) => v.accept(visitor),
|
||||||
Statement::Backward(v) => v.accept(visitor),
|
Self::Backward(v) => v.accept(visitor),
|
||||||
Statement::If(v) => v.accept(visitor),
|
Self::If(v) => v.accept(visitor),
|
||||||
Statement::Br(v) => v.accept(visitor),
|
Self::Br(v) => v.accept(visitor),
|
||||||
Statement::BrIf(v) => v.accept(visitor),
|
Self::BrIf(v) => v.accept(visitor),
|
||||||
Statement::BrTable(v) => v.accept(visitor),
|
Self::BrTable(v) => v.accept(visitor),
|
||||||
Statement::Return(v) => v.accept(visitor),
|
Self::Return(v) => v.accept(visitor),
|
||||||
Statement::Call(v) => v.accept(visitor),
|
Self::Call(v) => v.accept(visitor),
|
||||||
Statement::CallIndirect(v) => v.accept(visitor),
|
Self::CallIndirect(v) => v.accept(visitor),
|
||||||
Statement::SetLocal(v) => v.accept(visitor),
|
Self::SetLocal(v) => v.accept(visitor),
|
||||||
Statement::SetGlobal(v) => v.accept(visitor),
|
Self::SetGlobal(v) => v.accept(visitor),
|
||||||
Statement::AnyStore(v) => v.accept(visitor),
|
Self::AnyStore(v) => v.accept(visitor),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,11 +4,11 @@ use parity_wasm::elements::{
|
|||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
node::{
|
node::{
|
||||||
AnyBinOp, AnyLoad, AnyStore, AnyUnOp, Backward, Br, BrIf, BrTable, Call, CallIndirect,
|
AnyBinOp, AnyCmpOp, AnyLoad, AnyStore, AnyUnOp, Backward, Br, BrIf, BrTable, Call,
|
||||||
Else, Expression, Forward, Function, GetGlobal, GetLocal, If, Memorize, MemoryGrow,
|
CallIndirect, Else, Expression, Forward, Function, GetGlobal, GetLocal, If, Memorize,
|
||||||
MemorySize, Recall, Return, Select, SetGlobal, SetLocal, Statement, Value,
|
MemoryGrow, MemorySize, Recall, Return, Select, SetGlobal, SetLocal, Statement, Value,
|
||||||
},
|
},
|
||||||
tag::{BinOp, Load, Store, UnOp},
|
tag::{BinOp, CmpOp, Load, Store, UnOp},
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Arity {
|
struct Arity {
|
||||||
@ -310,6 +310,52 @@ impl<'a> Builder<'a> {
|
|||||||
.push(Expression::AnyBinOp(AnyBinOp { op, lhs, rhs }));
|
.push(Expression::AnyBinOp(AnyBinOp { op, lhs, rhs }));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn push_cmp_op(&mut self, op: CmpOp) {
|
||||||
|
let rhs = Box::new(self.stack.pop().unwrap());
|
||||||
|
let lhs = Box::new(self.stack.pop().unwrap());
|
||||||
|
|
||||||
|
self.stack
|
||||||
|
.push(Expression::AnyCmpOp(AnyCmpOp { op, lhs, rhs }));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Since Eqz is the only unary comparison it's cleaner to
|
||||||
|
// generate a simple CmpOp
|
||||||
|
fn from_equal_zero(&mut self, inst: &Instruction) -> bool {
|
||||||
|
match inst {
|
||||||
|
Instruction::I32Eqz => {
|
||||||
|
self.push_constant(Value::I32(0));
|
||||||
|
self.push_cmp_op(CmpOp::Eq_I32);
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
Instruction::I64Eqz => {
|
||||||
|
self.push_constant(Value::I64(0));
|
||||||
|
self.push_cmp_op(CmpOp::Eq_I64);
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_operation(&mut self, inst: &Instruction) -> bool {
|
||||||
|
if let Ok(op) = UnOp::try_from(inst) {
|
||||||
|
self.push_un_op(op);
|
||||||
|
|
||||||
|
true
|
||||||
|
} else if let Ok(op) = BinOp::try_from(inst) {
|
||||||
|
self.push_bin_op(op);
|
||||||
|
|
||||||
|
true
|
||||||
|
} else if let Ok(op) = CmpOp::try_from(inst) {
|
||||||
|
self.push_cmp_op(op);
|
||||||
|
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
self.from_equal_zero(inst)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn drop_unreachable(list: &mut &[Instruction]) {
|
fn drop_unreachable(list: &mut &[Instruction]) {
|
||||||
use Instruction as Inst;
|
use Instruction as Inst;
|
||||||
|
|
||||||
@ -353,13 +399,7 @@ impl<'a> Builder<'a> {
|
|||||||
|
|
||||||
*list = &list[1..];
|
*list = &list[1..];
|
||||||
|
|
||||||
if let Ok(op) = UnOp::try_from(inst) {
|
if self.from_operation(inst) {
|
||||||
self.push_un_op(op);
|
|
||||||
|
|
||||||
continue;
|
|
||||||
} else if let Ok(op) = BinOp::try_from(inst) {
|
|
||||||
self.push_bin_op(op);
|
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@ use std::ops::Range;
|
|||||||
|
|
||||||
use parity_wasm::elements::BrTableData;
|
use parity_wasm::elements::BrTableData;
|
||||||
|
|
||||||
use super::tag::{BinOp, Load, Store, UnOp};
|
use super::tag::{BinOp, CmpOp, Load, Store, UnOp};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Recall {
|
pub struct Recall {
|
||||||
@ -57,6 +57,12 @@ pub struct AnyBinOp {
|
|||||||
pub rhs: Box<Expression>,
|
pub rhs: Box<Expression>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct AnyCmpOp {
|
||||||
|
pub op: CmpOp,
|
||||||
|
pub lhs: Box<Expression>,
|
||||||
|
pub rhs: Box<Expression>,
|
||||||
|
}
|
||||||
|
|
||||||
pub enum Expression {
|
pub enum Expression {
|
||||||
Recall(Recall),
|
Recall(Recall),
|
||||||
Select(Select),
|
Select(Select),
|
||||||
@ -68,6 +74,7 @@ pub enum Expression {
|
|||||||
Value(Value),
|
Value(Value),
|
||||||
AnyUnOp(AnyUnOp),
|
AnyUnOp(AnyUnOp),
|
||||||
AnyBinOp(AnyBinOp),
|
AnyBinOp(AnyBinOp),
|
||||||
|
AnyCmpOp(AnyCmpOp),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Expression {
|
impl Expression {
|
||||||
|
@ -128,8 +128,6 @@ impl TryFrom<&Instruction> for Store {
|
|||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub enum UnOp {
|
pub enum UnOp {
|
||||||
Eqz_I32,
|
|
||||||
Eqz_I64,
|
|
||||||
Clz_I32,
|
Clz_I32,
|
||||||
Ctz_I32,
|
Ctz_I32,
|
||||||
Popcnt_I32,
|
Popcnt_I32,
|
||||||
@ -175,23 +173,8 @@ pub enum UnOp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl UnOp {
|
impl UnOp {
|
||||||
pub fn is_compare(self) -> bool {
|
|
||||||
matches!(self, Self::Eqz_I32 | Self::Eqz_I64)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn as_operator(self) -> Option<&'static str> {
|
|
||||||
let op = match self {
|
|
||||||
Self::Neg_FN => "-",
|
|
||||||
_ => return None,
|
|
||||||
};
|
|
||||||
|
|
||||||
Some(op)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn as_name(self) -> (&'static str, &'static str) {
|
pub fn as_name(self) -> (&'static str, &'static str) {
|
||||||
match self {
|
match self {
|
||||||
Self::Eqz_I32 => ("eqz", "i32"),
|
|
||||||
Self::Eqz_I64 => ("eqz", "i64"),
|
|
||||||
Self::Clz_I32 => ("clz", "i32"),
|
Self::Clz_I32 => ("clz", "i32"),
|
||||||
Self::Ctz_I32 => ("ctz", "i32"),
|
Self::Ctz_I32 => ("ctz", "i32"),
|
||||||
Self::Popcnt_I32 => ("popcnt", "i32"),
|
Self::Popcnt_I32 => ("popcnt", "i32"),
|
||||||
@ -252,8 +235,6 @@ impl TryFrom<&Instruction> for UnOp {
|
|||||||
SignExtInstruction::I64Extend16S => Self::Extend_I64_I16,
|
SignExtInstruction::I64Extend16S => Self::Extend_I64_I16,
|
||||||
SignExtInstruction::I64Extend32S => Self::Extend_I64_I32,
|
SignExtInstruction::I64Extend32S => Self::Extend_I64_I32,
|
||||||
},
|
},
|
||||||
Inst::I32Eqz => Self::Eqz_I32,
|
|
||||||
Inst::I64Eqz => Self::Eqz_I64,
|
|
||||||
Inst::I32Clz => Self::Clz_I32,
|
Inst::I32Clz => Self::Clz_I32,
|
||||||
Inst::I32Ctz => Self::Ctz_I32,
|
Inst::I32Ctz => Self::Ctz_I32,
|
||||||
Inst::I32Popcnt => Self::Popcnt_I32,
|
Inst::I32Popcnt => Self::Popcnt_I32,
|
||||||
@ -302,26 +283,6 @@ impl TryFrom<&Instruction> for UnOp {
|
|||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub enum BinOp {
|
pub enum BinOp {
|
||||||
Eq_I32,
|
|
||||||
Ne_I32,
|
|
||||||
LtS_I32,
|
|
||||||
LtU_I32,
|
|
||||||
GtS_I32,
|
|
||||||
GtU_I32,
|
|
||||||
LeS_I32,
|
|
||||||
LeU_I32,
|
|
||||||
GeS_I32,
|
|
||||||
GeU_I32,
|
|
||||||
Eq_I64,
|
|
||||||
Ne_I64,
|
|
||||||
LtS_I64,
|
|
||||||
LtU_I64,
|
|
||||||
GtS_I64,
|
|
||||||
GtU_I64,
|
|
||||||
LeS_I64,
|
|
||||||
LeU_I64,
|
|
||||||
GeS_I64,
|
|
||||||
GeU_I64,
|
|
||||||
Add_I32,
|
Add_I32,
|
||||||
Sub_I32,
|
Sub_I32,
|
||||||
Mul_I32,
|
Mul_I32,
|
||||||
@ -352,12 +313,6 @@ pub enum BinOp {
|
|||||||
ShrU_I64,
|
ShrU_I64,
|
||||||
Rotl_I64,
|
Rotl_I64,
|
||||||
Rotr_I64,
|
Rotr_I64,
|
||||||
Eq_FN,
|
|
||||||
Ne_FN,
|
|
||||||
Lt_FN,
|
|
||||||
Gt_FN,
|
|
||||||
Le_FN,
|
|
||||||
Ge_FN,
|
|
||||||
Add_FN,
|
Add_FN,
|
||||||
Sub_FN,
|
Sub_FN,
|
||||||
Mul_FN,
|
Mul_FN,
|
||||||
@ -368,26 +323,6 @@ pub enum BinOp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl BinOp {
|
impl BinOp {
|
||||||
pub fn is_compare(self) -> bool {
|
|
||||||
matches!(
|
|
||||||
self,
|
|
||||||
Self::Eq_I32
|
|
||||||
| Self::Ne_I32 | Self::LtS_I32
|
|
||||||
| Self::LtU_I32 | Self::GtS_I32
|
|
||||||
| Self::GtU_I32 | Self::LeS_I32
|
|
||||||
| Self::LeU_I32 | Self::GeS_I32
|
|
||||||
| Self::GeU_I32 | Self::Eq_I64
|
|
||||||
| Self::Ne_I64 | Self::LtS_I64
|
|
||||||
| Self::LtU_I64 | Self::GtS_I64
|
|
||||||
| Self::GtU_I64 | Self::LeS_I64
|
|
||||||
| Self::LeU_I64 | Self::GeS_I64
|
|
||||||
| Self::GeU_I64 | Self::Eq_FN
|
|
||||||
| Self::Ne_FN | Self::Lt_FN
|
|
||||||
| Self::Gt_FN | Self::Le_FN
|
|
||||||
| Self::Ge_FN
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn as_operator(self) -> Option<&'static str> {
|
pub fn as_operator(self) -> Option<&'static str> {
|
||||||
let op = match self {
|
let op = match self {
|
||||||
Self::Add_FN => "+",
|
Self::Add_FN => "+",
|
||||||
@ -395,6 +330,142 @@ impl BinOp {
|
|||||||
Self::Mul_FN => "*",
|
Self::Mul_FN => "*",
|
||||||
Self::Div_FN => "/",
|
Self::Div_FN => "/",
|
||||||
Self::RemS_I32 | Self::RemU_I32 | Self::RemS_I64 | Self::RemU_I64 => "%",
|
Self::RemS_I32 | Self::RemU_I32 | Self::RemS_I64 | Self::RemU_I64 => "%",
|
||||||
|
_ => return None,
|
||||||
|
};
|
||||||
|
|
||||||
|
Some(op)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_name(self) -> (&'static str, &'static str) {
|
||||||
|
match self {
|
||||||
|
Self::Add_I32 => ("add", "i32"),
|
||||||
|
Self::Sub_I32 => ("sub", "i32"),
|
||||||
|
Self::Mul_I32 => ("mul", "i32"),
|
||||||
|
Self::DivS_I32 => ("div", "i32"),
|
||||||
|
Self::DivU_I32 => ("div", "u32"),
|
||||||
|
Self::RemS_I32 => ("rem", "i32"),
|
||||||
|
Self::RemU_I32 => ("rem", "u32"),
|
||||||
|
Self::And_I32 => ("band", "i32"),
|
||||||
|
Self::Or_I32 => ("bor", "i32"),
|
||||||
|
Self::Xor_I32 => ("bxor", "i32"),
|
||||||
|
Self::Shl_I32 => ("shl", "i32"),
|
||||||
|
Self::ShrS_I32 => ("shr", "i32"),
|
||||||
|
Self::ShrU_I32 => ("shr", "u32"),
|
||||||
|
Self::Rotl_I32 => ("rotl", "i32"),
|
||||||
|
Self::Rotr_I32 => ("rotr", "i32"),
|
||||||
|
Self::Add_I64 => ("add", "i64"),
|
||||||
|
Self::Sub_I64 => ("sub", "i64"),
|
||||||
|
Self::Mul_I64 => ("mul", "i64"),
|
||||||
|
Self::DivS_I64 => ("div", "i64"),
|
||||||
|
Self::DivU_I64 => ("div", "u64"),
|
||||||
|
Self::RemS_I64 => ("rem", "i64"),
|
||||||
|
Self::RemU_I64 => ("rem", "u64"),
|
||||||
|
Self::And_I64 => ("band", "i64"),
|
||||||
|
Self::Or_I64 => ("bor", "i64"),
|
||||||
|
Self::Xor_I64 => ("bxor", "i64"),
|
||||||
|
Self::Shl_I64 => ("shl", "i64"),
|
||||||
|
Self::ShrS_I64 => ("shr", "i64"),
|
||||||
|
Self::ShrU_I64 => ("shr", "u64"),
|
||||||
|
Self::Rotl_I64 => ("rotl", "i64"),
|
||||||
|
Self::Rotr_I64 => ("rotr", "i64"),
|
||||||
|
Self::Add_FN => ("add", "num"),
|
||||||
|
Self::Sub_FN => ("sub", "num"),
|
||||||
|
Self::Mul_FN => ("mul", "num"),
|
||||||
|
Self::Div_FN => ("div", "num"),
|
||||||
|
Self::Min_FN => ("math", "min"),
|
||||||
|
Self::Max_FN => ("math", "max"),
|
||||||
|
Self::Copysign_FN => ("copysign", "num"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<&Instruction> for BinOp {
|
||||||
|
type Error = ();
|
||||||
|
|
||||||
|
fn try_from(inst: &Instruction) -> Result<Self, Self::Error> {
|
||||||
|
use Instruction as Inst;
|
||||||
|
|
||||||
|
let result = match inst {
|
||||||
|
Inst::I32Add => Self::Add_I32,
|
||||||
|
Inst::I32Sub => Self::Sub_I32,
|
||||||
|
Inst::I32Mul => Self::Mul_I32,
|
||||||
|
Inst::I32DivS => Self::DivS_I32,
|
||||||
|
Inst::I32DivU => Self::DivU_I32,
|
||||||
|
Inst::I32RemS => Self::RemS_I32,
|
||||||
|
Inst::I32RemU => Self::RemU_I32,
|
||||||
|
Inst::I32And => Self::And_I32,
|
||||||
|
Inst::I32Or => Self::Or_I32,
|
||||||
|
Inst::I32Xor => Self::Xor_I32,
|
||||||
|
Inst::I32Shl => Self::Shl_I32,
|
||||||
|
Inst::I32ShrS => Self::ShrS_I32,
|
||||||
|
Inst::I32ShrU => Self::ShrU_I32,
|
||||||
|
Inst::I32Rotl => Self::Rotl_I32,
|
||||||
|
Inst::I32Rotr => Self::Rotr_I32,
|
||||||
|
Inst::I64Add => Self::Add_I64,
|
||||||
|
Inst::I64Sub => Self::Sub_I64,
|
||||||
|
Inst::I64Mul => Self::Mul_I64,
|
||||||
|
Inst::I64DivS => Self::DivS_I64,
|
||||||
|
Inst::I64DivU => Self::DivU_I64,
|
||||||
|
Inst::I64RemS => Self::RemS_I64,
|
||||||
|
Inst::I64RemU => Self::RemU_I64,
|
||||||
|
Inst::I64And => Self::And_I64,
|
||||||
|
Inst::I64Or => Self::Or_I64,
|
||||||
|
Inst::I64Xor => Self::Xor_I64,
|
||||||
|
Inst::I64Shl => Self::Shl_I64,
|
||||||
|
Inst::I64ShrS => Self::ShrS_I64,
|
||||||
|
Inst::I64ShrU => Self::ShrU_I64,
|
||||||
|
Inst::I64Rotl => Self::Rotl_I64,
|
||||||
|
Inst::I64Rotr => Self::Rotr_I64,
|
||||||
|
Inst::F32Add | Inst::F64Add => Self::Add_FN,
|
||||||
|
Inst::F32Sub | Inst::F64Sub => Self::Sub_FN,
|
||||||
|
Inst::F32Mul | Inst::F64Mul => Self::Mul_FN,
|
||||||
|
Inst::F32Div | Inst::F64Div => Self::Div_FN,
|
||||||
|
Inst::F32Min | Inst::F64Min => Self::Min_FN,
|
||||||
|
Inst::F32Max | Inst::F64Max => Self::Max_FN,
|
||||||
|
Inst::F32Copysign | Inst::F64Copysign => Self::Copysign_FN,
|
||||||
|
_ => {
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(non_camel_case_types)]
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub enum CmpOp {
|
||||||
|
Eq_I32,
|
||||||
|
Ne_I32,
|
||||||
|
LtS_I32,
|
||||||
|
LtU_I32,
|
||||||
|
GtS_I32,
|
||||||
|
GtU_I32,
|
||||||
|
LeS_I32,
|
||||||
|
LeU_I32,
|
||||||
|
GeS_I32,
|
||||||
|
GeU_I32,
|
||||||
|
Eq_I64,
|
||||||
|
Ne_I64,
|
||||||
|
LtS_I64,
|
||||||
|
LtU_I64,
|
||||||
|
GtS_I64,
|
||||||
|
GtU_I64,
|
||||||
|
LeS_I64,
|
||||||
|
LeU_I64,
|
||||||
|
GeS_I64,
|
||||||
|
GeU_I64,
|
||||||
|
Eq_FN,
|
||||||
|
Ne_FN,
|
||||||
|
Lt_FN,
|
||||||
|
Gt_FN,
|
||||||
|
Le_FN,
|
||||||
|
Ge_FN,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CmpOp {
|
||||||
|
pub fn as_operator(self) -> Option<&'static str> {
|
||||||
|
let op = match self {
|
||||||
Self::Eq_I32 | Self::Eq_I64 | Self::Eq_FN => "==",
|
Self::Eq_I32 | Self::Eq_I64 | Self::Eq_FN => "==",
|
||||||
Self::Ne_I32 | Self::Ne_I64 | Self::Ne_FN => "~=",
|
Self::Ne_I32 | Self::Ne_I64 | Self::Ne_FN => "~=",
|
||||||
Self::LtS_I32 | Self::LtS_I64 | Self::Lt_FN => "<",
|
Self::LtS_I32 | Self::LtS_I64 | Self::Lt_FN => "<",
|
||||||
@ -429,54 +500,17 @@ impl BinOp {
|
|||||||
Self::LeU_I64 => ("le", "u64"),
|
Self::LeU_I64 => ("le", "u64"),
|
||||||
Self::GeS_I64 => ("ge", "i64"),
|
Self::GeS_I64 => ("ge", "i64"),
|
||||||
Self::GeU_I64 => ("ge", "u64"),
|
Self::GeU_I64 => ("ge", "u64"),
|
||||||
Self::Add_I32 => ("add", "i32"),
|
|
||||||
Self::Sub_I32 => ("sub", "i32"),
|
|
||||||
Self::Mul_I32 => ("mul", "i32"),
|
|
||||||
Self::DivS_I32 => ("div", "i32"),
|
|
||||||
Self::DivU_I32 => ("div", "u32"),
|
|
||||||
Self::RemS_I32 => ("rem", "i32"),
|
|
||||||
Self::RemU_I32 => ("rem", "u32"),
|
|
||||||
Self::And_I32 => ("band", "i32"),
|
|
||||||
Self::Or_I32 => ("bor", "i32"),
|
|
||||||
Self::Xor_I32 => ("bxor", "i32"),
|
|
||||||
Self::Shl_I32 => ("shl", "i32"),
|
|
||||||
Self::ShrS_I32 => ("shr", "i32"),
|
|
||||||
Self::ShrU_I32 => ("shr", "u32"),
|
|
||||||
Self::Rotl_I32 => ("rotl", "i32"),
|
|
||||||
Self::Rotr_I32 => ("rotr", "i32"),
|
|
||||||
Self::Add_I64 => ("add", "i64"),
|
|
||||||
Self::Sub_I64 => ("sub", "i64"),
|
|
||||||
Self::Mul_I64 => ("mul", "i64"),
|
|
||||||
Self::DivS_I64 => ("div", "i64"),
|
|
||||||
Self::DivU_I64 => ("div", "u64"),
|
|
||||||
Self::RemS_I64 => ("rem", "i64"),
|
|
||||||
Self::RemU_I64 => ("rem", "u64"),
|
|
||||||
Self::And_I64 => ("band", "i64"),
|
|
||||||
Self::Or_I64 => ("bor", "i64"),
|
|
||||||
Self::Xor_I64 => ("bxor", "i64"),
|
|
||||||
Self::Shl_I64 => ("shl", "i64"),
|
|
||||||
Self::ShrS_I64 => ("shr", "i64"),
|
|
||||||
Self::ShrU_I64 => ("shr", "u64"),
|
|
||||||
Self::Rotl_I64 => ("rotl", "i64"),
|
|
||||||
Self::Rotr_I64 => ("rotr", "i64"),
|
|
||||||
Self::Eq_FN => ("eq", "num"),
|
Self::Eq_FN => ("eq", "num"),
|
||||||
Self::Ne_FN => ("ne", "num"),
|
Self::Ne_FN => ("ne", "num"),
|
||||||
Self::Lt_FN => ("lt", "num"),
|
Self::Lt_FN => ("lt", "num"),
|
||||||
Self::Gt_FN => ("gt", "num"),
|
Self::Gt_FN => ("gt", "num"),
|
||||||
Self::Le_FN => ("le", "num"),
|
Self::Le_FN => ("le", "num"),
|
||||||
Self::Ge_FN => ("ge", "num"),
|
Self::Ge_FN => ("ge", "num"),
|
||||||
Self::Add_FN => ("add", "num"),
|
|
||||||
Self::Sub_FN => ("sub", "num"),
|
|
||||||
Self::Mul_FN => ("mul", "num"),
|
|
||||||
Self::Div_FN => ("div", "num"),
|
|
||||||
Self::Min_FN => ("math", "min"),
|
|
||||||
Self::Max_FN => ("math", "max"),
|
|
||||||
Self::Copysign_FN => ("copysign", "num"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<&Instruction> for BinOp {
|
impl TryFrom<&Instruction> for CmpOp {
|
||||||
type Error = ();
|
type Error = ();
|
||||||
|
|
||||||
fn try_from(inst: &Instruction) -> Result<Self, Self::Error> {
|
fn try_from(inst: &Instruction) -> Result<Self, Self::Error> {
|
||||||
@ -503,49 +537,12 @@ impl TryFrom<&Instruction> for BinOp {
|
|||||||
Inst::I64LeU => Self::LeU_I64,
|
Inst::I64LeU => Self::LeU_I64,
|
||||||
Inst::I64GeS => Self::GeS_I64,
|
Inst::I64GeS => Self::GeS_I64,
|
||||||
Inst::I64GeU => Self::GeU_I64,
|
Inst::I64GeU => Self::GeU_I64,
|
||||||
Inst::I32Add => Self::Add_I32,
|
|
||||||
Inst::I32Sub => Self::Sub_I32,
|
|
||||||
Inst::I32Mul => Self::Mul_I32,
|
|
||||||
Inst::I32DivS => Self::DivS_I32,
|
|
||||||
Inst::I32DivU => Self::DivU_I32,
|
|
||||||
Inst::I32RemS => Self::RemS_I32,
|
|
||||||
Inst::I32RemU => Self::RemU_I32,
|
|
||||||
Inst::I32And => Self::And_I32,
|
|
||||||
Inst::I32Or => Self::Or_I32,
|
|
||||||
Inst::I32Xor => Self::Xor_I32,
|
|
||||||
Inst::I32Shl => Self::Shl_I32,
|
|
||||||
Inst::I32ShrS => Self::ShrS_I32,
|
|
||||||
Inst::I32ShrU => Self::ShrU_I32,
|
|
||||||
Inst::I32Rotl => Self::Rotl_I32,
|
|
||||||
Inst::I32Rotr => Self::Rotr_I32,
|
|
||||||
Inst::I64Add => Self::Add_I64,
|
|
||||||
Inst::I64Sub => Self::Sub_I64,
|
|
||||||
Inst::I64Mul => Self::Mul_I64,
|
|
||||||
Inst::I64DivS => Self::DivS_I64,
|
|
||||||
Inst::I64DivU => Self::DivU_I64,
|
|
||||||
Inst::I64RemS => Self::RemS_I64,
|
|
||||||
Inst::I64RemU => Self::RemU_I64,
|
|
||||||
Inst::I64And => Self::And_I64,
|
|
||||||
Inst::I64Or => Self::Or_I64,
|
|
||||||
Inst::I64Xor => Self::Xor_I64,
|
|
||||||
Inst::I64Shl => Self::Shl_I64,
|
|
||||||
Inst::I64ShrS => Self::ShrS_I64,
|
|
||||||
Inst::I64ShrU => Self::ShrU_I64,
|
|
||||||
Inst::I64Rotl => Self::Rotl_I64,
|
|
||||||
Inst::I64Rotr => Self::Rotr_I64,
|
|
||||||
Inst::F32Eq | Inst::F64Eq => Self::Eq_FN,
|
Inst::F32Eq | Inst::F64Eq => Self::Eq_FN,
|
||||||
Inst::F32Ne | Inst::F64Ne => Self::Ne_FN,
|
Inst::F32Ne | Inst::F64Ne => Self::Ne_FN,
|
||||||
Inst::F32Lt | Inst::F64Lt => Self::Lt_FN,
|
Inst::F32Lt | Inst::F64Lt => Self::Lt_FN,
|
||||||
Inst::F32Gt | Inst::F64Gt => Self::Gt_FN,
|
Inst::F32Gt | Inst::F64Gt => Self::Gt_FN,
|
||||||
Inst::F32Le | Inst::F64Le => Self::Le_FN,
|
Inst::F32Le | Inst::F64Le => Self::Le_FN,
|
||||||
Inst::F32Ge | Inst::F64Ge => Self::Ge_FN,
|
Inst::F32Ge | Inst::F64Ge => Self::Ge_FN,
|
||||||
Inst::F32Add | Inst::F64Add => Self::Add_FN,
|
|
||||||
Inst::F32Sub | Inst::F64Sub => Self::Sub_FN,
|
|
||||||
Inst::F32Mul | Inst::F64Mul => Self::Mul_FN,
|
|
||||||
Inst::F32Div | Inst::F64Div => Self::Div_FN,
|
|
||||||
Inst::F32Min | Inst::F64Min => Self::Min_FN,
|
|
||||||
Inst::F32Max | Inst::F64Max => Self::Max_FN,
|
|
||||||
Inst::F32Copysign | Inst::F64Copysign => Self::Copysign_FN,
|
|
||||||
_ => {
|
_ => {
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
|
@ -7,9 +7,9 @@ use crate::{
|
|||||||
ast::{
|
ast::{
|
||||||
builder::{Arities, Builder},
|
builder::{Arities, Builder},
|
||||||
node::{
|
node::{
|
||||||
AnyBinOp, AnyLoad, AnyStore, AnyUnOp, Backward, Br, BrIf, BrTable, Call, CallIndirect,
|
AnyBinOp, AnyCmpOp, AnyLoad, AnyStore, AnyUnOp, Backward, Br, BrIf, BrTable, Call,
|
||||||
Else, Expression, Forward, Function, GetGlobal, GetLocal, If, Memorize, MemoryGrow,
|
CallIndirect, Else, Expression, Forward, Function, GetGlobal, GetLocal, If, Memorize,
|
||||||
MemorySize, Recall, Return, Select, SetGlobal, SetLocal, Statement, Value,
|
MemoryGrow, MemorySize, Recall, Return, Select, SetGlobal, SetLocal, Statement, Value,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -165,76 +165,69 @@ impl Driver for Value {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_un_op(un_op: &AnyUnOp, v: &mut Visitor, w: Writer) -> Result<()> {
|
|
||||||
if let Some(op) = un_op.op.as_operator() {
|
|
||||||
write!(w, "{} ", op)?;
|
|
||||||
un_op.rhs.visit(v, w)
|
|
||||||
} else {
|
|
||||||
let (a, b) = un_op.op.as_name();
|
|
||||||
|
|
||||||
write!(w, "{}_{}(", a, b)?;
|
|
||||||
un_op.rhs.visit(v, w)?;
|
|
||||||
write!(w, ")")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Driver for AnyUnOp {
|
impl Driver for AnyUnOp {
|
||||||
fn visit(&self, v: &mut Visitor, w: Writer) -> Result<()> {
|
fn visit(&self, v: &mut Visitor, w: Writer) -> Result<()> {
|
||||||
if self.op.is_compare() {
|
let (a, b) = self.op.as_name();
|
||||||
write!(w, "(")?;
|
|
||||||
}
|
|
||||||
|
|
||||||
write_un_op(self, v, w)?;
|
write!(w, "{}_{}(", a, b)?;
|
||||||
|
self.rhs.visit(v, w)?;
|
||||||
if self.op.is_compare() {
|
write!(w, ")")
|
||||||
write!(w, "and 1 or 0)")?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_bin_op(bin_op: &AnyBinOp, v: &mut Visitor, w: Writer) -> Result<()> {
|
fn write_bin_call(
|
||||||
if let Some(op) = bin_op.op.as_operator() {
|
op: (&str, &str),
|
||||||
bin_op.lhs.visit(v, w)?;
|
lhs: &Expression,
|
||||||
write!(w, "{} ", op)?;
|
rhs: &Expression,
|
||||||
bin_op.rhs.visit(v, w)
|
v: &mut Visitor,
|
||||||
} else {
|
w: Writer,
|
||||||
let (a, b) = bin_op.op.as_name();
|
) -> Result<()> {
|
||||||
|
write!(w, "{}_{}(", op.0, op.1)?;
|
||||||
write!(w, "{}_{}(", a, b)?;
|
lhs.visit(v, w)?;
|
||||||
bin_op.lhs.visit(v, w)?;
|
write!(w, ", ")?;
|
||||||
write!(w, ", ")?;
|
rhs.visit(v, w)?;
|
||||||
bin_op.rhs.visit(v, w)?;
|
write!(w, ")")
|
||||||
write!(w, ")")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Driver for AnyBinOp {
|
impl Driver for AnyBinOp {
|
||||||
fn visit(&self, v: &mut Visitor, w: Writer) -> Result<()> {
|
fn visit(&self, v: &mut Visitor, w: Writer) -> Result<()> {
|
||||||
if self.op.is_compare() {
|
if let Some(op) = self.op.as_operator() {
|
||||||
write!(w, "(")?;
|
write!(w, "(")?;
|
||||||
|
self.lhs.visit(v, w)?;
|
||||||
|
write!(w, "{} ", op)?;
|
||||||
|
self.rhs.visit(v, w)?;
|
||||||
|
write!(w, ")")
|
||||||
|
} else {
|
||||||
|
write_bin_call(self.op.as_name(), &self.lhs, &self.rhs, v, w)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
write_bin_op(self, v, w)?;
|
fn write_any_cmp(cmp: &AnyCmpOp, v: &mut Visitor, w: Writer) -> Result<()> {
|
||||||
|
if let Some(op) = cmp.op.as_operator() {
|
||||||
|
cmp.lhs.visit(v, w)?;
|
||||||
|
write!(w, "{} ", op)?;
|
||||||
|
cmp.rhs.visit(v, w)
|
||||||
|
} else {
|
||||||
|
write_bin_call(cmp.op.as_name(), &cmp.lhs, &cmp.rhs, v, w)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if self.op.is_compare() {
|
impl Driver for AnyCmpOp {
|
||||||
write!(w, "and 1 or 0)")?;
|
fn visit(&self, v: &mut Visitor, w: Writer) -> Result<()> {
|
||||||
}
|
write!(w, "(")?;
|
||||||
|
write_any_cmp(self, v, w)?;
|
||||||
Ok(())
|
write!(w, "and 1 or 0)")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Removes the boolean to integer conversion
|
// Removes the boolean to integer conversion
|
||||||
fn write_as_condition(data: &Expression, v: &mut Visitor, w: Writer) -> Result<()> {
|
fn write_as_condition(data: &Expression, v: &mut Visitor, w: Writer) -> Result<()> {
|
||||||
match data {
|
if let Expression::AnyCmpOp(o) = data {
|
||||||
Expression::AnyUnOp(o) if o.op.is_compare() => write_un_op(o, v, w),
|
write_any_cmp(o, v, w)
|
||||||
Expression::AnyBinOp(o) if o.op.is_compare() => write_bin_op(o, v, w),
|
} else {
|
||||||
_ => {
|
data.visit(v, w)?;
|
||||||
data.visit(v, w)?;
|
write!(w, "~= 0 ")
|
||||||
write!(w, "~= 0 ")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -261,6 +254,7 @@ impl Driver for Expression {
|
|||||||
Self::Value(e) => e.visit(v, w),
|
Self::Value(e) => e.visit(v, w),
|
||||||
Self::AnyUnOp(e) => e.visit(v, w),
|
Self::AnyUnOp(e) => e.visit(v, w),
|
||||||
Self::AnyBinOp(e) => e.visit(v, w),
|
Self::AnyBinOp(e) => e.visit(v, w),
|
||||||
|
Self::AnyCmpOp(e) => e.visit(v, w),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,9 +7,9 @@ use crate::{
|
|||||||
ast::{
|
ast::{
|
||||||
builder::{Arities, Builder},
|
builder::{Arities, Builder},
|
||||||
node::{
|
node::{
|
||||||
AnyBinOp, AnyLoad, AnyStore, AnyUnOp, Backward, Br, BrIf, BrTable, Call, CallIndirect,
|
AnyBinOp, AnyCmpOp, AnyLoad, AnyStore, AnyUnOp, Backward, Br, BrIf, BrTable, Call,
|
||||||
Else, Expression, Forward, Function, GetGlobal, GetLocal, If, Memorize, MemoryGrow,
|
CallIndirect, Else, Expression, Forward, Function, GetGlobal, GetLocal, If, Memorize,
|
||||||
MemorySize, Recall, Return, Select, SetGlobal, SetLocal, Statement, Value,
|
MemoryGrow, MemorySize, Recall, Return, Select, SetGlobal, SetLocal, Statement, Value,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -154,22 +154,13 @@ impl Driver for Value {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_un_op_call(un_op: &AnyUnOp, v: &mut Visitor, w: Writer) -> Result<()> {
|
|
||||||
let (a, b) = un_op.op.as_name();
|
|
||||||
|
|
||||||
write!(w, "{}_{}(", a, b)?;
|
|
||||||
un_op.rhs.visit(v, w)?;
|
|
||||||
write!(w, ")")
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Driver for AnyUnOp {
|
impl Driver for AnyUnOp {
|
||||||
fn visit(&self, v: &mut Visitor, w: Writer) -> Result<()> {
|
fn visit(&self, v: &mut Visitor, w: Writer) -> Result<()> {
|
||||||
if let Some(op) = self.op.as_operator() {
|
let (a, b) = self.op.as_name();
|
||||||
write!(w, "{}", op)?;
|
|
||||||
self.rhs.visit(v, w)
|
write!(w, "{}_{}(", a, b)?;
|
||||||
} else {
|
self.rhs.visit(v, w)?;
|
||||||
write_un_op_call(self, v, w)
|
write!(w, ")")
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -203,6 +194,18 @@ impl Driver for AnyBinOp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Driver for AnyCmpOp {
|
||||||
|
fn visit(&self, v: &mut Visitor, w: Writer) -> Result<()> {
|
||||||
|
let (a, b) = self.op.as_name();
|
||||||
|
|
||||||
|
write!(w, "{}_{}(", a, b)?;
|
||||||
|
self.lhs.visit(v, w)?;
|
||||||
|
write!(w, ", ")?;
|
||||||
|
self.rhs.visit(v, w)?;
|
||||||
|
write!(w, ")")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn write_expr_list(list: &[Expression], v: &mut Visitor, w: Writer) -> Result<()> {
|
fn write_expr_list(list: &[Expression], v: &mut Visitor, w: Writer) -> Result<()> {
|
||||||
list.iter().enumerate().try_for_each(|(i, e)| {
|
list.iter().enumerate().try_for_each(|(i, e)| {
|
||||||
if i != 0 {
|
if i != 0 {
|
||||||
@ -226,6 +229,7 @@ impl Driver for Expression {
|
|||||||
Self::Value(e) => e.visit(v, w),
|
Self::Value(e) => e.visit(v, w),
|
||||||
Self::AnyUnOp(e) => e.visit(v, w),
|
Self::AnyUnOp(e) => e.visit(v, w),
|
||||||
Self::AnyBinOp(e) => e.visit(v, w),
|
Self::AnyBinOp(e) => e.visit(v, w),
|
||||||
|
Self::AnyCmpOp(e) => e.visit(v, w),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user