Enough work to hopefully make hello world parse and build AST.

This commit is contained in:
Jesse Brault 2025-05-15 08:13:34 -05:00
parent 63dec99cb5
commit e3dc46e023
3 changed files with 335 additions and 55 deletions

View File

@ -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<T>(pair: Pair<Rule>, rule: Rule, f: fn(Pair<Rule>) -> T) -> T {
if pair.as_rule() != rule {
@ -702,15 +716,82 @@ fn build_statement(statement_pair: Pair<Rule>) -> Statement {
fn build_variable_declaration(
variable_declaration_pair: Pair<Rule>,
) -> 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<Rule>) -> 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<Rule>) -> 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<Rule>) -> ReturnStatement {
@ -734,63 +815,171 @@ fn build_for_statement(for_statement_pair: Pair<Rule>) -> ForStatement {
}
fn build_expression(expression_pair: Pair<Rule>) -> 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<Rule>) -> 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<Rule>) -> TernaryExpression {
todo!()
macro_rules! build_binary_expression {
( $pair:ident, $left_rule:expr, $left_fn:expr, $( $pat:pat => $arm:expr ),* $(,)? ) => {{
let mut inner: Pairs<Rule> = $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<Rule>) -> 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<Rule>) -> Expression {
todo!()
}
fn build_equality_expression(equality_pair: Pair<Rule>) -> 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<Rule>) -> 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<Rule>) -> 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<Rule>) -> 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<Rule>) -> 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<Rule>) -> 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<Rule>) -> Expression {
@ -870,7 +1059,9 @@ fn build_call_expression(callee: Expression, parentheses_call_pair: Pair<Rule>)
}
fn build_turbo_fish(turbo_fish_pair: Pair<Rule>) -> 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<Rule>) -> Expression {
@ -905,10 +1096,52 @@ fn build_object_access(receiver: Expression, navigations_pair: Pair<Rule>) -> Ob
}
}
fn build_literal(literal_pair: Pair<Rule>) -> Literal {
todo!()
}
fn build_closure(closure_pair: Pair<Rule>) -> Closure {
todo!()
}
fn build_literal(literal_pair: Pair<Rule>) -> 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<Rule>) -> Literal {
todo!()
}
fn build_string_literal(pair: Pair<Rule>) -> 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<Rule>) -> 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<Rule>) -> Literal {
let inner_pair = pair.into_inner().next().unwrap();
Literal::StringLiteral(inner_pair.to_string())
}
fn build_double_quote_string(pair: Pair<Rule>) -> Literal {
todo!()
}
fn build_backtick_string(pair: Pair<Rule>) -> Literal {
todo!()
}

View File

@ -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<Expression>);
@ -472,8 +470,8 @@ pub enum Expression {
#[derive(Debug)]
pub struct TernaryExpression {
pub condition: Box<Expression>,
pub true_block: Box<Expression>,
pub false_block: Box<Expression>,
pub true_expression: Box<Expression>,
pub false_expression: Box<Expression>,
}
#[derive(Debug)]

View File

@ -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" }