leo_grammar/
ast.rs

1// Copyright (C) 2019-2020 Aleo Systems Inc.
2// This file is part of the Leo library.
3
4// The Leo library is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// The Leo library is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
16
17//! Abstract syntax tree (ast) representation from leo.pest.
18use crate::{
19    common::Identifier,
20    expressions::{
21        ArrayInitializerExpression,
22        ArrayInlineExpression,
23        CircuitInlineExpression,
24        Expression,
25        PostfixExpression,
26        TernaryExpression,
27        UnaryExpression,
28    },
29    operations::{BinaryOperation, UnaryOperation},
30    values::Value,
31};
32
33use crate::expressions::TupleExpression;
34use from_pest::{ConversionError, FromPest, Void};
35use pest::{
36    error::Error,
37    iterators::{Pair, Pairs},
38    prec_climber::{Assoc, Operator, PrecClimber},
39    Parser,
40    Span,
41};
42
43#[derive(Parser)]
44#[grammar = "leo.pest"]
45pub struct LanguageParser;
46
47pub fn parse(input: &str) -> Result<Pairs<Rule>, Error<Rule>> {
48    LanguageParser::parse(Rule::file, input)
49}
50
51pub(crate) fn span_into_string(span: Span) -> String {
52    span.as_str().to_string()
53}
54
55lazy_static! {
56    static ref PRECEDENCE_CLIMBER: PrecClimber<Rule> = precedence_climber();
57}
58
59// Expressions
60
61fn precedence_climber() -> PrecClimber<Rule> {
62    PrecClimber::new(vec![
63        Operator::new(Rule::operation_or, Assoc::Left),
64        Operator::new(Rule::operation_and, Assoc::Left),
65        Operator::new(Rule::operation_eq, Assoc::Left)
66            | Operator::new(Rule::operation_ne, Assoc::Left)
67            | Operator::new(Rule::operation_ge, Assoc::Left)
68            | Operator::new(Rule::operation_gt, Assoc::Left)
69            | Operator::new(Rule::operation_le, Assoc::Left)
70            | Operator::new(Rule::operation_lt, Assoc::Left),
71        Operator::new(Rule::operation_add, Assoc::Left) | Operator::new(Rule::operation_sub, Assoc::Left),
72        Operator::new(Rule::operation_mul, Assoc::Left) | Operator::new(Rule::operation_div, Assoc::Left),
73        Operator::new(Rule::operation_pow, Assoc::Left),
74    ])
75}
76
77fn parse_term(pair: Pair<Rule>) -> Expression {
78    match pair.as_rule() {
79        Rule::expression_term => {
80            let clone = pair.clone();
81            let next = clone.into_inner().next().unwrap();
82            match next.as_rule() {
83                Rule::expression => Expression::from_pest(&mut pair.into_inner()).unwrap(), // Parenthesis case
84                Rule::expression_tuple => {
85                    Expression::Tuple(TupleExpression::from_pest(&mut pair.into_inner()).unwrap())
86                }
87                Rule::expression_array_inline => {
88                    Expression::ArrayInline(ArrayInlineExpression::from_pest(&mut pair.into_inner()).unwrap())
89                }
90                Rule::expression_array_initializer => Expression::ArrayInitializer(Box::new(
91                    ArrayInitializerExpression::from_pest(&mut pair.into_inner()).unwrap(),
92                )),
93                Rule::expression_circuit_inline => {
94                    Expression::CircuitInline(CircuitInlineExpression::from_pest(&mut pair.into_inner()).unwrap())
95                }
96                Rule::expression_conditional => {
97                    Expression::Ternary(Box::new(TernaryExpression::from_pest(&mut pair.into_inner()).unwrap()))
98                }
99                Rule::expression_unary => {
100                    // The following is necessary to match with the unary operator and its unary expression
101                    let span = next.as_span();
102                    let mut inner = next.into_inner();
103                    let operation = match inner.next().unwrap().as_rule() {
104                        Rule::operation_unary => {
105                            UnaryOperation::from_pest(&mut pair.into_inner().next().unwrap().into_inner()).unwrap()
106                        }
107                        rule => unreachable!("`expression_unary` should yield `operation_unary`, found {:#?}", rule),
108                    };
109                    let expression = parse_term(inner.next().unwrap());
110                    Expression::Unary(Box::new(UnaryExpression {
111                        operation,
112                        expression,
113                        span,
114                    }))
115                }
116                Rule::expression_postfix => {
117                    Expression::Postfix(PostfixExpression::from_pest(&mut pair.into_inner()).unwrap())
118                }
119                Rule::value => Expression::Value(Value::from_pest(&mut pair.into_inner()).unwrap()),
120                Rule::identifier => Expression::Identifier(Identifier::from_pest(&mut pair.into_inner()).unwrap()),
121                rule => unreachable!(
122                    "`term` should contain one of ['value', 'identifier', 'expression', 'expression_not', 'expression_increment', 'expression_decrement'], found {:#?}",
123                    rule
124                ),
125            }
126        }
127        rule => unreachable!(
128            "`parse_expression_term` should be invoked on `Rule::expression_term`, found {:#?}",
129            rule
130        ),
131    }
132}
133
134fn binary_expression<'ast>(lhs: Expression<'ast>, pair: Pair<'ast, Rule>, rhs: Expression<'ast>) -> Expression<'ast> {
135    let (start, _) = lhs.span().clone().split();
136    let (_, end) = rhs.span().clone().split();
137    let span = start.span(&end);
138
139    match pair.as_rule() {
140        Rule::operation_or => Expression::binary(BinaryOperation::Or, lhs, rhs, span),
141        Rule::operation_and => Expression::binary(BinaryOperation::And, lhs, rhs, span),
142        Rule::operation_eq => Expression::binary(BinaryOperation::Eq, lhs, rhs, span),
143        Rule::operation_ne => Expression::binary(BinaryOperation::Ne, lhs, rhs, span),
144        Rule::operation_ge => Expression::binary(BinaryOperation::Ge, lhs, rhs, span),
145        Rule::operation_gt => Expression::binary(BinaryOperation::Gt, lhs, rhs, span),
146        Rule::operation_le => Expression::binary(BinaryOperation::Le, lhs, rhs, span),
147        Rule::operation_lt => Expression::binary(BinaryOperation::Lt, lhs, rhs, span),
148        Rule::operation_add => Expression::binary(BinaryOperation::Add, lhs, rhs, span),
149        Rule::operation_sub => Expression::binary(BinaryOperation::Sub, lhs, rhs, span),
150        Rule::operation_mul => Expression::binary(BinaryOperation::Mul, lhs, rhs, span),
151        Rule::operation_div => Expression::binary(BinaryOperation::Div, lhs, rhs, span),
152        Rule::operation_pow => Expression::binary(BinaryOperation::Pow, lhs, rhs, span),
153        _ => unreachable!(),
154    }
155}
156
157impl<'ast> FromPest<'ast> for Expression<'ast> {
158    type FatalError = Void;
159    type Rule = Rule;
160
161    fn from_pest(pest: &mut Pairs<'ast, Rule>) -> Result<Self, ConversionError<Void>> {
162        let pair = pest.peek().ok_or(::from_pest::ConversionError::NoMatch)?;
163        match pair.as_rule() {
164            Rule::expression => {
165                // advance the iterator
166                pest.next();
167                Ok(PRECEDENCE_CLIMBER.climb(pair.into_inner(), parse_term, binary_expression))
168            }
169            _ => Err(ConversionError::NoMatch),
170        }
171    }
172}