bool, functions, some more tests

This commit is contained in:
LunarAkai 2025-08-09 20:33:31 +02:00
commit 4f8ca415aa
3 changed files with 131 additions and 30 deletions

View file

@ -15,7 +15,7 @@ pub enum Expr {
CharLiteral(char), CharLiteral(char),
CalExpr(Call), CallExpr(Call),
UnaryExpr(Unary), UnaryExpr(Unary),

View file

@ -97,10 +97,10 @@ pub struct Condition {
pub else_body: Option<BlockStatement>, pub else_body: Option<BlockStatement>,
} }
/// Example: `x = 5` /// Example: `x = y`
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct Assignment { pub struct Assignment {
pub target: Box<Expr>, pub target: String,
pub value: Box<Expr>, pub value: Box<Expr>,
} }
@ -119,7 +119,7 @@ pub struct Unary {
pub operand: Box<Expr>, pub operand: Box<Expr>,
} }
/// Example: `x++` /// Example: `1 + 1`
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct Binary { pub struct Binary {
pub lhs: Box<Expr>, pub lhs: Box<Expr>,
@ -144,11 +144,11 @@ pub struct Binary {
///``` ///```
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct Function { pub struct Function {
pub name: Rc<str>, pub name: String,
pub params: Vec<(Ident, Type)>, pub params: Option<Vec<(Ident, Type)>>,
pub return_type: Option<Type>, pub return_type: Option<Type>,
pub body: Vec<Statement>, pub body: Option<Vec<Expr>>,
pub body_expr: Option<Type>, pub body_expr: Option<Box<Expr>>,
} }
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]

View file

@ -1,7 +1,7 @@
use chumsky::{ use chumsky::{
Boxed, ConfigIterParser, IterParser, ParseResult, Parser, Boxed, ConfigIterParser, IterParser, ParseResult, Parser,
combinator::Or, combinator::Or,
error::Rich, error::{Rich, Simple},
extra, extra,
input::{Input, Stream, ValueInput}, input::{Input, Stream, ValueInput},
prelude::{choice, end, just, nested_delimiters, recursive, skip_then_retry_until, via_parser}, prelude::{choice, end, just, nested_delimiters, recursive, skip_then_retry_until, via_parser},
@ -43,27 +43,21 @@ fn parser<'src, I>() -> impl Parser<'src, I, Vec<Expr>, extra::Err<Rich<'src, To
where where
I: ValueInput<'src, Token = Token, Span = SimpleSpan>, I: ValueInput<'src, Token = Token, Span = SimpleSpan>,
{ {
let ident = select! { Token::Identifier(s) => s, }; let ident = select! { Token::Identifier(s) => s, }.labelled("identifier");
/*
let block = recursive(|block| {
let indent = just(Token::NewLine)
.ignore_then(just(Token::Indent))
.ignore_then(block.clone().separated_by(just(Token::NewLine)).at_least(1))
.then_ignore(just(Token::Dedent));
block.with_ctx(0)
});
*/
let expr = recursive(|expr| { let expr = recursive(|expr| {
let atom = select! { let atom = select! {
Token::FloatLiteral(x) => Expr::FloatLiteral(x), Token::FloatLiteral(x) => Expr::FloatLiteral(x),
Token::IntLiteral(x) => Expr::IntLiteral(x), Token::IntLiteral(x) => Expr::IntLiteral(x),
Token::BoolLiteral(x) => Expr::BoolLiteral(x),
Token::StringLiteral(s) => Expr::StringLiteral(s),
} }
.labelled("value")
.or(expr .or(expr
.clone() .clone()
.delimited_by(just(Token::LParen), just(Token::RParen))); .delimited_by(just(Token::LParen), just(Token::RParen)));
// Product
let mul_div = atom.clone().foldl( let mul_div = atom.clone().foldl(
choice(( choice((
just(Token::Multiply).to(BinaryOp::Multiply), just(Token::Multiply).to(BinaryOp::Multiply),
@ -81,6 +75,7 @@ where
}, },
); );
// Sum
let add_sub = mul_div.clone().foldl( let add_sub = mul_div.clone().foldl(
choice(( choice((
just(Token::Add).to(BinaryOp::Add), just(Token::Add).to(BinaryOp::Add),
@ -98,8 +93,19 @@ where
}, },
); );
add_sub let assign_expr = ident
.then_ignore(just(Token::Assign))
.then(expr.clone())
.map(|(name, value)| {
Expr::AssignmentExpr(Assignment {
target: name,
value: Box::new(value),
})
}); });
assign_expr.or(add_sub)
});
let decl = recursive(|decl| { let decl = recursive(|decl| {
let var = just(Token::Var) let var = just(Token::Var)
.ignore_then(ident) .ignore_then(ident)
@ -113,19 +119,33 @@ where
value: Box::new(rhs), value: Box::new(rhs),
}) })
}); });
/*
let fun = just(Token::Fun) let fun = just(Token::Fun)
.ignore_then(ident.clone()) .ignore_then(ident.clone())
.then_ignore(just(Token::LParen)) .then_ignore(just(Token::LParen))
//.then(param_parser().separated_by(just(Token::Comma)).or_not().map(|p| p.unwrap_or_default()))
.then_ignore(just(Token::RParen)) .then_ignore(just(Token::RParen))
.map(|(((name, args), ret), (body, body_expr))| Expr::Function(Function { .then(
just(Token::LBrace)
.then_ignore(just(Token::NewLine).or_not())
.ignore_then(decl.clone().repeated())
.then_ignore(just(Token::RBrace))
.map(|stmts| (Some(stmts), None))
.or(just(Token::Return)
.ignore_then(expr.clone())
.map(|e| (None, Some(e)))),
)
.then_ignore(just(Token::NewLine).or_not())
.map(|(name, (body, body_expr))| {
Expr::FunctionExpr(Function {
name, name,
params: args, params: None,
return_type: ret, return_type: None,
body, body: None,
body_expr body_expr: None,
})); */ })
var.or(expr) });
var.or(fun).or(expr)
}); });
decl.repeated().collect() decl.repeated().collect()
@ -148,6 +168,20 @@ mod tests {
) )
} }
#[test]
fn test_bool() {
let var_bool = parse("var isUwU = true");
assert!(var_bool.is_ok());
assert_eq!(
var_bool.clone().unwrap(),
vec![Expr::VarExpr(Var {
ty: None,
ident: String::from("isUwU"),
value: Box::new(Expr::BoolLiteral(true))
})]
)
}
#[test] #[test]
fn test_binary_expr() { fn test_binary_expr() {
let sum = parse("1 + 2"); let sum = parse("1 + 2");
@ -175,4 +209,71 @@ mod tests {
})] })]
) )
} }
#[test]
fn test_assignment() {
let assign = parse("x = 12");
assert!(assign.is_ok());
assert_eq!(
assign.clone().unwrap(),
vec![Expr::AssignmentExpr(Assignment {
target: String::from("x"),
value: Box::new(Expr::IntLiteral(12))
})]
)
}
#[test]
fn test_function_decl() {
let empty_fun = parse("fun helloWorld() { }");
assert!(empty_fun.is_ok());
assert_eq!(
empty_fun.clone().unwrap(),
vec![Expr::FunctionExpr(Function {
name: String::from("helloWorld"),
params: None,
return_type: None,
body: None,
body_expr: None,
})]
);
let empty_fun_with_new_lines = parse(
r"fun emptyMulLines() {
}
",
);
assert_eq!(
empty_fun_with_new_lines.clone().unwrap(),
vec![Expr::FunctionExpr(Function {
name: String::from("emptyMulLines"),
params: None,
return_type: None,
body: None,
body_expr: None,
})]
);
let fun_that_returns_int = parse(
r"fun returnsInt(): int {
-> 12
}
",
);
assert_eq!(
empty_fun_with_new_lines.clone().unwrap(),
vec![Expr::FunctionExpr(Function {
name: String::from("returnsInt"),
params: None,
return_type: Some(Type::Integer),
body: None,
body_expr: Some(Box::new(Expr::IntLiteral(12))),
})]
)
}
} }
/*
var x = 10\nvar y = 5\n{\n var z = 7\n}\n10 + 10\n10 - 5\n5 * 5\n10 / 2
*/