basic program compilation from ast

This commit is contained in:
collin 2020-03-23 15:19:47 -07:00
parent a143322f53
commit c798635e29
10 changed files with 900 additions and 393 deletions

View File

@ -4,6 +4,14 @@ version = "0.1.0"
authors = ["howardwu <howardwu@berkeley.edu>"]
edition = "2018"
[lib]
name = "language"
path = "src/lib.rs"
[[bin]]
name = "snarkLang"
path = "src/main.rs"
[dependencies]
from-pest = "0.3.1"
lazy_static = "1.3.0"

View File

@ -1,2 +1 @@
x = 5 + 3
y = x * (x * 2)
return a + b

443
src/ast.rs Normal file
View File

@ -0,0 +1,443 @@
use from_pest::{ConversionError, FromPest, Void};
use pest::{
error::Error,
iterators::{Pair, Pairs},
prec_climber::{Assoc, Operator, PrecClimber},
Parser, Span,
};
use pest_ast::FromPest;
use std::fmt;
#[derive(Parser)]
#[grammar = "language.pest"]
pub struct LanguageParser;
pub fn parse(input: &str) -> Result<Pairs<Rule>, Error<Rule>> {
LanguageParser::parse(Rule::file, input)
}
fn span_into_string(span: Span) -> String {
span.as_str().to_string()
}
lazy_static! {
static ref PRECEDENCE_CLIMBER: PrecClimber<Rule> = precedence_climber();
}
fn precedence_climber() -> PrecClimber<Rule> {
PrecClimber::new(vec![
Operator::new(Rule::operation_or, Assoc::Left),
Operator::new(Rule::operation_and, Assoc::Left),
Operator::new(Rule::operation_eq, Assoc::Left)
| Operator::new(Rule::operation_neq, Assoc::Left),
Operator::new(Rule::operation_geq, Assoc::Left)
| Operator::new(Rule::operation_gt, Assoc::Left)
| Operator::new(Rule::operation_leq, Assoc::Left)
| Operator::new(Rule::operation_lt, Assoc::Left),
Operator::new(Rule::operation_add, Assoc::Left)
| Operator::new(Rule::operation_sub, Assoc::Left),
Operator::new(Rule::operation_mul, Assoc::Left)
| Operator::new(Rule::operation_div, Assoc::Left),
Operator::new(Rule::operation_pow, Assoc::Left),
])
}
fn parse_term(pair: Pair<Rule>) -> Box<Expression> {
Box::new(match pair.as_rule() {
Rule::expression_term => {
let clone = pair.clone();
let next = clone.into_inner().next().unwrap();
match next.as_rule() {
Rule::expression_primitive => {
let next = next.into_inner().next().unwrap();
match next.as_rule() {
Rule::value => Expression::Value(
Value::from_pest(&mut pair.into_inner().next().unwrap().into_inner()).unwrap()
),
Rule::variable => Expression::Variable(
Variable::from_pest(&mut pair.into_inner().next().unwrap().into_inner()).unwrap(),
),
rule => unreachable!("`expression_primitive` should contain one of [`value`, `variable`], found {:#?}", rule)
}
}
Rule::expression_not => {
let span = next.as_span();
let mut inner = next.into_inner();
let operation = match inner.next().unwrap().as_rule() {
Rule::operation_pre_not => Not::from_pest(&mut pair.into_inner().next().unwrap().into_inner()).unwrap(),
rule => unreachable!("`expression_not` should yield `operation_pre_not`, found {:#?}", rule)
};
let expression = parse_term(inner.next().unwrap());
Expression::Not(NotExpression { operation, expression, span })
},
Rule::expression => Expression::from_pest(&mut pair.into_inner()).unwrap(), // Parenthesis case
// Rule::expression_increment => {
// let span = next.as_span();
// let mut inner = next.into_inner();
// let expression = parse_expression_term(inner.next().unwrap());
// let operation = match inner.next().unwrap().as_rule() {
// Rule::operation_post_increment => Increment::from_pest(&mut pair.into_inner().next().unwrap().into_inner()).unwrap(),
// rule => unreachable!("`expression_increment` should yield `operation_post_increment`, found {:#?}", rule)
// };
// Expression::Increment(IncrementExpression { operation, expression, span })
// },
// Rule::expression_decrement => {
// let span = next.as_span();
// let mut inner = next.into_inner();
// let expression = parse_expression_term(inner.next().unwrap());
// let operation = match inner.next().unwrap().as_rule() {
// Rule::operation_post_decrement => Decrement::from_pest(&mut pair.into_inner().next().unwrap().into_inner()).unwrap(),
// rule => unreachable!("`expression_decrement` should yield `operation_post_decrement`, found {:#?}", rule)
// };
// Expression::Decrement(DecrementExpression { operation, expression, span })
// },
rule => unreachable!("`term` should contain one of ['value', 'variable', 'expression', 'expression_not', 'expression_increment', 'expression_decrement'], found {:#?}", rule)
}
}
rule => unreachable!(
"`parse_expression_term` should be invoked on `Rule::expression_term`, found {:#?}",
rule
),
})
}
fn binary_expression<'ast>(
lhs: Box<Expression<'ast>>,
pair: Pair<'ast, Rule>,
rhs: Box<Expression<'ast>>,
) -> Box<Expression<'ast>> {
let (start, _) = lhs.span().clone().split();
let (_, end) = rhs.span().clone().split();
let span = start.span(&end);
Box::new(match pair.as_rule() {
Rule::operation_or => Expression::binary(BinaryOperator::Or, lhs, rhs, span),
Rule::operation_and => Expression::binary(BinaryOperator::And, lhs, rhs, span),
Rule::operation_eq => Expression::binary(BinaryOperator::Eq, lhs, rhs, span),
Rule::operation_neq => Expression::binary(BinaryOperator::Neq, lhs, rhs, span),
Rule::operation_geq => Expression::binary(BinaryOperator::Geq, lhs, rhs, span),
Rule::operation_gt => Expression::binary(BinaryOperator::Gt, lhs, rhs, span),
Rule::operation_leq => Expression::binary(BinaryOperator::Leq, lhs, rhs, span),
Rule::operation_lt => Expression::binary(BinaryOperator::Lt, lhs, rhs, span),
Rule::operation_add => Expression::binary(BinaryOperator::Add, lhs, rhs, span),
Rule::operation_sub => Expression::binary(BinaryOperator::Sub, lhs, rhs, span),
Rule::operation_mul => Expression::binary(BinaryOperator::Mul, lhs, rhs, span),
Rule::operation_div => Expression::binary(BinaryOperator::Div, lhs, rhs, span),
Rule::operation_pow => Expression::binary(BinaryOperator::Pow, lhs, rhs, span),
_ => unreachable!(),
})
}
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::file))]
pub struct File<'ast> {
pub statement: Vec<Statement<'ast>>,
pub eoi: EOI,
#[pest_ast(outer())]
pub span: Span<'ast>,
}
// Visibility
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::visibility_public))]
pub struct Public {}
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::visibility_private))]
pub struct Private {}
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::visibility))]
pub enum Visibility {
Public(Public),
Private(Private),
}
// Unary Operations
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::operation_pre_not))]
pub struct Not<'ast> {
#[pest_ast(outer())]
pub span: Span<'ast>,
}
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::operation_post_increment))]
pub struct Increment<'ast> {
#[pest_ast(outer())]
pub span: Span<'ast>,
}
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::operation_post_decrement))]
pub struct Decrement<'ast> {
#[pest_ast(outer())]
pub span: Span<'ast>,
}
// Binary Operations
#[derive(Debug, PartialEq, Clone)]
pub enum BinaryOperator {
Or,
And,
Eq,
Neq,
Geq,
Gt,
Leq,
Lt,
Add,
Sub,
Mul,
Div,
Pow,
}
// Values
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::value_boolean))]
pub struct Boolean<'ast> {
#[pest_ast(outer(with(span_into_string)))]
pub value: String,
#[pest_ast(outer())]
pub span: Span<'ast>,
}
impl<'ast> fmt::Display for Boolean<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.value)
}
}
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::value_field))]
pub struct Field<'ast> {
#[pest_ast(outer(with(span_into_string)))]
pub value: String,
#[pest_ast(outer())]
pub span: Span<'ast>,
}
impl<'ast> fmt::Display for Field<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.value)
}
}
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::value))]
pub enum Value<'ast> {
Boolean(Boolean<'ast>),
Field(Field<'ast>),
}
impl<'ast> Value<'ast> {
pub fn span(&self) -> &Span<'ast> {
match self {
Value::Boolean(value) => &value.span,
Value::Field(value) => &value.span,
}
}
}
impl<'ast> fmt::Display for Value<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Value::Boolean(ref value) => write!(f, "{}", value),
Value::Field(ref value) => write!(f, "{}", value),
}
}
}
// Variables
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::variable))]
pub struct Variable<'ast> {
#[pest_ast(outer(with(span_into_string)))]
pub value: String,
#[pest_ast(outer())]
pub span: Span<'ast>,
}
impl<'ast> fmt::Display for Variable<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.value)
}
}
// Expressions
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::expression_not))]
pub struct NotExpression<'ast> {
pub operation: Not<'ast>,
pub expression: Box<Expression<'ast>>,
#[pest_ast(outer())]
pub span: Span<'ast>,
}
// #[derive(Clone, Debug, FromPest, PartialEq)]
// #[pest_ast(rule(Rule::expression_increment))]
// pub struct IncrementExpression<'ast> {
// pub expression: Box<Expression<'ast>>,
// pub operation: Increment<'ast>,
// #[pest_ast(outer())]
// pub span: Span<'ast>,
// }
//
// #[derive(Clone, Debug, FromPest, PartialEq)]
// #[pest_ast(rule(Rule::expression_decrement))]
// pub struct DecrementExpression<'ast> {
// pub expression: Box<Expression<'ast>>,
// pub operation: Decrement<'ast>,
// #[pest_ast(outer())]
// pub span: Span<'ast>,
// }
#[derive(Clone, Debug, PartialEq)]
pub struct BinaryExpression<'ast> {
pub operation: BinaryOperator,
pub left: Box<Expression<'ast>>,
pub right: Box<Expression<'ast>>,
pub span: Span<'ast>,
}
// #[derive(Clong, Debug, PartialEq)]
// pub struct IdentifierExpression<'ast> {
// pub value: String,
// pub span: Span<'ast>,
// }
#[derive(Clone, Debug, PartialEq)]
pub enum Expression<'ast> {
Value(Value<'ast>),
Variable(Variable<'ast>),
Not(NotExpression<'ast>),
Binary(BinaryExpression<'ast>),
// Increment(IncrementExpression<'ast>),
// Decrement(DecrementExpression<'ast>),
}
impl<'ast> Expression<'ast> {
pub fn binary(
operation: BinaryOperator,
left: Box<Expression<'ast>>,
right: Box<Expression<'ast>>,
span: Span<'ast>,
) -> Self {
Expression::Binary(BinaryExpression {
operation,
left,
right,
span,
})
}
pub fn span(&self) -> &Span<'ast> {
match self {
Expression::Value(expression) => &expression.span(),
Expression::Variable(expression) => &expression.span,
Expression::Not(expression) => &expression.span,
Expression::Binary(expression) => &expression.span,
// Expression::Increment(expression) => &expression.span,
// Expression::Decrement(expression) => &expression.span,
}
}
}
impl<'ast> fmt::Display for Expression<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Expression::Value(ref expression) => write!(f, "{}", expression),
Expression::Variable(ref expression) => write!(f, "{}", expression),
Expression::Not(ref expression) => write!(f, "{}", expression.expression),
Expression::Binary(ref expression) => {
write!(f, "{} == {}", expression.left, expression.right)
}
}
}
}
impl<'ast> FromPest<'ast> for Expression<'ast> {
type Rule = Rule;
type FatalError = Void;
fn from_pest(pest: &mut Pairs<'ast, Rule>) -> Result<Self, ConversionError<Void>> {
let mut clone = pest.clone();
let pair = clone.next().ok_or(::from_pest::ConversionError::NoMatch)?;
match pair.as_rule() {
Rule::expression => {
// Transfer iterated state to pest.
*pest = clone;
Ok(*PRECEDENCE_CLIMBER.climb(pair.into_inner(), parse_term, binary_expression))
}
_ => Err(ConversionError::NoMatch),
}
}
}
// Statements
#[derive(Debug, FromPest, PartialEq, Clone)]
#[pest_ast(rule(Rule::statement_assign))]
pub struct AssignStatement<'ast> {
pub variable: Variable<'ast>,
pub expression: Expression<'ast>,
#[pest_ast(outer())]
pub span: Span<'ast>,
}
impl<'ast> fmt::Display for AssignStatement<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.expression)
}
}
#[derive(Debug, FromPest, PartialEq, Clone)]
#[pest_ast(rule(Rule::statement_return))]
pub struct ReturnStatement<'ast> {
pub expressions: Vec<Expression<'ast>>,
#[pest_ast(outer())]
pub span: Span<'ast>,
}
impl<'ast> fmt::Display for ReturnStatement<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for (i, expression) in self.expressions.iter().enumerate() {
write!(f, "{}", expression)?;
if i < self.expressions.len() - 1 {
write!(f, ", ")?;
}
}
write!(f, "")
}
}
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::statement))]
pub enum Statement<'ast> {
Assign(AssignStatement<'ast>),
Return(ReturnStatement<'ast>),
}
impl<'ast> fmt::Display for Statement<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Statement::Assign(ref statement) => write!(f, "{}", statement),
Statement::Return(ref statement) => write!(f, "{}", statement),
}
}
}
// Utilities
#[derive(Debug, FromPest, PartialEq, Clone)]
#[pest_ast(rule(Rule::EOI))]
pub struct EOI;

14
src/lib.rs Normal file
View File

@ -0,0 +1,14 @@
extern crate pest;
#[macro_use]
extern crate pest_derive;
extern crate from_pest;
#[macro_use]
extern crate pest_ast;
#[macro_use]
extern crate lazy_static;
pub mod ast;
pub mod program;

View File

@ -1,406 +1,56 @@
extern crate pest;
#[macro_use]
extern crate pest_derive;
use language::*;
extern crate from_pest;
#[macro_use]
extern crate pest_ast;
#[macro_use]
extern crate lazy_static;
use pest::Parser;
use from_pest::FromPest;
use std::fs;
#[derive(Parser)]
#[grammar = "language.pest"]
pub struct LanguageParser;
mod ast {
use from_pest::ConversionError;
use from_pest::FromPest;
use from_pest::Void;
use pest::iterators::{Pair, Pairs};
use pest::prec_climber::{Assoc, Operator, PrecClimber};
use pest::Span;
use pest_ast::FromPest;
use super::Rule;
fn span_into_string(span: Span) -> String {
span.as_str().to_string()
}
lazy_static! {
static ref PRECEDENCE_CLIMBER: PrecClimber<Rule> = precedence_climber();
}
fn precedence_climber() -> PrecClimber<Rule> {
PrecClimber::new(vec![
Operator::new(Rule::operation_or, Assoc::Left),
Operator::new(Rule::operation_and, Assoc::Left),
Operator::new(Rule::operation_eq, Assoc::Left)
| Operator::new(Rule::operation_neq, Assoc::Left),
Operator::new(Rule::operation_geq, Assoc::Left)
| Operator::new(Rule::operation_gt, Assoc::Left)
| Operator::new(Rule::operation_leq, Assoc::Left)
| Operator::new(Rule::operation_lt, Assoc::Left),
Operator::new(Rule::operation_add, Assoc::Left)
| Operator::new(Rule::operation_sub, Assoc::Left),
Operator::new(Rule::operation_mul, Assoc::Left)
| Operator::new(Rule::operation_div, Assoc::Left),
Operator::new(Rule::operation_pow, Assoc::Left),
])
}
fn parse_term(pair: Pair<Rule>) -> Box<Expression> {
Box::new(match pair.as_rule() {
Rule::expression_term => {
let clone = pair.clone();
let next = clone.into_inner().next().unwrap();
match next.as_rule() {
Rule::expression_primitive => {
let next = next.into_inner().next().unwrap();
match next.as_rule() {
Rule::value => Expression::Value(
Value::from_pest(&mut pair.into_inner().next().unwrap().into_inner()).unwrap()
),
Rule::variable => Expression::Variable(
Variable::from_pest(&mut pair.into_inner().next().unwrap().into_inner()).unwrap(),
),
rule => unreachable!("`expression_primitive` should contain one of [`value`, `variable`], found {:#?}", rule)
}
}
Rule::expression_not => {
let span = next.as_span();
let mut inner = next.into_inner();
let operation = match inner.next().unwrap().as_rule() {
Rule::operation_pre_not => Not::from_pest(&mut pair.into_inner().next().unwrap().into_inner()).unwrap(),
rule => unreachable!("`expression_not` should yield `operation_pre_not`, found {:#?}", rule)
};
let expression = parse_term(inner.next().unwrap());
Expression::Not(NotExpression { operation, expression, span })
},
Rule::expression => Expression::from_pest(&mut pair.into_inner()).unwrap(), // Parenthesis case
// Rule::expression_increment => {
// let span = next.as_span();
// let mut inner = next.into_inner();
// let expression = parse_expression_term(inner.next().unwrap());
// let operation = match inner.next().unwrap().as_rule() {
// Rule::operation_post_increment => Increment::from_pest(&mut pair.into_inner().next().unwrap().into_inner()).unwrap(),
// rule => unreachable!("`expression_increment` should yield `operation_post_increment`, found {:#?}", rule)
// };
// Expression::Increment(IncrementExpression { operation, expression, span })
// },
// Rule::expression_decrement => {
// let span = next.as_span();
// let mut inner = next.into_inner();
// let expression = parse_expression_term(inner.next().unwrap());
// let operation = match inner.next().unwrap().as_rule() {
// Rule::operation_post_decrement => Decrement::from_pest(&mut pair.into_inner().next().unwrap().into_inner()).unwrap(),
// rule => unreachable!("`expression_decrement` should yield `operation_post_decrement`, found {:#?}", rule)
// };
// Expression::Decrement(DecrementExpression { operation, expression, span })
// },
rule => unreachable!("`term` should contain one of ['value', 'variable', 'expression', 'expression_not', 'expression_increment', 'expression_decrement'], found {:#?}", rule)
}
}
rule => unreachable!("`parse_expression_term` should be invoked on `Rule::expression_term`, found {:#?}", rule),
})
}
fn binary_expression<'ast>(
lhs: Box<Expression<'ast>>,
pair: Pair<'ast, Rule>,
rhs: Box<Expression<'ast>>,
) -> Box<Expression<'ast>> {
let (start, _) = lhs.span().clone().split();
let (_, end) = rhs.span().clone().split();
let span = start.span(&end);
Box::new(match pair.as_rule() {
Rule::operation_or => Expression::binary(BinaryOperator::Or, lhs, rhs, span),
Rule::operation_and => Expression::binary(BinaryOperator::And, lhs, rhs, span),
Rule::operation_eq => Expression::binary(BinaryOperator::Eq, lhs, rhs, span),
Rule::operation_neq => Expression::binary(BinaryOperator::Neq, lhs, rhs, span),
Rule::operation_geq => Expression::binary(BinaryOperator::Geq, lhs, rhs, span),
Rule::operation_gt => Expression::binary(BinaryOperator::Gt, lhs, rhs, span),
Rule::operation_leq => Expression::binary(BinaryOperator::Leq, lhs, rhs, span),
Rule::operation_lt => Expression::binary(BinaryOperator::Lt, lhs, rhs, span),
Rule::operation_add => Expression::binary(BinaryOperator::Add, lhs, rhs, span),
Rule::operation_sub => Expression::binary(BinaryOperator::Sub, lhs, rhs, span),
Rule::operation_mul => Expression::binary(BinaryOperator::Mul, lhs, rhs, span),
Rule::operation_div => Expression::binary(BinaryOperator::Div, lhs, rhs, span),
Rule::operation_pow => Expression::binary(BinaryOperator::Pow, lhs, rhs, span),
_ => unreachable!(),
})
}
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::file))]
pub struct File<'ast> {
pub statement: Vec<Statement<'ast>>,
pub eoi: EOI,
#[pest_ast(outer())]
pub span: Span<'ast>,
}
// Visibility
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::visibility_public))]
pub struct Public {}
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::visibility_private))]
pub struct Private {}
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::visibility))]
pub enum Visibility {
Public(Public),
Private(Private),
}
// Unary Operations
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::operation_pre_not))]
pub struct Not<'ast> {
#[pest_ast(outer())]
pub span: Span<'ast>,
}
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::operation_post_increment))]
pub struct Increment<'ast> {
#[pest_ast(outer())]
pub span: Span<'ast>,
}
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::operation_post_decrement))]
pub struct Decrement<'ast> {
#[pest_ast(outer())]
pub span: Span<'ast>,
}
// Binary Operations
#[derive(Debug, PartialEq, Clone)]
pub enum BinaryOperator {
Or,
And,
Eq,
Neq,
Geq,
Gt,
Leq,
Lt,
Add,
Sub,
Mul,
Div,
Pow,
}
// Values
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::value_boolean))]
pub struct Boolean<'ast> {
#[pest_ast(outer(with(span_into_string)))]
pub value: String,
#[pest_ast(outer())]
pub span: Span<'ast>,
}
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::value_field))]
pub struct Field<'ast> {
#[pest_ast(outer(with(span_into_string)))]
pub value: String,
#[pest_ast(outer())]
pub span: Span<'ast>,
}
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::value))]
pub enum Value<'ast> {
Boolean(Boolean<'ast>),
Field(Field<'ast>),
}
impl<'ast> Value<'ast> {
pub fn span(&self) -> &Span<'ast> {
match self {
Value::Boolean(value) => &value.span,
Value::Field(value) => &value.span,
}
}
}
// Variables
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::variable))]
pub struct Variable<'ast> {
#[pest_ast(outer(with(span_into_string)))]
pub value: String,
#[pest_ast(outer())]
pub span: Span<'ast>,
}
// Expressions
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::expression_not))]
pub struct NotExpression<'ast> {
pub operation: Not<'ast>,
pub expression: Box<Expression<'ast>>,
#[pest_ast(outer())]
pub span: Span<'ast>,
}
// #[derive(Clone, Debug, FromPest, PartialEq)]
// #[pest_ast(rule(Rule::expression_increment))]
// pub struct IncrementExpression<'ast> {
// pub expression: Box<Expression<'ast>>,
// pub operation: Increment<'ast>,
// #[pest_ast(outer())]
// pub span: Span<'ast>,
// }
//
// #[derive(Clone, Debug, FromPest, PartialEq)]
// #[pest_ast(rule(Rule::expression_decrement))]
// pub struct DecrementExpression<'ast> {
// pub expression: Box<Expression<'ast>>,
// pub operation: Decrement<'ast>,
// #[pest_ast(outer())]
// pub span: Span<'ast>,
// }
#[derive(Clone, Debug, PartialEq)]
pub struct BinaryExpression<'ast> {
pub operation: BinaryOperator,
pub left: Box<Expression<'ast>>,
pub right: Box<Expression<'ast>>,
pub span: Span<'ast>,
}
#[derive(Clone, Debug, PartialEq)]
pub enum Expression<'ast> {
Value(Value<'ast>),
Variable(Variable<'ast>),
Not(NotExpression<'ast>),
Binary(BinaryExpression<'ast>),
// Increment(IncrementExpression<'ast>),
// Decrement(DecrementExpression<'ast>),
}
impl<'ast> Expression<'ast> {
pub fn binary(
operation: BinaryOperator,
left: Box<Expression<'ast>>,
right: Box<Expression<'ast>>,
span: Span<'ast>,
) -> Self {
Expression::Binary(BinaryExpression { operation, left, right, span })
}
pub fn span(&self) -> &Span<'ast> {
match self {
Expression::Value(expression) => &expression.span(),
Expression::Variable(expression) => &expression.span,
Expression::Not(expression) => &expression.span,
Expression::Binary(expression) => &expression.span,
// Expression::Increment(expression) => &expression.span,
// Expression::Decrement(expression) => &expression.span,
}
}
}
impl<'ast> FromPest<'ast> for Expression<'ast> {
type Rule = Rule;
type FatalError = Void;
fn from_pest(pest: &mut Pairs<'ast, Rule>) -> Result<Self, ConversionError<Void>> {
let mut clone = pest.clone();
let pair = clone.next().ok_or(::from_pest::ConversionError::NoMatch)?;
match pair.as_rule() {
Rule::expression => {
// Transfer iterated state to pest.
*pest = clone;
Ok(*PRECEDENCE_CLIMBER.climb(pair.into_inner(), parse_term, binary_expression))
}
_ => Err(ConversionError::NoMatch),
}
}
}
// Statements
#[derive(Debug, FromPest, PartialEq, Clone)]
#[pest_ast(rule(Rule::statement_assign))]
pub struct AssignStatement<'ast> {
pub variable: Variable<'ast>,
pub expression: Expression<'ast>,
#[pest_ast(outer())]
pub span: Span<'ast>,
}
#[derive(Debug, FromPest, PartialEq, Clone)]
#[pest_ast(rule(Rule::statement_return))]
pub struct ReturnStatement<'ast> {
pub expressions: Vec<Expression<'ast>>,
#[pest_ast(outer())]
pub span: Span<'ast>,
}
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::statement))]
pub enum Statement<'ast> {
Assign(AssignStatement<'ast>),
Return(ReturnStatement<'ast>),
}
// Utilities
#[derive(Debug, FromPest, PartialEq, Clone)]
#[pest_ast(rule(Rule::EOI))]
pub struct EOI;
}
fn main() {
use crate::from_pest::FromPest;
use snarkos_gadgets::curves::edwards_bls12::FqGadget;
use snarkos_models::gadgets::{r1cs::{ConstraintSystem, TestConstraintSystem, Fr}, utilities::{alloc::AllocGadget, boolean::Boolean}};
// use snarkos_gadgets::curves::edwards_bls12::FqGadget;
// use snarkos_models::gadgets::{
// r1cs::{ConstraintSystem, TestConstraintSystem, Fr},
// utilities::{
// alloc::{AllocGadget},
// boolean::Boolean,
// uint32::UInt32,
// }
// };
// Read in file as string
let unparsed_file = fs::read_to_string("simple.program").expect("cannot read file");
let mut file = LanguageParser::parse(Rule::file, &unparsed_file).expect("unsuccessful parse");
// Parse the file using langauge.pest
let mut file = ast::parse(&unparsed_file).expect("unsuccessful parse");
// Build the abstract syntax tree
let syntax_tree = ast::File::from_pest(&mut file).expect("infallible");
for statement in syntax_tree.statement {
match statement {
ast::Statement::Assign(statement) => {
println!("{:#?}", statement);
},
ast::Statement::Return(statement) => {
let program = program::Program::from(syntax_tree);
}
}
}
println!("{:?}", program);
let mut cs = TestConstraintSystem::<Fr>::new();
// // Use this code when proving
// let left_u32 = left_string.parse::<u32>().unwrap();
// let right_u32 = right_string.parse::<u32>().unwrap();
//
// println!("left u32 value: {:#?}", left_u32);
// println!("right u32 value: {:#?}", right_u32);
//
// let left_constraint = UInt32::alloc(cs.ns(|| "left variable"), Some(left_u32)).unwrap();
// let right_constraint = UInt32::constant(right_u32);
//
// let bool = Boolean::alloc(cs.ns(|| format!("boolean")), || Ok(true)).unwrap();
//
// left_constraint.conditional_enforce_equal(cs.ns(|| format!("enforce left == right")), &right_constraint, &bool).unwrap();
Boolean::alloc(cs.ns(|| format!("boolean")), || Ok(true));
// // Constraint testing
// let bool = Boolean::alloc(cs.ns(|| format!("boolean")), || Ok(true)).unwrap();
// let a_bit = UInt32::alloc(cs.ns(|| "a_bit"), Some(4u32)).unwrap();
// let b_bit = UInt32::constant(5u32);
//
// a_bit.conditional_enforce_equal(cs.ns(|| format!("enforce equal")), &b_bit, &bool).unwrap();
// println!("satisfied: {:?}", cs.is_satisfied());
println!("\n\n number of constraints for input: {}", cs.num_constraints());
// println!("\n\n number of constraints for input: {}", cs.num_constraints());
// for token in file.into_inner() {
// match token.as_rule() {
@ -411,7 +61,6 @@ fn main() {
// // println!("{:?}", token);
// }
// let mut field_sum: f64 = 0.0;
// let mut record_count: u64 = 0;
//

11
src/program/mod.rs Normal file
View File

@ -0,0 +1,11 @@
pub mod program;
pub use self::program::*;
pub mod types;
pub use self::types::*;
pub mod types_display;
pub use self::types_display::*;
pub mod types_from;
pub use self::types_from::*;

90
src/program/program.rs Normal file
View File

@ -0,0 +1,90 @@
use crate::program::{Expression, ExpressionList, Statement, StatementNode, Variable};
use pest::Span;
use std::fmt;
use std::fmt::Formatter;
// AST -> Program
/// Position in input file
#[derive(Clone, Copy)]
pub struct Position {
pub line: usize,
pub column: usize,
}
impl fmt::Display for Position {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}:{}", self.line, self.column)
}
}
impl fmt::Debug for Position {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "{}:{}", self.line, self.column)
}
}
/// Building blocks for a program
#[derive(Debug, Clone)]
pub struct Node<T: fmt::Display> {
start: Position,
end: Position,
value: T,
}
impl<T: fmt::Display> Node<T> {
pub fn new(start: Position, end: Position, value: T) -> Node<T> {
Self { start, end, value }
}
}
impl<T: fmt::Display> fmt::Display for Node<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.value)
}
}
impl<T: NodeValue> std::cmp::PartialEq for Node<T> {
fn eq(&self, other: &Node<T>) -> bool {
self.value.eq(&other.value)
}
}
pub trait NodeValue: fmt::Display + Sized + PartialEq {
fn span(self, span: Span) -> Node<Self> {
let start = span.start_pos().line_col();
let end = span.end_pos().line_col();
let start = Position {
line: start.0,
column: start.1,
};
let end = Position {
line: end.0,
column: end.1,
};
Node::new(start, end, self)
}
}
impl<V: NodeValue> From<V> for Node<V> {
fn from(v: V) -> Self {
let mock_position = Position { line: 1, column: 1 };
Self::new(mock_position, mock_position, v)
}
}
impl<'ast> NodeValue for Expression<'ast> {}
impl<'ast> NodeValue for ExpressionList<'ast> {}
impl<'ast> NodeValue for Statement<'ast> {}
impl<'ast> NodeValue for Variable<'ast> {}
/// A collection of nodes created from an abstract syntax tree.
#[derive(Debug)]
pub struct Program<'ast> {
pub nodes: Vec<StatementNode<'ast>>,
}

57
src/program/types.rs Normal file
View File

@ -0,0 +1,57 @@
use crate::program::Node;
// Program Nodes - Wrappers for different types in a program.
pub type ExpressionNode<'ast> = Node<Expression<'ast>>;
pub type ExpressionListNode<'ast> = Node<ExpressionList<'ast>>;
pub type StatementNode<'ast> = Node<Statement<'ast>>;
pub type VariableNode<'ast> = Node<Variable<'ast>>;
/// Identifier string
pub type Identifier<'ast> = &'ast str;
/// Program variable
#[derive(Debug, Clone, PartialEq)]
pub struct Variable<'ast> {
pub id: Identifier<'ast>,
}
/// Program expression that evaluates to a value
#[derive(Debug, Clone, PartialEq)]
pub enum Expression<'ast> {
// Expression identifier
Identifier(Identifier<'ast>),
// Values
Boolean(bool),
Field(Identifier<'ast>),
// Variable
Variable(VariableNode<'ast>),
// Not expression
Not(Box<ExpressionNode<'ast>>),
// Binary expression
Or(Box<ExpressionNode<'ast>>, Box<ExpressionNode<'ast>>),
And(Box<ExpressionNode<'ast>>, Box<ExpressionNode<'ast>>),
Eq(Box<ExpressionNode<'ast>>, Box<ExpressionNode<'ast>>),
Neq(Box<ExpressionNode<'ast>>, Box<ExpressionNode<'ast>>),
Geq(Box<ExpressionNode<'ast>>, Box<ExpressionNode<'ast>>),
Gt(Box<ExpressionNode<'ast>>, Box<ExpressionNode<'ast>>),
Leq(Box<ExpressionNode<'ast>>, Box<ExpressionNode<'ast>>),
Lt(Box<ExpressionNode<'ast>>, Box<ExpressionNode<'ast>>),
Add(Box<ExpressionNode<'ast>>, Box<ExpressionNode<'ast>>),
Sub(Box<ExpressionNode<'ast>>, Box<ExpressionNode<'ast>>),
Mul(Box<ExpressionNode<'ast>>, Box<ExpressionNode<'ast>>),
Div(Box<ExpressionNode<'ast>>, Box<ExpressionNode<'ast>>),
Pow(Box<ExpressionNode<'ast>>, Box<ExpressionNode<'ast>>),
}
#[derive(Debug, Clone, PartialEq)]
pub struct ExpressionList<'ast> {
pub expressions: Vec<ExpressionNode<'ast>>,
}
/// Program statement that defines some action (or expression) to be carried out
#[derive(Debug, PartialEq, Clone)]
pub enum Statement<'ast> {
Declaration(VariableNode<'ast>),
Definition(VariableNode<'ast>, ExpressionNode<'ast>),
Return(ExpressionListNode<'ast>),
}

View File

@ -0,0 +1,58 @@
use crate::program::{Expression, ExpressionList, Statement, Variable};
use std::fmt;
impl<'ast> fmt::Display for Variable<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.id)
}
}
impl<'ast> fmt::Display for Expression<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Expression::Identifier(ref s) => write!(f, "Identifier({:?})", s),
Expression::Boolean(ref b) => write!(f, "Boolean({:?})", b),
Expression::Field(ref s) => write!(f, "Field({:?})", s),
Expression::Variable(ref v) => write!(f, "{}", v),
Expression::Not(ref e) => write!(f, "{}", e),
Expression::Or(ref lhs, ref rhs) => write!(f, "{} || {}", lhs, rhs),
Expression::And(ref lhs, ref rhs) => write!(f, "{} && {}", lhs, rhs),
Expression::Eq(ref lhs, ref rhs) => write!(f, "{} == {}", lhs, rhs),
Expression::Neq(ref lhs, ref rhs) => write!(f, "{} != {}", lhs, rhs),
Expression::Geq(ref lhs, ref rhs) => write!(f, "{} >= {}", lhs, rhs),
Expression::Gt(ref lhs, ref rhs) => write!(f, "{} > {}", lhs, rhs),
Expression::Leq(ref lhs, ref rhs) => write!(f, "{} <= {}", lhs, rhs),
Expression::Lt(ref lhs, ref rhs) => write!(f, "{} < {}", lhs, rhs),
Expression::Add(ref lhs, ref rhs) => write!(f, "{} + {}", lhs, rhs),
Expression::Sub(ref lhs, ref rhs) => write!(f, "{} - {}", lhs, rhs),
Expression::Mul(ref lhs, ref rhs) => write!(f, "{} * {}", lhs, rhs),
Expression::Div(ref lhs, ref rhs) => write!(f, "{} / {}", lhs, rhs),
Expression::Pow(ref lhs, ref rhs) => write!(f, "{} ** {}", lhs, rhs),
}
}
}
impl<'ast> fmt::Display for ExpressionList<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for (i, expression) in self.expressions.iter().enumerate() {
write!(f, "{}", expression)?;
if i < self.expressions.len() - 1 {
write!(f, ", ")?;
}
}
write!(f, "")
}
}
impl<'ast> fmt::Display for Statement<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Statement::Return(ref expressions) => write!(f, "return {}", expressions),
Statement::Declaration(ref variable) => write!(f, "{}", variable),
Statement::Definition(ref variable, ref expression) => {
write!(f, "{} = {}", variable, expression)
}
}
}
}

178
src/program/types_from.rs Normal file
View File

@ -0,0 +1,178 @@
use crate::{
ast,
program::{program, types, NodeValue},
};
impl<'ast> From<ast::Boolean<'ast>> for types::ExpressionNode<'ast> {
fn from(boolean: ast::Boolean<'ast>) -> Self {
types::Expression::Boolean(
boolean
.value
.parse::<bool>()
.expect("unable to parse boolean"),
)
.span(boolean.span)
}
}
impl<'ast> From<ast::Field<'ast>> for types::ExpressionNode<'ast> {
fn from(field: ast::Field<'ast>) -> Self {
types::Expression::Field(field.span.as_str()).span(field.span)
}
}
impl<'ast> From<ast::Value<'ast>> for types::ExpressionNode<'ast> {
fn from(value: ast::Value<'ast>) -> Self {
match value {
ast::Value::Boolean(boolean) => types::ExpressionNode::from(boolean),
ast::Value::Field(field) => types::ExpressionNode::from(field),
}
}
}
impl<'ast> From<ast::Variable<'ast>> for types::VariableNode<'ast> {
fn from(variable: ast::Variable<'ast>) -> Self {
types::Variable {
id: variable.span.as_str(),
}
.span(variable.span)
}
}
impl<'ast> From<ast::Variable<'ast>> for types::ExpressionNode<'ast> {
fn from(variable: ast::Variable<'ast>) -> Self {
types::Expression::Variable(types::VariableNode::from(variable.clone())).span(variable.span)
}
}
impl<'ast> From<ast::NotExpression<'ast>> for types::ExpressionNode<'ast> {
fn from(expression: ast::NotExpression<'ast>) -> Self {
types::Expression::Not(Box::new(types::ExpressionNode::from(
*expression.expression,
)))
.span(expression.span)
}
}
impl<'ast> From<ast::BinaryExpression<'ast>> for types::ExpressionNode<'ast> {
fn from(expression: ast::BinaryExpression<'ast>) -> Self {
match expression.operation {
ast::BinaryOperator::Or => types::Expression::Or(
Box::new(types::ExpressionNode::from(*expression.left)),
Box::new(types::ExpressionNode::from(*expression.right)),
),
ast::BinaryOperator::And => types::Expression::And(
Box::new(types::ExpressionNode::from(*expression.left)),
Box::new(types::ExpressionNode::from(*expression.right)),
),
ast::BinaryOperator::Eq => types::Expression::Eq(
Box::new(types::ExpressionNode::from(*expression.left)),
Box::new(types::ExpressionNode::from(*expression.right)),
),
ast::BinaryOperator::Neq => types::Expression::Neq(
Box::new(types::ExpressionNode::from(*expression.left)),
Box::new(types::ExpressionNode::from(*expression.right)),
),
ast::BinaryOperator::Geq => types::Expression::Geq(
Box::new(types::ExpressionNode::from(*expression.left)),
Box::new(types::ExpressionNode::from(*expression.right)),
),
ast::BinaryOperator::Gt => types::Expression::Gt(
Box::new(types::ExpressionNode::from(*expression.left)),
Box::new(types::ExpressionNode::from(*expression.right)),
),
ast::BinaryOperator::Leq => types::Expression::Leq(
Box::new(types::ExpressionNode::from(*expression.left)),
Box::new(types::ExpressionNode::from(*expression.right)),
),
ast::BinaryOperator::Lt => types::Expression::Lt(
Box::new(types::ExpressionNode::from(*expression.left)),
Box::new(types::ExpressionNode::from(*expression.right)),
),
ast::BinaryOperator::Add => types::Expression::Add(
Box::new(types::ExpressionNode::from(*expression.left)),
Box::new(types::ExpressionNode::from(*expression.right)),
),
ast::BinaryOperator::Sub => types::Expression::Sub(
Box::new(types::ExpressionNode::from(*expression.left)),
Box::new(types::ExpressionNode::from(*expression.right)),
),
ast::BinaryOperator::Mul => types::Expression::Mul(
Box::new(types::ExpressionNode::from(*expression.left)),
Box::new(types::ExpressionNode::from(*expression.right)),
),
ast::BinaryOperator::Div => types::Expression::Div(
Box::new(types::ExpressionNode::from(*expression.left)),
Box::new(types::ExpressionNode::from(*expression.right)),
),
ast::BinaryOperator::Pow => types::Expression::Pow(
Box::new(types::ExpressionNode::from(*expression.left)),
Box::new(types::ExpressionNode::from(*expression.right)),
),
}
.span(expression.span)
}
}
impl<'ast> From<ast::Expression<'ast>> for types::ExpressionNode<'ast> {
fn from(expression: ast::Expression<'ast>) -> Self {
match expression {
ast::Expression::Value(expression) => types::ExpressionNode::from(expression),
ast::Expression::Variable(expression) => types::ExpressionNode::from(expression),
ast::Expression::Not(expression) => types::ExpressionNode::from(expression),
ast::Expression::Binary(expression) => types::ExpressionNode::from(expression),
}
}
}
impl<'ast> From<ast::AssignStatement<'ast>> for types::StatementNode<'ast> {
fn from(statement: ast::AssignStatement<'ast>) -> Self {
types::Statement::Definition(
types::VariableNode::from(statement.variable),
types::ExpressionNode::from(statement.expression),
)
.span(statement.span)
}
}
impl<'ast> From<ast::ReturnStatement<'ast>> for types::StatementNode<'ast> {
fn from(statement: ast::ReturnStatement<'ast>) -> Self {
types::Statement::Return(
types::ExpressionList {
expressions: statement
.expressions
.into_iter()
.map(|expression| types::ExpressionNode::from(expression))
.collect(),
}
.span(statement.span.clone()),
)
.span(statement.span)
}
}
impl<'ast> From<ast::Statement<'ast>> for types::StatementNode<'ast> {
fn from(statement: ast::Statement<'ast>) -> Self {
match statement {
ast::Statement::Assign(statement) => types::StatementNode::from(statement),
ast::Statement::Return(statement) => types::StatementNode::from(statement),
}
}
}
impl<'ast> From<ast::File<'ast>> for program::Program<'ast> {
fn from(file: ast::File<'ast>) -> Self {
program::Program {
nodes: file
.statement
.iter()
.map(|statement| types::StatementNode::from(statement.clone()))
.collect(),
}
// for statement in file.statement {
// // println!("statement {:?}", statement);
// let node = program::StatementNode::from(statement);
// println!("node {:?}", node);
// }
}
}