placeness, constants

This commit is contained in:
janis 2025-10-10 23:15:40 +02:00
parent f67bb61888
commit b0b87c68f2
Signed by: janis
SSH key fingerprint: SHA256:bB1qbbqmDXZNT0KKD5c2Dfjg53JGhj7B3CFcLIzSqq8

View file

@ -11,7 +11,7 @@ use chumsky::{
select, text, select, text,
}; };
use internment::Intern; use internment::Intern;
use lexer::{Token, TokenItemIterator, TokenIterator}; use lexer::{Radix, Token, TokenItemIterator, TokenIterator};
use thiserror::Error; use thiserror::Error;
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
@ -111,6 +111,15 @@ pub enum ControlFlowKind {
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Index(u32); 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)] #[derive(Debug)]
pub enum AstNode { pub enum AstNode {
Root { 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)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub enum Visibility { pub enum Visibility {
#[default] #[default]
@ -448,7 +472,7 @@ fn visibility<'a>() -> impl Parser<'a, TokenInput<'a>, Visibility, ParserExtra>
.map(|v| v.unwrap_or(Visibility::Private)) .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 ident = select! {Token::Ident(ident) => ident};
let param = just(Token::Mutable) let param = just(Token::Mutable)
@ -473,7 +497,7 @@ fn func_parser() {
.labelled("function parameters") .labelled("function parameters")
.map(|params| ParameterList { parameters: params }); .map(|params| ParameterList { parameters: params });
let func = visibility() visibility()
.then_ignore(just(Token::Fn)) .then_ignore(just(Token::Fn))
.then(ident) .then(ident)
.then(params) .then(params)
@ -491,22 +515,25 @@ fn func_parser() {
visibility: vis, visibility: vis,
return_type: ret.unwrap_or_else(|| Intern::new(InnerType::Unit)), return_type: ret.unwrap_or_else(|| Intern::new(InnerType::Unit)),
parameter_list: params, parameter_list: params,
body, body: body.index(),
})) }))
}); })
} }
type ParserExtra = chumsky::extra::Full<EmptyErr, SimpleState<Ast>, ()>; type ParserExtra = chumsky::extra::Full<EmptyErr, SimpleState<Ast>, ()>;
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) just(Token::OpenBrace)
.ignored() .ignored()
.then_ignore(just(Token::CloseBrace)) .then_ignore(just(Token::CloseBrace))
.map_with(|_, e: &mut MapExtra<'_, '_, _, ParserExtra>| { .map_with(|_, e: &mut MapExtra<'_, '_, _, ParserExtra>| {
e.state().push(AstNode::Block { e.state()
statements: vec![], .push(AstNode::Block {
expr: None, 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>; type E<'a, 'b> = MapExtra<'a, 'b, TokenInput<'a>, ParserExtra>;
fn simple_expr<'a, 'b>( fn simple_expr<'a, 'b>(
expr: Recursive<Direct<'a, 'b, TokenInput<'a>, Index, ParserExtra>>, expr: Recursive<Direct<'a, 'b, TokenInput<'a>, PlaceOrValue, ParserExtra>>,
) -> impl Parser<'a, TokenInput<'a>, Index, ParserExtra> + Clone { ) -> impl Parser<'a, TokenInput<'a>, PlaceOrValue, ParserExtra> + Clone {
let ident = select! {Token::Ident(ident) => ident}.map_with( let ident = select! {Token::Ident(ident) => ident}.map_with(
|ident, e: &mut MapExtra<TokenInput<'a>, ParserExtra>| { |ident, e: &mut MapExtra<TokenInput<'a>, ParserExtra>| {
e.state().push(AstNode::UnresolvedDeclRef { e.state()
name: ident.to_string(), .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(( choice((
unit(), unit().map(PlaceOrValue::Value),
ident, ident,
constant,
expr.delimited_by(just(Token::OpenParens), just(Token::CloseParens)), expr.delimited_by(just(Token::OpenParens), just(Token::CloseParens)),
block(), block(),
)) ))
} }
fn expr<'a>() -> impl Parser<'a, TokenInput<'a>, Index, ParserExtra> { fn expr<'a>() -> impl Parser<'a, TokenInput<'a>, PlaceOrValue, ParserExtra> {
let assignment = choice(( let assignment = choice((
just(Token::Equal), just(Token::Equal),
just(Token::PlusEqual), 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::<ParserExtra>()); let r#as = just(Token::As).ignore_then(type_parser::<ParserExtra>());
// 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 simple = simple_expr(_expr.clone());
let subscript = _expr.clone().delimited_by( let subscript = _expr
just(Token::OpenSquareBracket), .clone()
just(Token::CloseSquareBracket), .delimited_by(
); just(Token::OpenSquareBracket),
just(Token::CloseSquareBracket),
)
// subscript takes a value as the index
.map_with(into_value);
let arguments = _expr let arguments = _expr
.clone()
// arguments take values
.map_with(into_value)
.map(PlaceOrValue::index)
.separated_by(just(Token::Comma)) .separated_by(just(Token::Comma))
.allow_trailing() .allow_trailing()
.collect::<Vec<_>>() .collect::<Vec<_>>()
@ -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 field = just(Token::Dot).ignore_then(select! {Token::Ident(ident) => ident});
let assignment_expr = simple.pratt(( let assignment_expr = simple.pratt((
postfix(100, subscript, |expr, index, e: &mut E| { postfix(100, subscript, |expr, index: PlaceOrValue, e: &mut E| {
let node = AstNode::Subscript { expr, index }; let node = AstNode::Subscript {
e.state().push(node) 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| { postfix(100, arguments, |callee, arguments, e: &mut E| {
let node = AstNode::CallExpr { callee, arguments }; let node = AstNode::CallExpr {
e.state().push(node) 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| { postfix(100, field, |expr, field: &str, e: &mut E| {
let node = AstNode::FieldAccess { let node = AstNode::FieldAccess {
expr, expr: into_place(expr, e).index(),
field: field.to_string(), 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| { postfix(99, r#as, |expr, ty, e: &mut E| {
let node = AstNode::ExplicitCast { expr, ty }; let node = AstNode::ExplicitCast {
e.state().push(node) expr: into_value(expr, e).index(),
ty,
};
e.state().push(node).as_value()
}), }),
prefix(95, prefixes, |op, expr, e: &mut E| { prefix(95, prefixes, |op, expr, e: &mut E| {
let node = match op { let node = match op {
Token::Bang => AstNode::Not(expr), Token::Bang => AstNode::Not(into_value(expr, e).index()),
Token::Minus => AstNode::Negate(expr), Token::Minus => AstNode::Negate(into_value(expr, e).index()),
Token::Star => AstNode::Deref { expr }, Token::Star => {
Token::Ampersand => AstNode::AddressOf { expr }, return e
.state()
.push(AstNode::Deref { expr: expr.index() })
.as_place();
}
Token::Ampersand => AstNode::AddressOf {
expr: into_place(expr, e).index(),
},
_ => unreachable!(), _ => unreachable!(),
}; };
e.state().push(node) e.state().push(node).as_value()
}), }),
infix(left(90), multiplicative, |left, op, right, e: &mut E| { 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 { let node = match op {
Token::Star => AstNode::Multiply { left, right }, Token::Star => AstNode::Multiply { left, right },
Token::Slash => AstNode::Divide { left, right }, Token::Slash => AstNode::Divide { left, right },
Token::Percent => AstNode::Modulus { left, right }, Token::Percent => AstNode::Modulus { left, right },
_ => unreachable!(), _ => unreachable!(),
}; };
e.state().push(node) e.state().push(node).as_value()
}), }),
infix(left(80), additive, |left, op, right, e: &mut E| { 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 { let node = match op {
Token::Plus => AstNode::Add { left, right }, Token::Plus => AstNode::Add { left, right },
Token::Minus => AstNode::Subtract { left, right }, Token::Minus => AstNode::Subtract { left, right },
_ => unreachable!(), _ => unreachable!(),
}; };
e.state().push(node) e.state().push(node).as_value()
}), }),
infix(left(70), shift, |left, op, right, e: &mut E| { 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 { let node = match op {
Token::LessLess => AstNode::ShiftLeft { left, right }, Token::LessLess => AstNode::ShiftLeft { left, right },
Token::GreaterGreater => AstNode::ShiftRight { left, right }, Token::GreaterGreater => AstNode::ShiftRight { left, right },
_ => unreachable!(), _ => unreachable!(),
}; };
e.state().push(node) e.state().push(node).as_value()
}), }),
infix(left(60), relational, |left, op, right, e: &mut E| { 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 { let node = match op {
Token::Less => AstNode::Less { left, right }, Token::Less => AstNode::Less { left, right },
Token::LessEqual => AstNode::LessEq { 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 }, Token::GreaterEqual => AstNode::GreaterEq { left, right },
_ => unreachable!(), _ => unreachable!(),
}; };
e.state().push(node) e.state().push(node).as_value()
}), }),
infix(left(50), equality, |left, op, right, e: &mut E| { 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 { let node = match op {
Token::EqualEqual => AstNode::Eq { left, right }, Token::EqualEqual => AstNode::Eq { left, right },
Token::BangEqual => AstNode::NotEq { left, right }, Token::BangEqual => AstNode::NotEq { left, right },
_ => unreachable!(), _ => unreachable!(),
}; };
e.state().push(node) e.state().push(node).as_value()
}), }),
infix(left(40), and, |left, _op, right, e: &mut E| { 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 }; 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| { 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 }; 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| { 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 }; 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| { 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 }; 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| { 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 }; 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| { infix(right(1), assignment, |left, op, right, e: &mut E| {
let left = match op { let dest = into_place(left, e).index();
Token::Equal => { let right = into_value(right, e).index();
let node = AstNode::Assignment { let node = if op == Token::Equal {
dest: left, AstNode::Assignment { dest, expr: right }
expr: right, } else {
}; let left = into_value(left, e).index();
return e.state().push(node); let right = match op {
} Token::PlusEqual => e.state().push(AstNode::Add { left, right }),
Token::PlusEqual => e.state().push(AstNode::Add { left, right }), Token::MinusEqual => e.state().push(AstNode::Subtract { left, right }),
Token::MinusEqual => e.state().push(AstNode::Subtract { left, right }), Token::StarEqual => e.state().push(AstNode::Multiply { left, right }),
Token::StarEqual => e.state().push(AstNode::Multiply { left, right }), Token::SlashEqual => e.state().push(AstNode::Divide { left, right }),
Token::SlashEqual => e.state().push(AstNode::Divide { left, right }), Token::PercentEqual => e.state().push(AstNode::Modulus { left, right }),
Token::PercentEqual => e.state().push(AstNode::Modulus { left, right }), Token::AmpersandEqual => e.state().push(AstNode::BitAnd { left, right }),
Token::AmpersandEqual => e.state().push(AstNode::BitAnd { left, right }), Token::PipeEqual => e.state().push(AstNode::BitOr { left, right }),
Token::PipeEqual => e.state().push(AstNode::BitOr { left, right }), Token::CaretEqual => e.state().push(AstNode::BitXor { left, right }),
Token::CaretEqual => e.state().push(AstNode::BitXor { left, right }), Token::LessLessEqual => e.state().push(AstNode::ShiftLeft { left, right }),
Token::LessLessEqual => e.state().push(AstNode::ShiftLeft { left, right }), Token::GreaterGreaterEqual => {
Token::GreaterGreaterEqual => { e.state().push(AstNode::ShiftRight { left, right })
e.state().push(AstNode::ShiftRight { left, right }) }
} _ => unreachable!(),
_ => unreachable!(), };
AstNode::Assignment { dest, expr: right }
}; };
let node = AstNode::Assignment { e.state().push(node).as_value()
dest: left,
expr: right,
};
e.state().push(node)
}), }),
)); ));
@ -735,17 +844,20 @@ fn expr<'a>() -> impl Parser<'a, TokenInput<'a>, Index, ParserExtra> {
.ignore_then( .ignore_then(
_expr _expr
.clone() .clone()
.map_with(into_value)
.map(PlaceOrValue::index)
.delimited_by(just(Token::OpenParens), just(Token::CloseParens)), .delimited_by(just(Token::OpenParens), just(Token::CloseParens)),
) )
.then(_expr.clone()) .then(_expr.clone())
.then(else_expr.or_not()) .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 { let node = AstNode::If {
condition, condition,
then, then: then.index(),
r#else, 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"); 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("()"));
print_ast(new_token_input("!() as i32")); print_ast(new_token_input("!() as i32"));
print_ast(new_token_input("1 << 2 & 3"));
} }
} }