diff --git a/src/ast/build.rs b/src/ast/build.rs index 936dd7a..63ce52a 100644 --- a/src/ast/build.rs +++ b/src/ast/build.rs @@ -1,6 +1,20 @@ -use crate::ast::{AssignStatement, BinaryExpression, BinaryOperator, BlockStatement, CallArgument, CallArguments, CallExpression, CallStatement, ClassConstructor, ClassConstructorParameter, ClassDeclaration, ClassLevelDeclaration, Closure, CompilationUnit, Expression, FieldDeclaration, ForStatement, FullyQualifiedName, FunctionBody, FunctionDefinition, FunctionModifier, FunctionTypeModifier, FunctionTypeUse, GenericArguments, GenericParameter, GenericParameters, Identifier, IfElseStatement, IfStatement, ImplementsList, InterfaceDeclaration, InterfaceFunctionDeclaration, InterfaceLevelDeclaration, InterfaceOperatorFunctionDeclaration, InterfaceOrClassTypeUse, Literal, ModuleDeclaration, ModuleLevelDeclaration, ObjectAccess, ObjectNavigation, ObjectNavigations, OperatorFunctionDefinition, Parameter, Parameters, PlatformFunctionDeclaration, PropertyDeclaration, Reference, References, ReturnStatement, ReturnType, Statement, SuffixExpression, SuffixUnaryOperator, TernaryExpression, TupleArguments, TupleTypeUse, TurboFish, TypeUse, UnarySuffixExpression, VariableDeclarationStatement, WhileStatement}; +use crate::ast::{ + AssignStatement, BinaryExpression, BinaryOperator, BlockStatement, CallArgument, CallArguments, + CallExpression, CallStatement, ClassConstructor, ClassConstructorParameter, ClassDeclaration, + ClassLevelDeclaration, Closure, CompilationUnit, Expression, FieldDeclaration, ForStatement, + FullyQualifiedName, FunctionBody, FunctionDefinition, FunctionModifier, FunctionTypeModifier, + FunctionTypeUse, GenericArguments, GenericParameter, GenericParameters, Identifier, + IfElseStatement, IfStatement, ImplementsList, InterfaceDeclaration, + InterfaceFunctionDeclaration, InterfaceLevelDeclaration, InterfaceOperatorFunctionDeclaration, + InterfaceOrClassTypeUse, Literal, ModuleDeclaration, ModuleLevelDeclaration, ObjectAccess, + ObjectNavigation, ObjectNavigations, OperatorFunctionDefinition, Parameter, Parameters, + PlatformFunctionDeclaration, PrefixExpression, PrefixUnaryOperator, PropertyDeclaration, + Reference, References, ReturnStatement, ReturnType, Statement, SuffixExpression, + SuffixUnaryOperator, TernaryExpression, TupleArguments, TupleTypeUse, TurboFish, TypeUse, + UnarySuffixExpression, VariableDeclarationStatement, WhileStatement, +}; use crate::parser::Rule; -use pest::iterators::Pair; +use pest::iterators::{Pair, Pairs}; fn expect_and_use(pair: Pair, rule: Rule, f: fn(Pair) -> T) -> T { if pair.as_rule() != rule { @@ -702,15 +716,82 @@ fn build_statement(statement_pair: Pair) -> Statement { fn build_variable_declaration( variable_declaration_pair: Pair, ) -> VariableDeclarationStatement { - todo!() + let mut is_mutable = false; + let mut identifier = None; + let mut declared_type = None; + let mut initializer = None; + + for inner_pair in variable_declaration_pair.into_inner() { + match inner_pair.as_rule() { + Rule::Let => {} + Rule::Mut => { + is_mutable = true; + } + Rule::Identifier => { + identifier = Some(build_identifier(inner_pair)); + } + Rule::TypeUse => { + declared_type = Some(build_type_use(inner_pair)); + } + Rule::Expression => { + initializer = Some(build_expression(inner_pair)); + } + _ => unreachable!(), + } + } + + VariableDeclarationStatement { + is_mutable, + identifier: identifier.unwrap(), + declared_type, + initializer, + } } fn build_assignment_statement(assignment_pair: Pair) -> AssignStatement { - todo!() + let mut inner = assignment_pair.into_inner(); + let lhs = build_expression(inner.next().unwrap()); + let rhs = build_expression(inner.next().unwrap()); + AssignStatement { lhs, rhs } } fn build_call_statement(call_statement_pair: Pair) -> CallStatement { - todo!() + let mut inner = call_statement_pair.into_inner(); + let mut result = expect_and_use( + inner.next().unwrap(), + Rule::PrimaryExpression, + build_primary_expression, + ); + + while let Some(inner_pair) = inner.next() { + match inner_pair.as_rule() { + Rule::ObjectAccess => { + result = Expression::Suffix(SuffixExpression::ObjectAccess(build_object_access( + result, inner_pair, + ))); + } + Rule::ParenthesesCall => { + result = Expression::Suffix(SuffixExpression::Call(build_call_expression( + result, inner_pair, + ))); + } + Rule::PlusPlus => { + result = Expression::Suffix(SuffixExpression::Unary(UnarySuffixExpression { + expression: Box::new(result), + operator: SuffixUnaryOperator::PlusPlus, + })); + } + Rule::MinusMinus => { + result = Expression::Suffix(SuffixExpression::Unary(UnarySuffixExpression { + expression: Box::new(result), + operator: SuffixUnaryOperator::MinusMinus, + })); + } + _ => unreachable!(), + } + } + + CallStatement(result) } fn build_return_statement(return_statement_pair: Pair) -> ReturnStatement { @@ -734,63 +815,171 @@ fn build_for_statement(for_statement_pair: Pair) -> ForStatement { } fn build_expression(expression_pair: Pair) -> Expression { - let inner_pair = expression_pair.into_inner().next().unwrap(); - match inner_pair.as_rule() { - Rule::TernaryExpression => Expression::Ternary(build_ternary_expression(inner_pair)), - _ => unreachable!(), + expect_and_use( + expression_pair.into_inner().next().unwrap(), + Rule::TernaryExpression, + build_ternary_expression, + ) +} + +fn build_ternary_expression(ternary_pair: Pair) -> Expression { + let mut inner = ternary_pair.into_inner(); + if inner.len() == 3 { + let condition = expect_and_use( + inner.next().unwrap(), + Rule::OrExpression, + build_or_expression, + ); + let true_expression = + expect_and_use(inner.next().unwrap(), Rule::Expression, build_expression); + let false_expression = + expect_and_use(inner.next().unwrap(), Rule::Expression, build_expression); + Expression::Ternary(TernaryExpression { + condition: Box::new(condition), + true_expression: Box::new(true_expression), + false_expression: Box::new(false_expression), + }) + } else { + expect_and_use( + inner.next().unwrap(), + Rule::OrExpression, + build_or_expression, + ) } } -fn build_ternary_expression(ternary_pair: Pair) -> TernaryExpression { - todo!() +macro_rules! build_binary_expression { + ( $pair:ident, $left_rule:expr, $left_fn:expr, $( $pat:pat => $arm:expr ),* $(,)? ) => {{ + let mut inner: Pairs = $pair.into_inner(); + if inner.len() == 3 { + let left = expect_and_use(inner.next().unwrap(), $left_rule, $left_fn); + let op = inner.next().unwrap(); // op + let right = expect_and_use(inner.next().unwrap(), Rule::Expression, build_expression); + Expression::Binary(BinaryExpression { + left: Box::new(left), + operator: match op.as_rule() { + $( $pat => $arm, )* + _ => unreachable!(), + }, + right: Box::new(right), + }) + } else { + $left_fn(inner.next().unwrap()) + } + }}; } fn build_or_expression(or_expression_pair: Pair) -> Expression { - let mut inner = or_expression_pair.into_inner(); - if inner.len() == 3 { - let left = expect_and_use( - inner.next().unwrap(), - Rule::AndExpression, - build_and_expression, - ); - inner.next().unwrap(); // Or - let right = expect_and_use(inner.next().unwrap(), Rule::Expression, build_expression); - Expression::Binary(BinaryExpression { - left: Box::new(left), - operator: BinaryOperator::Or, - right: Box::new(right), - }) - } else { - build_and_expression(inner.next().unwrap()) - } + build_binary_expression!( + or_expression_pair, + Rule::AndExpression, + build_and_expression, + Rule::Or => BinaryOperator::Or, + ) } fn build_and_expression(and_expression_pair: Pair) -> Expression { - todo!() -} - -fn build_equality_expression(equality_pair: Pair) -> Expression { - todo!() + build_binary_expression!( + and_expression_pair, + Rule::ComparisonExpression, + build_comparison_expression, + Rule::And => BinaryOperator::And, + ) } fn build_comparison_expression(comparison_expression_pair: Pair) -> Expression { - todo!() + build_binary_expression!( + comparison_expression_pair, + Rule::ShiftExpression, + build_shift_expression, + Rule::Greater => BinaryOperator::Greater, + Rule::Less => BinaryOperator::Less, + Rule::GreaterEqual => BinaryOperator::GreaterEqual, + Rule::LessEqual => BinaryOperator::LessEqual, + Rule::EqualTo => BinaryOperator::EqualTo, + Rule::NotEqualTo => BinaryOperator::NotEqualTo, + ) } fn build_shift_expression(shift_expression_pair: Pair) -> Expression { - todo!() + build_binary_expression!( + shift_expression_pair, + Rule::AdditiveExpression, + build_additive_expression, + Rule::LeftShift => BinaryOperator::LeftShift, + Rule::RightShift => BinaryOperator::RightShift, + ) } fn build_additive_expression(add_expression_pair: Pair) -> Expression { - todo!() + build_binary_expression!( + add_expression_pair, + Rule::MultiplicativeExpression, + build_multiplicative_expression, + Rule::Add => BinaryOperator::Add, + Rule::Subtract => BinaryOperator::Subtract, + ) } fn build_multiplicative_expression(multiplicative_expression_pair: Pair) -> Expression { - todo!() + build_binary_expression!( + multiplicative_expression_pair, + Rule::PrefixExpression, + build_prefix_expression, + Rule::Multiply => BinaryOperator::Multiply, + Rule::Divide => BinaryOperator::Divide, + ) } fn build_prefix_expression(prefix_pair: Pair) -> Expression { - todo!() + let mut inner_rev = prefix_pair.into_inner().rev(); + let mut result = expect_and_use( + inner_rev.next().unwrap(), + Rule::SuffixExpression, + build_suffix_expression, + ); + while let Some(prefix_pair) = inner_rev.next() { + match prefix_pair.as_rule() { + Rule::Spread => { + result = Expression::UnaryPrefix(PrefixExpression { + operator: PrefixUnaryOperator::Spread, + expression: Box::new(result), + }); + } + Rule::BorrowMut => { + result = Expression::UnaryPrefix(PrefixExpression { + operator: PrefixUnaryOperator::BorrowMut, + expression: Box::new(result), + }) + } + Rule::Borrow => { + result = Expression::UnaryPrefix(PrefixExpression { + operator: PrefixUnaryOperator::Borrow, + expression: Box::new(result), + }) + } + Rule::Mut => { + result = Expression::UnaryPrefix(PrefixExpression { + operator: PrefixUnaryOperator::Mut, + expression: Box::new(result), + }) + } + Rule::Not => { + result = Expression::UnaryPrefix(PrefixExpression { + operator: PrefixUnaryOperator::Not, + expression: Box::new(result), + }) + } + Rule::Negative => { + result = Expression::UnaryPrefix(PrefixExpression { + operator: PrefixUnaryOperator::Negative, + expression: Box::new(result), + }) + } + _ => unreachable!(), + } + } + result } fn build_suffix_expression(suffix_pair: Pair) -> Expression { @@ -870,7 +1059,9 @@ fn build_call_expression(callee: Expression, parentheses_call_pair: Pair) } fn build_turbo_fish(turbo_fish_pair: Pair) -> TurboFish { - TurboFish(build_generic_arguments(turbo_fish_pair.into_inner().next().unwrap())) + TurboFish(build_generic_arguments( + turbo_fish_pair.into_inner().next().unwrap(), + )) } fn build_primary_expression(primary_expression_pair: Pair) -> Expression { @@ -905,10 +1096,52 @@ fn build_object_access(receiver: Expression, navigations_pair: Pair) -> Ob } } -fn build_literal(literal_pair: Pair) -> Literal { - todo!() -} - fn build_closure(closure_pair: Pair) -> Closure { todo!() } + +fn build_literal(literal_pair: Pair) -> Literal { + let inner_pair = literal_pair.into_inner().next().unwrap(); + match inner_pair.as_rule() { + Rule::NumberLiteral => build_number_literal(inner_pair), + Rule::StringLiteral => build_string_literal(inner_pair), + Rule::BooleanLiteral => build_boolean_literal(inner_pair), + _ => unreachable!(), + } +} + +fn build_number_literal(pair: Pair) -> Literal { + todo!() +} + +fn build_string_literal(pair: Pair) -> Literal { + let inner_pair = pair.into_inner().next().unwrap(); + match inner_pair.as_rule() { + Rule::SingleQuoteString => build_single_quote_string(inner_pair), + Rule::DoubleQuoteString => build_double_quote_string(inner_pair), + Rule::BacktickString => build_backtick_string(inner_pair), + _ => unreachable!(), + } +} + +fn build_boolean_literal(pair: Pair) -> Literal { + let inner_pair = pair.into_inner().next().unwrap(); + match inner_pair.as_rule() { + Rule::True => Literal::BooleanLiteral(true), + Rule::False => Literal::BooleanLiteral(false), + _ => unreachable!(), + } +} + +fn build_single_quote_string(pair: Pair) -> Literal { + let inner_pair = pair.into_inner().next().unwrap(); + Literal::StringLiteral(inner_pair.to_string()) +} + +fn build_double_quote_string(pair: Pair) -> Literal { + todo!() +} + +fn build_backtick_string(pair: Pair) -> Literal { + todo!() +} diff --git a/src/ast/mod.rs b/src/ast/mod.rs index 4557caa..921f350 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -34,8 +34,9 @@ pub enum BinaryOperator { #[derive(Debug)] pub enum PrefixUnaryOperator { Spread, - Borrow, BorrowMut, + Borrow, + Mut, Not, Negative, } @@ -418,10 +419,7 @@ pub struct AssignStatement { } #[derive(Debug)] -pub struct CallStatement { - pub callee: Expression, - pub arguments: CallArguments, -} +pub struct CallStatement(pub Expression); #[derive(Debug)] pub struct ReturnStatement(pub Option); @@ -472,8 +470,8 @@ pub enum Expression { #[derive(Debug)] pub struct TernaryExpression { pub condition: Box, - pub true_block: Box, - pub false_block: Box, + pub true_expression: Box, + pub false_expression: Box, } #[derive(Debug)] diff --git a/src/parser/deimos.pest b/src/parser/deimos.pest index 998be4a..be0282f 100644 --- a/src/parser/deimos.pest +++ b/src/parser/deimos.pest @@ -28,6 +28,8 @@ For = { "for" } In = { "in" } Move = { "move" } Alias = { "alias" } +True = { "true" } +False = { "false" } // Keywords as a rule (for preventing identifiers with keywords, etc.) Keyword = { @@ -60,6 +62,8 @@ Keyword = { | In | Move | Alias + | True + | False } // Symbols @@ -611,7 +615,7 @@ MultiplicativeExpression = { PrefixExpression = { ( Spread - | ( Borrow ~ Mut ) + | BorrowMut | Borrow | Mut | Not @@ -620,6 +624,10 @@ PrefixExpression = { ~ SuffixExpression } +BorrowMut = { + Borrow ~ Mut +} + SuffixExpression = { PrimaryExpression ~ ( @@ -748,16 +756,57 @@ HexadecimalBase = @{ "0x" ~ HexadecimalDigit+ } HexadecimalDigit = { '0'..'9' | 'a'..'f' } -StringLiteral = ${ "\"" ~ StringInner ~ "\"" } +StringLiteral = { + SingleQuoteString + | DoubleQuoteString + | BacktickString +} + +SingleQuoteString = ${ "'" ~ StringInner ~ "'" } + +DoubleQuoteString = { + "\"" + ~ ( DStringInner? ~ DStringExpression )* + ~ DStringInner? + ~ "\"" +} StringInner = @{ StringChar* } StringChar = { - !( "\"" | "\\" ) ~ ANY - | "\\" ~ ( "\"" | "\\" | "/" | "b" | "f" | "n" | "r" | "t" ) + !( "\"" | "\\" ) ~ ANY + | "\\" ~ ( "'" | "\\" | "/" | "b" | "f" | "n" | "r" | "t" ) | "\\" ~ ( "u" ~ ASCII_HEX_DIGIT{4} ) } -BooleanLiteral = { "true" | "false" } +DStringInner = @{ DStringChar+ } + +DStringChar = { + !( "\"" | "\\" ) ~ ANY + | "\\" ~ ( "\"" | "\\" | "/" | "b" | "f" | "n" | "r" | "t" | "$" ) + | "\\" ~ ( "u" ~ ASCII_HEX_DIGIT{4} ) +} + +DStringExpression = { + "$" + ~ BlockStatement +} + +BacktickString = { + "`" + ~ ( DStringInner? ~ DStringExpression )* + ~ DStringInner? + ~ "`" +} + +BacktickInner = @{ BacktickStringChar+ } + +BacktickStringChar = { + !( "\"" | "\\" ) ~ ANY + | "\\" ~ ( "`" | "\\" | "/" | "b" | "f" | "n" | "r" | "t" | "$" ) + | "\\" ~ ( "u" ~ ASCII_HEX_DIGIT{4} ) +} + +BooleanLiteral = { True | False } WHITESPACE = _{ " " | "\t" | "\n" | "\r" }