diff --git a/src/compiler.rs b/src/compiler.rs index 7091a9a..136aed5 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -41,7 +41,7 @@ pub fn build() { let ast = match parser::parse(&source) { Ok(ast) => { - println!(" ✓ parsed {} items", ast.statements.len()); + println!(" ✓ parsed {} items", ast.len()); ast } Err(e) => { @@ -52,7 +52,8 @@ pub fn build() { println!(" → generating Go code..."); - let output = gogen::generate(&ast); + // let output = gogen::generate(&ast); + let output = String::from("// TODO: implement code generation\n"); // 4. ensure build dir if let Err(e) = fs::create_dir_all(&out_dir) { diff --git a/src/gogen/mod.rs b/src/gogen/mod.rs index 4402e36..d41f710 100644 --- a/src/gogen/mod.rs +++ b/src/gogen/mod.rs @@ -1,283 +1,283 @@ -use crate::parser::ast::{ - BinOperator, Class, Expression, Function, Program, Statement, Struct, TopLevel, TypeExpr, -}; +// use crate::parser::ast::{ +// BinOperator, Class, Expression, Function, Statement, Struct, TopLevel, TopLevel, TypeExpr, +// }; -pub fn generate(program: &Program) -> String { - let mut out = String::new(); +// pub fn generate(program: &TopLevel) -> String { +// let mut out = String::new(); - out.push_str("package main\n\n"); +// out.push_str("package main\n\n"); - // imports - let mut imports = vec![]; - for item in &program.statements { - if let TopLevel::Import(i) = item { - imports.push(i.path.clone()); - } - } +// // imports +// let mut imports = vec![]; +// for item in &program.statements { +// if let TopLevel::Import(i) = item { +// imports.push(i.path.clone()); +// } +// } - if !imports.is_empty() { - out.push_str("import (\n"); - for imp in imports { - out.push_str(&format!(" {}\n", imp)); - } - out.push_str(")\n\n"); - } +// if !imports.is_empty() { +// out.push_str("import (\n"); +// for imp in imports { +// out.push_str(&format!(" {}\n", imp)); +// } +// out.push_str(")\n\n"); +// } - // rest - for item in &program.statements { - match item { - TopLevel::Function(f) => out.push_str(&gen_function(f)), - TopLevel::Struct(s) => out.push_str(&gen_struct(s)), - TopLevel::Class(c) => out.push_str(&gen_class(c)), - TopLevel::Import(_) => {} - } - out.push('\n'); - } +// // rest +// for item in &program.statements { +// match item { +// TopLevel::Function(f) => out.push_str(&gen_function(f)), +// TopLevel::Struct(s) => out.push_str(&gen_struct(s)), +// TopLevel::Class(c) => out.push_str(&gen_class(c)), +// TopLevel::Import(_) => {} +// } +// out.push('\n'); +// } - out -} +// out +// } -fn gen_struct(s: &Struct) -> String { - let mut out = format!("type {} struct {{\n", s.name); +// fn gen_struct(s: &Struct) -> String { +// let mut out = format!("type {} struct {{\n", s.name); - for field in &s.fields { - out.push_str(&format!( - " {} {}\n", - capitalize(&field.name), - gen_type(&field.type_expr) - )); - } +// for field in &s.fields { +// out.push_str(&format!( +// " {} {}\n", +// capitalize(&field.name), +// gen_type(&field.type_expr) +// )); +// } - out.push_str("}\n"); - out -} +// out.push_str("}\n"); +// out +// } -fn gen_class(c: &Class) -> String { - let mut out = String::new(); +// fn gen_class(c: &Class) -> String { +// let mut out = String::new(); - // struct - out.push_str(&format!("type {} struct {{\n", c.name)); - for field in &c.fields { - out.push_str(&format!( - " {} {}\n", - capitalize(&field.name), - gen_type(&field.type_expr) - )); - } - out.push_str("}\n\n"); +// // struct +// out.push_str(&format!("type {} struct {{\n", c.name)); +// for field in &c.fields { +// out.push_str(&format!( +// " {} {}\n", +// capitalize(&field.name), +// gen_type(&field.type_expr) +// )); +// } +// out.push_str("}\n\n"); - // methods - for method in &c.methods { - out.push_str(&gen_method(c, method)); - out.push('\n'); - } +// // methods +// for method in &c.methods { +// out.push_str(&gen_method(c, method)); +// out.push('\n'); +// } - out -} +// out +// } -fn gen_function(f: &Function) -> String { - let mut out = format!("func {}(", f.name); +// fn gen_function(f: &Function) -> String { +// let mut out = format!("func {}(", f.name); - // params - for (i, p) in f.params.iter().enumerate() { - if i > 0 { - out.push_str(", "); - } - out.push_str(&format!("{} {}", p.name, gen_type(&p.type_expr))); - } +// // params +// for (i, p) in f.params.iter().enumerate() { +// if i > 0 { +// out.push_str(", "); +// } +// out.push_str(&format!("{} {}", p.name, gen_type(&p.type_expr))); +// } - out.push(')'); +// out.push(')'); - // return - if let Some(ret) = &f.return_type { - out.push_str(&format!(" {}", gen_type(ret))); - } +// // return +// if let Some(ret) = &f.return_type { +// out.push_str(&format!(" {}", gen_type(ret))); +// } - out.push_str(" {\n"); +// out.push_str(" {\n"); - for stmt in &f.body { - out.push_str(&gen_statement(stmt)); - } +// for stmt in &f.body { +// out.push_str(&gen_statement(stmt)); +// } - out.push_str("}\n"); - out -} +// out.push_str("}\n"); +// out +// } -fn gen_method(class: &Class, f: &Function) -> String { - let mut out = format!("func (self *{}) {}(", class.name, f.name); +// fn gen_method(class: &Class, f: &Function) -> String { +// let mut out = format!("func (self *{}) {}(", class.name, f.name); - for (i, p) in f.params.iter().enumerate() { - if i > 0 { - out.push_str(", "); - } - out.push_str(&format!("{} {}", p.name, gen_type(&p.type_expr))); - } +// for (i, p) in f.params.iter().enumerate() { +// if i > 0 { +// out.push_str(", "); +// } +// out.push_str(&format!("{} {}", p.name, gen_type(&p.type_expr))); +// } - out.push(')'); +// out.push(')'); - if let Some(ret) = &f.return_type { - out.push_str(&format!(" {}", gen_type(ret))); - } +// if let Some(ret) = &f.return_type { +// out.push_str(&format!(" {}", gen_type(ret))); +// } - out.push_str(" {\n"); +// out.push_str(" {\n"); - for stmt in &f.body { - out.push_str(&gen_statement(stmt)); - } +// for stmt in &f.body { +// out.push_str(&gen_statement(stmt)); +// } - out.push_str("}\n"); +// out.push_str("}\n"); - out -} +// out +// } -fn gen_statement(stmt: &Statement) -> String { - match stmt { - Statement::Let(s) => { - let mut out = format!(" {} := {}", s.name, gen_expr(&s.value)); +// fn gen_statement(stmt: &Statement) -> String { +// match stmt { +// Statement::Let(s) => { +// let mut out = format!(" {} := {}", s.name, gen_expr(&s.value)); - out.push_str(";\n"); - out - } +// out.push_str(";\n"); +// out +// } - Statement::Return(r) => match &r.value { - Some(v) => format!(" return {};\n", gen_expr(v)), - None => " return;\n".to_string(), - }, +// Statement::Return(r) => match &r.value { +// Some(v) => format!(" return {};\n", gen_expr(v)), +// None => " return;\n".to_string(), +// }, - Statement::Expression(e) => { - format!(" {};\n", gen_expr(e)) - } +// Statement::Expression(e) => { +// format!(" {};\n", gen_expr(e)) +// } - Statement::If(i) => { - let mut out = format!(" if {} {{\n", gen_expr(&i.condition)); +// Statement::If(i) => { +// let mut out = format!(" if {} {{\n", gen_expr(&i.condition)); - for stmt in &i.body { - out.push_str(&gen_statement(stmt)); - } +// for stmt in &i.body { +// out.push_str(&gen_statement(stmt)); +// } - out.push_str(" }"); +// out.push_str(" }"); - if let Some(else_body) = &i.else_body { - out.push_str(" else {\n"); - for stmt in else_body { - out.push_str(&gen_statement(stmt)); - } - out.push_str(" }"); - } +// if let Some(else_body) = &i.else_body { +// out.push_str(" else {\n"); +// for stmt in else_body { +// out.push_str(&gen_statement(stmt)); +// } +// out.push_str(" }"); +// } - out.push('\n'); - out - } +// out.push('\n'); +// out +// } - Statement::For(f) => { - let mut out = format!( - " for _, {} := range {} {{\n", - f.var, - gen_expr(&f.iterator) - ); +// Statement::For(f) => { +// let mut out = format!( +// " for _, {} := range {} {{\n", +// f.var, +// gen_expr(&f.iterator) +// ); - for stmt in &f.body { - out.push_str(&gen_statement(stmt)); - } +// for stmt in &f.body { +// out.push_str(&gen_statement(stmt)); +// } - out.push_str(" }\n"); - out - } - } -} +// out.push_str(" }\n"); +// out +// } +// } +// } -fn gen_expr(expr: &Expression) -> String { - match expr { - Expression::Identifier(name, _) => name.clone(), - Expression::Integer(v, _) => v.to_string(), - Expression::Float(v, _) => v.to_string(), - Expression::StringLit(s, _) => format!("\"{}\"", s), - Expression::Bool(b, _) => b.to_string(), +// fn gen_expr(expr: &Expression) -> String { +// match expr { +// Expression::Identifier(name, _) => name.clone(), +// Expression::Integer(v, _) => v.to_string(), +// Expression::Float(v, _) => v.to_string(), +// Expression::StringLit(s, _) => format!("\"{}\"", s), +// Expression::Bool(b, _) => b.to_string(), - Expression::BinaryOp(b) => format!( - "{} {} {}", - gen_expr(&b.left), - op_to_str(&b.op), - gen_expr(&b.right) - ), +// Expression::BinaryOp(b) => format!( +// "{} {} {}", +// gen_expr(&b.left), +// op_to_str(&b.op), +// gen_expr(&b.right) +// ), - Expression::Call(c) => { - let args = c.args.iter().map(gen_expr).collect::>().join(", "); - format!("{}({})", gen_expr(&c.callee), args) - } +// Expression::Call(c) => { +// let args = c.args.iter().map(gen_expr).collect::>().join(", "); +// format!("{}({})", gen_expr(&c.callee), args) +// } - Expression::FieldAccess(f) => { - format!("{}.{}", gen_expr(&f.object), capitalize(&f.field)) - } +// Expression::FieldAccess(f) => { +// format!("{}.{}", gen_expr(&f.object), capitalize(&f.field)) +// } - Expression::StructInit(s) => { - let mut out = format!("{}{{", s.name); +// Expression::StructInit(s) => { +// let mut out = format!("{}{{", s.name); - for (i, (name, val)) in s.fields.iter().enumerate() { - if i > 0 { - out.push_str(", "); - } - out.push_str(&format!("{}: {}", capitalize(name), gen_expr(val))); - } +// for (i, (name, val)) in s.fields.iter().enumerate() { +// if i > 0 { +// out.push_str(", "); +// } +// out.push_str(&format!("{}: {}", capitalize(name), gen_expr(val))); +// } - out.push('}'); - out - } +// out.push('}'); +// out +// } - Expression::ArrayLiteral(arr) => { - let elems = arr - .elements - .iter() - .map(gen_expr) - .collect::>() - .join(", "); - format!("[]any{{{}}}", elems) // simple version - } +// Expression::ArrayLiteral(arr) => { +// let elems = arr +// .elements +// .iter() +// .map(gen_expr) +// .collect::>() +// .join(", "); +// format!("[]any{{{}}}", elems) // simple version +// } - _ => todo!(), - } -} +// _ => todo!(), +// } +// } -fn gen_type(t: &TypeExpr) -> String { - match t { - TypeExpr::Named(n) => match n.as_str() { - "int" => "int".into(), - "float" => "float64".into(), - "string" => "string".into(), - _ => n.clone(), - }, +// fn gen_type(t: &TypeExpr) -> String { +// match t { +// TypeExpr::Named(n) => match n.as_str() { +// "int" => "int".into(), +// "float" => "float64".into(), +// "string" => "string".into(), +// _ => n.clone(), +// }, - TypeExpr::Array(inner) => { - format!("[]{}", gen_type(inner)) - } +// TypeExpr::Array(inner) => { +// format!("[]{}", gen_type(inner)) +// } - TypeExpr::Optional(inner) => { - format!("*{}", gen_type(inner)) // pointer for optional - } - } -} +// TypeExpr::Optional(inner) => { +// format!("*{}", gen_type(inner)) // pointer for optional +// } +// } +// } -fn capitalize(s: &str) -> String { - let mut chars = s.chars(); - match chars.next() { - Some(c) => c.to_uppercase().collect::() + chars.as_str(), - None => String::new(), - } -} +// fn capitalize(s: &str) -> String { +// let mut chars = s.chars(); +// match chars.next() { +// Some(c) => c.to_uppercase().collect::() + chars.as_str(), +// None => String::new(), +// } +// } -fn op_to_str(op: &BinOperator) -> &'static str { - match op { - BinOperator::Add => "+", - BinOperator::Sub => "-", - BinOperator::Mul => "*", - BinOperator::Div => "/", - BinOperator::Eq => "==", - BinOperator::NotEq => "!=", - BinOperator::Lt => "<", - BinOperator::Gt => ">", - BinOperator::LtEq => "<=", - BinOperator::GtEq => ">=", - BinOperator::And => "&&", - BinOperator::Or => "||", - } -} +// fn op_to_str(op: &BinOperator) -> &'static str { +// match op { +// BinOperator::Add => "+", +// BinOperator::Sub => "-", +// BinOperator::Mul => "*", +// BinOperator::Div => "/", +// BinOperator::Eq => "==", +// BinOperator::NotEq => "!=", +// BinOperator::Lt => "<", +// BinOperator::Gt => ">", +// BinOperator::LtEq => "<=", +// BinOperator::GtEq => ">=", +// BinOperator::And => "&&", +// BinOperator::Or => "||", +// } +// } diff --git a/src/parser/ast.rs b/src/parser/ast.rs index 057fac0..e0de358 100644 --- a/src/parser/ast.rs +++ b/src/parser/ast.rs @@ -1,187 +1,32 @@ #[derive(Debug, Clone)] -pub struct Span { - pub start: usize, - pub end: usize, -} - -#[derive(Debug, Clone)] -pub struct Program { - pub statements: Vec, +pub enum TypeExpr { + Identifier(String), } #[derive(Debug, Clone)] pub enum TopLevel { - Function(Function), - Struct(Struct), - Class(Class), - Import(Import), -} - -#[derive(Debug, Clone)] -pub struct Function { - pub name: String, - pub params: Vec, - pub return_type: Option, - pub body: Vec, - pub span: Span, -} - -#[derive(Debug, Clone)] -pub struct Param { - pub name: String, - pub type_expr: TypeExpr, - pub span: Span, -} - -#[derive(Debug, Clone)] -pub struct Struct { - pub name: String, - pub fields: Vec, - pub span: Span, -} - -#[derive(Debug, Clone)] -pub struct StructField { - pub name: String, - pub type_expr: TypeExpr, - pub span: Span, -} - -#[derive(Debug, Clone)] -pub struct Class { - pub name: String, - pub fields: Vec, - pub methods: Vec, - pub span: Span, -} - -#[derive(Debug, Clone)] -pub struct Import { - pub path: String, - pub span: Span, + Import(String), + StructDecl { + name: String, + fields: Vec<(String, TypeExpr)>, + }, + FunctionDecl { + name: String, + params: Vec<(String, TypeExpr)>, + return_type: Option, + body: Vec, + }, } #[derive(Debug, Clone)] pub enum Statement { - Let(LetStatement), - Return(ReturnStatement), - Expression(Expression), - If(IfStatement), - For(ForStatement), + Expression(String), } -#[derive(Debug, Clone)] -pub struct LetStatement { - pub name: String, - pub type_expr: Option, - pub value: Expression, - pub span: Span, -} - -#[derive(Debug, Clone)] -pub struct ReturnStatement { - pub value: Option, - pub span: Span, -} - -#[derive(Debug, Clone)] -pub struct IfStatement { - pub condition: Expression, - pub body: Vec, - pub else_body: Option>, - pub span: Span, -} - -#[derive(Debug, Clone)] -pub struct ForStatement { - pub var: String, - pub iterator: Expression, - pub body: Vec, - pub span: Span, -} - -#[derive(Debug, Clone)] pub enum Expression { - Identifier(String, Span), - Integer(i64, Span), - Float(f64, Span), - StringLit(String, Span), - Bool(bool, Span), - BinaryOp(Box), - UnaryOp(Box), - Call(Box), - FieldAccess(Box), - StructInit(Box), - ArrayLiteral(Box), -} - -#[derive(Debug, Clone)] -pub struct BinaryOp { - pub left: Expression, - pub op: BinOperator, - pub right: Expression, - pub span: Span, -} - -#[derive(Debug, Clone)] -pub enum BinOperator { - Add, - Sub, - Mul, - Div, - Eq, - NotEq, - Lt, - Gt, - LtEq, - GtEq, - And, - Or, -} - -#[derive(Debug, Clone)] -pub struct UnaryOp { - pub op: UnaryOperator, - pub expr: Expression, - pub span: Span, -} - -#[derive(Debug, Clone)] -pub enum UnaryOperator { - Neg, - Not, -} - -#[derive(Debug, Clone)] -pub struct CallExpr { - pub callee: Expression, - pub args: Vec, - pub span: Span, -} - -#[derive(Debug, Clone)] -pub struct FieldAccess { - pub object: Expression, - pub field: String, - pub span: Span, -} - -#[derive(Debug, Clone)] -pub struct StructInit { - pub name: String, - pub fields: Vec<(String, Expression)>, - pub span: Span, -} - -#[derive(Debug, Clone)] -pub enum TypeExpr { - Named(String), - Array(Box), - Optional(Box), -} - -#[derive(Debug, Clone)] -pub struct ArrayLiteral { - pub elements: Vec, - pub span: Span, + Identifier(String), + IntLiteral(i64), + FloatLiteral(f64), + BoolLiteral(bool), + StringLiteral(String), } diff --git a/src/parser/grammar.pest b/src/parser/grammar.pest index 8a59ca2..b8c4418 100644 --- a/src/parser/grammar.pest +++ b/src/parser/grammar.pest @@ -2,7 +2,7 @@ WHITESPACE = _{ " " | "\t" | "\r" | "\n" } COMMENT = _{ "//" ~ (!"\n" ~ ANY)* } program = { SOI ~ item* ~ EOI } -item = _{ import_decl | function_decl | struct_decl | class_decl } +item = _{ import_decl | function_decl | struct_decl } // primitives identifier = @{ (ASCII_ALPHA | "_") ~ (ASCII_ALPHANUMERIC | "_")* } @@ -12,152 +12,26 @@ boolean = { "true" | "false" } string_lit = { "\"" ~ inner_str ~ "\"" } inner_str = @{ (!"\"" ~ ANY)* } -// ================= TYPE SCRIPT STYLE CHANGES ================= +// ================= TOP LEVEL ================= -// import becomes TS-like (still identical structure) import_decl = { "import" ~ string_lit ~ ";" } -// struct stays, but feels like TS "type object shape" -struct_decl = { +struct_field = { identifier ~ ":" ~ type_expr ~ ";" } +struct_decl = { "struct" ~ identifier ~ "{" ~ struct_field* ~ "}" } -// class already TS-like — just improved consistency -class_decl = { - "class" ~ identifier ~ "{" ~ class_member* ~ "}" -} - -class_member = _{ struct_field | function_decl } - -// function keyword changed feel: fn → function +param_list = { param ~ ("," ~ param)* ~ ","? } +param = { identifier ~ ":" ~ type_expr } function_decl = { "function" ~ identifier ~ "(" ~ param_list? ~ ")" ~ ("->" ~ type_expr)? ~ block } -// struct fields: TS-style semicolon consistency (already good) -struct_field = { identifier ~ ":" ~ type_expr ~ ";" } - -// params: TS optional typing style feel (unchanged structure) -param_list = { param ~ ("," ~ param)* ~ ","? } -param = { identifier ~ ":" ~ type_expr } - // ================= STATEMENTS ================= block = { "{" ~ statement* ~ "}" } -statement = _{ - let_stmt - | return_stmt - | if_stmt - | for_stmt - | assign_stmt - | expression_stmt -} - -// expression statements: TS allows no semicolon in real life, -// but we keep your structure -expression_stmt = { expression ~ ";" } - -// assignment unchanged (JS/TS feel already) -assign_stmt = { identifier ~ "=" ~ expression ~ ";" } - -// let → const/let feel (still your rule, just TS naming) -let_stmt = { - "const" ~ identifier ~ (":" ~ type_expr)? ~ "=" ~ expression ~ ";" -} - -// return: TS-like (no change except feel consistency) -return_stmt = { "return" ~ expression? ~ ";" } - -// if: add TS-style parentheses (MAJOR feel upgrade, same structure) -if_stmt = { - "if" ~ "(" ~ expression ~ ")" ~ block ~ ("else" ~ block)? -} - -// for: TS-like "of" -for_stmt = { - "for" ~ identifier ~ "of" ~ expression ~ block -} - -// ================= TYPES (KEEP STRUCTURE, TS FEEL) ================= - -type_expr = { base_type ~ "?"? } -base_type = _{ array_type | identifier } -array_type = { "[" ~ type_expr ~ "]" } +statement = _{ "idk" } // ================= EXPRESSIONS ================= - -expression = { term ~ (bin_op ~ term)* } - -bin_op = _{ - eq - | neq - | lte - | gte - | lt - | gt - | and - | or - | add - | sub - | mul - | div -} - -add = { "+" } -sub = { "-" } -mul = { "*" } -div = { "/" } -eq = { "==" } -neq = { "!=" } -lte = { "<=" } -gte = { ">=" } -lt = { "<" } -gt = { ">" } -and = { "&&" } -or = { "||" } - -// ================= LITERALS ================= - -struct_literal = { - identifier ~ "{" ~ struct_init_list? ~ "}" -} - -struct_init_list = { - struct_init_field ~ ("," ~ struct_init_field)* ~ ","? -} - -struct_init_field = { - identifier ~ ":" ~ expression -} - -array_literal = { - "[" ~ (expression ~ ("," ~ expression)*)? ~ ","? ~ "]" -} - -// ================= CHAINING ================= - -term = { primary ~ (field_access | call_suffix)* } - -field_access = { "." ~ identifier } - -call_suffix = { - "(" ~ (expression ~ ("," ~ expression)*)? ~ ","? ~ ")" -} - -// ================= PRIMARY ================= - -primary = _{ - struct_literal - | array_literal - | float - | integer - | string_lit - | boolean - | self_kw - | null_kw - | identifier -} - -self_kw = { "this" } -null_kw = { "null" } +type_expr = _{ identifier } diff --git a/src/parser/mod.rs b/src/parser/mod.rs index a8ad54b..faaa5e7 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -1,5 +1,4 @@ use pest::Parser; -use pest::iterators::Pair; use pest_derive::Parser; pub mod ast; @@ -12,7 +11,7 @@ pub struct MistParser; // convenience alias for pest errors pub type ParseError = pest::error::Error; -pub fn parse(source: &str) -> Result { +pub fn parse(source: &str) -> Result, ParseError> { let pairs = MistParser::parse(Rule::program, source)?; let mut statements = vec![]; @@ -24,12 +23,10 @@ pub fn parse(source: &str) -> Result { Rule::program => { for inner in pair.into_inner() { match inner.as_rule() { - Rule::function_decl => { - statements.push(TopLevel::Function(parse_function(inner))) + Rule::import_decl => { + let path = inner.into_inner().next().unwrap().as_str().to_string(); + statements.push(TopLevel::Import(path)); } - Rule::struct_decl => statements.push(TopLevel::Struct(parse_struct(inner))), - Rule::class_decl => statements.push(TopLevel::Class(parse_class(inner))), - Rule::import_decl => statements.push(TopLevel::Import(parse_import(inner))), Rule::EOI => {} _ => {} } @@ -40,324 +37,5 @@ pub fn parse(source: &str) -> Result { } } - Ok(Program { statements }) -} - -fn span_of(pair: &Pair) -> Span { - let s = pair.as_span(); - Span { - start: s.start(), - end: s.end(), - } -} - -fn parse_function(pair: Pair) -> Function { - let span = span_of(&pair); - let mut inner = pair.into_inner(); - - let name = inner.next().unwrap().as_str().to_string(); - - let mut params = vec![]; - let mut return_type = None; - let mut body = vec![]; - - for part in inner { - match part.as_rule() { - Rule::param_list => params = parse_param_list(part), - Rule::type_expr => return_type = Some(parse_type_expr(part)), - Rule::block => body = parse_block(part), - _ => {} - } - } - - Function { - name, - params, - return_type, - body, - span, - } -} - -fn parse_param_list(pair: Pair) -> Vec { - pair.into_inner() - .map(|p| { - let span = span_of(&p); - let mut inner = p.into_inner(); - let name = inner.next().unwrap().as_str().to_string(); - let type_expr = parse_type_expr(inner.next().unwrap()); - Param { - name, - type_expr, - span, - } - }) - .collect() -} - -fn parse_struct(pair: Pair) -> Struct { - let span = span_of(&pair); - let mut inner = pair.into_inner(); - let name = inner.next().unwrap().as_str().to_string(); - let fields = inner.map(|f| parse_struct_field(f)).collect(); - Struct { name, fields, span } -} - -fn parse_struct_field(pair: Pair) -> StructField { - let span = span_of(&pair); - let mut inner = pair.into_inner(); - let name = inner.next().unwrap().as_str().to_string(); - let type_expr = parse_type_expr(inner.next().unwrap()); - StructField { - name, - type_expr, - span, - } -} - -fn parse_class(pair: Pair) -> Class { - let span = span_of(&pair); - let mut inner = pair.into_inner(); - let name = inner.next().unwrap().as_str().to_string(); - let mut fields = vec![]; - let mut methods = vec![]; - - for part in inner { - match part.as_rule() { - Rule::struct_field => fields.push(parse_struct_field(part)), - Rule::function_decl => methods.push(parse_function(part)), - _ => {} - } - } - - Class { - name, - fields, - methods, - span, - } -} - -fn parse_import(pair: Pair) -> Import { - let span = span_of(&pair); - let path = pair.into_inner().next().unwrap().as_str().to_string(); - Import { path, span } -} - -fn parse_block(pair: Pair) -> Vec { - pair.into_inner() - .filter_map(|p| parse_statement(p)) - .collect() -} - -fn parse_statement(pair: Pair) -> Option { - match pair.as_rule() { - Rule::let_stmt => Some(Statement::Let(parse_let(pair))), - Rule::return_stmt => Some(Statement::Return(parse_return(pair))), - Rule::if_stmt => Some(Statement::If(parse_if(pair))), - Rule::for_stmt => Some(Statement::For(parse_for(pair))), - Rule::expression_stmt => { - let expr = pair.into_inner().next().unwrap(); - Some(Statement::Expression(parse_expression(expr))) - } - Rule::expression => Some(Statement::Expression(parse_expression(pair))), - _ => None, - } -} - -fn parse_let(pair: Pair) -> LetStatement { - let span = span_of(&pair); - let mut inner = pair.into_inner(); - let name = inner.next().unwrap().as_str().to_string(); - - // peek ahead — next is either a type or an expression - let next = inner.next().unwrap(); - let (type_expr, value) = if next.as_rule() == Rule::type_expr { - ( - Some(parse_type_expr(next)), - parse_expression(inner.next().unwrap()), - ) - } else { - (None, parse_expression(next)) - }; - - LetStatement { - name, - type_expr, - value, - span, - } -} - -fn parse_return(pair: Pair) -> ReturnStatement { - let span = span_of(&pair); - let value = pair.into_inner().next().map(|p| parse_expression(p)); - ReturnStatement { value, span } -} - -fn parse_if(pair: Pair) -> IfStatement { - let span = span_of(&pair); - let mut inner = pair.into_inner(); - let condition = parse_expression(inner.next().unwrap()); - let body = parse_block(inner.next().unwrap()); - let else_body = inner.next().map(|p| parse_block(p)); - IfStatement { - condition, - body, - else_body, - span, - } -} - -fn parse_for(pair: Pair) -> ForStatement { - let span = span_of(&pair); - let mut inner = pair.into_inner(); - let var = inner.next().unwrap().as_str().to_string(); - let iterator = parse_expression(inner.next().unwrap()); - let body = parse_block(inner.next().unwrap()); - ForStatement { - var, - iterator, - body, - span, - } -} - -fn parse_expression(pair: Pair) -> Expression { - match pair.as_rule() { - Rule::expression => { - let mut inner = pair.into_inner(); - let mut expr = parse_term(inner.next().unwrap()); - - // consume pairs of (bin_op, term) - while let Some(op_pair) = inner.next() { - let right = parse_term(inner.next().unwrap()); - let span = span_of(&op_pair); - let op = match op_pair.as_rule() { - Rule::add => BinOperator::Add, - Rule::sub => BinOperator::Sub, - Rule::mul => BinOperator::Mul, - Rule::div => BinOperator::Div, - Rule::eq => BinOperator::Eq, - Rule::neq => BinOperator::NotEq, - Rule::lt => BinOperator::Lt, - Rule::gt => BinOperator::Gt, - Rule::lte => BinOperator::LtEq, - Rule::gte => BinOperator::GtEq, - Rule::and => BinOperator::And, - Rule::or => BinOperator::Or, - _ => unreachable!(), - }; - expr = Expression::BinaryOp(Box::new(BinaryOp { - left: expr, - op, - right, - span, - })); - } - - expr - } - _ => parse_term(pair), - } -} - -fn parse_term(pair: Pair) -> Expression { - let mut inner = pair.into_inner(); - let mut expr = parse_primary(inner.next().unwrap()); - - for part in inner { - let span = span_of(&part); - match part.as_rule() { - Rule::field_access => { - let field = part.into_inner().next().unwrap().as_str().to_string(); - expr = Expression::FieldAccess(Box::new(FieldAccess { - object: expr, - field, - span, - })); - } - Rule::call_suffix => { - let args = part.into_inner().map(|p| parse_expression(p)).collect(); - expr = Expression::Call(Box::new(CallExpr { - callee: expr, - args, - span, - })); - } - _ => {} - } - } - - expr -} - -fn parse_primary(pair: Pair) -> Expression { - let span = span_of(&pair); - - match pair.as_rule() { - Rule::struct_literal => { - let mut inner = pair.into_inner(); - let name = inner.next().unwrap().as_str().to_string(); - - inner = inner.next().unwrap().into_inner(); - - // println!("{inner:#?}"); - - let mut fields = vec![]; - for field in inner { - let mut f_inner = field.into_inner(); - let field_name = f_inner.next().unwrap().as_str().to_string(); - let value = parse_expression(f_inner.next().unwrap()); - - fields.push((field_name, value)); - } - - Expression::StructInit(Box::new(StructInit { name, fields, span })) - } - - Rule::array_literal => { - let elements = pair.into_inner().map(|p| parse_expression(p)).collect(); - - Expression::ArrayLiteral(Box::new(ArrayLiteral { elements, span })) - } - - Rule::integer => Expression::Integer(pair.as_str().parse().unwrap(), span), - Rule::float => Expression::Float(pair.as_str().parse().unwrap(), span), - - Rule::string_lit => { - Expression::StringLit(pair.into_inner().next().unwrap().as_str().to_string(), span) - } - - Rule::boolean => Expression::Bool(pair.as_str() == "true", span), - - Rule::self_kw => Expression::Identifier("self".to_string(), span), - Rule::null_kw => Expression::Identifier("null".to_string(), span), - Rule::identifier => Expression::Identifier(pair.as_str().to_string(), span), - - Rule::term => parse_term(pair), - - _ => unreachable!("unexpected primary rule: {:?}", pair.as_rule()), - } -} - -fn parse_type_expr(pair: Pair) -> TypeExpr { - let mut inner = pair.into_inner(); - let base = inner.next().unwrap(); - - let base_type = match base.as_rule() { - Rule::array_type => { - let inner_type = parse_type_expr(base.into_inner().next().unwrap()); - TypeExpr::Array(Box::new(inner_type)) - } - Rule::identifier => TypeExpr::Named(base.as_str().to_string()), - _ => unreachable!(), - }; - - // if a "?" suffix was present, wrap in Optional - if inner.next().is_some() { - TypeExpr::Optional(Box::new(base_type)) - } else { - base_type - } + Ok(statements) }