var decls

This commit is contained in:
janis 2025-10-14 15:10:03 +02:00
parent 0ee6bbad61
commit 51ef019fd1
Signed by: janis
SSH key fingerprint: SHA256:bB1qbbqmDXZNT0KKD5c2Dfjg53JGhj7B3CFcLIzSqq8
2 changed files with 118 additions and 15 deletions

View file

@ -240,7 +240,7 @@ pub enum AstNode {
VarDecl {
mutable: bool,
name: String,
var_type: Type,
var_type: Option<Type>,
},
Assignment {
dest: Index,
@ -414,6 +414,14 @@ impl PlaceOrValue {
PlaceOrValue::Value(_) => PlaceOrValue::Value(index),
}
}
pub fn eq_placeness(&self, other: &Self) -> bool {
match (self, other) {
(PlaceOrValue::Place(_), PlaceOrValue::Place(_))
| (PlaceOrValue::Value(_), PlaceOrValue::Value(_)) => true,
_ => false,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
@ -603,9 +611,48 @@ where
self.function.clone()
}
fn stmt(&self) -> impl Parser<'src, TokenInput<'src>, Index, ParserExtra> + Clone {
fn var_decl(
&self,
) -> impl Parser<'src, TokenInput<'src>, Index, ParserExtra> + Clone + use<'src, 'b> {
let ident = select! {Token::Ident(ident) => ident};
just(Token::Let)
.ignored()
.then(select! {Token::Mutable => ()}.or_not())
.then(ident)
.then(
just(Token::Colon)
.ignore_then(type_parser::<ParserExtra>())
.or_not(),
)
.then(
just(Token::Equal)
.ignore_then(self.expr().map_with(Self::into_value))
.or_not(),
)
.then_ignore(just(Token::Semi))
.map_with(|((((_, mutable), ident), var_type), val), e: &mut E| {
let decl = e.state().push(AstNode::VarDecl {
mutable: mutable.is_some(),
name: ident.to_string(),
var_type,
});
if let Some(expr) = val {
e.state().push(AstNode::Assignment {
dest: decl,
expr: expr.index(),
})
} else {
decl
}
})
}
fn stmt(
&self,
) -> impl Parser<'src, TokenInput<'src>, Index, ParserExtra> + Clone + use<'src, 'b> {
choice((
self.function.clone(),
self.var_decl(),
self.expr
.clone()
.then_ignore(just(Token::Semi))
@ -718,10 +765,7 @@ where
&self,
) -> impl Parser<'src, TokenInput<'src>, PlaceOrValue, ParserExtra> + Clone + use<'src, 'b>
{
self.expr
.clone()
.then_ignore(just(Token::Semi))
.map(PlaceOrValue::index)
self.stmt()
.repeated()
.collect::<Vec<_>>()
.then(self.expr.clone().or_not())
@ -1022,13 +1066,20 @@ where
.then(self.expr())
.then(else_expr.or_not())
.map_with(|((condition, then), or), e: &mut E| {
// TODO: determine placeness from branches
use PlaceOrValue::*;
let (then, or) = match (then, or) {
(Place(then), Some(Place(or))) => (Place(then), Some(Place(or))),
_ => (
Self::into_value(then, e),
or.map(|or| Self::into_value(or, e)),
),
};
let node = AstNode::If {
condition,
then: then.index(),
r#else: or.map(PlaceOrValue::index),
};
e.state().push(node).as_value()
then.with_index(e.state().push(node))
})
}
@ -1095,7 +1146,7 @@ mod symbols;
#[cfg(test)]
mod tests {
use chumsky::{Parser, extra::SimpleState};
use chumsky::{ParseResult, Parser, extra::SimpleState};
use crate::{Ast, AstNode, ParserCtx, ParserExtra, new_token_input, pretty, type_parser};
@ -1163,6 +1214,10 @@ mod tests {
) {
let mut state = SimpleState(Ast::new());
let out = parser.parse_with_state(tokens, &mut state);
for e in out.errors() {
eprintln!("Error: {}", e);
panic!("errors occured while parsing.")
}
let ast = state.0;
let mut pretty = pretty::PrettyPrint::new();
pretty.print(&ast);
@ -1184,6 +1239,7 @@ mod tests {
r#"
/// docs!
fn my_function(a: i32, b: *const u8) -> i32 {
let mut x: i32;
x = a + 1;
x
}
@ -1193,6 +1249,40 @@ fn my_function(a: i32, b: *const u8) -> i32 {
);
}
#[test]
fn parse_var_decl() {
let ctx = crate::ParserCtx::new();
print_ast(
new_token_input(
r#"
let mut x: i32 = 10;
"#,
),
ctx.var_decl(),
);
}
#[test]
fn parse_stmts() {
let ctx = crate::ParserCtx::new();
print_ast(
new_token_input(
r#"
let mut x: i32 = 10;
"#,
),
ctx.stmt(),
);
print_ast(
new_token_input(
r#"
(if (true) {x} else {y}) = x + x;
"#,
),
ctx.stmt(),
);
}
#[test]
fn parse_if_expr() {
let ctx = crate::ParserCtx::new();

View file

@ -164,7 +164,15 @@ impl PrettyPrint {
mutable,
name,
var_type,
} => todo!(),
} => {
self.push_line(format!(
"{} [{} {}: {}]",
node_name(node),
name,
mutable.then_some(" mut").unwrap_or(""),
var_type.map_or("?".to_string(), |ty| format!("{ty}"))
));
}
AstNode::Assignment { dest, expr } => {
self.push_line(format!("{}", node_name(node),));
self.indents.push(Indent::Vertical);
@ -174,7 +182,7 @@ impl PrettyPrint {
});
*self.indents.last_mut().unwrap() = Indent::End;
self.push_line("EXPR".to_string());
self.with_indent(core::iter::once(*dest), |this, idx| {
self.with_indent(core::iter::once(*expr), |this, idx| {
this.stuff(ast, idx);
});
self.indents.pop();
@ -182,8 +190,13 @@ impl PrettyPrint {
AstNode::GlobalDecl {
name,
var_type,
expr: value,
} => todo!(),
expr,
} => {
self.push_line(format!("{} [{}: {}]", node_name(node), name, var_type));
self.with_indent(core::iter::once(*expr), |this, idx| {
this.stuff(ast, idx);
});
}
AstNode::StructDecl { name, fields } => todo!(),
AstNode::FieldDecl { name, field_type } => todo!(),
AstNode::FieldAccess { expr, field } => todo!(),
@ -350,8 +363,8 @@ fn node_name(node: &AstNode) -> &'static str {
AstNode::ExplicitCast { .. } => "AS",
AstNode::Deref { .. } => "DEREF",
AstNode::AddressOf { .. } => "ADDR_OF",
AstNode::PlaceToValue { .. } => "INTO_PLACE",
AstNode::ValueToPlace { .. } => "INTO_VALUE",
AstNode::PlaceToValue { .. } => "INTO_VALUE",
AstNode::ValueToPlace { .. } => "INTO_PLACE",
AstNode::CallExpr { .. } => "CALL",
AstNode::Argument { .. } => "ARG",
AstNode::Not(_) => "NOT",