From 078db23fa6c5a5fb5811306dc0fd3704a71a411a Mon Sep 17 00:00:00 2001 From: howardwu Date: Wed, 11 Mar 2020 14:56:54 -0700 Subject: [PATCH] AST WIP --- Cargo.lock | 193 ++++++++++++++++++++++- Cargo.toml | 3 + src/language.pest | 114 +++++++------- src/main.rs | 383 ++++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 619 insertions(+), 74 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 547f243c72..6de251f875 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,27 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +[[package]] +name = "backtrace" +version = "0.3.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad235dabf00f36301792cfe82499880ba54c6486be094d1047b02bacb67c14e8" +dependencies = [ + "backtrace-sys", + "cfg-if", + "libc", + "rustc-demangle", +] + +[[package]] +name = "backtrace-sys" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca797db0057bae1a7aa2eef3283a874695455cecf08a43bfb8507ee0ebc1ed69" +dependencies = [ + "cc", + "libc", +] + [[package]] name = "block-buffer" version = "0.7.3" @@ -33,6 +55,18 @@ version = "1.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" +[[package]] +name = "cc" +version = "1.0.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95e28fa049fda1c330bcf9d723be7663a899c4679724b34c81e9f5a326aab8cd" + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + [[package]] name = "digest" version = "0.8.1" @@ -42,12 +76,50 @@ dependencies = [ "generic-array", ] +[[package]] +name = "either" +version = "1.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3" + +[[package]] +name = "failure" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8529c2421efa3066a5cbd8063d2244603824daccb6936b079010bb2aa89464b" +dependencies = [ + "backtrace", + "failure_derive", +] + +[[package]] +name = "failure_derive" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "030a733c8287d6213886dd487564ff5c8f6aae10278b3588ed177f9d18f8d231" +dependencies = [ + "proc-macro2 1.0.9", + "quote 1.0.3", + "syn 1.0.16", + "synstructure", +] + [[package]] name = "fake-simd" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" +[[package]] +name = "from-pest" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aba9389cedcba1fb3a2aa2ed00f584f2606bce8e0106614a17327a24513bc60f" +dependencies = [ + "pest", + "void", +] + [[package]] name = "generic-array" version = "0.12.3" @@ -57,14 +129,38 @@ dependencies = [ "typenum", ] +[[package]] +name = "itertools" +version = "0.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d47946d458e94a1b7bcabbf6521ea7c037062c81f534615abcad76e84d4970d" +dependencies = [ + "either", +] + [[package]] name = "language" version = "0.1.0" dependencies = [ + "from-pest", + "lazy_static", "pest", + "pest-ast", "pest_derive", ] +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb147597cdf94ed43ab7a9038716637d2d1bf2bc571da995d0028dec06bd3018" + [[package]] name = "maplit" version = "1.0.2" @@ -86,6 +182,19 @@ dependencies = [ "ucd-trie", ] +[[package]] +name = "pest-ast" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fbf404899169771dd6a32c84248b83cd67a26cc7cc957aac87661490e1227e4" +dependencies = [ + "itertools", + "proc-macro2 0.4.30", + "quote 0.6.13", + "single", + "syn 0.15.44", +] + [[package]] name = "pest_derive" version = "2.1.0" @@ -104,9 +213,9 @@ checksum = "27e5277315f6b4f27e0e6744feb5d5ba1891e7164871033d3c8344c6783b349a" dependencies = [ "pest", "pest_meta", - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.9", + "quote 1.0.3", + "syn 1.0.16", ] [[package]] @@ -120,13 +229,31 @@ dependencies = [ "sha-1", ] +[[package]] +name = "proc-macro2" +version = "0.4.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" +dependencies = [ + "unicode-xid 0.1.0", +] + [[package]] name = "proc-macro2" version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c09721c6781493a2a492a96b5a5bf19b65917fe6728884e7c44dd0c60ca3435" dependencies = [ - "unicode-xid", + "unicode-xid 0.2.0", +] + +[[package]] +name = "quote" +version = "0.6.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" +dependencies = [ + "proc-macro2 0.4.30", ] [[package]] @@ -135,9 +262,15 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2bdc6c187c65bca4260c9011c9e3132efe4909da44726bad24cf7572ae338d7f" dependencies = [ - "proc-macro2", + "proc-macro2 1.0.9", ] +[[package]] +name = "rustc-demangle" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" + [[package]] name = "sha-1" version = "0.8.2" @@ -150,15 +283,47 @@ dependencies = [ "opaque-debug", ] +[[package]] +name = "single" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd5add732a1ab689845591a1b50339cf5310b563e08dc5813c65991f30369ea2" +dependencies = [ + "failure", +] + +[[package]] +name = "syn" +version = "0.15.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" +dependencies = [ + "proc-macro2 0.4.30", + "quote 0.6.13", + "unicode-xid 0.1.0", +] + [[package]] name = "syn" version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "123bd9499cfb380418d509322d7a6d52e5315f064fe4b3ad18a53d6b92c07859" dependencies = [ - "proc-macro2", - "quote", - "unicode-xid", + "proc-macro2 1.0.9", + "quote 1.0.3", + "unicode-xid 0.2.0", +] + +[[package]] +name = "synstructure" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67656ea1dc1b41b1451851562ea232ec2e5a80242139f7e679ceccfb5d61f545" +dependencies = [ + "proc-macro2 1.0.9", + "quote 1.0.3", + "syn 1.0.16", + "unicode-xid 0.2.0", ] [[package]] @@ -173,8 +338,20 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f00ed7be0c1ff1e24f46c3d2af4859f7e863672ba3a6e92e7cff702bf9f06c2" +[[package]] +name = "unicode-xid" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" + [[package]] name = "unicode-xid" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" + +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" diff --git a/Cargo.toml b/Cargo.toml index a537aa7cf8..91357f2780 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,5 +5,8 @@ authors = ["howardwu "] edition = "2018" [dependencies] +from-pest = "0.3.1" +lazy_static = "1.3.0" pest = "2.0" pest_derive = "2.0" +pest-ast = "0.3.3" diff --git a/src/language.pest b/src/language.pest index 82ec21e6d1..bf104c46a8 100644 --- a/src/language.pest +++ b/src/language.pest @@ -6,28 +6,57 @@ file = { SOI ~ NEWLINE* ~ statement* ~ NEWLINE* ~ EOI } COMMENT = _{ ("/*" ~ (!"*/" ~ ANY)* ~ "*/") | ("//" ~ (!NEWLINE ~ ANY)*) } WHITESPACE = _{ " " | "\t" ~ NEWLINE } - /// Visibility visibility_public = { "public" } visibility_private = { "private" } visibility = { visibility_public | visibility_private } -// /// Conditionals -// -// conditional_if = { "if" } -// conditional_else = { "else" } -// -// conditional_for = { "for" } -// -// conditional = { conditional_if | conditional_else | conditional_for } +/// Unary Operations + +operation_pre_not = { "!" } + +operation_post_increment = { "++" } +operation_post_decrement = { "--" } + +/// Binary Operations + +operation_and = { "&&" } +operation_or = { "||" } + +operation_eq = { "==" } +operation_neq = { "!=" } + +operation_geq = { ">=" } +operation_gt = { ">" } +operation_leq = { "<=" } +operation_lt = { "<" } + +operation_add = { "+" } +operation_sub = { "-" } +operation_mul = { "*" } +operation_div = { "/" } +operation_pow = { "**" } + +operation_binary = { + operation_and | operation_or | + operation_eq | operation_neq | + operation_geq | operation_gt | operation_leq | operation_lt | + operation_add | operation_sub | operation_mul | operation_div | operation_pow +} + +// operation_add_assign = { "+=" } +// operation_sub_assign = { "-=" } +// operation_mul_assign = { "*=" } +// operation_div_assign = { "/=" } /// Values value_boolean = { "true" | "false" } - value_field = @{ "-"? ~ ("0" | ASCII_NONZERO_DIGIT ~ ASCII_DIGIT*) } +// TODO: Boolean array, field array + value = { value_boolean | value_field } /// Variables @@ -41,60 +70,37 @@ protected_name = { visibility | value_boolean | "return" } variable = @{ ((!protected_name ~ ASCII_ALPHA) | (protected_name ~ (ASCII_ALPHANUMERIC | "_"))) ~ (ASCII_ALPHANUMERIC | "_")* } -/// Unary Operations - -operation_not = { "!" } - -operation_increment = { "++" } -operation_decrement = { "--" } - -operation_unary = { - operation_not | - operation_increment | operation_decrement -} - -/// Binary Operations - -operation_and = { "&&" } -operation_or = { "||" } - -operation_eq = { "==" } -operation_geq = { ">=" } -operation_leq = { "<=" } -operation_neq = { "!=" } - -operation_add = { "+" } -operation_sub = { "-" } -operation_mul = { "*" } -operation_div = { "/" } -operation_pow = { "**" } - -// operation_assign = { "=" } -// operation_add_assign = { "+=" } -// operation_sub_assign = { "-=" } -// operation_mul_assign = { "*=" } -// operation_div_assign = { "/=" } - -operation_binary = { - operation_and | operation_or | - operation_eq | operation_geq | operation_leq | operation_neq | - operation_add | operation_sub | operation_mul | operation_div | operation_pow -} - /// Expressions -expression_unary = { operation_unary ~ (value | variable) } -expression_binary = { (value | variable) ~ (operation_binary ~ (value | variable))* } +// Consider structs, conditionals, postfix, primary, inline array, array initializer, and unary +term = { value | variable | ("(" ~ expression ~ ")") } -expression = { expression_unary | expression_binary } +expression_not = { operation_pre_not ~ term } +expression_increment = { term ~ operation_post_increment } +expression_decrement = { term ~ operation_post_decrement } + +expression_binary = { term ~ (operation_binary ~ term)* } + +expression = { expression_not | expression_increment | expression_decrement | expression_binary } + +expression_tuple = _{ (expression ~ ("," ~ expression)*)? } /// Statements statement_assign = { variable ~ "=" ~ expression } -statement_return = { "return" ~ expression } +statement_return = { "return" ~ expression_tuple } statement = { statement_assign | statement_return } +// /// Conditionals +// +// conditional_if = { "if" } +// conditional_else = { "else" } +// +// conditional_for = { "for" } +// +// conditional = { conditional_if | conditional_else | conditional_for } + // /// Helpers // // helper_range = { expression+ ~ ".." ~ expression+ } // Confirm that '+' is the correct repetition diff --git a/src/main.rs b/src/main.rs index f346ab0f24..2b282c4180 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,6 +2,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; + + use pest::Parser; use std::fs; @@ -9,23 +17,374 @@ use std::fs; #[grammar = "language.pest"] pub struct LanguageParser; -// pub struct Statement +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 = precedence_climber(); + } + + fn precedence_climber() -> PrecClimber { + 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 binary_expression_rule<'ast>( + lhs: Box>, + pair: Pair<'ast, Rule>, + rhs: Box>, + ) -> Box> { + 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!(), + }) + } + + fn parse_rule_term(pair: Pair) -> Box { + Box::new(match pair.as_rule() { + Rule::term => { + let clone = pair.clone(); + let next = clone.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::expression => Expression::from_pest(&mut pair.into_inner()).unwrap(), // Parenthesis case + + 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_rule_term(inner.next().unwrap()); + Expression::Not(NotExpression { operation, expression, span }) + }, + Rule::expression_increment => { + let span = next.as_span(); + let mut inner = next.into_inner(); + let expression = parse_rule_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_rule_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_rule_term` should be invoked on `Rule::term`, found {:#?}", rule), + }) + } + + #[derive(Clone, Debug, FromPest, PartialEq)] + #[pest_ast(rule(Rule::file))] + pub struct File<'ast> { + pub statement: Vec>, + 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>, + #[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>, + 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>, + pub operation: Decrement<'ast>, + #[pest_ast(outer())] + pub span: Span<'ast>, + } + + #[derive(Debug, PartialEq, Clone)] + pub struct BinaryExpression<'ast> { + pub operation: BinaryOperator, + pub left: Box>, + pub right: Box>, + pub span: Span<'ast>, + } + + #[derive(Debug, PartialEq, Clone)] + pub enum Expression<'ast> { + Value(Value<'ast>), + Variable(Variable<'ast>), + Not(NotExpression<'ast>), + Increment(IncrementExpression<'ast>), + Decrement(DecrementExpression<'ast>), + Binary(BinaryExpression<'ast>), + } + + impl<'ast> Expression<'ast> { + pub fn binary( + operation: BinaryOperator, + left: Box>, + right: Box>, + 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::Increment(expression) => &expression.span, + Expression::Decrement(expression) => &expression.span, + Expression::Binary(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> { + let mut pairs = pest.clone(); + println!("{:?}\n", pairs); + let pair = pairs.next().ok_or(::from_pest::ConversionError::NoMatch)?; + match pair.as_rule() { + Rule::expression => { + // Transfer iterated state to pest. + *pest = pairs; + Ok(*PRECEDENCE_CLIMBER.climb(pair.into_inner(), parse_rule_term, binary_expression_rule)) + } + _ => 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>, + #[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; + 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"); + let syntax_tree = ast::File::from_pest(&mut file).expect("infallible"); - let file = LanguageParser::parse(Rule::file, &unparsed_file) - .expect("unsuccessful parse") // unwrap the parse result - .next().unwrap(); // get and unwrap the `file` rule; never fails + println!("{:?}", syntax_tree); + + // for token in file.into_inner() { + // match token.as_rule() { + // Rule::statement => println!("{:?}", token.into_inner()), + // Rule::EOI => println!("END"), + // _ => println!("{:?}", token.into_inner()), + // } + // // println!("{:?}", token); + // } - for token in file.into_inner() { - match token.as_rule() { - Rule::statement => println!("{:?}", token.into_inner()), - Rule::EOI => println!("END"), - _ => println!("{:?}", token.into_inner()), - } - // println!("{:?}", token); - } // let mut field_sum: f64 = 0.0; // let mut record_count: u64 = 0;