diff --git a/src/parser/ast.rs b/src/parser/ast.rs index 9e63b3b..35bfca5 100644 --- a/src/parser/ast.rs +++ b/src/parser/ast.rs @@ -1,5 +1,11 @@ use serde::Serialize; +#[derive(Debug, Clone, Serialize)] +pub struct ParamList(pub Vec<(String, TypeExpr)>); + +#[derive(Debug, Clone, Serialize)] +pub struct Block(pub Vec); + #[derive(Debug, Clone, Serialize)] #[serde(tag = "type", content = "value")] pub enum TypeExpr { @@ -24,10 +30,55 @@ pub enum TopLevel { }, } +#[derive(Debug, Clone, Serialize)] +#[serde(tag = "type", content = "value")] +pub enum Postfix { + FieldAccess(String), + FunctionCall(Vec), +} + #[derive(Debug, Clone, Serialize)] #[serde(tag = "type", content = "value")] pub enum Statement { + // expr; Expression(Expression), + + // { ... } + Block(Block), + + // let/const/var x = ... + VarDecl { + kind: VarKind, + name: String, + init: Option, + }, + + // if (...) stmt else stmt + If { + condition: Expression, + then_branch: Box, + else_branch: Option>, + }, + + // while (...) stmt + While { + condition: Expression, + body: Box, + }, + + // for (...) stmt + For { + init: Option, + condition: Option, + update: Option, + body: Box, + }, + + // return expr?; + Return(Option), + + Break, + Continue, } #[derive(Debug, Clone, Serialize)] @@ -45,14 +96,18 @@ pub enum Expression { } #[derive(Debug, Clone, Serialize)] -#[serde(tag = "type", content = "value")] -pub enum Postfix { - FieldAccess(String), - FunctionCall(Vec), +pub enum VarKind { + Let, + Const, + Var, } #[derive(Debug, Clone, Serialize)] -pub struct ParamList(pub Vec<(String, TypeExpr)>); - -#[derive(Debug, Clone, Serialize)] -pub struct Block(pub Vec); +pub enum ForInit { + VarDecl { + kind: VarKind, + name: String, + init: Option, + }, + Expr(Expression), +} diff --git a/src/parser/grammar.pest b/src/parser/grammar.pest index 5258991..4723880 100644 --- a/src/parser/grammar.pest +++ b/src/parser/grammar.pest @@ -36,10 +36,56 @@ block = { "{" ~ statement_list ~ "}" } statement_list = { statement* } -statement = _{ expr_stmt } +statement = _{ + expr_stmt + | var_decl + | if_stmt + | while_stmt + | for_stmt + | return_stmt + | break_stmt + | continue_stmt + | block +} + +// --- basic statements --- expr_stmt = { expr ~ ";" } +return_stmt = { "return" ~ expr? ~ ";" } + +break_stmt = { "break" ~ ";" } + +continue_stmt = { "continue" ~ ";" } + +// --- variable declarations --- + +var_decl = { + ("let" | "const" | "var") ~ identifier ~ ("=" ~ expr)? ~ ";" +} + +// --- control flow --- + +if_stmt = { + "if" ~ "(" ~ expr ~ ")" ~ statement ~ ("else" ~ statement)? +} + +while_stmt = { + "while" ~ "(" ~ expr ~ ")" ~ statement +} + +for_stmt = { + "for" ~ "(" ~ (var_decl_no_semicolon | expr_stmt | ";") + ~ expr? ~ ";" + ~ expr? ~ ")" + ~ statement +} + +// helper (same as var_decl but no trailing ;) +var_decl_no_semicolon = { + ("let" | "const" | "var") ~ identifier ~ ("=" ~ expr)? +} + // ================= EXPRESSIONS ================= type_expr = { identifier } diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 60af79d..f5e2e1e 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -154,10 +154,118 @@ impl Statement { let inner = pair.into_inner().next().unwrap(); Statement::from_pair(inner) } + Rule::expr_stmt => { let expr_pair = pair.into_inner().next().unwrap(); Statement::Expression(Expression::from_pair(expr_pair)) } + + Rule::block => Statement::Block(Block::from_pair(pair.into_inner().next().unwrap())), + + Rule::var_decl => { + let mut inner = pair.into_inner(); + + let kind_pair = inner.next().unwrap(); // let/const/var + let name_pair = inner.next().unwrap(); // identifier + + let init = inner.next().map(|expr_pair| { + // expects "=" expr + Expression::from_pair(expr_pair.into_inner().next().unwrap()) + }); + + let kind = match kind_pair.as_str() { + "let" => VarKind::Let, + "const" => VarKind::Const, + "var" => VarKind::Var, + _ => unreachable!(), + }; + + Statement::VarDecl { + kind, + name: name_pair.as_str().to_string(), + init, + } + } + + Rule::return_stmt => { + let mut inner = pair.into_inner(); + + let expr = inner.next().map(Expression::from_pair); + + Statement::Return(expr) + } + + Rule::break_stmt => Statement::Break, + + Rule::continue_stmt => Statement::Continue, + + Rule::if_stmt => { + let mut inner = pair.into_inner(); + + let condition = Expression::from_pair(inner.next().unwrap()); + let then_branch = Statement::from_pair(inner.next().unwrap()); + + let else_branch = inner.next().map(Statement::from_pair); + + Statement::If { + condition, + then_branch: Box::new(then_branch), + else_branch: else_branch.map(Box::new), + } + } + + Rule::while_stmt => { + let mut inner = pair.into_inner(); + + let condition = Expression::from_pair(inner.next().unwrap()); + let body = Statement::from_pair(inner.next().unwrap()); + + Statement::While { + condition, + body: Box::new(body), + } + } + + Rule::for_stmt => { + let mut inner = pair.into_inner(); + + let init = inner.next().map(|p| match p.as_rule() { + Rule::var_decl_no_semicolon => { + let mut it = p.into_inner(); + + let kind = match it.next().unwrap().as_str() { + "let" => VarKind::Let, + "const" => VarKind::Const, + "var" => VarKind::Var, + _ => unreachable!(), + }; + + let name = it.next().unwrap().as_str().to_string(); + let init_expr = it + .next() + .map(|e| Expression::from_pair(e.into_inner().next().unwrap())); + + ForInit::VarDecl { + kind, + name, + init: init_expr, + } + } + _ => ForInit::Expr(Expression::from_pair(p)), + }); + + let condition = inner.next().map(Expression::from_pair); + let update = inner.next().map(Expression::from_pair); + let body = Statement::from_pair(inner.next().unwrap()); + + Statement::For { + init, + condition, + update, + body: Box::new(body), + } + } + _ => unimplemented!( "Statement parsing not implemented yet: {:?}", pair.as_rule() diff --git a/test/src/main.ms b/test/src/main.ms index 2e183dd..77c55b6 100644 --- a/test/src/main.ms +++ b/test/src/main.ms @@ -6,5 +6,7 @@ struct Point { } function add(a: int, b: int): int { - idk.do_something(123, "abc"); + if (x) { + if (y) return 1; + } }