Add some simple desugaring to the compiler.
This commit is contained in:
parent
a45d9627dc
commit
91a52574c8
11 changed files with 317 additions and 14 deletions
|
@ -188,6 +188,7 @@ impl Context {
|
||||||
let types = vec![
|
let types = vec![
|
||||||
Ty::native_array(strings.intern("Huia.Native.Array")),
|
Ty::native_array(strings.intern("Huia.Native.Array")),
|
||||||
Ty::native_atom(strings.intern("Huia.Native.Atom")),
|
Ty::native_atom(strings.intern("Huia.Native.Atom")),
|
||||||
|
Ty::native_boolean(strings.intern("Huia.Native.Boolean")),
|
||||||
Ty::native_float(strings.intern("Huia.Native.Float")),
|
Ty::native_float(strings.intern("Huia.Native.Float")),
|
||||||
Ty::native_integer(strings.intern("Huia.Native.Integer")),
|
Ty::native_integer(strings.intern("Huia.Native.Integer")),
|
||||||
Ty::native_map(strings.intern("Huia.Native.Map")),
|
Ty::native_map(strings.intern("Huia.Native.Map")),
|
||||||
|
|
|
@ -19,6 +19,7 @@ impl Builder {
|
||||||
/// Consume an AST node and build IR.
|
/// Consume an AST node and build IR.
|
||||||
///
|
///
|
||||||
/// Any IR will be on the Builder's stack.
|
/// Any IR will be on the Builder's stack.
|
||||||
|
#[allow(clippy::cyclomatic_complexity)]
|
||||||
pub fn build(&mut self, node: Term, mut context: &mut Context) {
|
pub fn build(&mut self, node: Term, mut context: &mut Context) {
|
||||||
match node.node_type() {
|
match node.node_type() {
|
||||||
NodeType::Array => {
|
NodeType::Array => {
|
||||||
|
@ -58,7 +59,18 @@ impl Builder {
|
||||||
self.build(rhs.clone(), &mut context);
|
self.build(rhs.clone(), &mut context);
|
||||||
let rhs = self.pop_ir().unwrap();
|
let rhs = self.pop_ir().unwrap();
|
||||||
let lhs = self.pop_ir().unwrap();
|
let lhs = self.pop_ir().unwrap();
|
||||||
let result_type = lhs.result_type();
|
|
||||||
|
let result_type = if op.is_logical() {
|
||||||
|
let name = context.constant_string("Huia.Native.Boolean");
|
||||||
|
context.reference_type(&name, location.clone())
|
||||||
|
}
|
||||||
|
else if op.is_arithmetic() {
|
||||||
|
lhs.result_type()
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
panic!("Operator {:?} is neither arithmetic nor logical", op);
|
||||||
|
};
|
||||||
|
|
||||||
self.push_ir(IR::new_infix(
|
self.push_ir(IR::new_infix(
|
||||||
result_type,
|
result_type,
|
||||||
location,
|
location,
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use crate::context::Context;
|
use crate::context::Context;
|
||||||
use crate::ir::{IRKind, Val, IR};
|
use crate::ir::{IRKind, Val, IR};
|
||||||
use huia_parser::ast::binary::Operator as BinOp;
|
use huia_parser::ast::binary::Operator as BinOp;
|
||||||
|
use huia_parser::ast::unary::Operator as UnOp;
|
||||||
use std::f64;
|
use std::f64;
|
||||||
|
|
||||||
/// Perform constant folding on the provided node, or not.
|
/// Perform constant folding on the provided node, or not.
|
||||||
|
@ -17,7 +18,7 @@ pub fn pass(ir: &mut IR, context: &mut Context) {
|
||||||
if lhs.is_integer() && rhs.is_integer() {
|
if lhs.is_integer() && rhs.is_integer() {
|
||||||
let lhs = lhs.integer().unwrap();
|
let lhs = lhs.integer().unwrap();
|
||||||
let rhs = rhs.integer().unwrap();
|
let rhs = rhs.integer().unwrap();
|
||||||
let value = perform_i64(&op, lhs, rhs);
|
let value = perform_i64_infix_fold(&op, lhs, rhs);
|
||||||
if let Some(value) = value {
|
if let Some(value) = value {
|
||||||
ir.set_kind(IRKind::Constant(Val::Integer(value)));
|
ir.set_kind(IRKind::Constant(Val::Integer(value)));
|
||||||
let idx = context.constant_string("Huia.Native.Integer");
|
let idx = context.constant_string("Huia.Native.Integer");
|
||||||
|
@ -26,17 +27,57 @@ pub fn pass(ir: &mut IR, context: &mut Context) {
|
||||||
} else if lhs.is_float() && rhs.is_float() {
|
} else if lhs.is_float() && rhs.is_float() {
|
||||||
let lhs = lhs.float().unwrap();
|
let lhs = lhs.float().unwrap();
|
||||||
let rhs = rhs.float().unwrap();
|
let rhs = rhs.float().unwrap();
|
||||||
let value = perform_f64(&op, lhs, rhs);
|
let value = perform_f64_infix_fold(&op, lhs, rhs);
|
||||||
if let Some(value) = value {
|
if let Some(value) = value {
|
||||||
ir.set_kind(IRKind::Constant(Val::Float(value)));
|
ir.set_kind(IRKind::Constant(Val::Float(value)));
|
||||||
let idx = context.constant_string("Huia.Native.Float");
|
let idx = context.constant_string("Huia.Native.Float");
|
||||||
ir.set_result_type(context.reference_type(&idx, ir.location.clone()));
|
ir.set_result_type(context.reference_type(&idx, ir.location.clone()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if ir.is_unary() {
|
||||||
|
let (op, rhs) = ir.get_unary().unwrap();
|
||||||
|
if !rhs.is_constant() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let rhs = rhs.get_value().unwrap();
|
||||||
|
|
||||||
|
match op {
|
||||||
|
UnOp::LogicalNot => {
|
||||||
|
if rhs.is_boolean() {
|
||||||
|
// if the RHS is a boolean constant then fold it.
|
||||||
|
let value = rhs.boolean().unwrap();
|
||||||
|
ir.set_kind(IRKind::Constant(Val::Boolean(!value)));
|
||||||
|
} else {
|
||||||
|
// otherwise just return false for all other constant values.
|
||||||
|
ir.set_kind(IRKind::Constant(Val::Boolean(false)));
|
||||||
|
}
|
||||||
|
let tyname = context.constant_string("Huia.Native.Boolean");
|
||||||
|
let ty = context.reference_type(&tyname, ir.location.clone());
|
||||||
|
ir.set_result_type(ty)
|
||||||
|
}
|
||||||
|
UnOp::Minus => {
|
||||||
|
if rhs.is_integer() {
|
||||||
|
let value = rhs.integer().unwrap();
|
||||||
|
ir.set_kind(IRKind::Constant(Val::Integer(-value)));
|
||||||
|
} else if rhs.is_float() {
|
||||||
|
let value = rhs.float().unwrap();
|
||||||
|
ir.set_kind(IRKind::Constant(Val::Float(-value)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
UnOp::Plus => {
|
||||||
|
if rhs.is_integer() {
|
||||||
|
let value = rhs.integer().unwrap();
|
||||||
|
ir.set_kind(IRKind::Constant(Val::Integer(value)));
|
||||||
|
} else if rhs.is_float() {
|
||||||
|
let value = rhs.float().unwrap();
|
||||||
|
ir.set_kind(IRKind::Constant(Val::Float(value)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn perform_i64(op: &BinOp, lhs: i64, rhs: i64) -> Option<i64> {
|
fn perform_i64_infix_fold(op: &BinOp, lhs: i64, rhs: i64) -> Option<i64> {
|
||||||
match op {
|
match op {
|
||||||
BinOp::BitwiseAnd => Some(lhs & rhs),
|
BinOp::BitwiseAnd => Some(lhs & rhs),
|
||||||
BinOp::BitwiseOr => Some(lhs | rhs),
|
BinOp::BitwiseOr => Some(lhs | rhs),
|
||||||
|
@ -53,7 +94,7 @@ fn perform_i64(op: &BinOp, lhs: i64, rhs: i64) -> Option<i64> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn perform_f64(op: &BinOp, lhs: f64, rhs: f64) -> Option<f64> {
|
fn perform_f64_infix_fold(op: &BinOp, lhs: f64, rhs: f64) -> Option<f64> {
|
||||||
match op {
|
match op {
|
||||||
BinOp::Divide => Some(lhs / rhs),
|
BinOp::Divide => Some(lhs / rhs),
|
||||||
BinOp::Minus => Some(lhs - rhs),
|
BinOp::Minus => Some(lhs - rhs),
|
||||||
|
@ -71,7 +112,7 @@ mod test {
|
||||||
use huia_parser::ast::Term;
|
use huia_parser::ast::Term;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn integer_folding() {
|
fn integer_infix_folding() {
|
||||||
let term = Term::input("3 * 2 + 13 / 2").unwrap()[0].clone();
|
let term = Term::input("3 * 2 + 13 / 2").unwrap()[0].clone();
|
||||||
let mut context = Context::test();
|
let mut context = Context::test();
|
||||||
let mut builder = Builder::default();
|
let mut builder = Builder::default();
|
||||||
|
@ -85,7 +126,7 @@ mod test {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn float_folding() {
|
fn float_infix_folding() {
|
||||||
let term = Term::input("1.5 * 2.0 / 3.0").unwrap()[0].clone();
|
let term = Term::input("1.5 * 2.0 / 3.0").unwrap()[0].clone();
|
||||||
let mut context = Context::test();
|
let mut context = Context::test();
|
||||||
let mut builder = Builder::default();
|
let mut builder = Builder::default();
|
||||||
|
@ -97,4 +138,21 @@ mod test {
|
||||||
assert!(ir.is_constant());
|
assert!(ir.is_constant());
|
||||||
assert!(ir.get_value().unwrap().float().unwrap() - 1.0 < f64::EPSILON);
|
assert!(ir.get_value().unwrap().float().unwrap() - 1.0 < f64::EPSILON);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn integer_unary_folding() {
|
||||||
|
let term = Term::input("!3").unwrap()[0].clone();
|
||||||
|
let mut context = Context::test();
|
||||||
|
let mut builder = Builder::default();
|
||||||
|
|
||||||
|
builder.build(term, &mut context);
|
||||||
|
let mut ir = builder.pop_ir().unwrap();
|
||||||
|
ir.improve(&mut context, pass);
|
||||||
|
|
||||||
|
assert!(ir.is_constant());
|
||||||
|
assert!(!ir.get_value().unwrap().boolean().unwrap());
|
||||||
|
|
||||||
|
let ty = context.get_type(&ir.result_type()).unwrap();
|
||||||
|
assert!(ty.is_native_boolean());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
59
huia-compiler/src/ir/desugar_infix.rs
Normal file
59
huia-compiler/src/ir/desugar_infix.rs
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
use crate::context::Context;
|
||||||
|
use crate::ir::{IRKind, IR};
|
||||||
|
use huia_parser::ast::binary::Operator as BinOp;
|
||||||
|
|
||||||
|
/// Desugar infix operations into method calls.
|
||||||
|
pub fn pass(ir: &mut IR, context: &mut Context) {
|
||||||
|
if ir.is_infix() {
|
||||||
|
let (op, lhs, rhs) = ir.get_infix().unwrap();
|
||||||
|
let method_name = match op {
|
||||||
|
BinOp::BitwiseAnd => "bitwise_and",
|
||||||
|
BinOp::BitwiseOr => "bitwise_or",
|
||||||
|
BinOp::BitwiseXor => "bitwise_xor",
|
||||||
|
BinOp::Divide => "divide",
|
||||||
|
BinOp::Equal => "equal",
|
||||||
|
BinOp::Exponent => "exponent",
|
||||||
|
BinOp::GreaterThan => "greater_than",
|
||||||
|
BinOp::GreaterThanOrEqual => "greater_than_or_equal",
|
||||||
|
BinOp::LessThan => "less_than",
|
||||||
|
BinOp::LessThanOrEqual => "less_than_or_equal",
|
||||||
|
BinOp::LogicalAnd => "logical_and",
|
||||||
|
BinOp::LogicalOr => "logical_or",
|
||||||
|
BinOp::Minus => "minus",
|
||||||
|
BinOp::Modulus => "modulus",
|
||||||
|
BinOp::Multiply => "multiply",
|
||||||
|
BinOp::NotEqual => "not_equal",
|
||||||
|
BinOp::Plus => "plus",
|
||||||
|
BinOp::ShiftLeft => "shift_left",
|
||||||
|
BinOp::ShiftRight => "shift_right",
|
||||||
|
};
|
||||||
|
let method_name = context.constant_string(method_name);
|
||||||
|
ir.kind = IRKind::MethodCall(Box::new(lhs.clone()), method_name, vec![rhs.clone()]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
use crate::ir::builder::Builder;
|
||||||
|
use huia_parser::ast::Term;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn works() {
|
||||||
|
let terms = Term::input("3 * 2").unwrap();
|
||||||
|
let mut context = Context::test();
|
||||||
|
let mut builder = Builder::default();
|
||||||
|
|
||||||
|
for term in terms {
|
||||||
|
builder.build(term, &mut context);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut ir = builder.pop_ir().unwrap();
|
||||||
|
|
||||||
|
assert!(ir.is_infix());
|
||||||
|
|
||||||
|
ir.improve(&mut context, pass);
|
||||||
|
|
||||||
|
assert!(ir.is_method_call());
|
||||||
|
}
|
||||||
|
}
|
43
huia-compiler/src/ir/desugar_unary.rs
Normal file
43
huia-compiler/src/ir/desugar_unary.rs
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
use crate::context::Context;
|
||||||
|
use crate::ir::{IRKind, IR};
|
||||||
|
use huia_parser::ast::unary::Operator as UnOp;
|
||||||
|
|
||||||
|
/// Desugar unary operations into method calls.
|
||||||
|
pub fn pass(ir: &mut IR, context: &mut Context) {
|
||||||
|
if ir.is_unary() {
|
||||||
|
let (op, rhs) = ir.get_unary().unwrap();
|
||||||
|
let method_name = match op {
|
||||||
|
UnOp::LogicalNot => "logical_not",
|
||||||
|
UnOp::Minus => "unary_minus",
|
||||||
|
UnOp::Plus => "unary_plus",
|
||||||
|
};
|
||||||
|
let method_name = context.constant_string(method_name);
|
||||||
|
ir.kind = IRKind::MethodCall(Box::new(rhs.clone()), method_name, Vec::default());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
use crate::ir::builder::Builder;
|
||||||
|
use huia_parser::ast::Term;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn works() {
|
||||||
|
let terms = Term::input("!3").unwrap();
|
||||||
|
let mut context = Context::test();
|
||||||
|
let mut builder = Builder::default();
|
||||||
|
|
||||||
|
for term in terms {
|
||||||
|
builder.build(term, &mut context);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut ir = builder.pop_ir().unwrap();
|
||||||
|
|
||||||
|
assert!(ir.is_unary());
|
||||||
|
|
||||||
|
ir.improve(&mut context, pass);
|
||||||
|
|
||||||
|
assert!(ir.is_method_call());
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,7 @@
|
||||||
mod builder;
|
pub mod builder;
|
||||||
mod constant_folding;
|
pub mod constant_folding;
|
||||||
|
pub mod desugar_infix;
|
||||||
|
pub mod desugar_unary;
|
||||||
|
|
||||||
use crate::block::BlockIdx;
|
use crate::block::BlockIdx;
|
||||||
use crate::context::Context;
|
use crate::context::Context;
|
||||||
|
@ -33,6 +35,13 @@ impl IR {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_unary(&self) -> Option<(&UnOp, &IR)> {
|
||||||
|
match self.kind {
|
||||||
|
IRKind::Unary(ref op, ref rhs) => Some((op, rhs)),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_value(&self) -> Option<&Val> {
|
pub fn get_value(&self) -> Option<&Val> {
|
||||||
match self.kind {
|
match self.kind {
|
||||||
IRKind::Constant(ref value) => Some(value),
|
IRKind::Constant(ref value) => Some(value),
|
||||||
|
@ -92,7 +101,7 @@ impl IR {
|
||||||
}
|
}
|
||||||
IRKind::MethodCall(ref mut callee, _, ref mut arguments) => {
|
IRKind::MethodCall(ref mut callee, _, ref mut arguments) => {
|
||||||
improver(callee, &mut context);
|
improver(callee, &mut context);
|
||||||
for ref mut argument in arguments {
|
for argument in arguments {
|
||||||
improver(argument, &mut context);
|
improver(argument, &mut context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -189,6 +198,13 @@ impl IR {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_method_call(&self) -> bool {
|
||||||
|
match self.kind {
|
||||||
|
IRKind::MethodCall(..) => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn is_type_reference(&self) -> bool {
|
pub fn is_type_reference(&self) -> bool {
|
||||||
match self.kind {
|
match self.kind {
|
||||||
IRKind::TypeReference(..) => true,
|
IRKind::TypeReference(..) => true,
|
||||||
|
@ -428,6 +444,13 @@ impl Val {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn boolean(&self) -> Option<bool> {
|
||||||
|
match self {
|
||||||
|
Val::Boolean(ref value) => Some(*value),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn float(&self) -> Option<f64> {
|
pub fn float(&self) -> Option<f64> {
|
||||||
match self {
|
match self {
|
||||||
Val::Float(ref value) => Some(*value),
|
Val::Float(ref value) => Some(*value),
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
mod block;
|
mod block;
|
||||||
mod context;
|
mod context;
|
||||||
|
mod env;
|
||||||
mod error;
|
mod error;
|
||||||
mod function;
|
mod function;
|
||||||
mod ir;
|
mod ir;
|
||||||
|
@ -7,4 +8,25 @@ mod location;
|
||||||
mod method;
|
mod method;
|
||||||
mod stable;
|
mod stable;
|
||||||
mod ty;
|
mod ty;
|
||||||
mod env;
|
|
||||||
|
use crate::context::Context;
|
||||||
|
use huia_parser::ast::Term;
|
||||||
|
use std::fs;
|
||||||
|
|
||||||
|
pub fn compile_file(path: &str) -> Context {
|
||||||
|
let contents = fs::read_to_string(path).expect("Unable to open file");
|
||||||
|
let terms = Term::file(&contents).expect("Unable to parse file");
|
||||||
|
let mut context = Context::new(path);
|
||||||
|
let mut builder = ir::builder::Builder::default();
|
||||||
|
for term in terms {
|
||||||
|
builder.build(term, &mut context);
|
||||||
|
}
|
||||||
|
|
||||||
|
context.improve_ir(|mut ir, mut context| {
|
||||||
|
ir::constant_folding::pass(&mut ir, &mut context);
|
||||||
|
ir::desugar_infix::pass(&mut ir, &mut context);
|
||||||
|
ir::desugar_unary::pass(&mut ir, &mut context);
|
||||||
|
});
|
||||||
|
|
||||||
|
context
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
use crate::ir::IR;
|
|
||||||
use crate::location::Location;
|
use crate::location::Location;
|
||||||
use crate::stable::StringIdx;
|
use crate::stable::StringIdx;
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
@ -32,6 +31,13 @@ impl Ty {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_native_boolean(&self) -> bool {
|
||||||
|
match self.inner {
|
||||||
|
TyInner::NativeBoolean => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn is_unresolved(&self) -> bool {
|
pub fn is_unresolved(&self) -> bool {
|
||||||
match self.kind {
|
match self.kind {
|
||||||
TyKind::Unresolved => true,
|
TyKind::Unresolved => true,
|
||||||
|
@ -135,6 +141,15 @@ impl Ty {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn native_boolean(name: StringIdx) -> Ty {
|
||||||
|
Ty {
|
||||||
|
name: Some(name),
|
||||||
|
location: None,
|
||||||
|
kind: TyKind::Native,
|
||||||
|
inner: TyInner::NativeBoolean,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn native_float(name: StringIdx) -> Ty {
|
pub fn native_float(name: StringIdx) -> Ty {
|
||||||
Ty {
|
Ty {
|
||||||
name: Some(name),
|
name: Some(name),
|
||||||
|
@ -223,6 +238,7 @@ enum TyInner {
|
||||||
},
|
},
|
||||||
NativeArray,
|
NativeArray,
|
||||||
NativeAtom,
|
NativeAtom,
|
||||||
|
NativeBoolean,
|
||||||
NativeFloat,
|
NativeFloat,
|
||||||
NativeInteger,
|
NativeInteger,
|
||||||
NativeMap,
|
NativeMap,
|
||||||
|
|
|
@ -9,6 +9,16 @@ pub struct Binary {
|
||||||
location: InputLocation,
|
location: InputLocation,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Binary {
|
||||||
|
pub fn is_arithmetic(&self) -> bool {
|
||||||
|
self.value.is_arithmetic()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_logical(&self) -> bool {
|
||||||
|
self.value.is_logical()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub enum Operator {
|
pub enum Operator {
|
||||||
BitwiseAnd,
|
BitwiseAnd,
|
||||||
|
@ -23,7 +33,6 @@ pub enum Operator {
|
||||||
LessThanOrEqual,
|
LessThanOrEqual,
|
||||||
LogicalAnd,
|
LogicalAnd,
|
||||||
LogicalOr,
|
LogicalOr,
|
||||||
Method,
|
|
||||||
Minus,
|
Minus,
|
||||||
Modulus,
|
Modulus,
|
||||||
Multiply,
|
Multiply,
|
||||||
|
@ -33,6 +42,39 @@ pub enum Operator {
|
||||||
ShiftRight,
|
ShiftRight,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Operator {
|
||||||
|
pub fn is_arithmetic(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
Operator::BitwiseAnd => true,
|
||||||
|
Operator::BitwiseOr => true,
|
||||||
|
Operator::BitwiseXor => true,
|
||||||
|
Operator::Divide => true,
|
||||||
|
Operator::Exponent => true,
|
||||||
|
Operator::Minus => true,
|
||||||
|
Operator::Modulus => true,
|
||||||
|
Operator::Multiply => true,
|
||||||
|
Operator::Plus => true,
|
||||||
|
Operator::ShiftLeft => true,
|
||||||
|
Operator::ShiftRight => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_logical(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
Operator::Equal => true,
|
||||||
|
Operator::GreaterThan => true,
|
||||||
|
Operator::GreaterThanOrEqual => true,
|
||||||
|
Operator::LessThan => true,
|
||||||
|
Operator::LessThanOrEqual => true,
|
||||||
|
Operator::LogicalAnd => true,
|
||||||
|
Operator::LogicalOr => true,
|
||||||
|
Operator::NotEqual => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Value for Binary {
|
impl Value for Binary {
|
||||||
type Item = Operator;
|
type Item = Operator;
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@ impl<'a> From<Pair<'a, Rule>> for Function {
|
||||||
fn from(pair: Pair<'a, Rule>) -> Self {
|
fn from(pair: Pair<'a, Rule>) -> Self {
|
||||||
match pair.as_rule() {
|
match pair.as_rule() {
|
||||||
Rule::function => {
|
Rule::function => {
|
||||||
let clauses = pair.clone().into_inner().map(|p| Clause::from(p)).collect();
|
let clauses = pair.clone().into_inner().map(Clause::from).collect();
|
||||||
let location = InputLocation::from(pair.into_span());
|
let location = InputLocation::from(pair.into_span());
|
||||||
Function { clauses, location }
|
Function { clauses, location }
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,16 @@ pub struct Unary {
|
||||||
location: InputLocation,
|
location: InputLocation,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Unary {
|
||||||
|
pub fn is_arithmetic(&self) -> bool {
|
||||||
|
self.value.is_arithmetic()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_logical(&self) -> bool {
|
||||||
|
self.value.is_logical()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub enum Operator {
|
pub enum Operator {
|
||||||
LogicalNot,
|
LogicalNot,
|
||||||
|
@ -16,6 +26,23 @@ pub enum Operator {
|
||||||
Plus,
|
Plus,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Operator {
|
||||||
|
pub fn is_arithmetic(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
Operator::Minus => true,
|
||||||
|
Operator::Plus => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_logical(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
Operator::LogicalNot => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Value for Unary {
|
impl Value for Unary {
|
||||||
type Item = Operator;
|
type Item = Operator;
|
||||||
|
|
||||||
|
|
Reference in a new issue