From b0b87c68f26a81d370c804daa4552d50792ae88b Mon Sep 17 00:00:00 2001 From: janis Date: Fri, 10 Oct 2025 23:15:40 +0200 Subject: [PATCH] placeness, constants --- crates/parser/src/lib.rs | 267 ++++++++++++++++++++++++++++----------- 1 file changed, 190 insertions(+), 77 deletions(-) diff --git a/crates/parser/src/lib.rs b/crates/parser/src/lib.rs index e4be2e3..d4a61aa 100644 --- a/crates/parser/src/lib.rs +++ b/crates/parser/src/lib.rs @@ -11,7 +11,7 @@ use chumsky::{ select, text, }; use internment::Intern; -use lexer::{Token, TokenItemIterator, TokenIterator}; +use lexer::{Radix, Token, TokenItemIterator, TokenIterator}; use thiserror::Error; #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -111,6 +111,15 @@ pub enum ControlFlowKind { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct Index(u32); +impl Index { + pub fn as_value(self) -> PlaceOrValue { + PlaceOrValue::Value(self) + } + pub fn as_place(self) -> PlaceOrValue { + PlaceOrValue::Place(self) + } +} + #[derive(Debug)] pub enum AstNode { Root { @@ -303,6 +312,21 @@ pub enum AstNode { }, } +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum PlaceOrValue { + Place(Index), + Value(Index), +} + +impl PlaceOrValue { + pub fn index(self) -> Index { + match self { + PlaceOrValue::Place(i) => i, + PlaceOrValue::Value(i) => i, + } + } +} + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)] pub enum Visibility { #[default] @@ -448,7 +472,7 @@ fn visibility<'a>() -> impl Parser<'a, TokenInput<'a>, Visibility, ParserExtra> .map(|v| v.unwrap_or(Visibility::Private)) } -fn func_parser() { +fn func_parser<'a>() -> impl Parser<'a, TokenInput<'a>, Index, ParserExtra> { let ident = select! {Token::Ident(ident) => ident}; let param = just(Token::Mutable) @@ -473,7 +497,7 @@ fn func_parser() { .labelled("function parameters") .map(|params| ParameterList { parameters: params }); - let func = visibility() + visibility() .then_ignore(just(Token::Fn)) .then(ident) .then(params) @@ -491,22 +515,25 @@ fn func_parser() { visibility: vis, return_type: ret.unwrap_or_else(|| Intern::new(InnerType::Unit)), parameter_list: params, - body, + body: body.index(), })) - }); + }) } type ParserExtra = chumsky::extra::Full, ()>; -fn block<'a>() -> impl Parser<'a, TokenInput<'a>, Index, ParserExtra> + Clone { +fn block<'a>() -> impl Parser<'a, TokenInput<'a>, PlaceOrValue, ParserExtra> + Clone { just(Token::OpenBrace) .ignored() .then_ignore(just(Token::CloseBrace)) .map_with(|_, e: &mut MapExtra<'_, '_, _, ParserExtra>| { - e.state().push(AstNode::Block { - statements: vec![], - expr: None, - }) + e.state() + .push(AstNode::Block { + statements: vec![], + expr: None, + }) + .as_value() + // TODO: add statements and expr and map placeness by expr }) } @@ -525,24 +552,47 @@ fn unit<'a>() -> impl Parser<'a, TokenInput<'a>, Index, ParserExtra> + Clone { type E<'a, 'b> = MapExtra<'a, 'b, TokenInput<'a>, ParserExtra>; fn simple_expr<'a, 'b>( - expr: Recursive, Index, ParserExtra>>, -) -> impl Parser<'a, TokenInput<'a>, Index, ParserExtra> + Clone { + expr: Recursive, PlaceOrValue, ParserExtra>>, +) -> impl Parser<'a, TokenInput<'a>, PlaceOrValue, ParserExtra> + Clone { let ident = select! {Token::Ident(ident) => ident}.map_with( |ident, e: &mut MapExtra, ParserExtra>| { - e.state().push(AstNode::UnresolvedDeclRef { - name: ident.to_string(), - }) + e.state() + .push(AstNode::UnresolvedDeclRef { + name: ident.to_string(), + }) + .as_place() }, ); + + let constant = select! { + Token::FloatingConstant(lexeme)| + Token::DotFloatingConstant(lexeme)| + Token::FloatingExpConstant(lexeme)| + Token::DotFloatingExpConstant(lexeme) => { + constants::parse_floating_constant(lexeme) + }, + Token::IntegerConstant(lexeme) => { + constants::parse_integer_constant(lexeme, Radix::Dec) + }, + tok @ Token::IntegerHexConstant(lexeme)| + tok @ Token::IntegerOctConstant(lexeme)| + tok @ Token::IntegerBinConstant(lexeme) => { + let radix = Radix::from_token(tok).unwrap(); + constants::parse_integer_constant(&lexeme[2..], radix) + }, + } + .map_with(|(value, ty), e: &mut E| e.state().push(AstNode::Constant { ty, value }).as_value()); + choice(( - unit(), + unit().map(PlaceOrValue::Value), ident, + constant, expr.delimited_by(just(Token::OpenParens), just(Token::CloseParens)), block(), )) } -fn expr<'a>() -> impl Parser<'a, TokenInput<'a>, Index, ParserExtra> { +fn expr<'a>() -> impl Parser<'a, TokenInput<'a>, PlaceOrValue, ParserExtra> { let assignment = choice(( just(Token::Equal), just(Token::PlusEqual), @@ -587,17 +637,40 @@ fn expr<'a>() -> impl Parser<'a, TokenInput<'a>, Index, ParserExtra> { let r#as = just(Token::As).ignore_then(type_parser::()); - // TODO: postfix: function call, field access, array subscript + fn into_value(idx: PlaceOrValue, e: &mut E) -> PlaceOrValue { + match idx { + PlaceOrValue::Place(index) => e.state().push(AstNode::PlaceToValue { expr: index }), + PlaceOrValue::Value(index) => index, + } + .as_value() + } - recursive(|_expr| { + fn into_place(idx: PlaceOrValue, e: &mut E) -> PlaceOrValue { + match idx { + PlaceOrValue::Value(index) => e.state().push(AstNode::ValueToPlace { expr: index }), + PlaceOrValue::Place(index) => index, + } + .as_place() + } + + // TODO: postfix: function call, field access, array subscript + recursive(move |_expr| { let simple = simple_expr(_expr.clone()); - let subscript = _expr.clone().delimited_by( - just(Token::OpenSquareBracket), - just(Token::CloseSquareBracket), - ); + let subscript = _expr + .clone() + .delimited_by( + just(Token::OpenSquareBracket), + just(Token::CloseSquareBracket), + ) + // subscript takes a value as the index + .map_with(into_value); let arguments = _expr + .clone() + // arguments take values + .map_with(into_value) + .map(PlaceOrValue::index) .separated_by(just(Token::Comma)) .allow_trailing() .collect::>() @@ -606,61 +679,88 @@ fn expr<'a>() -> impl Parser<'a, TokenInput<'a>, Index, ParserExtra> { let field = just(Token::Dot).ignore_then(select! {Token::Ident(ident) => ident}); let assignment_expr = simple.pratt(( - postfix(100, subscript, |expr, index, e: &mut E| { - let node = AstNode::Subscript { expr, index }; - e.state().push(node) + postfix(100, subscript, |expr, index: PlaceOrValue, e: &mut E| { + let node = AstNode::Subscript { + expr: into_value(expr, e).index(), + index: index.index(), + }; + // subscript yields a place + e.state().push(node).as_place() }), postfix(100, arguments, |callee, arguments, e: &mut E| { - let node = AstNode::CallExpr { callee, arguments }; - e.state().push(node) + let node = AstNode::CallExpr { + callee: into_value(callee, e).index(), + arguments, + }; + // function call yields a value + e.state().push(node).as_value() }), postfix(100, field, |expr, field: &str, e: &mut E| { let node = AstNode::FieldAccess { - expr, + expr: into_place(expr, e).index(), field: field.to_string(), }; - e.state().push(node) + // field access yields a place + e.state().push(node).as_place() }), postfix(99, r#as, |expr, ty, e: &mut E| { - let node = AstNode::ExplicitCast { expr, ty }; - e.state().push(node) + let node = AstNode::ExplicitCast { + expr: into_value(expr, e).index(), + ty, + }; + e.state().push(node).as_value() }), prefix(95, prefixes, |op, expr, e: &mut E| { let node = match op { - Token::Bang => AstNode::Not(expr), - Token::Minus => AstNode::Negate(expr), - Token::Star => AstNode::Deref { expr }, - Token::Ampersand => AstNode::AddressOf { expr }, + Token::Bang => AstNode::Not(into_value(expr, e).index()), + Token::Minus => AstNode::Negate(into_value(expr, e).index()), + Token::Star => { + return e + .state() + .push(AstNode::Deref { expr: expr.index() }) + .as_place(); + } + Token::Ampersand => AstNode::AddressOf { + expr: into_place(expr, e).index(), + }, _ => unreachable!(), }; - e.state().push(node) + e.state().push(node).as_value() }), infix(left(90), multiplicative, |left, op, right, e: &mut E| { + let left = into_value(left, e).index(); + let right = into_value(right, e).index(); let node = match op { Token::Star => AstNode::Multiply { left, right }, Token::Slash => AstNode::Divide { left, right }, Token::Percent => AstNode::Modulus { left, right }, _ => unreachable!(), }; - e.state().push(node) + e.state().push(node).as_value() }), infix(left(80), additive, |left, op, right, e: &mut E| { + let left = into_value(left, e).index(); + let right = into_value(right, e).index(); let node = match op { Token::Plus => AstNode::Add { left, right }, Token::Minus => AstNode::Subtract { left, right }, _ => unreachable!(), }; - e.state().push(node) + e.state().push(node).as_value() }), infix(left(70), shift, |left, op, right, e: &mut E| { + let left = into_value(left, e).index(); + let right = into_value(right, e).index(); let node = match op { Token::LessLess => AstNode::ShiftLeft { left, right }, Token::GreaterGreater => AstNode::ShiftRight { left, right }, _ => unreachable!(), }; - e.state().push(node) + e.state().push(node).as_value() }), infix(left(60), relational, |left, op, right, e: &mut E| { + let left = into_value(left, e).index(); + let right = into_value(right, e).index(); let node = match op { Token::Less => AstNode::Less { left, right }, Token::LessEqual => AstNode::LessEq { left, right }, @@ -668,64 +768,73 @@ fn expr<'a>() -> impl Parser<'a, TokenInput<'a>, Index, ParserExtra> { Token::GreaterEqual => AstNode::GreaterEq { left, right }, _ => unreachable!(), }; - e.state().push(node) + e.state().push(node).as_value() }), infix(left(50), equality, |left, op, right, e: &mut E| { + let left = into_value(left, e).index(); + let right = into_value(right, e).index(); let node = match op { Token::EqualEqual => AstNode::Eq { left, right }, Token::BangEqual => AstNode::NotEq { left, right }, _ => unreachable!(), }; - e.state().push(node) + e.state().push(node).as_value() }), infix(left(40), and, |left, _op, right, e: &mut E| { + let left = into_value(left, e).index(); + let right = into_value(right, e).index(); let node = AstNode::BitAnd { left, right }; - e.state().push(node) + e.state().push(node).as_value() }), infix(left(30), xor, |left, _op, right, e: &mut E| { + let left = into_value(left, e).index(); + let right = into_value(right, e).index(); let node = AstNode::BitXor { left, right }; - e.state().push(node) + e.state().push(node).as_value() }), infix(left(20), or, |left, _op, right, e: &mut E| { + let left = into_value(left, e).index(); + let right = into_value(right, e).index(); let node = AstNode::BitOr { left, right }; - e.state().push(node) + e.state().push(node).as_value() }), infix(left(10), logical_and, |left, _op, right, e: &mut E| { + let left = into_value(left, e).index(); + let right = into_value(right, e).index(); let node = AstNode::LogicalAnd { left, right }; - e.state().push(node) + e.state().push(node).as_value() }), infix(left(5), logical_or, |left, _op, right, e: &mut E| { + let left = into_value(left, e).index(); + let right = into_value(right, e).index(); let node = AstNode::LogicalOr { left, right }; - e.state().push(node) + e.state().push(node).as_value() }), infix(right(1), assignment, |left, op, right, e: &mut E| { - let left = match op { - Token::Equal => { - let node = AstNode::Assignment { - dest: left, - expr: right, - }; - return e.state().push(node); - } - Token::PlusEqual => e.state().push(AstNode::Add { left, right }), - Token::MinusEqual => e.state().push(AstNode::Subtract { left, right }), - Token::StarEqual => e.state().push(AstNode::Multiply { left, right }), - Token::SlashEqual => e.state().push(AstNode::Divide { left, right }), - Token::PercentEqual => e.state().push(AstNode::Modulus { left, right }), - Token::AmpersandEqual => e.state().push(AstNode::BitAnd { left, right }), - Token::PipeEqual => e.state().push(AstNode::BitOr { left, right }), - Token::CaretEqual => e.state().push(AstNode::BitXor { left, right }), - Token::LessLessEqual => e.state().push(AstNode::ShiftLeft { left, right }), - Token::GreaterGreaterEqual => { - e.state().push(AstNode::ShiftRight { left, right }) - } - _ => unreachable!(), + let dest = into_place(left, e).index(); + let right = into_value(right, e).index(); + let node = if op == Token::Equal { + AstNode::Assignment { dest, expr: right } + } else { + let left = into_value(left, e).index(); + let right = match op { + Token::PlusEqual => e.state().push(AstNode::Add { left, right }), + Token::MinusEqual => e.state().push(AstNode::Subtract { left, right }), + Token::StarEqual => e.state().push(AstNode::Multiply { left, right }), + Token::SlashEqual => e.state().push(AstNode::Divide { left, right }), + Token::PercentEqual => e.state().push(AstNode::Modulus { left, right }), + Token::AmpersandEqual => e.state().push(AstNode::BitAnd { left, right }), + Token::PipeEqual => e.state().push(AstNode::BitOr { left, right }), + Token::CaretEqual => e.state().push(AstNode::BitXor { left, right }), + Token::LessLessEqual => e.state().push(AstNode::ShiftLeft { left, right }), + Token::GreaterGreaterEqual => { + e.state().push(AstNode::ShiftRight { left, right }) + } + _ => unreachable!(), + }; + AstNode::Assignment { dest, expr: right } }; - let node = AstNode::Assignment { - dest: left, - expr: right, - }; - e.state().push(node) + e.state().push(node).as_value() }), )); @@ -735,17 +844,20 @@ fn expr<'a>() -> impl Parser<'a, TokenInput<'a>, Index, ParserExtra> { .ignore_then( _expr .clone() + .map_with(into_value) + .map(PlaceOrValue::index) .delimited_by(just(Token::OpenParens), just(Token::CloseParens)), ) .then(_expr.clone()) .then(else_expr.or_not()) - .map_with(|((condition, then), r#else), e: &mut E| { + .map_with(|((condition, then), or), e: &mut E| { + // TODO: determine placeness from branches let node = AstNode::If { condition, - then, - r#else, + then: then.index(), + r#else: or.map(PlaceOrValue::index), }; - e.state().push(node) + e.state().push(node).as_value() }); let expr = choice((if_expr, assignment_expr)).labelled("expression"); @@ -830,5 +942,6 @@ mod tests { print_ast(new_token_input("()")); print_ast(new_token_input("!() as i32")); + print_ast(new_token_input("1 << 2 & 3")); } }