symoxide 0.1.2

Intermediate Representation and Transformations for Computer Algebra Systems
Documentation
// Copyright (c) 2022 Kaushik Kulkarni
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

use crate::primitives::{Expression, BinaryOpType, UnaryOpType, LiteralT,
  SmallVecExprT};
use std::rc::Rc;
use std::str::FromStr;
use smallvec::{smallvec};

grammar;

pub Expr: Rc<Expression>  = {
      IfExpr,
};

IfExpr: Rc<Expression> = {
    <then_expr: OrExpr> "if" <cond_expr: OrExpr> "else" <else_expr: IfExpr>
        => Rc::new(Expression::If(cond_expr.clone(), then_expr.clone(), else_expr.clone())),
    OrExpr,
}


OrExpr: Rc<Expression> = {
    <left_op: OrExpr> "or" <right_op: AndExpr>
        => Rc::new(Expression::BinaryOp(left_op.clone(), BinaryOpType::LogicalOr, right_op.clone())),
    AndExpr,
};

AndExpr: Rc<Expression> = {
    <left_op: AndExpr> "and" <right_op: NotExpr>
        => Rc::new(Expression::BinaryOp(left_op.clone(), BinaryOpType::LogicalAnd, right_op.clone())),
    NotExpr,
};

NotExpr: Rc<Expression> = {
    "not" <op: NotExpr>
        => Rc::new(Expression::UnaryOp(UnaryOpType::LogicalNot, op.clone())),
    CmpExpr,
};

CmpExpr: Rc<Expression> = {
    <left_op: CmpExpr> <operator: CmpOperator> <right_op: BitwiseOrExpr>
         => Rc::new(Expression::BinaryOp(left_op.clone(), operator, right_op.clone())),
    BitwiseOrExpr,
};

BitwiseOrExpr: Rc<Expression> = {
    <left_op: BitwiseOrExpr> "|" <right_op: BitwiseXorExpr>
         => Rc::new(Expression::BinaryOp(left_op.clone(),  BinaryOpType::BitwiseOr, right_op.clone())),
    BitwiseXorExpr,
};

BitwiseXorExpr: Rc<Expression> = {
    <left_op: BitwiseXorExpr> "^" <right_op: BitwiseAndExpr>
         => Rc::new(Expression::BinaryOp(left_op.clone(), BinaryOpType::BitwiseXor, right_op.clone())),
    BitwiseAndExpr,
};


BitwiseAndExpr: Rc<Expression> = {
    <left_op: BitwiseAndExpr> "&" <right_op: ShiftExpr>
         => Rc::new(Expression::BinaryOp(left_op.clone(),  BinaryOpType::BitwiseAnd, right_op.clone())),
    ShiftExpr,
};

ShiftExpr: Rc<Expression> = {
    <left_op: ShiftExpr> <operator: ShiftOperator> <right_op: SumExpr>
         => Rc::new(Expression::BinaryOp(left_op.clone(),  operator, right_op.clone())),
    SumExpr,
};

SumExpr: Rc<Expression> = {
    <left_op: SumExpr> "+" <right_op: ProdExpr>
        => Rc::new(Expression::BinaryOp(left_op.clone(), BinaryOpType::Sum, right_op.clone())),
    <left_op: SumExpr> "-" <right_op: ProdExpr>
        => Rc::new(Expression::BinaryOp(left_op.clone(), BinaryOpType::Subtract, right_op.clone())),
    ProdExpr,
};

ProdExpr: Rc<Expression> = {
    <left_op: ProdExpr> "*" <right_op: AtomExpr>
        => Rc::new(Expression::BinaryOp(left_op.clone(), BinaryOpType::Product, right_op.clone())),
    <left_op: ProdExpr> "/" <right_op: AtomExpr>
        => Rc::new(Expression::BinaryOp(left_op.clone(), BinaryOpType::Divide, right_op.clone())),
    <left_op: ProdExpr> "//" <right_op: AtomExpr>
        => Rc::new(Expression::BinaryOp(left_op.clone(), BinaryOpType::FloorDiv, right_op.clone())),
    <left_op: ProdExpr> "%" <right_op: AtomExpr>
        => Rc::new(Expression::BinaryOp(left_op.clone(), BinaryOpType::Modulo, right_op.clone())),
    UnaryExpr,
};

UnaryExpr: Rc<Expression> = {
    "-" <op: UnaryExpr>  => Rc::new(Expression::UnaryOp(UnaryOpType::Minus, op.clone())),
    "~" <op: UnaryExpr>  => Rc::new(Expression::UnaryOp(UnaryOpType::BitwiseNot, op.clone())),
    "+" <op: UnaryExpr>  => op,
    ExponentExpr,
};

ExponentExpr: Rc<Expression> = {
    <left_op: AtomExpr> "**" <right_op: ExponentExpr>
        => Rc::new(Expression::BinaryOp(left_op.clone(), BinaryOpType::Exponent, right_op.clone())),
    AtomExpr,
};

AtomExpr: Rc<Expression> = {
    <identifier: Identifier>                                    => Rc::new(Expression::Variable(identifier)),
    <call: AtomExpr> "(" <commaed_exprs: CommaedExprsFinal> ")" => Rc::new(Expression::Call(call.clone(), commaed_exprs)),
    <call: AtomExpr> "("  ")"                                   => Rc::new(Expression::Call(call.clone(), smallvec![])),
    <agg: AtomExpr> "[" <commaed_exprs: CommaedExprsFinal> "]"  => Rc::new(Expression::Subscript(agg.clone(), commaed_exprs)),
    <agg: AtomExpr> "["  "]"                                    => Rc::new(Expression::Subscript(agg.clone(), smallvec![])),
    "(" <expr: Expr> ")"                                        => expr,
    <int_literal: IntLiteral>                                   => Rc::new(Expression::Scalar(LiteralT::I32(int_literal))),
    <float_literal: FloatLiteral>                               => Rc::new(Expression::Scalar(LiteralT::F64(float_literal))),
};

CommaedExprs: Vec<Rc<Expression>> = {
    <commaed_exprs: CommaedExprs> "," <expr: Expr>             => [commaed_exprs.as_slice(), vec![expr].as_slice()].concat(),
    <expr: Expr>                                               => vec![expr],
}

CommaedExprsFinal: SmallVecExprT = {
    <commaed_exprs: CommaedExprs>      => SmallVecExprT::from_vec(commaed_exprs),
    <commaed_exprs: CommaedExprs> ","  => SmallVecExprT::from_vec(commaed_exprs),
};

CmpOperator: BinaryOpType = {
    "==" => BinaryOpType::Equal,
    "!=" => BinaryOpType::NotEqual,
    ">"  => BinaryOpType::Greater,
    ">=" => BinaryOpType::GreaterEqual,
    "<"  => BinaryOpType::Less,
    "<=" => BinaryOpType::LessEqual,
};

ShiftOperator: BinaryOpType = {
    ">>" => BinaryOpType::RightShift,
    "<<" => BinaryOpType::LeftShift,
};

Identifier: String =  {
    <s:r"[a-zA-Z_][a-zA-Z0-9_]*"> => s.to_string(),
};

IntLiteral: i32 = {
    <s:r"(-?)([1-9][0-9]*)|0"> => i32::from_str(s).unwrap(),
}

FloatLiteral: f64 = {
    // f64 with the decimal point
    <s:r"((-?)([1-9][0-9]*)|0)\.([0-9]*)(([eE]((-?)([1-9][0-9]*)|0))?)"> => f64::from_str(s).unwrap(),
    // f64 without the decimal point
    <s:r"((-?)([1-9][0-9]*)|0)([eE]((-?)([1-9][0-9]*)|0))"> => f64::from_str(s).unwrap(),
}

// vim:syntax=rust