diff --git a/.gitignore b/.gitignore index a2cc1c5..f7f3481 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ target [Cc]argo.lock *.llvm -*.ll \ No newline at end of file +*.ll +# used for debugging. no need to check it in +out.txt diff --git a/Cargo.lock b/Cargo.lock index 0918e8c..8b57922 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -151,8 +151,10 @@ dependencies = [ "lazy_static", "pretty_assertions", "regex", + "take_mut", "thiserror", "utf8-chars", + "winnow", ] [[package]] @@ -400,6 +402,12 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "take_mut" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60" + [[package]] name = "thiserror" version = "1.0.63" @@ -514,6 +522,15 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "winnow" +version = "0.6.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" +dependencies = [ + "memchr", +] + [[package]] name = "yansi" version = "0.5.1" diff --git a/compiler/Cargo.toml b/compiler/Cargo.toml index 7c2d36c..fcee4db 100644 --- a/compiler/Cargo.toml +++ b/compiler/Cargo.toml @@ -17,7 +17,8 @@ regex = "1.6.0" lazy_static = "1.4.0" bimap = "0.6.3" thiserror = "1.0.57" - +winnow = "0.6.18" +take_mut = "0.2.2" [dev-dependencies] -pretty_assertions = "1.4" \ No newline at end of file +pretty_assertions = "1.4" diff --git a/compiler/src/ast.rs b/compiler/src/ast.rs index 9db7b35..c6b4e51 100644 --- a/compiler/src/ast.rs +++ b/compiler/src/ast.rs @@ -140,21 +140,21 @@ impl ModuleDeclaration { let ident = variant.get_ident(); let new_ident = format!("{}::{}", &e.ident, ident); let generics = e - .generics - .as_ref() - .map(|generics| { - generics - .decls - .iter() - .map(|(loc, name)| ResolvedType::Generic { - name: name.clone(), - loc: *loc, - }) - .collect() - }) - .unwrap_or_default(); + .generics + .as_ref() + .map(|generics| { + generics + .decls + .iter() + .map(|(loc, name)| ResolvedType::Generic { + name: name.clone(), + loc: *loc, + }) + .collect() + }) + .unwrap_or_default(); match variant { - EnumVariant::Unit { ident:_, loc } => out.push(( + EnumVariant::Unit { ident: _, loc } => out.push(( new_ident.clone(), ResolvedType::Dependent { base: base_ty.clone().into(), @@ -164,7 +164,7 @@ impl ModuleDeclaration { loc: *loc, }, )), - EnumVariant::Tuple { ident:_, ty, loc } => out.push(( + EnumVariant::Tuple { ident: _, ty, loc } => out.push(( new_ident.clone(), ResolvedType::Dependent { base: base_ty.clone().into(), @@ -174,26 +174,21 @@ impl ModuleDeclaration { loc: *loc, }, )), - EnumVariant::Struct { - ident:_, loc, .. - } => { - - out.push(( - new_ident.clone(), - ResolvedType::Dependent { - base: base_ty.clone().into(), - ident: new_ident.clone(), - actual: ResolvedType::User { - name: new_ident, - generics:generics.clone(), - loc: *loc, - } - .into(), - generics, + EnumVariant::Struct { ident: _, loc, .. } => out.push(( + new_ident.clone(), + ResolvedType::Dependent { + base: base_ty.clone().into(), + ident: new_ident.clone(), + actual: ResolvedType::User { + name: new_ident, + generics: generics.clone(), loc: *loc, - }, - )) - } + } + .into(), + generics, + loc: *loc, + }, + )), } } HashMap::from_iter(out) @@ -253,6 +248,32 @@ impl TopLevelValue { } } + pub fn bind_generics(&mut self) { + let Self { + ty, + generics, + value, + args, + .. + } = self; + if let Some(generics) = generics { + for (_,generic) in &mut generics.decls { + if let Some(ty) = ty.as_mut() { + ty.replace_generic_inplace(generic); + + } + for arg in args.iter_mut() { + arg.apply_generic(generic); + } + match value { + ValueType::Expr(expr) => expr.apply_generic(generic), + ValueType::Function(block) => block.apply_generic(generic), + ValueType::External => (), + } + } + } + } + fn get_dependencies(&self) -> HashSet { let mut values = self .args @@ -335,6 +356,43 @@ impl TypeDefinition { } } } + + pub(crate) fn bind_generics(&mut self) { + match self { + TypeDefinition::Alias(_, resolved_type) => (), // todo! generic alias + TypeDefinition::Enum(EnumDeclaration { + generics, values, .. + }) => { + if let Some(generics) = generics { + for generic in generics.decls.iter().map(|(_,it)| it) { + + for value in values.iter_mut() { + match value { + EnumVariant::Unit { .. } => (), + EnumVariant::Tuple { ty, .. } => { take_mut::take(ty,|ty| ty.replace_user_with_generic(generic)); }, + EnumVariant::Struct { fields, .. } => { + for FieldDecl { ty, .. } in fields { + take_mut::take(ty,|ty| ty.replace_user_with_generic(generic)); + } + }, + } + } + } + } + } + TypeDefinition::Struct(StructDefinition { generics, values, .. }) => { + if let Some(generics) = generics { + for (_,generic) in &generics.decls { + for FieldDecl { ty, .. } in values.iter_mut() { + take_mut::take(ty, |ty| { + ty.replace_user_with_generic(generic) + }); + } + } + } + }, + } + } } /// {generics} enum {ident} = {values} #[derive(PartialEq, Debug, Clone)] @@ -436,12 +494,12 @@ impl ArgDeclaration { match self { Self::Discard { ty, .. } | Self::Unit { ty, .. } | Self::Simple { ty, .. } => { if let Some(ty) = ty { - *ty = ty.clone().replace_user_with_generic(generic); + take_mut::take(ty,|ty| ty.replace_user_with_generic(generic)); } } Self::DestructureTuple(contents, ty, _) => { if let Some(ty) = ty { - *ty = ty.clone().replace_user_with_generic(generic); + take_mut::take(ty,|ty| ty.replace_user_with_generic(generic)); } contents.iter_mut().for_each(|it| it.apply_generic(generic)) } @@ -539,11 +597,27 @@ impl ValueDeclaration { output.extend(dependencies); output } + + fn apply_generic(&mut self, generic: &str) { + let Self { + ty, + args, + value, + .. + } = self; + if let Some(ty) = ty.as_mut() { + ty.replace_generic_inplace(generic); + } + for arg in args { + arg.apply_generic(generic); + } + value.apply_generic(generic); + } } #[derive(PartialEq, Debug)] pub enum ValueType { Expr(Expr), - Function(Vec), + Function(Block), External, } impl ValueType { @@ -551,6 +625,7 @@ impl ValueType { match self { Self::Expr(expr) => expr.replace(nice_name, actual), Self::Function(stmnts) => stmnts + .statements .iter_mut() .for_each(|it| it.replace(nice_name, actual)), Self::External => (), @@ -560,8 +635,9 @@ impl ValueType { fn get_dependencies(&self, known_values: Vec) -> HashSet { match self { Self::Expr(expr) => expr.get_dependencies(known_values), - Self::Function(stmnts) => { - stmnts + Self::Function(block) => { + let (values,mut deps) = block + .statements //todo! add the implicit ret .iter() .fold( (known_values, HashSet::new()), @@ -573,21 +649,35 @@ impl ValueType { (known_values, dependencies) }, ) - .1 + ; + if let Some(ret) = &block.implicit_ret { + deps.extend(ret.get_dependencies(values)); + } + deps } Self::External => HashSet::new(), } } + + fn apply_generic(&mut self, generic:&str) { + match self { + ValueType::Expr(expr) => expr.apply_generic(generic), + ValueType::Function(block) => block.apply_generic(generic), + ValueType::External => (), + } + } } #[derive(PartialEq, Debug)] pub enum Statement { Declaration(ValueDeclaration), Return(Expr, crate::Location), + #[deprecated(note = "use expr instead.")] FnCall(FnCall), Pipe(Pipe), - IfStatement(IfBranching), + IfStatement(If), Match(Match), + Expr(Expr), Error, } impl Statement { @@ -597,8 +687,9 @@ impl Statement { Self::Return(expr, _) => expr.replace(nice_name, actual), Self::FnCall(fncall) => fncall.replace(nice_name, actual), Self::Pipe(_) => todo!(), - Self::IfStatement(ifbranches) => ifbranches.replace(nice_name, actual), + Self::IfStatement(ifbranches) => todo!(), //ifbranches.replace(nice_name, actual), Self::Match(match_) => match_.replace(nice_name, actual), + Self::Expr(e) => e.replace(nice_name, actual), Self::Error => (), } } @@ -611,73 +702,118 @@ impl Statement { Self::Pipe(_) => todo!(), Self::IfStatement(if_) => if_.loc, Self::Match(match_) => match_.loc, + Self::Expr(e) => e.get_loc(), Self::Error => (0, 0), } } fn get_dependencies(&self, known_values: Vec) -> HashSet { match self { - Statement::Declaration(decl) => decl.get_dependencies(), - Statement::Return(expr, _) => expr.get_dependencies(known_values), - Statement::FnCall(fncall) => fncall.get_dependencies(known_values), - Statement::Pipe(_) => todo!(), - Statement::IfStatement(if_) => { + Self::Declaration(decl) => decl.get_dependencies(), + Self::Return(expr, _) => expr.get_dependencies(known_values), + Self::FnCall(fncall) => fncall.get_dependencies(known_values), + Self::Pipe(_) => todo!(), + Self::Expr(e) => e.get_dependencies(known_values), + Self::IfStatement(if_) => { let mut dependencies = if_.cond.get_dependencies(known_values.clone()); { let mut known_values = known_values.clone(); - for stmnt in &if_.true_branch { + for stmnt in &if_.true_branch.statements { dependencies.extend(stmnt.get_dependencies(known_values.clone())); - if let Statement::Declaration(decl) = stmnt { + if let Self::Declaration(decl) = stmnt { known_values.extend(decl.target.get_idents()); } } } - for elif in &if_.else_ifs { + /*for elif in &if_.else_ifs { dependencies.extend(elif.0.get_dependencies(known_values.clone())); { let mut known_values = known_values.clone(); for stmnt in &elif.1 { dependencies.extend(stmnt.get_dependencies(known_values.clone())); - if let Statement::Declaration(decl) = stmnt { + if let Self::Declaration(decl) = stmnt { known_values.extend(decl.target.get_idents()); } } } - } + }*/ { let mut known_values = known_values.clone(); - for stmnt in &if_.else_branch { + for stmnt in if_ + .else_branch + .as_ref() + .map(|b| &b.statements) + .unwrap_or(&Vec::new()) + { dependencies.extend(stmnt.get_dependencies(known_values.clone())); - if let Statement::Declaration(decl) = stmnt { + if let Self::Declaration(decl) = stmnt { known_values.extend(decl.target.get_idents()); } } } dependencies } - Statement::Match(match_) => { + Self::Match(match_) => { let mut dependencies = match_.on.get_dependencies(known_values.clone()); for arm in &match_.arms { { let mut known_values = known_values.clone(); - for stmnt in &arm.block { + for stmnt in &arm.block.statements { dependencies.extend(stmnt.get_dependencies(known_values.clone())); - if let Statement::Declaration(decl) = stmnt { + if let Self::Declaration(decl) = stmnt { known_values.extend(decl.target.get_idents()); } } - if let Some(ret) = &arm.ret { + if let Some(ret) = &arm.block.implicit_ret { dependencies.extend(ret.get_dependencies(known_values)); } } } dependencies } - Statement::Error => todo!(), + Self::Error => todo!(), + } + } + + fn apply_generic(&mut self, generic: &str) { + match self { + Self::Declaration(value_declaration) => value_declaration.apply_generic(generic), + Self::FnCall(fn_call) => (),// replaced. + Self::Pipe(pipe) => todo!(), + Self::IfStatement(_) => todo!(), + Self::Match(match_) => match_.apply_generic(generic), + Self::Return(expr, _) | + Self::Expr(expr) => (),//todo! apply generics for exprs + Self::Error => (), } } } +#[derive(PartialEq, Debug)] +pub struct Block { + pub statements: Vec, + pub implicit_ret: Option>, +} +impl Block { + fn apply_generic(&mut self, generic: &str) { + let Self { + statements, + .. //todo handle expressions + } = self; + for statement in statements { + statement.apply_generic(generic); + } + } +} + +#[derive(PartialEq, Debug)] +pub struct If { + pub loc: crate::Location, + pub cond: Box, + pub true_branch: Block, + pub else_branch: Option, +} + #[derive(PartialEq, Debug)] pub struct IfBranching { pub cond: Box, @@ -833,7 +969,7 @@ pub enum Expr { StructConstruction(StructConstruction), BoolLiteral(bool, crate::Location), - If(IfExpr), + If(If), Match(Match), } impl Expr { @@ -855,7 +991,7 @@ impl Expr { lhs.replace(nice_name, actual); rhs.replace(nice_name, actual); } - Expr::If(ifexpr) => ifexpr.replace(nice_name, actual), + Expr::If(ifexpr) => todo!(), //ifexpr.replace(nice_name, actual), Expr::Match(match_) => match_.replace(nice_name, actual), _ => (), } @@ -909,36 +1045,50 @@ impl Expr { let mut dependencies = if_.cond.get_dependencies(known_values.clone()); { let mut known_values = known_values.clone(); - for stmnt in &if_.true_branch.0 { + for stmnt in &if_.true_branch.statements { dependencies.extend(stmnt.get_dependencies(known_values.clone())); if let Statement::Declaration(decl) = stmnt { known_values.extend(decl.target.get_idents()); } } - dependencies.extend(if_.true_branch.1.get_dependencies(known_values)); - } - for elif in &if_.else_ifs { - dependencies.extend(elif.0.get_dependencies(known_values.clone())); - { - let mut known_values = known_values.clone(); - for stmnt in &elif.1 { - dependencies.extend(stmnt.get_dependencies(known_values.clone())); - if let Statement::Declaration(decl) = stmnt { - known_values.extend(decl.target.get_idents()); - } - } - dependencies.extend(elif.2.get_dependencies(known_values)); - } + dependencies.extend( + if_.true_branch + .implicit_ret + .as_ref() + .unwrap() + .get_dependencies(known_values), + ); } + // for elif in &if_.else_ifs { + // dependencies.extend(elif.0.get_dependencies(known_values.clone())); + // { + // let mut known_values = known_values.clone(); + // for stmnt in &elif.1 { + // dependencies.extend(stmnt.get_dependencies(known_values.clone())); + // if let Statement::Declaration(decl) = stmnt { + // known_values.extend(decl.target.get_idents()); + // } + // } + // dependencies.extend(elif.2.get_dependencies(known_values)); + // } + // } { let mut known_values = known_values.clone(); - for stmnt in &if_.else_branch.0 { + for stmnt in &if_.else_branch.as_ref().unwrap().statements { dependencies.extend(stmnt.get_dependencies(known_values.clone())); if let Statement::Declaration(decl) = stmnt { known_values.extend(decl.target.get_idents()); } } - dependencies.extend(if_.else_branch.1.get_dependencies(known_values)); + dependencies.extend( + if_.else_branch + .as_ref() + .unwrap() + .implicit_ret + .as_ref() + .unwrap() + .get_dependencies(known_values), + ); } dependencies } @@ -947,13 +1097,13 @@ impl Expr { for arm in &match_.arms { { let mut known_values = known_values.clone(); - for stmnt in &arm.block { + for stmnt in &arm.block.statements { dependencies.extend(stmnt.get_dependencies(known_values.clone())); if let Statement::Declaration(decl) = stmnt { known_values.extend(decl.target.get_idents()); } } - if let Some(ret) = &arm.ret { + if let Some(ret) = &arm.block.implicit_ret { dependencies.extend(ret.get_dependencies(known_values)); } } @@ -962,6 +1112,69 @@ impl Expr { } } } + pub fn get_loc(&self) -> crate::Location { + match self { + Expr::NumericLiteral { .. } + | Expr::StringLiteral(_) + | Expr::CharLiteral(_) + | Expr::UnitLiteral + | Expr::Error => (0, 0), + Expr::Compose { lhs, rhs } => todo!("REMOVE"), + Expr::UnaryOpCall(UnaryOpCall { loc, .. }) + | Expr::FnCall(FnCall { loc, .. }) + | Expr::ValueRead(_, loc) + | Expr::ArrayLiteral { loc, .. } + | Expr::ListLiteral { loc, .. } + | Expr::TupleLiteral { loc, .. } + | Expr::StructConstruction(StructConstruction { loc, .. }) + | Expr::If(If { loc, .. }) + | Expr::BoolLiteral(_, loc) + | Expr::Match(Match { loc, .. }) + | Expr::BinaryOpCall(BinaryOpCall { loc, .. }) => *loc, + } + } + + fn apply_generic(&mut self, generic:&str) { + match self { + Expr::Error| + Expr::NumericLiteral { .. }| + Expr::StringLiteral(_) | + Expr::CharLiteral(_) | + Expr::UnitLiteral => (), + Expr::BinaryOpCall(BinaryOpCall{ lhs, rhs, .. }) | + Expr::Compose { lhs, rhs } => { + lhs.apply_generic(generic); + rhs.apply_generic(generic); + }, + Expr::UnaryOpCall(unary_op_call) => todo!("unary ops not implemented yet."), + Expr::FnCall(FnCall {value, arg,..}) => { + value.apply_generic(generic); + if let Some(arg) = arg { + arg.apply_generic(generic) + } + + }, + Expr::ValueRead(_, _) => (),// TODO! apply generics to explicit generic args + Expr::ArrayLiteral { contents, .. } | + Expr::ListLiteral { contents, .. } | + Expr::TupleLiteral { contents, .. } =>{ + for expr in contents { + expr.apply_generic(generic); + } + }, + Expr::StructConstruction(StructConstruction{ fields, .. }) => todo!("struct Constsructions"), + Expr::BoolLiteral(_, _) => (), + Expr::If(If { cond, true_branch, else_branch, .. }) => { + cond.apply_generic(generic); + true_branch.apply_generic(generic); + else_branch.as_mut().unwrap()//else would be a parse error + .apply_generic(generic); + }, + Expr::Match(match_) => { + match_.apply_generic(generic); + }, + } + } } #[derive(PartialEq, Debug)] @@ -1009,26 +1222,40 @@ impl Match { arm.replace(nice_name, actual); } } + + fn apply_generic(&mut self, generic: &str) { + let Self { + on:_,// todo! apply generics to expr + arms, + .. + } = self; + for MatchArm { block, .. } in arms { + block.apply_generic(generic); + + } + } } #[derive(Debug, PartialEq)] pub struct MatchArm { - pub block: Vec, - pub ret: Option>, + pub block: Block, pub cond: Pattern, pub loc: crate::Location, } impl MatchArm { fn replace(&mut self, nice_name: &str, actual: &str) { - self.cond.replace(nice_name,actual); + self.cond.replace(nice_name, actual); let names = self.cond.get_idents(); if names.contains(nice_name) { return; } - for stmnt in &mut self.block { + for stmnt in &mut self.block.statements { stmnt.replace(nice_name, actual); } - self.ret.as_mut().map(|it| it.replace(nice_name, actual)); + self.block + .implicit_ret + .as_mut() + .map(|it| it.replace(nice_name, actual)); //TODO! allowing for named consts in patterns and handling replacing them with cannon names. } @@ -1079,10 +1306,9 @@ impl Pattern { _ => HashSet::new(), } } - + fn replace(&mut self, nice_name: &str, actual: &str) { match self { - Self::Destructure(destructure) => match destructure { PatternDestructure::Struct { base_ty, .. } => { if let Some(ty) = base_ty { @@ -1090,15 +1316,20 @@ impl Pattern { *ty = actual.into(); } } - }, + } PatternDestructure::Tuple(pats) => { for pat in pats { - pat.replace(nice_name,actual) + pat.replace(nice_name, actual) } - }, + } PatternDestructure::Unit => (), }, - Self::EnumVariant { ty, variant, pattern, .. } => { + Self::EnumVariant { + ty, + variant, + pattern, + .. + } => { if let Some(ty) = ty { if ty == nice_name { *ty = actual.into(); @@ -1109,15 +1340,15 @@ impl Pattern { } } if let Some(pat) = pattern { - pat.replace(nice_name,actual); + pat.replace(nice_name, actual); } - }, - + } + Self::Or(lhs, rhs) => { - lhs.replace(nice_name,actual); - rhs.replace(nice_name,actual); + lhs.replace(nice_name, actual); + rhs.replace(nice_name, actual); } - _=>() + _ => (), } } } diff --git a/compiler/src/inference.rs b/compiler/src/inference.rs index 5ca9239..0acc295 100644 --- a/compiler/src/inference.rs +++ b/compiler/src/inference.rs @@ -132,6 +132,7 @@ impl Context { } untyped_ast::ValueType::Function(stmnts) => ast::ValueType::Function( stmnts + .statements .into_iter() .map(|stmnt| self.assign_ids_stmnt(stmnt)) .collect(), @@ -259,7 +260,7 @@ impl Context { } untyped_ast::ValueType::Function(stmnts) => ast::ValueType::Function( stmnts - .into_iter() + .statements.into_iter() .map(|stmnt| self.assign_ids_stmnt(stmnt)) .collect(), ), @@ -278,6 +279,16 @@ impl Context { } } + fn assign_ids_block(&mut self, untyped_ast::Block{ statements, implicit_ret} : untyped_ast::Block, expected: Option) -> ast::Block { + let id = self.get_next_expr_id(); + ast::Block { + statements : statements.into_iter().map(|stmnt| self.assign_ids_stmnt(stmnt)).collect(), + implicit_ret : implicit_ret.map(|expr| self.assign_ids_expr(*expr,expected.clone()).into()), + id, + ret_ty : expected + } + } + fn assign_ids_stmnt(&mut self, stmnt: untyped_ast::Statement) -> ast::Statement { match stmnt { untyped_ast::Statement::Declaration(decl) => { @@ -296,44 +307,31 @@ impl Context { } untyped_ast::Statement::Pipe(_) => unimplemented!(), untyped_ast::Statement::IfStatement(if_) => { - let untyped_ast::IfBranching { + + let untyped_ast::If { cond, true_branch, - else_ifs, else_branch, loc, } = if_; let cond = self.assign_ids_expr(*cond, Some(types::BOOL)); - let true_branch = true_branch - .into_iter() - .map(|stmnt| self.assign_ids_stmnt(stmnt)) - .collect(); - let else_ifs = else_ifs - .into_iter() - .map(|(cond, branch)| { - let cond = self.assign_ids_expr(*cond, Some(types::BOOL)); - let branch = branch - .into_iter() - .map(|stmnt| self.assign_ids_stmnt(stmnt)) - .collect(); - (cond.into(), branch) - }) - .collect(); - let else_branch = else_branch - .into_iter() - .map(|stmnt| self.assign_ids_stmnt(stmnt)) - .collect(); - ast::Statement::IfStatement(ast::IfBranching { + let true_branch = self.assign_ids_block(true_branch,Some(types::UNIT)); + + let else_branch = else_branch.map(|block| self.assign_ids_block(block,Some(types::UNIT))); + ast::Statement::IfStatement(ast::If { cond: cond.into(), true_branch, - else_ifs, else_branch, loc, + result:types::UNIT, + id : usize::MAX, }) + } untyped_ast::Statement::Match(match_) => { ast::Statement::Match(self.assign_ids_match(match_)) } + untyped_ast::Statement::Expr(expr) => ast::Statement::Expr(self.assign_ids_expr(expr,None)), untyped_ast::Statement::Error => ast::Statement::Error, } } @@ -347,8 +345,10 @@ impl Context { .into_iter() .map(|arm| { let untyped_ast::MatchArm { - block, - ret, + block:untyped_ast::Block{ + statements:block, + implicit_ret:ret, + }, cond, loc, } = arm; @@ -591,43 +591,21 @@ impl Context { untyped_ast::Expr::If(if_) => { let id = self.get_next_expr_id(); let result = self.get_next_type_id(); - let untyped_ast::IfExpr { + let untyped_ast::If { cond, true_branch, - else_ifs, else_branch, loc, } = if_; let cond = self.assign_ids_expr(*cond, Some(types::BOOL)).into(); - let (true_block, true_ret) = true_branch; - let true_block = true_block - .into_iter() - .map(|stmnt| self.assign_ids_stmnt(stmnt)) - .collect_vec(); - let true_ret = self.assign_ids_expr(*true_ret, None).into(); - let else_ifs = else_ifs - .into_iter() - .map(|(cond, block, ret)| { - let cond = self.assign_ids_expr(*cond, Some(types::BOOL)).into(); - let block = block - .into_iter() - .map(|stmnt| self.assign_ids_stmnt(stmnt)) - .collect_vec(); - let ret = self.assign_ids_expr(*ret, None).into(); - (cond, block, ret) - }) - .collect_vec(); - let (else_block, else_ret) = else_branch; - let else_block = else_block - .into_iter() - .map(|stmnt| self.assign_ids_stmnt(stmnt)) - .collect_vec(); - let else_ret = self.assign_ids_expr(*else_ret, None).into(); - ast::Expr::If(ast::IfExpr { + + let ty = self.get_next_type_id(); + let true_branch = self.assign_ids_block(true_branch, Some(ty)); + let else_branch = self.assign_ids_block(else_branch.unwrap(), dbg!(true_branch.ret_ty.clone())); + ast::Expr::If(ast::If { cond, - true_branch: (true_block, true_ret), - else_ifs, - else_branch: (else_block, else_ret), + true_branch, + else_branch:dbg!(else_branch).into(), loc, id, result, @@ -836,7 +814,7 @@ impl Context { ty, } => { if let Some(ety) = expected { - let is_ety_valid = ety.is_float() || ety.is_int(); + let is_ety_valid = ety.is_float() || ety.is_int() || ety.is_unknown(); let is_replacable = ty == &ResolvedType::Number || ty.is_error() || ty.is_unknown(); *ty = if is_ety_valid && is_replacable { @@ -940,7 +918,7 @@ impl Context { } ast::Expr::FnCall(fncall) => self.infer_call(fncall, fun_ret_ty), ast::Expr::ValueRead(ident, _, _) => { - if let Some(ty) = self.known_locals.get_mut(ident) { + if let Some(ty) = dbg!(self.known_locals.get_mut(*dbg!(&ident))) { if let Some(ety) = expected { if let ResolvedType::Unknown(id) = ty { if let Some(new_ty) = self.equations.get(id) { @@ -996,7 +974,9 @@ impl Context { out }) .expect("no empty array literals"); - if underlining != types::ERROR { + + + if dbg!(&underlining) != &types::ERROR { for elem in contents.iter_mut() { self.get_actual_type(elem, Some(underlining.clone()), fun_ret_ty); } @@ -1050,44 +1030,23 @@ impl Context { .unwrap_or(ResolvedType::Error) } ast::Expr::BoolLiteral(_, _, _) => ResolvedType::Bool, - ast::Expr::If(ast::IfExpr { + ast::Expr::If(ast::If { cond, true_branch, - else_ifs, else_branch, loc: _, id: _, result, }) => { self.get_actual_type(cond, Some(types::BOOL), fun_ret_ty); - let (true_block, true_ret) = true_branch; - for stmnt in true_block { - self.infer_stmnt(stmnt, fun_ret_ty); - } - let mut ety = self.get_actual_type(true_ret, expected.clone(), fun_ret_ty); - for (cond, block, ret) in else_ifs { - self.get_actual_type(cond, Some(types::BOOL), fun_ret_ty); - for stmnt in block { - self.infer_stmnt(stmnt, fun_ret_ty); - } - if ety == types::ERROR { - ety = self.get_actual_type(ret, expected.clone(), fun_ret_ty); - } else { - self.get_actual_type(ret, Some(ety.clone()), fun_ret_ty); - } - } - let (block, ret) = else_branch; - for stmnt in block { - self.infer_stmnt(stmnt, fun_ret_ty); - } - if ety == types::ERROR { - ety = self.get_actual_type(ret, expected, fun_ret_ty); - } else { - self.get_actual_type(ret, Some(ety.clone()), fun_ret_ty); - } + + self.infer_block(true_branch,fun_ret_ty, expected); + let mut ety = true_branch.ret_ty.clone().unwrap_or(types::ERROR); + + self.infer_block(else_branch.as_mut().unwrap(), fun_ret_ty, Some(dbg!(ety.clone()))); *result = ety.clone(); - ety + dbg!(ety) } ast::Expr::Match(match_) => self.handle_match(match_, expected, fun_ret_ty), } @@ -1117,7 +1076,6 @@ impl Context { }, ) in arms.iter_mut().enumerate() { - println!("doing equations of arm {idx}"); self.add_equation_of_pattern(cond, &on_ty); for stmnt in block { self.infer_stmnt(stmnt, fun_ret_ty); @@ -1130,7 +1088,6 @@ impl Context { } } if let ast::Pattern::EnumVariant { ty, .. } = cond { - println!("end type {ty:#?}"); } } if !ety.is_error() { @@ -1145,19 +1102,16 @@ impl Context { match pattern { ast::Pattern::Read { ident, loc, ty, id } => { //todo? check if ty is unknown first - println!("setting ty {ty:?} to {on_ty:?}"); *ty = on_ty.clone(); self.expr_ty.insert(*id, on_ty.clone()); self.known_locals.insert(ident.clone(), on_ty.clone()); } ast::Pattern::ConstNumber(_num, ty) => { //TODO? check for non-number types. - println!("setting ty {ty:?} to {on_ty:?}"); *ty = on_ty.clone(); } ast::Pattern::Destructure(d) => { - println!("destructure"); match d { ast::DestructurePattern::Tuple(contents, ty, id) => { @@ -1177,7 +1131,6 @@ impl Context { self.add_equation_of_pattern(pat, ty); } } else { - println!("Error before finding tuple"); *ty = types::ERROR // TODO! error reporting. } @@ -1266,30 +1219,26 @@ impl Context { ast::Statement::FnCall(fncall) => { self.infer_call(fncall, fun_ret_ty); } - ast::Statement::IfStatement(ast::IfBranching { + ast::Statement::IfStatement(ast::If { cond, true_branch, - else_ifs, else_branch, loc: _, + id:_, + result:_ }) => { self.get_actual_type(cond, Some(types::BOOL), fun_ret_ty); - for stmnt in true_branch { - self.infer_stmnt(stmnt, fun_ret_ty); - } - for (cond, block) in else_ifs { - self.get_actual_type(cond, Some(types::BOOL), fun_ret_ty); - for stmnt in block { - self.infer_stmnt(stmnt, fun_ret_ty); - } - } - for stmnt in else_branch { - self.infer_stmnt(stmnt, fun_ret_ty); + self.infer_block(true_branch, fun_ret_ty, None); + if let Some(else_branch) = else_branch.as_mut() { + self.infer_block(else_branch, fun_ret_ty, None); } } ast::Statement::Match(match_) => { self.handle_match(match_, None, fun_ret_ty); } + ast::Statement::Expr(expr) => { + self.get_actual_type(expr, None, fun_ret_ty); + } }; } @@ -1303,13 +1252,15 @@ impl Context { arg, returns, .. - } = fncall; + } = dbg!(fncall); if let ResolvedType::Function { arg: arg_t, returns: return_t, loc: _, - } = self.get_actual_type(value.as_mut(), None, fun_ret_ty) + } = dbg!(self.get_actual_type(value.as_mut(), None, fun_ret_ty)) { + + println!("successful got the type for the value"); self.get_actual_type( arg.as_mut(), if arg_t.is_generic() || arg_t.is_unknown() || arg_t.is_error() { @@ -1322,39 +1273,36 @@ impl Context { *returns = return_t.as_ref().clone(); *return_t } else { + println!("getting the value was unsuccessful"); ResolvedType::Error } } fn apply_equations(&mut self, module: &mut ast::ModuleDeclaration) { - println!( - "equations {:#?}\nexpr_ty {:#?}", - &self.equations, &self.expr_ty - ); + self.apply_substutions(module); - println!("post subs\n{module:#?}"); let ast::ModuleDeclaration { loc: _, name: _, decls, } = module; - let mut equations = self.equations.clone().into_iter().collect_vec(); - equations.sort_by(|(lhs_id, lhs_ty), (rhs_id, rhs_ty)| { - match ( - lhs_ty.contains_unknown(*rhs_id), - rhs_ty.contains_unknown(*lhs_id), - ) { - (true, true) => todo!("handle circular equations?"), - (false, false) => Ordering::Equal, - (true, false) => Ordering::Greater, - (false, true) => Ordering::Less, - } - }); + let mut equations = dbg!(self.equations.clone()).into_iter().collect_vec(); + for (id,ty) in &self.equations { + for equation in &mut equations { + if id == &equation.0 { + continue; + } + equation.1.replace_unknown_with(*id,ty.clone()); + } + } + for decl in decls { match decl { ast::TopLevelDeclaration::Value(v) => { + dbg!(&v.ty); for (id, ty) in &equations { v.ty.replace_unknown_with(*id, ty.clone()); + dbg!(&v.ty); for arg in &mut v.args { arg.replace_unknown_with(*id, ty.clone()); } @@ -1367,9 +1315,7 @@ impl Context { if let Some(rt) = self.apply_equation_stmnt(stmnt, *id, ty.clone()) { - if v.ty.is_unknown() || v.ty.is_error() { - v.ty = rt; - } + //todo? } } } @@ -1515,29 +1461,33 @@ impl Context { match stmnt { ast::Statement::Declaration(v) => self.apply_substution_decl(sub, v), ast::Statement::FnCall(call) => self.apply_substution_fncall(sub, call), - ast::Statement::IfStatement(ast::IfBranching { + ast::Statement::IfStatement(ast::If { cond, true_branch, - else_ifs, else_branch, .. }) => { self.apply_substution_expr(sub, cond.as_mut()); - for stmnt in true_branch { + for stmnt in &mut true_branch.statements { self.apply_substution_statement(sub, stmnt); } - for (cond, block) in else_ifs { - self.apply_substution_expr(sub, cond.as_mut()); - for stmnt in block { + if let Some(ret) = true_branch.implicit_ret.as_mut() { + self.apply_substution_expr(sub, ret.as_mut()); + } + + if let Some(else_branch) = else_branch.as_mut() { + + for stmnt in &mut else_branch.statements { self.apply_substution_statement(sub, stmnt); } - } - for stmnt in else_branch { - self.apply_substution_statement(sub, stmnt); + if let Some(ret) = else_branch.implicit_ret.as_mut() { + self.apply_substution_expr(sub, ret.as_mut()); + } } } ast::Statement::Match(match_) => self.apply_substution_match(sub, match_), - ast::Statement::Return(expr, _) => self.apply_substution_expr(sub, expr), + ast::Statement::Expr(expr) + | ast::Statement::Return(expr, _) => self.apply_substution_expr(sub, expr), ast::Statement::Error => (), } } @@ -1564,10 +1514,9 @@ impl Context { } } ast::Expr::FnCall(call) => self.apply_substution_fncall((id, ty), call), - ast::Expr::If(ast::IfExpr { + ast::Expr::If(ast::If { cond, true_branch, - else_ifs, else_branch, id: ifid, result, @@ -1577,23 +1526,19 @@ impl Context { *result = ty.clone(); } else { self.apply_substution_expr((id, ty), cond.as_mut()); - for stmnt in &mut true_branch.0 { + for stmnt in &mut true_branch.statements { self.apply_substution_statement((id, ty), stmnt); } - self.apply_substution_expr((id, ty), true_branch.1.as_mut()); + self.apply_substution_expr((id, ty), true_branch.implicit_ret.as_mut().unwrap()); - for (cond, block, ret) in else_ifs { - self.apply_substution_expr((id, ty), cond.as_mut()); - for stmnt in block { - self.apply_substution_statement((id, ty), stmnt); - } - self.apply_substution_expr((id, ty), ret.as_mut()); - } + let else_branch = else_branch.as_mut().unwrap(); - for stmnt in &mut else_branch.0 { + for stmnt in &mut else_branch.statements { self.apply_substution_statement((id, ty), stmnt); } - self.apply_substution_expr((id, ty), else_branch.1.as_mut()); + if let Some(ret) = else_branch.implicit_ret.as_mut() { + self.apply_substution_expr((id, ty), ret.as_mut()); + } } } ast::Expr::Match(match_) => self.apply_substution_match((id, ty), match_), @@ -1653,26 +1598,32 @@ impl Context { None } ast::Statement::IfStatement(if_) => { - let ast::IfBranching { + let ast::If { cond, true_branch, - else_ifs, else_branch, loc: _, + id:self_id, + result } = if_; + if id == *self_id { + *result = ty.clone(); + } self.apply_equation_expr(cond.as_mut(), id, ty.clone()); - for stmnt in true_branch { + for stmnt in &mut true_branch.statements { self.apply_equation_stmnt(stmnt, id, ty.clone()); } + if let Some(ret) = true_branch.implicit_ret.as_mut() { + self.apply_equation_expr(ret.as_mut(),id,ty.clone()); + } + if let Some(else_branch) = else_branch.as_mut() { - for (cond, block) in else_ifs.iter_mut() { - self.apply_equation_expr(cond.as_mut(), id, ty.clone()); - for stmnt in block { + for stmnt in &mut else_branch.statements { self.apply_equation_stmnt(stmnt, id, ty.clone()); } - } - for stmnt in else_branch { - self.apply_equation_stmnt(stmnt, id, ty.clone()); + if let Some(ret) = else_branch.implicit_ret.as_mut() { + self.apply_equation_expr(ret.as_mut(),id,ty.clone()); + } } None } @@ -1680,6 +1631,10 @@ impl Context { self.apply_equation_match(match_, id, ty); None } + ast::Statement::Expr(expr) => { + self.apply_equation_expr(expr,id,ty); + None + } ast::Statement::Error => None, //nothing to do for errors } } @@ -1927,37 +1882,30 @@ impl Context { } } ast::Expr::StructConstruction(_) => todo!(), - ast::Expr::If(ast::IfExpr { + ast::Expr::If(ast::If { cond, true_branch, - else_ifs, else_branch, loc: _, id: _, result, }) => { self.apply_equation_expr(cond.as_mut(), id, ty.clone()); - for stmnt in &mut true_branch.0 { + true_branch.ret_ty.as_mut().unwrap().replace_unknown_with(id, ty.clone()); + for stmnt in &mut true_branch.statements { self.apply_equation_stmnt(stmnt, id, ty.clone()); } - let true_result = self.apply_equation_expr(true_branch.1.as_mut(), id, ty.clone()); + let true_result = self.apply_equation_expr(true_branch.implicit_ret.as_mut().unwrap().as_mut(), id, ty.clone()); if result.is_unknown() || result.is_error() { *result = true_result; } - for (cond, block, ret) in else_ifs.iter_mut() { - self.apply_equation_expr(cond.as_mut(), id, ty.clone()); - for stmnt in block { - self.apply_equation_stmnt(stmnt, id, ty.clone()); - } - let block_result = self.apply_equation_expr(ret.as_mut(), id, ty.clone()); - if result.is_unknown() || result.is_error() { - *result = block_result; - } - } - for stmnt in &mut else_branch.0 { + let else_branch = dbg!(else_branch.as_mut().unwrap()); + + else_branch.ret_ty.as_mut().unwrap().replace_unknown_with(id, ty.clone()); + for stmnt in &mut else_branch.statements { self.apply_equation_stmnt(stmnt, id, ty.clone()); } - let else_result = self.apply_equation_expr(else_branch.1.as_mut(), id, ty.clone()); + let else_result = self.apply_equation_expr(else_branch.implicit_ret.as_mut().unwrap().as_mut(), id, ty.clone()); if result.is_unknown() || result.is_error() { *result = else_result; } @@ -2017,6 +1965,45 @@ impl Context { _ => (), } } + +fn infer_block(&mut self, block: &mut ast::Block, fun_ret_ty:&mut Option, expected: Option) { + let ast::Block { + statements, + implicit_ret, + id:_, + ret_ty, + } = block; + let statements = dbg!(statements); + let implicit_ret = dbg!(implicit_ret); + for stmnt in statements { + self.infer_stmnt(stmnt, fun_ret_ty); + } + if let Some(ret) = implicit_ret.as_mut() { + let ty = dbg!(self.get_actual_type(dbg!(ret.as_mut()), dbg!(expected), fun_ret_ty)); + if let Some(ret_ty) = ret_ty.as_mut() { + if let ResolvedType::Unknown(idx) = *ret_ty { + println!("[line:1987]replacing ret_ty {} with {}", idx,ty.to_string()); + *ret_ty = ty.clone(); + self.equations.insert(idx, dbg!(ty)); + } else if ret_ty == &types::ERROR { + println!("[line:1990]replacing ret_ty {} with {}", ret_ty.to_string(),ty.to_string()); + + *ret_ty = ty; + } + + } else { + println!("[line:1991]replacing ret_ty {} with {}", ret_ty.as_ref().map(|it|it.to_string()).unwrap_or("None".into()),ty.to_string()); + ret_ty.replace(ty); + } + } else { + if expected.is_some() { + println!("Expected type but no implicit ret. possibly warn and check for unconditional branching"); + implicit_ret.replace(ast::Expr::Error(usize::MAX).into()); + } + } +} + + } fn sort_on_tree(src: Vec, dependencies: &HashMap>) -> Vec { @@ -2056,12 +2043,11 @@ impl Context { self.next_unknown_id = 0; } } - #[cfg(test)] mod tests { use crate::{ inference::ast::TopLevelValue, - parser::Parser, + parser::file, types::{self, ResolvedType}, }; use pretty_assertions::assert_eq; @@ -2131,49 +2117,51 @@ mod tests { ); ctx.reset(); let ast = - crate::Parser::from_source(r"let foo a = if a then 0 else 1").module("foo".to_string()); + file("foo", r"let foo a : bool -> int32 = if a then 0 else 1;"); assert_eq!( super::ast::ModuleDeclaration { loc: (0, 0), name: "foo".to_string(), decls: vec![super::ast::TopLevelDeclaration::Value( super::ast::TopLevelValue { - loc: (0, 4), + loc: (4,7), is_op: false, ident: "foo".to_string(), args: vec![super::ast::ArgDeclaration::Simple { - loc: (0, 8), + loc: (8,9), ident: "a".to_string(), - ty: ResolvedType::Unknown(1), + ty: types::BOOL, id: 1 }], - ty: ResolvedType::Unknown(0), + ty: types::BOOL.fn_ty(&types::INT32), value: super::ast::ValueType::Expr(super::ast::Expr::If( - super::ast::IfExpr { - cond: super::ast::Expr::ValueRead("a".to_string(), (0, 15), 3) + super::ast::If { + cond: super::ast::Expr::ValueRead("a".to_string(), (31,32), 3) .into(), - true_branch: ( - Vec::new(), - super::ast::Expr::NumericLiteral { + true_branch: super::ast::Block{ + statements:Vec::new(), + implicit_ret:Some(super::ast::Expr::NumericLiteral { value: "0".to_string(), - id: 4, - ty: types::NUMBER, - } - .into() - ), - else_ifs: Vec::new(), - else_branch: ( - Vec::new(), - super::ast::Expr::NumericLiteral { - value: "1".to_string(), id: 5, - ty: types::NUMBER, - } - .into() - ), - loc: (0, 12), + ty: ResolvedType::Unknown(2), + }.into()), + id:4, + ret_ty:ResolvedType::Unknown(1).into(), + }.into(), + else_branch: super::ast::Block { + statements:Vec::new(), + implicit_ret:Some(super::ast::Expr::NumericLiteral { + value: "1".to_string(), + id:7, + ty: ResolvedType::Unknown(3), + }.into()), + id:6, + ret_ty:ResolvedType::Unknown(1).into(), + } + .into(), + loc: (28,30), id: 2, - result: ResolvedType::Unknown(2), + result: ResolvedType::Unknown(0), } )), generics: None, @@ -2182,31 +2170,30 @@ mod tests { } )] }, - ctx.assign_ids_module(ast.ast), + ctx.assign_ids_module(ast), "with if expr", ); ctx.reset(); - let ast = crate::Parser::from_source( + let ast = file("foo", r" -let foo a = match a where +let foo a = match a where | 0 -> 'a', | 1 -> 'b', | 2 -> 'c', | _ -> 'd', ", - ) - .module("foo".to_string()); + ); assert_eq!( super::ast::ModuleDeclaration { loc: (0, 0), name: "foo".to_string(), decls: vec![super::ast::TopLevelDeclaration::Value( super::ast::TopLevelValue { - loc: (1, 4), + loc: (5,8), is_op: false, ident: "foo".to_string(), args: vec![super::ast::ArgDeclaration::Simple { - loc: (1, 8), + loc: (9,10), ident: "a".to_string(), ty: types::ResolvedType::Unknown(1), id: 1 @@ -2214,8 +2201,8 @@ let foo a = match a where ty: types::ResolvedType::Unknown(0), value: super::ast::ValueType::Expr(super::ast::Expr::Match( super::ast::Match { - loc: (1, 12), - on: super::ast::Expr::ValueRead("a".to_string(), (1, 18), 3).into(), + loc: (13,18), + on: super::ast::Expr::ValueRead("a".to_string(), (19,20), 3).into(), arms: vec![ super::ast::MatchArm { block: Vec::new(), @@ -2226,7 +2213,7 @@ let foo a = match a where "0".to_string(), ResolvedType::Unknown(2), ), - loc: (2, 6) + loc: (33,34) }, super::ast::MatchArm { block: Vec::new(), @@ -2237,7 +2224,7 @@ let foo a = match a where "1".to_string(), ResolvedType::Unknown(2), ), - loc: (3, 6) + loc: (49,50) }, super::ast::MatchArm { block: Vec::new(), @@ -2248,7 +2235,7 @@ let foo a = match a where "2".to_string(), ResolvedType::Unknown(2), ), - loc: (4, 6) + loc: (65,66) }, super::ast::MatchArm { block: Vec::new(), @@ -2256,7 +2243,7 @@ let foo a = match a where super::ast::Expr::CharLiteral("d".to_string()).into() ), cond: super::ast::Pattern::Default, - loc: (5, 6) + loc: (81,82) }, ], id: 2 @@ -2268,21 +2255,21 @@ let foo a = match a where } )] }, - ctx.assign_ids_module(ast.ast), + ctx.assign_ids_module(ast), ); ctx.reset(); - let ast = crate::Parser::from_source("let foo a = a == 3").module("foo".to_string()); + let ast = file("foo","let foo a = a == 3;"); assert_eq!( super::ast::ModuleDeclaration { loc: (0, 0), name: "foo".to_string(), decls: vec![super::ast::TopLevelDeclaration::Value( super::ast::TopLevelValue { - loc: (0, 4), + loc: (4,7), is_op: false, ident: "foo".to_string(), args: vec![super::ast::ArgDeclaration::Simple { - loc: (0, 8), + loc: (8,9), ident: "a".to_string(), ty: ResolvedType::Unknown(1), id: 1 @@ -2290,8 +2277,8 @@ let foo a = match a where ty: ResolvedType::Unknown(0), value: super::ast::ValueType::Expr(super::ast::Expr::BinaryOpCall( super::ast::BinaryOpCall { - loc: (0, 14), - lhs: super::ast::Expr::ValueRead("a".to_string(), (0, 12), 3) + loc: (14,16), + lhs: super::ast::Expr::ValueRead("a".to_string(), (12,13), 3) .into(), rhs: super::ast::Expr::NumericLiteral { value: "3".to_string(), @@ -2310,92 +2297,18 @@ let foo a = match a where } )] }, - ctx.assign_ids_module(ast.ast), + ctx.assign_ids_module(ast), "binary op" ); } - #[test] - fn generic_tying() { - const SRC: &'static str = r#" -for let foo x y : T -> T -> () = () -"#; - let ast = crate::Parser::from_source(SRC).module("foo".to_string()); - let mut ctx = super::Context::new( - HashMap::new(), - HashMap::new(), - HashMap::new(), - HashMap::new(), - HashMap::new(), - ); - - assert_eq!( - super::ast::ModuleDeclaration { - loc: (0, 0), - name: "foo".to_string(), - decls: vec![super::ast::TopLevelDeclaration::Value( - super::ast::TopLevelValue { - loc: (1, 11), - is_op: false, - ident: "foo".to_string(), - args: vec![ - super::ast::ArgDeclaration::Simple { - loc: (1, 15), - ident: "x".to_string(), - ty: ResolvedType::Generic { - name: "T".to_string(), - loc: (1, 21) - }, - id: 1 - }, - super::ast::ArgDeclaration::Simple { - loc: (1, 17), - ident: "y".to_string(), - ty: ResolvedType::Generic { - name: "T".to_string(), - loc: (1, 26) - }, - id: 2 - }, - ], - ty: ResolvedType::Function { - arg: ResolvedType::Generic { - name: "T".to_string(), - loc: (1, 21) - } - .into(), - returns: ResolvedType::Function { - arg: ResolvedType::Generic { - name: "T".to_string(), - loc: (1, 26) - } - .into(), - returns: types::UNIT.into(), - loc: (1, 28) - } - .into(), - loc: (1, 23) - }, - value: super::ast::ValueType::Expr(super::ast::Expr::UnitLiteral), - generics: Some(crate::ast::GenericsDecl { - for_loc: (1, 0), - decls: vec![((1, 4), "T".to_string())] - }), - abi: None, - id: 0 - } - )] - }, - ctx.assign_ids_module(ast.ast), - ) - } #[test] fn finale() { const SRC: &'static str = r#" -let annotated_arg (x:int32) = [x,1,2,3] +let annotated_arg (x:int32) = [x,1,2,3]; let complex x = print_int32 x; @@ -2415,17 +2328,14 @@ let complex x = annoated_arg x */ - let ast = crate::Parser::from_source(SRC).module("foo".to_string()); + let ast = file("foo",SRC); + let dtree=ast.get_dependencies(); + let dtree = dtree + .into_iter() + .map(|(key, value)| (key, value.into_iter().collect())) + .collect(); let mut ctx = super::Context::new( - [ - ("simple".to_string(), Vec::new()), - ("annotated_arg".to_string(), Vec::new()), - ( - "complex".to_string(), - vec!["print_int32".to_string(), "annoated_arg".to_string()], - ), - ] - .into(), + dtree, [("print_int32".to_string(), types::INT32.fn_ty(&types::UNIT))].into(), HashMap::new(), [( @@ -2435,8 +2345,9 @@ let complex x = .into(), HashMap::new(), ); - let mut ast = ctx.assign_ids_module(ast.ast); + let mut ast = ctx.assign_ids_module(ast); ctx.try_to_infer(&mut ast); + dbg!(&ctx.equations); ctx.apply_equations(&mut ast); ast.decls.sort_by_key(|it| it.get_ident()); assert_eq!( @@ -2445,11 +2356,11 @@ let complex x = name: "foo".to_string(), decls: vec![ super::ast::TopLevelDeclaration::Value(super::ast::TopLevelValue { - loc: (3, 4), + loc: (8,21), is_op: false, ident: "annotated_arg".to_string(), args: vec![super::ast::ArgDeclaration::Simple { - loc: (3, 19), + loc: (23,24), ident: "x".to_string(), ty: types::INT32, id: 1 @@ -2465,7 +2376,7 @@ let complex x = }, value: super::ast::ValueType::Expr(super::ast::Expr::ArrayLiteral { contents: vec![ - super::ast::Expr::ValueRead("x".to_string(), (3, 31), 3), + super::ast::Expr::ValueRead("x".to_string(), (35,36), 3), super::ast::Expr::NumericLiteral { value: "1".to_string(), id: 4, @@ -2482,7 +2393,7 @@ let complex x = ty: types::INT32 }, ], - loc: (3, 30), + loc: (34,43), id: 2 }), generics: None, @@ -2490,11 +2401,11 @@ let complex x = id: 0 }), super::ast::TopLevelDeclaration::Value(super::ast::TopLevelValue { - loc: (5, 4), + loc: (50,57), is_op: false, ident: "complex".to_string(), args: vec![super::ast::ArgDeclaration::Simple { - loc: (5, 12), + loc: (58,59), ident: "x".to_string(), ty: types::INT32, id: 8 @@ -2504,27 +2415,28 @@ let complex x = size: 4 }), value: super::ast::ValueType::Function(vec![ - super::ast::Statement::FnCall(super::ast::FnCall { - loc: (6, 4), + super::ast::Statement::Expr(super::ast::Expr::FnCall(super::ast::FnCall { + loc: (66, 77), value: super::ast::Expr::ValueRead( "print_int32".to_string(), - (6, 4), + (66, 77), 10 ) .into(), - arg: super::ast::Expr::ValueRead("x".to_string(), (6, 16), 9) + arg: super::ast::Expr::ValueRead("x".to_string(), (78,79), 9) .into(), id: 11, returns: types::UNIT - }), + })), super::ast::Statement::Return( - super::ast::Expr::If(super::ast::IfExpr { + super::ast::Expr::If(super::ast::If { + loc: (92,94), cond: super::ast::Expr::BinaryOpCall( super::ast::BinaryOpCall { - loc: (7, 16), + loc: (97,99), lhs: super::ast::Expr::ValueRead( "x".to_string(), - (7, 14), + (95,96), 14 ) .into(), @@ -2540,69 +2452,77 @@ let complex x = } ) .into(), - true_branch: ( - Vec::new(), - super::ast::Expr::ArrayLiteral { + true_branch: super::ast::Block{ + statements:Vec::new(), + implicit_ret:Some(super::ast::Expr::ArrayLiteral { contents: vec![ super::ast::Expr::ValueRead( "x".to_string(), - (7, 27), - 17 + (108,109), + 18 ), super::ast::Expr::NumericLiteral { value: "0".to_string(), - id: 18, + id: 19, ty: types::INT32 }, super::ast::Expr::NumericLiteral { value: "0".to_string(), - id: 19, + id: 20, ty: types::INT32 }, super::ast::Expr::NumericLiteral { value: "0".to_string(), - id: 20, + id: 21, ty: types::INT32 }, ], - loc: (7, 26), - id: 16 + loc: (107,116), + id: 17 } - .into() - ), - else_ifs: Vec::new(), - else_branch: ( - Vec::new(), - super::ast::Expr::FnCall(super::ast::FnCall { - loc: (7, 41), + .into()), + id:16, + ret_ty:Some(ResolvedType::Array{ + underlining:types::INT32.into(), + size:4, + }) + }, + else_branch: super::ast::Block { + statements:Vec::new(), + implicit_ret:Some(super::ast::Expr::FnCall(super::ast::FnCall { + loc: (122,135), value: super::ast::Expr::ValueRead( "annotated_arg".to_string(), - (7, 41), - 22 + (122,135), + 24 ) .into(), arg: super::ast::Expr::ValueRead( "x".to_string(), - (7, 55), - 21 + (136,137), + 23 ) .into(), - id: 23, + id: 25, returns: ResolvedType::Array { underlining: types::INT32.into(), size: 4 } }) - .into() - ), - loc: (7, 11), + .into()), + id:22, + ret_ty:Some(ResolvedType::Array{ + underlining:types::INT32.into(), + size:4, + }) + }.into(), id: 12, result: ResolvedType::Array { underlining: types::INT32.into(), size: 4 } }), - (7, 4) + (85,91) ) ]), generics: None, @@ -2618,16 +2538,16 @@ let complex x = #[test] fn type_bindings() { const SRC: &'static str = " -let int_unit _ : int32 -> () = () +let int_unit _ : int32 -> () = (); -let unit_int _ : () -> int16 = 0 +let unit_int _ : () -> int16 = 0; -let int_int x : int32 -> int32 = x +let int_int x : int32 -> int32 = x; -let unit_unit _ : () -> () = () +let unit_unit _ : () -> () = (); "; - let module = crate::parser::Parser::from_source(SRC).module("test".to_string()); + let module = file("test",SRC); let dtree = [ ("int_unit".to_string(), Vec::new()), @@ -2645,7 +2565,7 @@ let unit_unit _ : () -> () = () HashMap::new(), ); - let mut module = ctx.inference(module.ast); + let mut module = ctx.inference(module); module .decls @@ -2655,11 +2575,11 @@ let unit_unit _ : () -> () = () }; assert_eq!( &super::ast::TopLevelDeclaration::Value(TopLevelValue { - loc: (5, 4), + loc: (76,83), is_op: false, ident: "int_int".to_string(), args: vec![super::ast::ArgDeclaration::Simple { - loc: (5, 12), + loc: (84,85), ident: "x".to_string(), ty: types::INT32, id: 4 @@ -2667,11 +2587,11 @@ let unit_unit _ : () -> () = () ty: ResolvedType::Function { arg: types::INT32.into(), returns: types::INT32.into(), - loc: (5, 22) + loc: (94,96) }, value: super::ast::ValueType::Expr(super::ast::Expr::ValueRead( "x".to_string(), - (5, 33), + (105,106), 5 )), generics: None, @@ -2683,17 +2603,17 @@ let unit_unit _ : () -> () = () ); assert_eq!( &super::ast::TopLevelDeclaration::Value(TopLevelValue { - loc: (1, 4), + loc: (5,13), is_op: false, ident: "int_unit".to_string(), args: vec![super::ast::ArgDeclaration::Discard { - loc: (1, 13), + loc: (14,15), ty: types::INT32, }], ty: ResolvedType::Function { arg: types::INT32.into(), returns: types::UNIT.into(), - loc: (1, 23), + loc: (24,26), }, value: super::ast::ValueType::Expr(super::ast::Expr::UnitLiteral), generics: None, @@ -2705,17 +2625,17 @@ let unit_unit _ : () -> () = () ); assert_eq!( &super::ast::TopLevelDeclaration::Value(TopLevelValue { - loc: (3, 4), + loc: (41,49), is_op: false, ident: "unit_int".to_string(), args: vec![super::ast::ArgDeclaration::Discard { - loc: (3, 13), + loc: (50,51), ty: types::UNIT, }], ty: ResolvedType::Function { arg: types::UNIT.into(), returns: types::INT16.into(), - loc: (3, 20) + loc: (57,59) }, value: super::ast::ValueType::Expr(super::ast::Expr::NumericLiteral { value: "0".to_string(), @@ -2731,17 +2651,17 @@ let unit_unit _ : () -> () = () ); assert_eq!( &super::ast::TopLevelDeclaration::Value(TopLevelValue { - loc: (7, 4), + loc: (113,122), is_op: false, ident: "unit_unit".to_string(), args: vec![super::ast::ArgDeclaration::Discard { - loc: (7, 14), + loc: (123,124), ty: types::UNIT, }], ty: ResolvedType::Function { arg: types::UNIT.into(), returns: types::UNIT.into(), - loc: (7, 21) + loc: (130,132) }, value: super::ast::ValueType::Expr(super::ast::Expr::UnitLiteral), generics: None, @@ -2756,10 +2676,10 @@ let unit_unit _ : () -> () = () #[test] fn if_expr() { const SRC: &'static str = " -let if_expr a b : bool -> int32 -> int32 = if a then b else 0 +let if_expr a b : bool -> int32 -> int32 = if a then b else 0; "; - let module = crate::Parser::from_source(SRC).module("".to_string()); + let module = file("",SRC); let mut ctx = super::Context::new( [("if_expr".to_string(), Vec::new())].into(), HashMap::new(), @@ -2767,25 +2687,25 @@ let if_expr a b : bool -> int32 -> int32 = if a then b else 0 HashMap::new(), HashMap::new(), ); - let module = ctx.inference(module.ast); + let module = ctx.inference(module); let [if_expr] = &module.decls[..] else { unreachable!() }; assert_eq!( &super::ast::TopLevelDeclaration::Value(super::ast::TopLevelValue { - loc: (1, 4), + loc: (5,12), is_op: false, ident: "if_expr".to_string(), args: vec![ super::ast::ArgDeclaration::Simple { - loc: (1, 12), + loc: (13,14), ident: "a".to_string(), ty: types::BOOL, id: 1, }, super::ast::ArgDeclaration::Simple { - loc: (1, 14), + loc: (15,16), ident: "b".to_string(), ty: types::INT32, id: 2, @@ -2796,28 +2716,31 @@ let if_expr a b : bool -> int32 -> int32 = if a then b else 0 returns: ResolvedType::Function { arg: types::INT32.into(), returns: types::INT32.into(), - loc: (1, 32) + loc: (33,35) } .into(), - loc: (1, 23) + loc: (24,26) }, - value: super::ast::ValueType::Expr(super::ast::Expr::If(super::ast::IfExpr { - cond: super::ast::Expr::ValueRead("a".to_string(), (1, 46), 4).into(), - true_branch: ( - Vec::new(), - super::ast::Expr::ValueRead("b".to_string(), (1, 53), 5).into() - ), - else_ifs: Vec::new(), - else_branch: ( - Vec::new(), - super::ast::Expr::NumericLiteral { + value: super::ast::ValueType::Expr(super::ast::Expr::If(super::ast::If { + cond: super::ast::Expr::ValueRead("a".to_string(), (47,48), 4).into(), + true_branch: super::ast::Block { + statements:Vec::new(), + implicit_ret:Some(super::ast::Expr::ValueRead("b".to_string(), (54,55), 6).into()), + id:5, + ret_ty:types::INT32.into(), + }, + else_branch: super::ast::Block { + statements:Vec::new(), + implicit_ret:Some(super::ast::Expr::NumericLiteral { value: "0".to_string(), - id: 6, + id: 8, ty: types::INT32 } - .into() - ), - loc: (1, 43), + .into()), + id:7, + ret_ty:types::INT32.into() + }.into(), + loc: (44,46), id: 3, result: types::INT32 })), @@ -2830,7 +2753,7 @@ let if_expr a b : bool -> int32 -> int32 = if a then b else 0 } #[test] - fn returns() { + fn returns() { const SRC: &'static str = " let returns a : bool -> int32 = if a then @@ -2838,7 +2761,7 @@ let returns a : bool -> int32 = return 1; "; - let module = crate::Parser::from_source(SRC).module("".to_string()); + let module = file("",SRC); let mut ctx = super::Context::new( [("returns".to_string(), Vec::new())].into(), HashMap::new(), @@ -2846,18 +2769,18 @@ let returns a : bool -> int32 = HashMap::new(), HashMap::new(), ); - let module = ctx.inference(module.ast); + let module = ctx.inference(module); let [returns] = &module.decls[..] else { unreachable!() }; assert_eq!( &super::ast::TopLevelDeclaration::Value(super::ast::TopLevelValue { - loc: (1, 4), + loc: (5,12), is_op: false, ident: "returns".to_string(), args: vec![super::ast::ArgDeclaration::Simple { - loc: (1, 12), + loc: (13, 14), ident: "a".to_string(), ty: types::BOOL, id: 1, @@ -2865,30 +2788,36 @@ let returns a : bool -> int32 = ty: ResolvedType::Function { arg: types::BOOL.into(), returns: types::INT32.into(), - loc: (1, 21) + loc: (22,24) }, value: super::ast::ValueType::Function(vec![ - super::ast::Statement::IfStatement(super::ast::IfBranching { - cond: super::ast::Expr::ValueRead("a".to_string(), (2, 7), 2).into(), - true_branch: vec![super::ast::Statement::Return( - super::ast::Expr::NumericLiteral { - value: "0".to_string(), - id: 3, - ty: types::INT32 - }, - (3, 8) - )], - else_ifs: Vec::new(), - else_branch: Vec::new(), - loc: (2, 4) + super::ast::Statement::IfStatement(super::ast::If { + cond: super::ast::Expr::ValueRead("a".to_string(), (40,41), 2).into(), + true_branch: super::ast::Block { + statements:vec![super::ast::Statement::Return( + super::ast::Expr::NumericLiteral { + value: "0".to_string(), + id: 4, + ty: types::INT32 + }, + (55,61) + )], + implicit_ret:None, + id:3, + ret_ty:Some(types::UNIT), + }, + else_branch: None, + loc: (37,39), + id:usize::MAX, + result:types::UNIT, }), super::ast::Statement::Return( super::ast::Expr::NumericLiteral { value: "1".to_string(), - id: 4, + id: 5, ty: types::INT32 }, - (4, 4) + (69, 75) ) ]), generics: None, @@ -2902,7 +2831,7 @@ let returns a : bool -> int32 = fn tuples() { const SRC: &'static str = " let produce (a:int32) = (a,a); -// in theory this could be `let consume = fst` but let's ignore that case for now +#! in theory this could be `let consume = fst` but let's ignore that case for now let consume a = fst a; "; let predefined = [( @@ -2915,7 +2844,7 @@ let consume a = fst a; )] .into(); - let ast = crate::Parser::from_source(SRC).module("".to_string()).ast; + let ast = file("",SRC); let dtree = ast.get_dependencies(); let dtree = dtree .into_iter() @@ -2937,11 +2866,11 @@ let consume a = fst a; }; assert_eq!( &super::ast::TopLevelDeclaration::Value(super::ast::TopLevelValue { - loc: (3, 4), + loc: (118,125), is_op: false, ident: "consume".to_string(), args: vec![super::ast::ArgDeclaration::Simple { - loc: (3, 12), + loc: (126,127), ident: "a".to_string(), ty: ResolvedType::Tuple { underlining: vec![types::INT32, types::INT32,], @@ -2955,9 +2884,9 @@ let consume a = fst a; } .fn_ty(&types::INT32), value: super::ast::ValueType::Expr(super::ast::Expr::FnCall(super::ast::FnCall { - loc: (3, 16), - value: super::ast::Expr::ValueRead("fst".to_string(), (3, 16), 8).into(), - arg: super::ast::Expr::ValueRead("a".to_string(), (3, 20), 7).into(), + loc: (130,133), + value: super::ast::Expr::ValueRead("fst".to_string(), (130,133), 8).into(), + arg: super::ast::Expr::ValueRead("a".to_string(), (134,135), 7).into(), id: 9, returns: types::INT32, })), @@ -2971,11 +2900,11 @@ let consume a = fst a; assert_eq!( &super::ast::TopLevelDeclaration::Value(super::ast::TopLevelValue { - loc: (1, 4), + loc: (5,12), is_op: false, ident: "produce".to_string(), args: vec![super::ast::ArgDeclaration::Simple { - loc: (1, 13), + loc: (14,15), ident: "a".to_string(), ty: types::INT32, id: 1 @@ -2989,11 +2918,11 @@ let consume a = fst a; abi: None, value: super::ast::ValueType::Expr(super::ast::Expr::TupleLiteral { contents: vec![ - super::ast::Expr::ValueRead("a".to_string(), (1, 25), 3), - super::ast::Expr::ValueRead("a".to_string(), (1, 27), 4), + super::ast::Expr::ValueRead("a".to_string(), (26,27), 3), + super::ast::Expr::ValueRead("a".to_string(), (28,29), 4), ], id: 2, - loc: (1, 24), + loc: (25,30), }) }), produce, @@ -3011,7 +2940,7 @@ let main _ : () -> () = return (); "; - let ast = crate::Parser::from_source(SRC).module(String::new()).ast; + let ast = file("",SRC); let dtree = ast.get_dependencies(); let dtree = dtree .into_iter() @@ -3031,11 +2960,11 @@ let main _ : () -> () = }; assert_eq!( &super::ast::TopLevelDeclaration::Value(super::ast::TopLevelValue { - loc: (1, 4), + loc: (5,6), is_op: false, ident: "f".to_string(), args: vec![super::ast::ArgDeclaration::Simple { - loc: (1, 7), + loc: (8,9), ident: "a".to_string(), ty: ResolvedType::Array { underlining: types::INT32.into(), @@ -3058,18 +2987,18 @@ let main _ : () -> () = ); assert_eq!( &super::ast::TopLevelDeclaration::Value(super::ast::TopLevelValue { - loc: (3, 4), + loc: (32,36), is_op: false, ident: "main".to_string(), args: vec![super::ast::ArgDeclaration::Discard { - loc: (3, 9), + loc: (37, 38), ty: types::UNIT, },], ty: types::UNIT.fn_ty(&types::UNIT), value: super::ast::ValueType::Function(vec![ - super::ast::Statement::FnCall(super::ast::FnCall { - loc: (4, 4), - value: super::ast::Expr::ValueRead("f".to_string(), (4, 4), 9).into(), + super::ast::Statement::Expr(super::ast::Expr::FnCall(super::ast::FnCall { + loc: (56,57), + value: super::ast::Expr::ValueRead("f".to_string(), (56,57), 9).into(), arg: super::ast::Expr::ArrayLiteral { contents: vec![ super::ast::Expr::NumericLiteral { @@ -3098,14 +3027,14 @@ let main _ : () -> () = ty: types::INT32 }, ], - loc: (4, 6), + loc: (58,69), id: 3 } .into(), id: 10, returns: types::UNIT - }), - super::ast::Statement::Return(super::ast::Expr::UnitLiteral, (5, 4)) + })), + super::ast::Statement::Return(super::ast::Expr::UnitLiteral, (75,81)) ]), generics: None, abi: None, @@ -3127,7 +3056,7 @@ let tuples (v:(int32,int32)) = match v where | (1,b) -> b, | _ -> 0, "; - let ast = crate::Parser::from_source(SRC).module(String::new()).ast; + let ast = file("",SRC); let dtree = ast.get_dependencies(); let dtree = dtree .into_iter() @@ -3147,19 +3076,19 @@ let tuples (v:(int32,int32)) = match v where }; assert_eq!( &super::ast::TopLevelDeclaration::Value(super::ast::TopLevelValue { - loc: (1, 4), + loc: (5,8), is_op: false, ident: "ors".to_string(), args: vec![super::ast::ArgDeclaration::Simple { - loc: (1, 9), + loc: (10,11), ident: "a".to_string(), ty: types::INT32, id: 1 }], ty: types::INT32.fn_ty(&types::INT32), value: super::ast::ValueType::Expr(super::ast::Expr::Match(super::ast::Match { - loc: (1, 20), - on: super::ast::Expr::ValueRead("a".to_string(), (1, 26), 3).into(), + loc: (21,26), + on: super::ast::Expr::ValueRead("a".to_string(), (27,28), 3).into(), arms: vec![ super::ast::MatchArm { block: Vec::new(), @@ -3182,20 +3111,20 @@ let tuples (v:(int32,int32)) = match v where ) .into() ), - loc: (2, 6), + loc: (39,40), }, super::ast::MatchArm { block: Vec::new(), ret: Some( - super::ast::Expr::ValueRead("a".to_string(), (3, 11), 6).into() + super::ast::Expr::ValueRead("a".to_string(), (68,69), 6).into() ), cond: super::ast::Pattern::Read { ident: "a".to_string(), - loc: (3, 6), + loc: (63,64), ty: types::INT32, id: 5 }, - loc: (3, 6), + loc: (61,62), } ], id: 2 @@ -3209,11 +3138,11 @@ let tuples (v:(int32,int32)) = match v where assert_eq!( &super::ast::TopLevelDeclaration::Value(super::ast::TopLevelValue { - loc: (4, 4), + loc: (75,81), is_op: false, ident: "tuples".to_string(), args: vec![super::ast::ArgDeclaration::Simple { - loc: (4, 12), + loc: (83,84), ident: "v".to_string(), ty: ResolvedType::Tuple { underlining: vec![types::INT32, types::INT32,], @@ -3227,20 +3156,20 @@ let tuples (v:(int32,int32)) = match v where } .fn_ty(&types::INT32), value: super::ast::ValueType::Expr(super::ast::Expr::Match(super::ast::Match { - loc: (4, 31), - on: super::ast::Expr::ValueRead("v".to_string(), (4, 37), 10).into(), + loc: (102,107), + on: super::ast::Expr::ValueRead("v".to_string(), (108,109), 10).into(), arms: vec![ super::ast::MatchArm { block: Vec::new(), ret: Some( - super::ast::Expr::ValueRead("a".to_string(), (5, 15), 13).into() + super::ast::Expr::ValueRead("a".to_string(), (131,132), 13).into() ), cond: super::ast::Pattern::Destructure( super::ast::DestructurePattern::Tuple( vec![ super::ast::Pattern::Read { ident: "a".to_string(), - loc: (5, 7), + loc: (123,124), ty: types::INT32, id: 12 }, @@ -3256,12 +3185,12 @@ let tuples (v:(int32,int32)) = match v where 11 ) ), - loc: (5, 6) + loc: (120,121) }, super::ast::MatchArm { block: Vec::new(), ret: Some( - super::ast::Expr::ValueRead("b".to_string(), (6, 15), 16).into() + super::ast::Expr::ValueRead("b".to_string(), (149,150), 16).into() ), cond: super::ast::Pattern::Destructure( super::ast::DestructurePattern::Tuple( @@ -3272,7 +3201,7 @@ let tuples (v:(int32,int32)) = match v where ), super::ast::Pattern::Read { ident: "b".to_string(), - loc: (6, 9), + loc: (143,144), ty: types::INT32, id: 15 }, @@ -3284,7 +3213,7 @@ let tuples (v:(int32,int32)) = match v where 14 ) ), - loc: (6, 6) + loc: (138,139) }, super::ast::MatchArm { block: Vec::new(), @@ -3297,7 +3226,7 @@ let tuples (v:(int32,int32)) = match v where .into() ), cond: super::ast::Pattern::Default, - loc: (7, 6) + loc: (156,157) } ], id: 9, @@ -3312,15 +3241,13 @@ let tuples (v:(int32,int32)) = match v where } #[test] fn destructureing_statement() { - let ast = Parser::from_source( + let ast = file("", " let a (v:(int32,int32)) = let (x,y) = v; return (); ", - ) - .module("".to_string()) - .ast; + ); let dtree = ast.get_dependencies(); let dtree = dtree .into_iter() @@ -3338,7 +3265,7 @@ let a (v:(int32,int32)) = use super::ast; assert_eq!( &ast::TopLevelDeclaration::Value(ast::TopLevelValue { - loc: (1, 4), + loc: (5,6), is_op: false, ident: "a".to_string(), args: vec![ast::ArgDeclaration::Simple { @@ -3347,7 +3274,7 @@ let a (v:(int32,int32)) = underlining: vec![types::INT32, types::INT32,], loc: (0, 0) }, - loc: (1, 7), + loc: (8,9), id: 1, }], ty: ResolvedType::Tuple { @@ -3357,20 +3284,20 @@ let a (v:(int32,int32)) = .fn_ty(&types::UNIT), value: ast::ValueType::Function(vec![ ast::Statement::Declaration(ast::ValueDeclaration { - loc: (2, 8), + loc: (35,40), is_op: false, target: ast::Pattern::Destructure(ast::DestructurePattern::Tuple( vec![ ast::Pattern::Read { ident: "x".to_string(), ty: types::INT32, - loc: (2, 9), + loc: (36,37), id: 3 }, ast::Pattern::Read { ident: "y".to_string(), ty: types::INT32, - loc: (2, 11), + loc: (38,39), id: 4 }, ], @@ -3383,7 +3310,7 @@ let a (v:(int32,int32)) = args: Vec::new(), value: ast::ValueType::Expr(ast::Expr::ValueRead( "v".to_string(), - (2, 16), + (43,44), 6 )), ty: ResolvedType::Tuple { @@ -3394,7 +3321,7 @@ let a (v:(int32,int32)) = abi: None, id: 5 }), - ast::Statement::Return(ast::Expr::UnitLiteral, (3, 4)) + ast::Statement::Return(ast::Expr::UnitLiteral, (50,56)) ]), generics: None, abi: None, @@ -3406,7 +3333,7 @@ let a (v:(int32,int32)) = #[test] fn enum_patterns() { - let parser = Parser::from_source( + let ast = file("", " enum IP = | V4 (int8,int8,int8,int8) | V6 (int8,int8,int8,int8,int8,int8) @@ -3416,8 +3343,6 @@ let do_something a = match a where | IP::V6 _ -> (), ", ); - let ast = parser.module("".to_string()); - assert_eq!(ast.errors.len(), 0, "no errors"); let mut ctx = super::Context::new( [].into(), @@ -3426,18 +3351,17 @@ let do_something a = match a where [].into(), [].into(), ); - let ast = ctx.inference(ast.ast); + let ast = ctx.inference(ast); let [_enum_, func] = &ast.decls[..] else { panic!("too much? too little?") }; assert_eq!( - func, &super::ast::TopLevelDeclaration::Value(super::ast::TopLevelValue { - loc: (3, 4), + loc: (80,92), is_op: false, ident: "do_something".to_string(), args: vec![super::ast::ArgDeclaration::Simple { - loc: (3, 17), + loc: (93,94), ident: "a".to_string(), ty: ResolvedType::User { name: "IP".to_string(), @@ -3453,8 +3377,8 @@ let do_something a = match a where } .fn_ty(&types::UNIT), value: super::ast::ValueType::Expr(super::ast::Expr::Match(super::ast::Match { - loc: (3, 21), - on: super::ast::Expr::ValueRead("a".to_string(), (3, 27), 3).into(), + loc: (97,102), + on: super::ast::Expr::ValueRead("a".to_string(), (103,104), 3).into(), arms: vec![ super::ast::MatchArm { block: Vec::new(), @@ -3511,9 +3435,9 @@ let do_something a = match a where ) .into() ), - loc: (4, 2) + loc: (113,119), }, - loc: (4, 2) + loc: (111,112), }, super::ast::MatchArm { block: Vec::new(), @@ -3544,7 +3468,7 @@ let do_something a = match a where pattern: Some( super::ast::Pattern::Read { ident: "a".into(), - loc: (5, 9), + loc: (148,149), ty: ResolvedType::Tuple { underlining: vec![ types::INT8;4 @@ -3555,9 +3479,9 @@ let do_something a = match a where } .into() ), - loc: (5, 2) + loc: (141,147) }, - loc: (5, 2), + loc: (139,140), }, super::ast::MatchArm { block: Vec::new(), @@ -3588,9 +3512,9 @@ let do_something a = match a where }, variant: "IP::V6".into(), pattern: Some(super::ast::Pattern::Default.into()), - loc: (6, 2) + loc: (159,165) }, - loc: (6, 2) + loc: (157,158) } ], id: 2 @@ -3599,6 +3523,7 @@ let do_something a = match a where abi: None, id: 0, }), + func, ); } @@ -3615,7 +3540,7 @@ let fun test = match test where | Testing::One _ -> 1, | Testing::Two -> 2, "#; - let mut ast = Parser::from_source(SRC).module("".to_string()).ast; + let mut ast = file("",SRC); ast.canonialize(vec!["v".into()]); let dtree = ast.get_dependencies(); let dtree = dtree diff --git a/compiler/src/inference/ast.rs b/compiler/src/inference/ast.rs index ae918ab..a0e9ea8 100644 --- a/compiler/src/inference/ast.rs +++ b/compiler/src/inference/ast.rs @@ -106,7 +106,7 @@ impl ArgDeclaration { match self { Self::Unit { .. } | Self::DestructureStruct { .. } => (), Self::Simple { ty, .. } | Self::Discard { ty, .. } => { - println!("chaging {id} to {new_ty:#?}"); + ty.replace_unknown_with(id, new_ty) } Self::DestructureTuple(contents, ty, _) => { @@ -126,23 +126,35 @@ pub(crate) enum ValueType { External, } + + +#[derive(PartialEq, Debug)] +pub(crate) struct Block { + pub(crate) statements:Vec, + pub(crate) implicit_ret:Option>, + pub(crate) id : usize, + pub(crate) ret_ty : Option, +} #[derive(PartialEq, Debug)] pub(crate) enum Statement { Error, Declaration(ValueDeclaration), Return(Expr, crate::Location), FnCall(FnCall), - IfStatement(IfBranching), + IfStatement(If), Match(Match), + Expr(Expr), } #[derive(PartialEq, Debug)] -pub(crate) struct IfBranching { - pub(crate) cond: Box, - pub(crate) true_branch: Vec, - pub(crate) else_ifs: Vec<(Box, Vec)>, - pub(crate) else_branch: Vec, - pub(crate) loc: crate::Location, +pub(crate) struct If { + pub(crate) loc : crate::Location, + pub(crate) cond : Box, + pub(crate) true_branch : Block, + pub(crate) else_branch : Option, + pub(crate) id : usize, + pub(crate) result : ResolvedType, + } #[derive(PartialEq, Debug)] @@ -267,7 +279,7 @@ pub(crate) enum Expr { #[allow(unused)] // TODO! why is this unused? StructConstruction(StructConstruction), BoolLiteral(bool, crate::Location, usize), - If(IfExpr), + If(If), Match(Match), } impl Expr { @@ -278,7 +290,7 @@ impl Expr { | Self::ListLiteral { id, .. } | Self::NumericLiteral { id, .. } | Self::ValueRead(_, _, id) - | Self::If(IfExpr { id, .. }) + | Self::If(If { id, .. }) | Self::BinaryOpCall(BinaryOpCall { id, .. }) | Self::FnCall(FnCall { id, .. }) | Self::ArrayLiteral { id, .. } diff --git a/compiler/src/lib.rs b/compiler/src/lib.rs index bbbb953..574b49d 100644 --- a/compiler/src/lib.rs +++ b/compiler/src/lib.rs @@ -4,7 +4,6 @@ use std::{cmp::Ordering, collections::HashMap}; pub mod ast; // mod langstd; mod inference; -mod lexer; mod parser; mod tokens; pub mod typed_ast; @@ -22,14 +21,14 @@ use typed_ast::{ #[derive(Error, Debug)] #[error(transparent)] pub enum Error { - ParseError(#[from] parser::ParseError), + // ParseError(#[from] parser::ParseError), Io(#[from] std::io::Error), } #[derive(Error, Debug)] #[error(transparent)] pub enum Warning { - Parsing(#[from] parser::Warning), + // Parsing(#[from] parser::Warning), } #[derive(Error, Debug)] @@ -39,8 +38,8 @@ pub enum WarningAndError { Warning(#[from] Warning), } -use lexer::TokenStream; -use parser::{Parser, ParserReturns}; +// use lexer::TokenStream; +// use parser::{Parser, ParserReturns}; use types::ResolvedType; type Location = (usize, usize); @@ -48,50 +47,53 @@ pub fn get_untyped_ast( input: &str, file_name: &str, ) -> (ast::ModuleDeclaration, Vec) { - let ts = TokenStream::from_source(input); - let ParserReturns { - ast, - loc: _, - warnings, - errors, - } = Parser::from_stream(ts).module(file_name.to_string()); - let warningsanderrors = warnings - .into_iter() - .map(|w| Warning::from(w).into()) - .chain(errors.into_iter().map(|e| Error::from(e).into())) - .collect(); - (ast, warningsanderrors) + // let ts = TokenStream::from_source(input); + // let ParserReturns { + // ast, + // loc: _, + // warnings, + // errors, + // } = Parser::from_stream(ts).module(file_name.to_string()); + // let warningsanderrors = warnings + // .into_iter() + // .map(|w| Warning::from(w).into()) + // .chain(errors.into_iter().map(|e| Error::from(e).into())) + // .collect(); + // (ast, warningsanderrors) + let ast = parser::file(file_name, input); + (ast,Vec::new()) } pub fn get_ast(input: &str, file_name: &str) -> typed_ast::TypedModuleDeclaration { - let ts = TokenStream::from_source(input); - let ParserReturns { - ast: module, - loc: _, - warnings: _, - errors: _, - } = Parser::from_stream(ts).module(file_name.to_string()); - // TODO! better report errors. - // TODO! get prelude. - let dep_tree = module - .get_dependencies() - .into_iter() - .map(|(k, v)| (k, v.into_iter().collect())) - .collect(); - let ops: HashMap<_, _> = [( - "+".to_string(), - vec![types::INT32.fn_ty(&types::INT32.fn_ty(&types::INT32))], - )] - .into(); - let mut infer_context = inference::Context::new( - dep_tree, - HashMap::new(), - HashMap::new(), - ops.clone(), - HashMap::new(), - ); - let ast = infer_context.inference(module); - TypedModuleDeclaration::from(ast, &HashMap::new(), &ops) + todo!("fix parsing.") + // let ts = TokenStream::from_source(input); + // let ParserReturns { + // ast: module, + // loc: _, + // warnings: _, + // errors: _, + // } = Parser::from_stream(ts).module(file_name.to_string()); + // // TODO! better report errors. + // // TODO! get prelude. + // let dep_tree = module + // .get_dependencies() + // .into_iter() + // .map(|(k, v)| (k, v.into_iter().collect())) + // .collect(); + // let ops: HashMap<_, _> = [( + // "+".to_string(), + // vec![types::INT32.fn_ty(&types::INT32.fn_ty(&types::INT32))], + // )] + // .into(); + // let mut infer_context = inference::Context::new( + // dep_tree, + // HashMap::new(), + // HashMap::new(), + // ops.clone(), + // HashMap::new(), + // ); + // let ast = infer_context.inference(module); + // TypedModuleDeclaration::from(ast, &HashMap::new(), &ops) } fn unfold_global_curries( mut ast: TypedModuleDeclaration, @@ -199,6 +201,7 @@ pub fn from_file<'ctx>( fwd_ops: HashMap>, project_name: String, ) -> (Result>, Vec) { + // TODO: I would like to make this work for now I will read the whole file to a string then // let file = File::open(file).map_err(Box::new).map_err(|err| vec![err as Box])?; // let file = BufReader::new(file); @@ -221,19 +224,8 @@ pub fn from_file<'ctx>( Ok(contents) => contents, Err(e) => return (Err(vec![e]), Vec::new()), }; - // lexer - let strm = TokenStream::from_source(&contents); - // parser - let parser = Parser::from_stream(strm); - - let ParserReturns { - mut ast, - loc: _, - warnings, - errors, - } = parser.module(file_name.to_str().unwrap().to_string()); - let warnings = warnings.into_iter().map(Warning::from).collect_vec(); - let errors = errors.into_iter().map(Error::from).collect_vec(); + let mut ast = parser::file(file_name.to_str().unwrap(), &contents); + ast.canonialize(vec![project_name]); let dependency_graph = ast.get_dependencies(); let dependency_tree: HashMap<_, _> = dependency_graph @@ -255,11 +247,8 @@ pub fn from_file<'ctx>( ast.lower_generics(&HashMap::new()); let ast = unfold_global_curries(ast, HashMap::new(), dependency_tree); ( - if errors.is_empty() { - Ok(ast) - } else { - Err(errors) - }, - warnings, + Ok(ast), + Vec::new() ) + } diff --git a/compiler/src/lexer.rs b/compiler/src/old_lexer.rs similarity index 98% rename from compiler/src/lexer.rs rename to compiler/src/old_lexer.rs index 5f40ec9..887bda6 100644 --- a/compiler/src/lexer.rs +++ b/compiler/src/old_lexer.rs @@ -15,6 +15,18 @@ macro_rules! operators { }; } +use crate::tokens; +fn lex(input :&mut Located<&str>) -> PResult)>> { + combinator::opt(comment).parse_next(input)?; + combinator::repeat(0..,combinator::alt(( + "for".span().map(|span|(tokens::Token::For,span)), + "let".span().map(|span|(tokens::Token::Let,span)), + '('.span().map(|span| (tokens::Token::GroupOpen,span)), + ')'.span().map(|span| (tokens::Token::GroupClose,span)), + '<' + ))).parse_next(input) +} + use itertools::Itertools; use crate::{tokens::Token, util::ExtraIterUtils}; diff --git a/compiler/src/old_parser.rs b/compiler/src/old_parser.rs new file mode 100644 index 0000000..584214e --- /dev/null +++ b/compiler/src/old_parser.rs @@ -0,0 +1,5924 @@ +use std::{ + collections::{HashMap, HashSet}, + fmt::Error, + iter::Peekable, + str::Chars, +}; + +use ast::{GenericsDecl, TypeDefinition}; +use itertools::Itertools; + +use crate::{ + ast::{ + self, ArgDeclaration, BinaryOpCall, Expr, FieldDecl, FnCall, Match, Pattern, + PatternDestructure, Statement, StructConstruction, StructDefinition, TopLevelDeclaration, + TopLevelValue, ValueDeclaration, ValueType, + }, + lexer::TokenStream, + tokens::Token, + types::{self, ResolvedType}, +}; + +use thiserror::Error; + +#[derive(Error, Debug)] +#[error("")] +pub enum Warning {} + +#[allow(unused)] +#[derive(Error, Debug)] +#[error("{reason:?} at {span:?}")] +pub struct ParseError { + span: (usize, usize), + reason: ParseErrorReason, +} +#[derive(Debug)] +#[allow(unused)] +enum ParseErrorReason { + UnbalancedBraces, + InvalidIdent, + IndentError, + TypeError, + ArgumentError, + DeclarationError, + UnexpectedEndOfFile, + UnsupportedEscape, + UnsupportedFeature, + UnexpectedToken, + NoElseBlock, + UnknownError, //internal use. should basically never be hit. +} + +#[derive(Debug)] +pub struct ParserReturns { + pub ast: T, + pub loc: crate::Location, + pub warnings: Vec, //TODO! add warnings and a way next_toplevel treat warnings as errors + pub errors: Vec, +} + +pub(crate) struct Parser +where + T: Iterator, +{ + stream: Peekable, +} + +impl<'str> Parser>>> { + #[cfg(test)] + pub(crate) fn from_source(source: &'str str) -> Self { + Self { + stream: TokenStream::from_source(source).peekable(), + } + } +} + +impl Parser +where + T: Iterator + Clone, +{ + pub fn from_stream(stream: T) -> Self { + Self { + stream: stream.peekable(), + } + } + + pub fn has_next(&mut self) -> bool { + let _ = self + .stream + .peeking_take_while(|(token, _)| match token { + Token::Seq | Token::EndBlock => true, + _ => false, + }) + .collect_vec(); + self.stream + .peek() + .map_or(false, |(token, _)| !token.is_eof()) + } + pub(crate) fn module(mut self, name: String) -> ParserReturns { + let mut decls = Vec::new(); + let mut warnings = Vec::new(); + let mut errors = Vec::new(); + while self.has_next() { + let decl = self.next_toplevel(); + warnings.extend(decl.warnings); + errors.extend(decl.errors); + decls.push(decl.ast); + } + ParserReturns { + ast: ast::ModuleDeclaration { + loc: None, + name, + declarations: decls, + }, + loc: (0, 0), + warnings, + errors, + } + } + + pub fn next_toplevel(&mut self) -> ParserReturns { + let ParserReturns { + ast: abi, + loc: extern_loc, + mut warnings, + mut errors, + } = self.abi(); + let ParserReturns { + ast: generics, + loc: for_loc, + warnings: for_warnings, + errors: for_errors, + } = self.collect_generics(); + warnings.extend(for_warnings); + errors.extend(for_errors); + if abi.is_some() && generics.is_some() { + errors.push(ParseError { + span: for_loc, + reason: ParseErrorReason::DeclarationError, + }); + } + match self.stream.clone().next() { + Some((Token::For, loc)) => { + errors.push(ParseError { + span: loc, + reason: ParseErrorReason::DeclarationError, + }); + ParserReturns { + ast: ast::TopLevelDeclaration::Value(TopLevelValue { + loc, + is_op: false, + ident: "".to_string(), + args: vec![ArgDeclaration::Simple { + loc, + ident: "".to_string(), + ty: Some(types::ERROR), + }], + ty: Some(types::ERROR), + value: ValueType::Expr(Expr::Error), + generics: generics, + abi: None, + }), + loc, + warnings, + errors, + } + } + Some((Token::Type | Token::Enum, loc)) => { + if abi.is_some() { + errors.push(ParseError { + span: extern_loc, + reason: ParseErrorReason::DeclarationError, + }); + } + let decl = self.type_decl(generics); + warnings.extend(decl.warnings); + errors.extend(decl.errors); + ParserReturns { + ast: ast::TopLevelDeclaration::TypeDefinition(decl.ast), + loc, + warnings, + errors, + } + } + Some((Token::Let, _)) => { + let _ = self.stream.next(); + let (token, ident_span) = self.stream.next().unwrap(); + let (ident, is_op) = match token { + Token::Ident(ident) => (ident, false), + Token::Op(ident) => (ident, true), + _ => { + return ParserReturns { + ast: TopLevelDeclaration::Value(TopLevelValue { + loc: ident_span, + is_op: false, + ident: "".to_string(), + args: vec![ArgDeclaration::Simple { + loc: (0, 0), + ident: "".to_string(), + ty: Some(types::ERROR), + }], + ty: Some(types::ERROR), + value: ValueType::Expr(Expr::Error), + generics, + abi, + }), + loc: ident_span, + warnings: Vec::new(), + errors: vec![ParseError { + span: ident_span, + reason: ParseErrorReason::DeclarationError, + }], + } + } + }; + let args = self.collect_args(); + warnings.extend(args.warnings); + errors.extend(args.errors); + let mut args = args.ast; + if is_op && (args.len() > 2 || args.len() == 0) { + errors.push(ParseError { + span: ident_span, + reason: ParseErrorReason::ArgumentError, + }); + } + let mut ty = if let Some((Token::Colon, _)) = self.stream.peek() { + let _ = self.stream.next(); + let ty = self.collect_type(); + warnings.extend(ty.warnings); + errors.extend(ty.errors); + Some(ty.ast) + } else { + if is_op { + errors.push(ParseError { + span: ident_span, + reason: ParseErrorReason::DeclarationError, + }); + } + None + }; + let value = match self.stream.peek() { + Some((Token::Op(op), _)) if op == "=" => { + let _ = self.stream.next(); + match self.stream.peek() { + Some((Token::BeginBlock, _)) => { + let block = self.collect_block(); + warnings.extend(block.warnings); + errors.extend(block.errors); + ValueType::Function(block.ast) + } + Some(_) => { + let expr = self.next_expr(); + warnings.extend(expr.warnings); + errors.extend(expr.errors); + ValueType::Expr(expr.ast) + } + None => { + errors.push(ParseError { + span: (0, 0), + reason: ParseErrorReason::UnexpectedEndOfFile, + }); + ValueType::Expr(Expr::Error) + } + } + } + Some((Token::Seq, _)) if abi.is_some() => { + let _ = self.stream.next(); + ValueType::External + } + Some((_, loc)) => { + errors.push(ParseError { + span: *loc, + reason: ParseErrorReason::UnexpectedToken, + }); + ValueType::Expr(Expr::Error) + } + None => { + errors.push(ParseError { + span: (0, 0), + reason: ParseErrorReason::UnexpectedEndOfFile, + }); + ValueType::Expr(Expr::Error) + } + }; + if let Some(generics) = &generics { + for arg in &mut args { + generics + .decls + .iter() + .map(|(_, it)| it) + .for_each(|name| arg.apply_generic(name)); + } + if let Some(ty) = &mut ty { + *ty = generics + .decls + .iter() + .map(|(_, it)| it) + .fold(ty.clone(), |ty, name| ty.replace_user_with_generic(name)); + } + } + ParserReturns { + ast: TopLevelDeclaration::Value(TopLevelValue { + loc: ident_span, + is_op, + ident, + args, + ty, + value, + generics, + abi, + }), + loc: ident_span, + warnings, + errors, + } + } + Some((Token::EoF, loc)) => { + errors.push(ParseError { + span: loc, + reason: ParseErrorReason::UnexpectedEndOfFile, + }); + ParserReturns { + ast: ast::TopLevelDeclaration::Value(TopLevelValue { + loc, + is_op: false, + ident: "".to_string(), + args: vec![ArgDeclaration::Simple { + loc, + ident: "".to_string(), + ty: Some(types::ERROR), + }], + ty: Some(types::ERROR), + value: ValueType::Expr(Expr::Error), + generics: generics, + abi: None, + }), + loc, + warnings, + errors, + } + } + Some((_, loc)) => { + errors.push(ParseError { + span: (0, 0), + reason: ParseErrorReason::UnexpectedToken, + }); + ParserReturns { + ast: ast::TopLevelDeclaration::Value(TopLevelValue { + loc, + is_op: false, + ident: "".to_string(), + args: vec![ArgDeclaration::Simple { + loc, + ident: "".to_string(), + ty: Some(types::ERROR), + }], + ty: Some(types::ERROR), + value: ValueType::Expr(Expr::Error), + generics: generics, + abi: None, + }), + loc, + warnings, + errors, + } + } + None => { + errors.push(ParseError { + span: (0, 0), + reason: ParseErrorReason::UnexpectedEndOfFile, + }); + ParserReturns { + ast: ast::TopLevelDeclaration::Value(TopLevelValue { + loc: (0, 0), + is_op: false, + ident: "".to_string(), + args: vec![ArgDeclaration::Simple { + loc: (0, 0), + ident: "".to_string(), + ty: Some(types::ERROR), + }], + ty: Some(types::ERROR), + value: ValueType::Expr(Expr::Error), + generics: generics, + abi: None, + }), + loc: (0, 0), + warnings, + errors, + } + } + } + } + pub fn next_statement(&mut self) -> ParserReturns { + match self.stream.clone().next() { + Some((Token::For, _)) => { + let ParserReturns { + ast: generics, + loc, + mut warnings, + mut errors, + } = self.collect_generics(); + let inner = self.fn_declaration(None, generics); + warnings.extend(inner.warnings); + errors.extend(inner.errors); + if let Some((Token::Seq, _)) = self.stream.clone().next() { + self.stream.next(); + } else { + // TODO generated error here. + println!("expected ; on line {}", inner.loc.0); + } + ParserReturns { + ast: Statement::Declaration(inner.ast), + loc, + warnings, + errors, + } + } + Some((Token::Let, _)) => { + let inner = match self.stream.clone().nth(1) { + Some((Token::GroupOpen, _)) => self.destructuring_declaration(), + Some((Token::Ident(_), _)) + if self.stream.clone().nth(2).map(|(a, _)| a) == Some(Token::CurlOpen) => + { + self.destructuring_declaration() + } + _ => self.fn_declaration(None, None), + }; + if let Some((Token::Seq, _)) = self.stream.clone().next() { + self.stream.next(); + } else { + // TODO generated error here. + println!("expected ; on line {}", inner.loc.0); + } + + ParserReturns { + ast: Statement::Declaration(inner.ast), + loc: inner.loc, + warnings: inner.warnings, + errors: inner.errors, + } + } + Some((Token::Return, _)) => { + let inner = self.ret(); + if let Some((Token::Seq, _)) = self.stream.clone().next() { + self.stream.next(); + } else { + println!("expected ; on line {}", inner.loc.0); + //TODO! convert next_toplevel an error that is added and returned as part of the ast. + } + inner + } + // hmmm should handle if it's actually a binary op call esp and/or compose. + Some((Token::Ident(_), _)) => + // for now last statement in a block is not treated as return though will allow for that soon. + { + let ParserReturns { + ast, + loc, + warnings, + errors, + } = self.function_call(); + let inner = Statement::FnCall(ast); + if let Some((Token::Seq, _)) = self.stream.clone().next() { + self.stream.next(); + } else { + println!("expected ; on line {}", inner.get_loc().0); + //TODO! convert next_toplevel a warning that is added and returned as part of the ast. + } + ParserReturns { + ast: inner, + loc, + warnings, + errors, + } + } + Some((Token::If, _)) => { + let inner = self.ifstatement(); + + ParserReturns { + ast: Statement::IfStatement(inner.ast), + loc: inner.loc, + warnings: inner.warnings, + errors: inner.errors, + } + } + Some((Token::Match, _)) => { + let ParserReturns { + ast: match_, + loc, + warnings, + errors, + } = self.match_(); + let ast = Statement::Match(match_); + ParserReturns { + ast, + loc, + warnings, + errors, + } + } + _ => unreachable!("how?"), + } + } + + pub fn next_expr(&mut self) -> ParserReturns { + match self.stream.clone().next() { + Some((Token::If, loc)) => { + let ParserReturns { + ast, + loc: _, + warnings, + errors, + } = self.ifexpr(); + ParserReturns { + ast: Expr::If(ast), + loc, + warnings, + errors, + } + } + Some((Token::BracketOpen, _)) => self.array_literal(), + Some((Token::GroupOpen, loc)) + if matches!(self.stream.clone().nth(1), Some((Token::GroupClose, _))) => + { + self.stream.next(); + self.stream.next(); + return ParserReturns { + ast: Expr::UnitLiteral, + loc, + warnings: Vec::new(), + errors: Vec::new(), + }; + } + Some((Token::GroupOpen, group_loc)) => { + let mut group_opens = 0; + if let Some((Token::Op(_), _)) = self + .stream + .clone() + .skip(1) + .skip_while(|(it, _)| match it { + //skip this whole expression next_toplevel examine what's after it. + Token::GroupOpen => { + group_opens += 1; + true + } + Token::Ident(_) + | Token::FloatingPoint(_, _) + | Token::Integer(_, _) + | Token::Op(_) => true, + Token::GroupClose => { + group_opens -= 1; + group_opens >= 0 + } + _ => false, + }) + .skip(1) + .next() + { + self.binary_op() + } else { + self.stream.next(); + let mut out = self.next_expr(); + + match self.stream.peek() { + Some((Token::GroupClose, _)) => { + let _ = self.stream.next(); + } + Some((Token::Comma, _)) => { + let _ = self.stream.next(); + let mut ast = vec![out.ast]; + loop { + let ParserReturns { + ast: expr, + loc, + warnings, + errors, + } = self.next_expr(); + out.errors.extend(errors); + out.warnings.extend(warnings); + ast.push(expr); + match self.stream.clone().next() { + Some((Token::Comma, _)) => { + self.stream.next(); + continue; + } + Some((Token::GroupClose, _)) => { + self.stream.next(); + break; + } + Some((Token::EoF, _)) | None => { + out.errors.push(ParseError { + span: (0, 0), + reason: ParseErrorReason::UnexpectedEndOfFile, + }); + break; + } + // TODO better error reporting. + Some((_other, loc)) => { + out.errors.push(ParseError { + span: loc, + reason: ParseErrorReason::UnexpectedToken, + }); + ast.push(ast::Expr::Error); + break; + } + } + } + + out.ast = if ast.len() == 1 { + ast.pop().unwrap() + } else { + Expr::TupleLiteral { + contents: ast, + loc: group_loc, + } + } + } + _ => (), + } + return out; + } + } + Some((Token::Ident(_), _)) + if match self.stream.clone().nth(1) { + Some((Token::Op(s), _)) => s == "<", + _ => false, + } => + { + let mut angle_depth = 1; + let mut skipped = self.stream.clone().skip(2).skip_while(|(it, _)| { + if angle_depth == 0 { + false + } else { + match it { + Token::Op(op) if op.chars().all_equal_value() == Ok('>') => { + if angle_depth <= op.len() { + angle_depth -= op.len(); + true + } else { + false + } + } + _ => true, + } + } + }); + if let Some((Token::CurlOpen, _)) = skipped.next() { + let ParserReturns { + ast, + loc, + warnings, + errors, + } = self.struct_construct(); + ParserReturns { + ast: Expr::StructConstruction(ast), + loc, + warnings, + errors, + } + } else { + self.binary_op() + } + } + Some(( + Token::Integer(_, _) + | Token::FloatingPoint(_, _) + | Token::CharLiteral(_) + | Token::StringLiteral(_) + | Token::Ident(_) + | Token::True + | Token::False, + _, + )) if match self.stream.clone().nth(1) { + Some((Token::Op(_), _)) => true, + _ => false, + } => + { + self.binary_op() + } + Some(( + Token::CharLiteral(_) + | Token::StringLiteral(_) + | Token::FloatingPoint(_, _) + | Token::Integer(_, _), + _, + )) => self.literal(), + Some((Token::Ident(_), _)) => { + if let Some(( + Token::Ident(_) + | Token::GroupOpen + | Token::StringLiteral(_) + | Token::CharLiteral(_) + | Token::FloatingPoint(_, _) + | Token::Integer(_, _), + _, + )) = self.stream.clone().nth(1) + { + let ParserReturns { + ast, + loc, + warnings, + errors, + } = self.function_call(); + ParserReturns { + ast: Expr::FnCall(ast), + loc, + warnings, + errors, + } + } else if let Some((Token::CurlOpen, _)) = self + .stream + .clone() + .skip(1) + .skip_while(|(it, _)| matches!(it, Token::BeginBlock)) + .next() + { + let ParserReturns { + ast, + loc, + warnings, + errors, + } = self.struct_construct(); + ParserReturns { + ast: Expr::StructConstruction(ast), + loc, + warnings, + errors, + } + } else { + self.value() + } + } + Some((Token::True, loc)) => { + let _ = self.stream.next(); + ParserReturns { + ast: Expr::BoolLiteral(true, loc), + loc, + warnings: Vec::new(), + errors: Vec::new(), + } + } + Some((Token::False, loc)) => { + let _ = self.stream.next(); + ParserReturns { + ast: Expr::BoolLiteral(false, loc), + loc, + warnings: Vec::new(), + errors: Vec::new(), + } + } + Some((Token::Match, _)) => { + let ParserReturns { + ast, + loc, + warnings, + errors, + } = self.match_(); + ParserReturns { + ast: Expr::Match(ast), + loc, + warnings, + errors, + } + } + _ => ParserReturns { + ast: Expr::Error, + loc: (0, 0), + warnings: Vec::new(), + errors: vec![ParseError { + span: (0, 0), + reason: ParseErrorReason::UnknownError, + }], + }, + } + } + + fn ifexpr(&mut self) -> ParserReturns { + let Some((Token::If, if_loc)) = self.stream.next() else { + unreachable!() + }; + let ParserReturns { + ast: root_cond, + loc: _, + mut warnings, + mut errors, + } = self.next_expr(); + if let Some((Token::Then, _)) = self.stream.peek() { + let _ = self.stream.next(); + } else { + let (_token, loc) = self.stream.next().unwrap(); + // TODO! recovery? + errors.push(ParseError { + span: loc, + reason: ParseErrorReason::UnexpectedToken, + }); + } + let true_body = match self.stream.clone().next() { + Some((Token::BeginBlock, _)) => { + let _ = self.stream.next(); + let mut body = Vec::new(); + while self + .stream + .clone() + .skip_while(|(it, _)| it != &Token::Seq && it != &Token::EndBlock) + .next() + .map(|a| a.0) + != Some(Token::EndBlock) + { + let stmnt = self.next_statement(); + warnings.extend(stmnt.warnings); + errors.extend(stmnt.errors); + body.push(stmnt.ast); + } + let ret = self.next_expr(); + errors.extend(ret.errors); + warnings.extend(ret.warnings); + let _ = self.stream.next(); + (body, ret.ast) + } + _ => (Vec::new(), { + let ret = self.next_expr(); + warnings.extend(ret.warnings); + errors.extend(ret.errors); + ret.ast + }), + }; + if let Some((Token::Else, _)) = self.stream.peek() { + let _ = self.stream.next(); + let mut else_ifs = Vec::new(); + + while let Some((Token::If, _)) = self.stream.peek() { + let Some((Token::If, loc)) = self.stream.next() else { + unreachable!() + }; + let cond = self.next_expr(); + warnings.extend(cond.warnings); + errors.extend(cond.errors); + let cond = cond.ast.into(); + + if let Some((Token::Then, _)) = self.stream.peek() { + let _ = self.stream.next(); + } else { + let (_token, loc) = self.stream.next().unwrap(); + // TODO! recovery? + errors.push(ParseError { + span: loc, + reason: ParseErrorReason::UnexpectedToken, + }); + } + let (body, ret) = match self.stream.clone().next() { + Some((Token::BeginBlock, _)) => { + let _ = self.stream.next(); + let mut body = Vec::new(); + while self + .stream + .clone() + .skip_while(|(it, _)| it != &Token::Seq && it != &Token::EndBlock) + .next() + .map(|a| a.0) + != Some(Token::EndBlock) + { + let stmnt = self.next_statement(); + warnings.extend(stmnt.warnings); + errors.extend(stmnt.errors); + body.push(stmnt.ast); + } + let ret = self.next_expr(); + errors.extend(ret.errors); + warnings.extend(ret.warnings); + let _ = self.stream.next(); + (body, ret.ast) + } + _ => { + let ret = self.next_expr(); + warnings.extend(ret.warnings); + errors.extend(ret.errors); + (Vec::new(), ret.ast) + } + }; + else_ifs.push((cond, body, ret.into())); + + if let Some((Token::Else, _loc)) = self.stream.clone().next() { + let _else_token = self.stream.next(); + } else { + //todo! recovery? + errors.push(ParseError { + span: loc, + reason: ParseErrorReason::UnexpectedToken, + }); + return ParserReturns { + ast: ast::IfExpr { + cond: root_cond.into(), + loc: if_loc, + true_branch: (true_body.0, true_body.1.into()), + else_ifs, + else_branch: (Vec::new(), ast::Expr::Error.into()), + }, + loc: if_loc, + warnings, + errors, + }; + }; + } + + let else_branch = match self.stream.clone().next() { + Some((Token::BeginBlock, _)) => { + let _ = self.stream.next(); + + let mut body = Vec::new(); + while self + .stream + .clone() + .skip_while(|(it, _)| it != &Token::Seq && it != &Token::EndBlock) + .next() + .map(|a| a.0 != Token::EndBlock && a.0 != Token::EoF) + .unwrap_or(false) + { + let stmnt = self.next_statement(); + warnings.extend(stmnt.warnings); + errors.extend(stmnt.errors); + body.push(stmnt.ast); + } + let ret = self.next_expr(); + warnings.extend(ret.warnings); + errors.extend(ret.errors); + + let _ = self.stream.next(); + (body, ret.ast.into()) + } + _ => { + let ret = self.next_expr(); + warnings.extend(ret.warnings); + errors.extend(ret.errors); + (Vec::new(), ret.ast.into()) + } + }; + + ParserReturns { + ast: ast::IfExpr { + cond: root_cond.into(), + true_branch: (true_body.0, true_body.1.into()), + else_ifs, + else_branch, + loc: if_loc, + }, + loc: if_loc, + warnings, + errors, + } + } else { + if let Some((_, loc)) = self.stream.clone().next() { + errors.push(ParseError { + span: loc, + reason: ParseErrorReason::UnexpectedToken, + }); + } + // TODO! recover + ParserReturns { + ast: ast::IfExpr { + cond: root_cond.into(), + true_branch: (true_body.0, true_body.1.into()), + else_ifs: Vec::new(), + else_branch: (Vec::new(), Expr::Error.into()), + loc: if_loc, + }, + loc: if_loc, + warnings, + errors, + } + } + } + + fn value(&mut self) -> ParserReturns { + if let Some((Token::Ident(ident), loc)) = self.stream.clone().next() { + let _ = self.stream.next(); + ParserReturns { + ast: ast::Expr::ValueRead(ident, loc), + loc, + warnings: Vec::new(), + errors: Vec::new(), + } + } else { + let loc = if let Some((_, loc)) = self.stream.peek() { + *loc + } else { + return ParserReturns { + ast: Expr::Error, + loc: (0, 0), + warnings: Vec::new(), + errors: vec![ParseError { + span: (0, 0), + reason: ParseErrorReason::UnexpectedEndOfFile, + }], + }; + }; + ParserReturns { + ast: Expr::Error, + loc: loc, + warnings: Vec::new(), + errors: vec![ParseError { + span: loc, + reason: ParseErrorReason::UnknownError, + }], + } + } + } + + fn function_call(&mut self) -> ParserReturns { + let mut errors = Vec::new(); + let mut warnings = Vec::new(); + if let Some((Token::Ident(ident), value_loc)) = self.stream.next() { + let mut values = Vec::<(ast::Expr, (usize, usize))>::new(); + while let Some(( + | Token::GroupOpen + | Token::Ident(_) + // | Token::Op(_) // TODO! this will need some special handling. ie for `foo bar >>> baz` should that be parsed as `(foo bar) >>> baz` or `foo (bar >>> baz)` + | Token::Integer(_,_) + | Token::FloatingPoint(_, _) + | Token::CharLiteral(_) + | Token::StringLiteral(_) + | Token::True + | Token::False + | Token::BracketOpen + ,_ + )) = self.stream.peek() { + match self.stream.peek().map(|(a,_)| a) { + Some(Token::Ident(_)) => { + let test = self.stream.clone().nth(1); + if let Some((Token::Op(_),_)) = test { + let ParserReturns { ast:expr, loc, warnings:expr_warnings, errors:expr_errors } =self.binary_op(); + values.push((expr,loc)); + warnings.extend(expr_warnings); + errors.extend(expr_errors); + } else { + let ParserReturns { ast:expr, loc, warnings:expr_warnings, errors:expr_errors } =self.value(); + values.push((expr,loc)); + warnings.extend(expr_warnings); + errors.extend(expr_errors); + } + } + Some(Token::GroupOpen | Token::BracketOpen) =>{ + let value = self.next_expr(); + errors.extend(value.errors); + warnings.extend(value.warnings); + values.push((value.ast,value.loc)) + }, + Some( + | Token::Integer(_,_) + | Token::FloatingPoint(_, _) + | Token::CharLiteral(_) + | Token::StringLiteral(_) + | Token::True + | Token::False + ) => { + let test = self.stream.clone().nth(1); + if let Some(( + | Token::Ident(_) + | Token::Integer(_,_) + | Token::FloatingPoint(_, _) + | Token::CharLiteral(_) + | Token::StringLiteral(_) + ,loc)) = test { + let ParserReturns { ast, loc:_, warnings:lit_warnings, errors:lit_errors, }= self.literal(); + warnings.extend(lit_warnings); + errors.extend(lit_errors); + values.push((ast,loc)) + } else if let Some((Token::Op(_),_)) = test { + let ParserReturns { ast:expr, loc, warnings:expr_warnings, errors:expr_errors } =self.binary_op(); + values.push((expr,loc)); + warnings.extend(expr_warnings); + errors.extend(expr_errors); + } else { + let ParserReturns { ast, loc:_, warnings:lit_warnings, errors:lit_errors, }= self.literal(); + warnings.extend(lit_warnings); + errors.extend(lit_errors); + values.push((ast,value_loc)) + } + }, + _ => unreachable!() + // TODO! add in operator case special handling + } + } + let (ast, _loc) = values.into_iter().fold( + ( + FnCall { + loc: value_loc, + value: ast::Expr::ValueRead(ident, value_loc).into(), + arg: None, + }, + value_loc, + ), + |(inner, loc), (next, next_loc)| { + if let FnCall { + value, arg: None, .. + } = inner + { + ( + FnCall { + loc, + value, + arg: Some(next.into()), + }, + next_loc, + ) + } else { + ( + FnCall { + loc, + value: Expr::FnCall(inner).into(), + arg: Some(next.into()), + }, + next_loc, + ) + } + }, + ); + ParserReturns { + ast, + loc: value_loc, + warnings, + errors, + } + } else { + errors.push(ParseError { + span: (0, 0), + reason: ParseErrorReason::UnknownError, + }); + ParserReturns { + ast: FnCall { + value: Expr::Error.into(), + arg: Some(Expr::Error.into()), + loc: (0, 0), + }, + loc: (0, 0), + warnings, + errors, + } + } + } + + fn struct_construct(&mut self) -> ParserReturns { + let mut warnings = Vec::new(); + let mut errors = Vec::new(); + let Some((_, loc)) = self.stream.clone().next() else { + unreachable!("ICE: somehow reached struct construction with no token?") + }; + + let ty = self.collect_type(); + warnings.extend(ty.warnings); + errors.extend(ty.errors); + let (name, generics) = if let ResolvedType::User { name, generics, .. } = ty.ast { + (name, generics) + } else { + ("".to_string(), vec![types::ERROR]) + }; + let Some((Token::CurlOpen, loc)) = self.stream.next() else { + /* TODO? handle blocks? + EG: ``` + let x = Foo + { + y:0 + } + ``` + though idomatic would be the following or inline. + ``` + let x = Foo { + y:0 + } + ``` + */ + unreachable!("ICE: reached struct construction with no braces?") + }; + let mut fields = HashMap::new(); + while let Some((Token::Ident(_), _)) = self.stream.peek() { + let Some((Token::Ident(ident), loc)) = self.stream.next() else { + unreachable!() + }; + let Some((Token::Colon, _)) = self.stream.next() else { + todo!("handle infered assignment") + }; + let ParserReturns { + ast: expr, + loc: _, + warnings: expr_warnings, + errors: expr_errors, + } = self.next_expr(); + warnings.extend(expr_warnings); + errors.extend(expr_errors); + if fields.contains_key(&ident) { + let (_, loc): &(_, crate::Location) = &fields[&ident]; + errors.push(ParseError { + span: *loc, + reason: ParseErrorReason::DeclarationError, + }) + } else { + fields.insert(ident, (expr, loc)); + } + if let Some((Token::Comma, _)) = self.stream.peek() { + self.stream.next(); + } + } + let _: Vec<_> = self + .stream + .peeking_take_while(|(t, _)| matches!(t, Token::EndBlock)) + .collect(); + let Some((Token::CurlClose, _)) = self.stream.next() else { + errors.push(ParseError { + span: loc, + reason: ParseErrorReason::UnbalancedBraces, + }); + fields.insert("".to_string(), (Expr::Error, (0, 0))); + return ParserReturns { + ast: StructConstruction { + loc, + fields, + generics, + ident: "".to_string(), + }, + loc, + warnings, + errors, + }; + }; + ParserReturns { + ast: StructConstruction { + loc, + fields, + generics, + ident: name, + }, + loc, + warnings, + errors, + } + } + + fn ret(&mut self) -> ParserReturns { + let (token, span) = self.stream.next().unwrap(); + if token == Token::Return { + let ParserReturns { + ast: expr, + loc: _, + warnings, + errors, + } = self.next_expr(); + ParserReturns { + ast: ast::Statement::Return(expr, span), + loc: span, + warnings, + errors, + } + } else { + ParserReturns { + ast: Statement::Error, + loc: span, + warnings: Vec::new(), + errors: vec![ParseError { + span, + reason: ParseErrorReason::UnknownError, + }], + } + } + } + + fn literal(&mut self) -> ParserReturns { + let (token, span) = self.stream.next().unwrap(); + match make_literal(token, span) { + Ok(lit) => ParserReturns { + ast: lit, + loc: span, + warnings: Vec::new(), + errors: Vec::new(), + }, + Err(e) => ParserReturns { + ast: Expr::Error, + loc: span, + warnings: Vec::new(), + errors: vec![e], + }, + } + } + + fn ifstatement(&mut self) -> ParserReturns { + let Some((Token::If, if_loc)) = self.stream.next() else { + unreachable!() + }; + let ParserReturns { + ast: cond, + mut warnings, + mut errors, + loc: _, + } = self.next_expr(); + let cond = cond.into(); + if let Some((Token::Then, _)) = self.stream.peek() { + let _ = self.stream.next(); + } else { + let (token, loc) = self.stream.next().unwrap(); + println!( + "Expected then but got {:?} at line:{} col:{}", + token, loc.0, loc.1 + ); + errors.push(ParseError { + span: loc, + reason: ParseErrorReason::UnexpectedToken, + }); + //TODO? more recovery? + return ParserReturns { + ast: ast::IfBranching { + cond, + true_branch: vec![Statement::Error], + else_ifs: Vec::new(), + else_branch: Vec::new(), + loc: if_loc, + }, + loc: if_loc, + warnings, + errors, + }; + }; + + let body = match self.stream.peek() { + Some((Token::BeginBlock, _)) => { + let block = self.collect_block(); + warnings.extend(block.warnings); + errors.extend(block.errors); + block.ast + } + _ => { + let stmnt = self.next_statement(); + warnings.extend(stmnt.warnings); + errors.extend(stmnt.errors); + vec![stmnt.ast] + } + }; + + if let Some((Token::Else, _)) = self.stream.peek() { + let mut else_ifs = Vec::new(); + while let Some((Token::If, _)) = self.stream.clone().nth(1) { + let Some((Token::Else, _)) = self.stream.next() else { + unreachable!() + }; + let Some((Token::If, _loc)) = self.stream.next() else { + unreachable!() + }; + + let ParserReturns { + ast: cond, + warnings: new_warnings, + errors: new_errors, + loc: _, + } = self.next_expr(); + warnings.extend(new_warnings); + errors.extend(new_errors); + let cond = cond.into(); + if let Some((Token::Then, _)) = self.stream.peek() { + let _ = self.stream.next(); + } else { + let (token, loc) = self.stream.next().unwrap(); + println!( + "Expected then but got {:?} at line:{} col:{}", + token, loc.0, loc.1 + ); + errors.push(ParseError { + span: loc, + reason: ParseErrorReason::UnexpectedToken, + }); + }; + let body = match self.stream.peek() { + Some((Token::BeginBlock, _)) => { + let block = self.collect_block(); + warnings.extend(block.warnings); + errors.extend(block.errors); + block.ast + } + _ => { + let stmnt = self.next_statement(); + warnings.extend(stmnt.warnings); + errors.extend(stmnt.errors); + vec![stmnt.ast] + } + }; + else_ifs.push((cond, body)); + } + + let else_branch = if let Some((Token::Else, _)) = self.stream.clone().next() { + let _ = self.stream.next(); + + match self.stream.peek() { + Some((Token::BeginBlock, _)) => { + let block = self.collect_block(); + warnings.extend(block.warnings); + errors.extend(block.errors); + block.ast + } + _ => { + let stmnt = self.next_statement(); + warnings.extend(stmnt.warnings); + errors.extend(stmnt.errors); + vec![stmnt.ast] + } + } + } else { + Vec::new() + }; + ParserReturns { + ast: ast::IfBranching { + cond, + true_branch: body, + else_ifs, + else_branch, + loc: if_loc, + }, + loc: if_loc, + warnings, + errors, + } + } else { + ParserReturns { + ast: ast::IfBranching { + cond, + true_branch: body, + else_ifs: Vec::new(), + else_branch: Vec::new(), + loc: if_loc, + }, + loc: if_loc, + warnings, + errors, + } + } + } + + pub(crate) fn collect_type(&mut self) -> ParserReturns { + let mut warnings = Vec::new(); + let mut errors = Vec::new(); + let ty = self.stream.next(); + match ty { + Some((Token::Ident(ty), loc)) => { + let mut generic_args = Vec::new(); + if self.stream.peek().map(|(a, _)| a) == Some(&Token::Op("<".to_string())) { + self.stream.next(); + while { + let ty = self.collect_type(); + warnings.extend(ty.warnings); + errors.extend(ty.errors); + generic_args.push(ty.ast); + #[cfg(debug_assertions)] + let _peek = self.stream.peek(); + if self.stream.peek().map(|(a, _)| a) == Some(&Token::Comma) { + let _ = self.stream.next(); + true + } else { + false + } + } {} + if !generic_args.is_empty() { + let mut should_pop = false; + if let Some((Token::Op(s), _)) = self.stream.peek_mut() { + if s.chars().all_equal_value() == Ok('>') { + s.pop(); + if s.len() == 0 { + should_pop = true; + } + } else { + errors.push(ParseError { + span: loc, + reason: ParseErrorReason::UnbalancedBraces, + }); + return ParserReturns { + ast: types::ERROR, + loc, + warnings, + errors, + }; + } + } + if should_pop { + let _ = self.stream.next(); + } + } + } + if let Some((Token::Arrow, fn_loc)) = self.stream.clone().next() { + self.stream.next(); + let result = self.collect_type(); + let ty = type_from_string(&ty, generic_args, loc); + warnings.extend(result.warnings); + errors.extend(result.errors); + ParserReturns { + ast: ResolvedType::Function { + arg: ty.into(), + returns: result.ast.into(), + loc: fn_loc, + }, + loc: fn_loc, + warnings, + errors, + } + } else { + let ty = type_from_string(&ty, generic_args, loc); + ParserReturns { + ast: ty, + loc, + warnings, + errors, + } + } + } + Some((Token::GroupOpen, span)) => { + if let Some((Token::GroupClose, _)) = self.stream.peek() { + self.stream.next(); + return if let Some((Token::Arrow, arr_loc)) = self.stream.clone().next() { + self.stream.next(); + let returns = self.collect_type(); + warnings.extend(returns.warnings); + errors.extend(returns.errors); + ParserReturns { + ast: ResolvedType::Function { + arg: types::UNIT.into(), + returns: returns.ast.into(), + loc: arr_loc, + }, + loc: span, + warnings, + errors, + } + } else { + ParserReturns { + ast: types::UNIT, + loc: span, + warnings, + errors, + } + }; + } + let ty = self.collect_type(); + warnings.extend(ty.warnings); + errors.extend(ty.errors); + let loc = ty.loc; + let mut tys = vec![ty.ast]; + loop { + if let Some((Token::Comma, _)) = self.stream.clone().next() { + let _ = self.stream.next(); + let ty = self.collect_type(); + warnings.extend(ty.warnings); + errors.extend(ty.errors); + tys.push(ty.ast); + match self.stream.clone().next() { + Some((Token::GroupClose, _)) => { + break; + } + Some((Token::Comma, _)) => continue, + _ => { + errors.push(ParseError { + span: span, + reason: ParseErrorReason::TypeError, + }); + return ParserReturns { + ast: types::ERROR, + loc: (0, 0), + warnings, + errors, + }; + } + } + } else { + break; + //TODO! error reporting? + } + } + let ty = if tys.len() == 1 { + tys.pop().unwrap() + } else { + ResolvedType::Tuple { + underlining: tys, + loc: span, + } + }; + if let Some((Token::GroupClose, _)) = self.stream.clone().next() { + let _ = self.stream.next(); + } else { + errors.push(ParseError { + span, + reason: ParseErrorReason::UnbalancedBraces, + }); + } + if let Some((Token::Arrow, arr_loc)) = self.stream.clone().next() { + self.stream.next(); + let result = self.collect_type(); + warnings.extend(result.warnings); + errors.extend(result.errors); + ParserReturns { + ast: ResolvedType::Function { + arg: ty.into(), + returns: result.ast.into(), + loc: arr_loc, + }, + loc: arr_loc, + warnings, + errors, + } + } else { + ParserReturns { + ast: ty, + loc, + warnings, + errors, + } + } + } + Some((Token::BracketOpen, loc)) => { + let ty = self.collect_type(); + warnings.extend(ty.warnings); + errors.extend(ty.errors); + let ty = ty.ast; + match self.stream.clone().next() { + Some((Token::Seq, _)) => { + let _ = self.stream.next(); + match self.stream.clone().next() { + Some((Token::Integer(false, _), _)) => { + let Some((Token::Integer(_, value), _)) = self.stream.next() else { + unreachable!() + }; + match self.stream.peek() { + Some((Token::BracketClose, _)) => { + let _ = self.stream.next(); + ParserReturns { + ast: ResolvedType::Array { + underlining: ty.into(), + size: value.parse().unwrap(), + }, + loc, + warnings, + errors, + } + } + Some((t, loc)) => { + println!( + "unexpected token:{t:?} at line:{}, col:{}", + loc.0, loc.1 + ); + errors.push(ParseError { + span: *loc, + reason: ParseErrorReason::UnbalancedBraces, + }); + ParserReturns { + ast: types::ERROR, + loc: *loc, + warnings, + errors, + } + } + None => { + unreachable!("how did this happen. this is an ice please report it."); + } + } + } + Some((t, loc)) => { + println!("unexpected token:{t:?} at line:{}, col:{}", loc.0, loc.1); + errors.push(ParseError { + span: loc, + reason: ParseErrorReason::UnbalancedBraces, + }); + ParserReturns { + ast: types::ERROR, + loc, + warnings, + errors, + } + } + None => { + unreachable!( + "how did this happen. this is an ice please report it." + ); + } + } + } + Some((Token::BracketClose, _)) => { + let _ = self.stream.next(); + ParserReturns { + ast: ResolvedType::Slice { + underlining: ty.into(), + }, + loc, + warnings, + errors, + } + } + Some((t, loc)) => { + println!("unexpected token:{t:?} at line:{}, col:{}", loc.0, loc.1); + errors.push(ParseError { + span: loc, + reason: ParseErrorReason::UnbalancedBraces, + }); + ParserReturns { + ast: types::ERROR, + loc, + warnings, + errors, + } + } + None => { + unreachable!("how did this happen. this is an ICE please report it."); + } + } + } + Some((_, span)) => { + errors.push(ParseError { + span, + reason: ParseErrorReason::TypeError, + }); + ParserReturns { + ast: types::ERROR, + loc: span, + warnings, + errors, + } + } + None => { + errors.push(ParseError { + span: (0, 0), + reason: ParseErrorReason::TypeError, + }); + ParserReturns { + ast: types::ERROR, + loc: (0, 0), + warnings, + errors, + } + } + } + } + #[allow(unused)] + fn pipe(&mut self) -> Result { + todo!("pipes") + } + #[allow(unused)] + /// will probably remove as it can easily be defined in lang? + fn compose(&mut self) -> Result { + todo!("compose") + } + + fn abi(&mut self) -> ParserReturns> { + match self.stream.clone().next() { + Some((Token::Extern, loc)) => { + let _ = self.stream.next(); + let mut errors = Vec::new(); + let abi = if let Some((Token::StringLiteral(_), _)) = self.stream.clone().next() { + let Some((Token::StringLiteral(name), _)) = self.stream.next() else { + unreachable!() + }; + name + } else { + errors.push(ParseError { + span: loc, + reason: ParseErrorReason::UnexpectedToken, + }); + "".to_string() + }; + ParserReturns { + ast: Some(ast::Abi { + loc, + identifier: abi, + }), + loc, + warnings: Vec::new(), + errors, + } + } + _ => ParserReturns { + ast: None, + loc: (0, 0), + warnings: Vec::new(), + errors: Vec::new(), + }, + } + } + + fn declaration(&mut self) -> ParserReturns { + let ParserReturns { + ast: abi, + loc: extern_loc, + mut warnings, + mut errors, + } = self.abi(); + let ParserReturns { + ast: generics, + loc: for_loc, + warnings: for_warnings, + errors: for_errors, + } = self.collect_generics(); + warnings.extend(for_warnings); + errors.extend(for_errors); + if abi.is_some() && generics.is_some() { + errors.push(ParseError { + span: for_loc, + reason: ParseErrorReason::DeclarationError, + }); + } + let next = self.stream.clone().next(); + match next { + Some((Token::Let, _)) => self.fn_declaration(abi, generics), + Some((Token::Seq, _)) => { + let _ = self.stream.next(); + self.declaration() + } + _ => unimplemented!(), + } + } + + fn type_decl( + &mut self, + generics: Option, + ) -> ParserReturns { + let mut warnings = Vec::new(); + let mut errors = Vec::new(); + let Some((t, loc)) = self.stream.next() else { + unreachable!() + }; + match t { + Token::Type => { + let (ident, loc) = match self.stream.next() { + Some((Token::Ident(ident), loc)) => (ident, loc), + _ => { + // todo recover? + errors.push(ParseError { + span: loc, + reason: ParseErrorReason::DeclarationError, + }); + return ParserReturns { + ast: TypeDefinition::Alias("".to_string(), types::ERROR), + loc, + warnings, + errors, + }; + } + }; + let Some((Token::Op(op), _)) = self.stream.next() else { + errors.push(ParseError { + span: loc, + reason: ParseErrorReason::DeclarationError, + }); + return ParserReturns { + ast: TypeDefinition::Alias("".to_string(), types::ERROR), + loc, + warnings, + errors, + }; + }; + if op != "=" { + errors.push(ParseError { + span: loc, + reason: ParseErrorReason::DeclarationError, + }); + return ParserReturns { + ast: TypeDefinition::Alias("".to_string(), types::ERROR), + loc, + warnings, + errors, + }; + } + match self.stream.peek() { + Some((Token::Ident(_), _)) => { + let ty = self.collect_type(); + warnings.extend(ty.warnings); + errors.extend(ty.errors); + ParserReturns { + ast: ast::TypeDefinition::Alias(ident, ty.ast), + loc, + warnings, + errors, + } + } + Some((Token::CurlOpen, _)) => { + let strct = self.struct_declaration(ident, generics, loc); + warnings.extend(strct.warnings); + errors.extend(strct.errors); + ParserReturns { + ast: ast::TypeDefinition::Struct(strct.ast), + loc, + warnings, + errors, + } + } + // Some((Token::Op(op), _)) if op == "|" => Ok(ast::TypeDefinition::Enum( + // ident, + // self.enum_declaration(generics)?, + // loc, + // )), + _ => { + errors.push(ParseError { + span: loc, + reason: ParseErrorReason::DeclarationError, + }); + ParserReturns { + ast: ast::TypeDefinition::Alias("".to_string(), types::ERROR), + loc, + warnings, + errors, + } + } + } + } + Token::Enum => { + let enum_ = self.enum_declaration(generics); + ParserReturns { + ast: ast::TypeDefinition::Enum(enum_.ast), + loc, + warnings: enum_.warnings, + errors: enum_.errors, + } + } + _ => unreachable!(), + } + } + + #[allow(unused)] + fn enum_declaration( + &mut self, + generics: Option, + ) -> ParserReturns { + let mut errors = Vec::new(); + let mut warnings = Vec::new(); + let (ident, loc) = match self.stream.clone().next() { + Some((Token::Ident(_), _)) => { + let Some((Token::Ident(ident), loc)) = self.stream.next() else { + unreachable!() + }; + (ident, loc) + } + Some((Token::EoF, loc)) => { + errors.push(ParseError { + span: loc, + reason: ParseErrorReason::UnexpectedEndOfFile, + }); + return ParserReturns { + ast: ast::EnumDeclaration { + ident: "".to_string(), + generics, + values: Vec::new(), + loc: (0, 0), + }, + loc: (0, 0), + warnings, + errors, + }; + } + Some((_, loc)) => { + let _ = self + .stream + .peeking_take_while(|(token, _)| match token { + Token::Op(op) if op == "=" || op == "|" => false, + _ => true, + }) + .collect_vec(); + errors.push(ParseError { + span: loc, + reason: ParseErrorReason::UnexpectedToken, + }); + ("".to_string(), loc) + } + None => { + errors.push(ParseError { + span: (0, 0), + reason: ParseErrorReason::UnexpectedEndOfFile, + }); + return ParserReturns { + ast: ast::EnumDeclaration { + ident: "".to_string(), + generics, + values: Vec::new(), + loc: (0, 0), + }, + loc: (0, 0), + warnings, + errors, + }; + } + }; + let op = match self.stream.next() { + Some((Token::Op(op), _)) => op, + _ => { + //TODO! progress next_toplevel valid point. + errors.push(ParseError { + span: loc, + reason: ParseErrorReason::DeclarationError, + }); + return ParserReturns { + ast: ast::EnumDeclaration { + ident, + generics, + values: vec![ast::EnumVariant::Tuple { + ident: "".to_string(), + ty: types::ERROR, + loc: (0, 0), + }], + loc, + }, + loc, + warnings, + errors, + }; + } + }; + + if op != "=" { + //TODO! progress next_toplevel until valid point. + errors.push(ParseError { + span: loc, + reason: ParseErrorReason::DeclarationError, + }); + return ParserReturns { + ast: ast::EnumDeclaration { + ident, + generics, + values: vec![ast::EnumVariant::Tuple { + ident: "".to_string(), + ty: types::ERROR, + loc: (0, 0), + }], + loc, + }, + loc, + warnings, + errors, + }; + } + let mut values = Vec::new(); + while let Some((Token::Op(op), _)) = self.stream.peek() { + if op == "|" { + let _ = self.stream.next(); + let (ident, variant_loc) = match self.stream.clone().next() { + Some((Token::Ident(_), _)) => { + let Some((Token::Ident(ident), loc)) = self.stream.next() else { + unreachable!() + }; + (ident, loc) + } + Some((Token::EoF, loc)) => { + errors.push(ParseError { + span: loc, + reason: ParseErrorReason::UnexpectedEndOfFile, + }); + return ParserReturns { + ast: ast::EnumDeclaration { + ident, + generics, + values: vec![ast::EnumVariant::Tuple { + ident: "".to_string(), + ty: types::ERROR, + loc: (0, 0), + }], + loc, + }, + loc, + warnings, + errors, + }; + } + Some((_, loc)) => { + let _ = self + .stream + .peeking_take_while(|(token, _)| match token { + Token::Op(op) if op == "=" || op == "|" => false, + _ => true, + }) + .collect_vec(); + errors.push(ParseError { + span: loc, + reason: ParseErrorReason::UnexpectedToken, + }); + ("".to_string(), loc) + } + None => { + errors.push(ParseError { + span: (0, 0), + reason: ParseErrorReason::UnexpectedEndOfFile, + }); + return ParserReturns { + ast: ast::EnumDeclaration { + ident, + generics, + values: vec![ast::EnumVariant::Tuple { + ident: "".to_string(), + ty: types::ERROR, + loc: (0, 0), + }], + loc, + }, + loc, + warnings, + errors, + }; + } + }; + match self.stream.peek() { + Some((Token::CurlOpen, _)) => { + let fields = self.struct_declaration("".to_string(), generics.clone(), loc); + warnings.extend(fields.warnings); + errors.extend(fields.errors); + values.push(ast::EnumVariant::Struct { + ident, + fields: fields.ast.values, + loc: variant_loc, + }); + } + Some((Token::Op(op), _)) if op == "|" => { + values.push(ast::EnumVariant::Unit { + ident, + loc: variant_loc, + }); + } + Some((Token::Ident(_) | Token::BracketOpen | Token::GroupOpen, _)) => { + let ty = self.collect_type(); + warnings.extend(ty.warnings); + errors.extend(ty.errors); + let ty = ty.ast; + let ty = if let Some(generics) = &generics { + generics + .decls + .iter() + .map(|(_, name)| name) + .fold(ty, |accum, name| accum.replace_user_with_generic(name)) + } else { + ty + }; + values.push(ast::EnumVariant::Tuple { + ident, + ty, + loc: variant_loc, + }); + } + _ => { + values.push(ast::EnumVariant::Unit { + ident, + loc: variant_loc, + }); + break; + } + } + } else { + break; + } + } + ParserReturns { + ast: ast::EnumDeclaration { + ident, + generics, + values, + loc, + }, + loc, + warnings, + errors, + } + } + + fn struct_declaration( + &mut self, + ident: String, + generics: Option, + loc: crate::Location, + ) -> ParserReturns { + let Some((Token::CurlOpen, _)) = self.stream.next() else { + unreachable!() + }; + while let Some((Token::BeginBlock, _)) = self.stream.clone().next() { + self.stream.next(); + } + let mut errors = Vec::new(); + #[allow(unused_mut)] + let mut warnings = Vec::new(); + let mut fields = Vec::::new(); + while let Some((Token::Ident(_), _)) = self.stream.clone().next() { + let Some((Token::Ident(name), loc)) = self.stream.next() else { + unreachable!(); + }; + let Some((Token::Colon, _)) = self.stream.next() else { + errors.push(ParseError { + span: (0, 10000), + reason: ParseErrorReason::DeclarationError, + }); + fields.push(FieldDecl { + name, + ty: ResolvedType::Error, + loc, + }); + let ts = self + .stream + .clone() + .take_while(|(it, _)| match it { + Token::Comma | Token::CurlClose | Token::EndBlock => false, + _ => true, + }) + .collect_vec(); + for _ in ts { + let _ = self.stream.next(); + } + continue; + }; + let ty = self.collect_type(); + warnings.extend(ty.warnings); + errors.extend(ty.errors); + let ty = ty.ast; + let ty = if let Some(generics) = &generics { + generics + .decls + .iter() + .map(|(_, it)| it) + .fold(ty, |result, it| result.replace_user_with_generic(it)) + } else { + ty + }; + if let Some((Token::Comma, _)) = self.stream.clone().next() { + self.stream.next(); + } else { + if let Some((Token::Ident(_), loc)) = self.stream.clone().next() { + println!("expected comma at line:{},col:{}", loc.0, loc.1); + while let Some((token, _)) = self.stream.clone().next() { + match token { + Token::CurlClose => { + self.stream.next(); + break; + } + _ => { + self.stream.next(); + } + } + } + errors.push(ParseError { + span: loc, + reason: ParseErrorReason::DeclarationError, + }); + } + } + while let Some((Token::EndBlock, _)) = self.stream.clone().next() { + self.stream.next(); + } + fields.push(ast::FieldDecl { name, ty, loc }); + } + while let Some((Token::EndBlock | Token::Comma, _)) = self.stream.clone().next() { + self.stream.next(); + } + let Some((Token::CurlClose, _)) = self.stream.next() else { + errors.push(ParseError { + span: (0, 11111), + reason: ParseErrorReason::DeclarationError, + }); + return ParserReturns { + ast: StructDefinition { + ident, + generics, + values: fields, + loc, + }, + loc, + warnings, + errors, + }; + }; + ParserReturns { + ast: StructDefinition { + ident, + generics, + values: fields, + loc, + }, + loc, + warnings, + errors, + } + } + + fn collect_generics(&mut self) -> ParserReturns> { + #[allow(unused_mut)] + let mut warnings = Vec::new(); + let mut errors = Vec::new(); + let generics = if let Some((Token::For, _)) = self.stream.clone().next() { + let Some((_, for_loc)) = self.stream.next() else { + unreachable!() + }; + match self.stream.next() { + Some((Token::Op(op), _)) if op == "<" => { + let mut out = self + .stream + .clone() + .filter(|(token, _)| &Token::Comma != token) + .take_while(|(token, _)| &Token::Op(">".to_string()) != token) + .collect_vec(); + // TODO should probably fold next_toplevel ensure that it is comma seperated. + let first_span = out.first().unwrap().1; + let num = out.len(); + out.dedup_by_key(|(it, _)| it.clone()); + if out.len() == num { + Some(ast::GenericsDecl { + for_loc, + decls: out + .into_iter() + .filter_map(|(t, loc)| { + let Token::Ident(name) = t else { return None }; + Some((loc, name)) + }) + .collect(), + }) + } else { + errors.push(ParseError { + span: first_span, + reason: ParseErrorReason::DeclarationError, + }); + return ParserReturns { + ast: None, + loc: first_span, + warnings, + errors, + }; + } + } + _ => { + errors.push(ParseError { + span: for_loc, + reason: ParseErrorReason::DeclarationError, + }); + return ParserReturns { + ast: None, + loc: for_loc, + warnings, + errors, + }; + } + } + } else { + None + }; + if generics.is_some() { + while let Some((token, _)) = self.stream.clone().next() { + match token { + Token::Op(op) if op == ">" => { + self.stream.next(); + break; + } + _ => { + self.stream.next(); + } + } + } + } + ParserReturns { + loc: generics.as_ref().map(|it| it.for_loc).unwrap_or_default(), + ast: generics, + warnings, + errors, + } + } + + fn parse_arg(&mut self) -> ParserReturns { + #[allow(unused_mut)] + let mut warnings = Vec::new(); + let mut errors = Vec::new(); + match self.stream.clone().next() { + Some((Token::GroupOpen, _)) => { + //( + let Some((Token::GroupOpen, open_loc)) = self.stream.next() else { + unreachable!() + }; + match self.stream.clone().next() { + Some((Token::GroupClose, _)) => { + //() + let _ = self.stream.next(); // ) + let ty = if let Some((Token::Colon, _)) = self.stream.clone().next() { + let _ = self.stream.next(); // : + let ty = self.collect_type(); + warnings.extend(ty.warnings); + errors.extend(ty.errors); + // will error at type checking/inference phase if not a unit type. + Some(ty.ast) + } else { + None + }; + ParserReturns { + ast: ArgDeclaration::Unit { loc: open_loc, ty }, + loc: open_loc, + warnings, + errors, + } + } + Some((Token::Ident(_), _)) => { + // ( + let Some((Token::Ident(name), loc)) = self.stream.next() else { + unreachable!() + }; + match self.stream.clone().next() { + Some((Token::Colon, _)) => { + //(: + let _ = self.stream.next(); // : + let ty = self.collect_type(); + warnings.extend(ty.warnings); + errors.extend(ty.errors); + let ty = ty.ast; + match self.stream.clone().next() { + Some((Token::GroupClose, _)) => { + let _ = self.stream.next(); + } + Some((_, loc)) => { + errors.push(ParseError { + span: loc, + reason: ParseErrorReason::UnbalancedBraces, + }); + } + None => { + errors.push(ParseError { + span: (0, 0), + reason: ParseErrorReason::UnbalancedBraces, + }); + } + } + ParserReturns { + ast: if name == "_" { + ArgDeclaration::Discard { loc, ty: Some(ty) } + } else { + ArgDeclaration::Simple { + loc, + ident: name, + ty: Some(ty), + } + }, + loc, + warnings, + errors, + } + } + Some((Token::Comma, _)) => { + //(, + let mut contents = vec![if name == "_" { + ArgDeclaration::Discard { loc, ty: None } + } else { + ArgDeclaration::Simple { + loc, + ident: name, + ty: None, + } + }]; + let _ = self.stream.next(); //, + while let Some((Token::Ident(_) | Token::GroupOpen, _)) = + self.stream.clone().next() + { + let arg = self.parse_arg(); + warnings.extend(arg.warnings); + errors.extend(arg.errors); + contents.push(arg.ast); + } + let ty = if let Some((Token::Colon, _)) = self.stream.clone().next() + { + let _ = self.stream.next(); + let ty = self.collect_type(); + warnings.extend(ty.warnings); + errors.extend(ty.errors); + Some(ty.ast) + } else { + None + }; + if let Some((Token::GroupClose, _)) = self.stream.clone().next() { + let _ = self.stream.next(); + } else { + errors.push(ParseError { + span: loc, + reason: ParseErrorReason::UnbalancedBraces, + }); + } + ParserReturns { + ast: ArgDeclaration::DestructureTuple(contents, ty, open_loc), + loc: open_loc, + warnings, + errors, + } + } + Some((Token::GroupClose, _)) => { + //() + let _ = self.stream.next(); + ParserReturns { + ast: if name == "_" { + ArgDeclaration::Discard { loc, ty: None } + } else { + ArgDeclaration::Simple { + loc, + ident: name, + ty: None, + } + }, + loc: open_loc, + warnings, + errors, + } + } + Some((_, loc)) => { + errors.push(ParseError { + span: loc, + reason: ParseErrorReason::UnbalancedBraces, + }); + ParserReturns { + ast: ArgDeclaration::Simple { + loc, + ident: "".to_string(), + ty: Some(types::ERROR), + }, + loc, + warnings, + errors, + } + } + None => { + errors.push(ParseError { + span: (0, 0), + reason: ParseErrorReason::UnbalancedBraces, + }); + ParserReturns { + ast: ArgDeclaration::Simple { + loc: (0, 0), + ident: "".to_string(), + ty: Some(types::ERROR), + }, + loc: (0, 0), + warnings, + errors, + } + } + } + } + _ => { + //( + let inner = self.parse_arg(); + warnings.extend(inner.warnings); + errors.extend(inner.errors); + let mut inner = inner.ast; + if let Some((Token::Colon, _)) = self.stream.clone().next() { + let _ = self.stream.next(); + let ty = self.collect_type(); + warnings.extend(ty.warnings); + errors.extend(ty.errors); + let new_ty = ty.ast; + match &mut inner { + ArgDeclaration::DestructureStruct { + loc, + struct_ident, + fields, + renamed_fields, + } => (), //generate warning. + ArgDeclaration::Discard { ty, .. } + | ArgDeclaration::DestructureTuple(_, ty, _) + | ArgDeclaration::Unit { ty, .. } + | ArgDeclaration::Simple { ty, .. } => *ty = Some(new_ty), + } + } + if let Some((Token::GroupClose, _)) = self.stream.clone().next() { + let _ = self.stream.next(); + } else { + errors.push(ParseError { + span: open_loc, + reason: ParseErrorReason::UnbalancedBraces, + }); + } + ParserReturns { + ast: inner, + loc: open_loc, + warnings, + errors, + } + } + } + } + Some((Token::Ident(_), _)) => { + let Some((Token::Ident(ident), loc)) = self.stream.next() else { + unreachable!() + }; + ParserReturns { + loc, + ast: if ident == "_" { + ArgDeclaration::Discard { loc, ty: None } + } else { + ArgDeclaration::Simple { + loc, + ident, + ty: None, + } + }, + warnings, + errors, + } + } + Some((Token::EoF, loc)) => { + errors.push(ParseError { + span: loc, + reason: ParseErrorReason::UnexpectedEndOfFile, + }); + ParserReturns { + ast: ArgDeclaration::Simple { + loc, + ident: "".to_string(), + ty: Some(types::ERROR), + }, + loc, + warnings, + errors, + } + } + Some((_token, loc)) => { + errors.push(ParseError { + span: loc, + reason: ParseErrorReason::UnexpectedToken, + }); + ParserReturns { + loc, + ast: ArgDeclaration::Simple { + loc, + ident: "".to_string(), + ty: Some(types::ERROR), + }, + warnings, + errors, + } + } + None => { + errors.push(ParseError { + span: (0, 0), + reason: ParseErrorReason::UnexpectedEndOfFile, + }); + ParserReturns { + ast: ArgDeclaration::Simple { + loc: (0, 0), + ident: "".to_string(), + ty: Some(types::ERROR), + }, + loc: (0, 0), + warnings, + errors, + } + } + } + } + + fn collect_args(&mut self) -> ParserReturns> { + let mut out = Vec::new(); + let mut warnings = Vec::new(); + let mut errors = Vec::new(); + while let Some((t, _)) = self.stream.clone().next() { + if let Token::Op(eq) = &t { + if eq == "=" { + break; + } + } + if t == Token::Colon { + break; + } + let arg = self.parse_arg(); + warnings.extend(arg.warnings); + errors.extend(arg.errors); + out.push(arg.ast) + } + ParserReturns { + ast: out, + loc: (0, 0), //this is discarded. + warnings, + errors, + } + } + + fn destructuring_declaration(&mut self) -> ParserReturns { + let Some((Token::Let, _)) = self.stream.next() else { + unreachable!() + }; + let ParserReturns { + ast: kind, + loc, + mut warnings, + mut errors, + } = self.collect_pattern(); + let ty = if let Some((Token::Colon, _)) = self.stream.peek() { + let _ = self.stream.next(); + let ty = self.collect_type(); + warnings.extend(ty.warnings); + errors.extend(ty.errors); + Some(ty.ast) + } else { + None + }; + if let Some((Token::Op(eq), loc)) = self.stream.peek() { + if eq != "=" { + errors.push(ParseError { + span: *loc, + reason: ParseErrorReason::UnexpectedToken, + }); + } else { + let _ = self.stream.next(); + } + } else { + errors.push(ParseError { + span: loc, + reason: ParseErrorReason::UnexpectedToken, + }); + } + let expr = match self.stream.peek() { + Some((Token::BeginBlock, loc)) => { + errors.push(ParseError { + span: *loc, + reason: ParseErrorReason::UnsupportedFeature, + }); + let result = self.collect_block(); + warnings.extend(result.warnings); + errors.extend(result.errors); + ast::Expr::Error + } + Some(_) => { + let result = self.next_expr(); + warnings.extend(result.warnings); + errors.extend(result.errors); + result.ast + } + _ => { + errors.push(ParseError { + span: (0, 0), + reason: ParseErrorReason::UnexpectedEndOfFile, + }); + ast::Expr::Error + } + }; + ParserReturns { + ast: ValueDeclaration { + loc, + is_op: false, + target: kind, + args: Vec::new(), + ty, + value: ValueType::Expr(expr), + generictypes: None, + abi: None, + }, + loc, + warnings, + errors, + } + } + + fn fn_declaration( + &mut self, + abi: Option, + generics: Option, + ) -> ParserReturns { + if let Some((Token::Let, _start)) = self.stream.next() { + let (token, ident_span) = self.stream.next().unwrap(); + let (ident, is_op) = match token { + Token::Ident(ident) => (ident, false), + Token::Op(ident) => (ident, true), + _ => { + return ParserReturns { + ast: ValueDeclaration { + loc: ident_span, + is_op: false, + target: ast::Pattern::Read("".to_string(), ident_span), + args: vec![ArgDeclaration::Simple { + loc: (0, 0), + ident: "".to_string(), + ty: Some(types::ERROR), + }], + ty: Some(types::ERROR), + value: ValueType::Expr(Expr::Error), + generictypes: generics, + abi, + }, + loc: ident_span, + warnings: Vec::new(), + errors: vec![ParseError { + span: ident_span, + reason: ParseErrorReason::DeclarationError, + }], + } + } + }; + let ParserReturns { + ast: mut args, + loc: _, + mut warnings, + mut errors, + } = self.collect_args(); + if is_op && (args.len() > 2 || args.len() == 0) { + if let Some((Token::Colon, _)) = self.stream.clone().next() { + let _ = self.stream.next(); + let _ = self.collect_type(); + } + if let Some((Token::Op(op), _)) = self.stream.clone().next() { + if op == "=" { + let _ = self.stream.next(); + match self.stream.clone().next() { + Some((Token::BeginBlock, _)) => { + let _ = self.collect_block(); + } + Some(_) => { + let _ = self.next_expr(); + } + _ => (), + } + } + } + errors.push(ParseError { + span: ident_span, + reason: ParseErrorReason::DeclarationError, + }); + return ParserReturns { + ast: ValueDeclaration { + loc: ident_span, + is_op, + target: ast::Pattern::Read(ident, ident_span), + args, + ty: Some(types::ERROR), + value: ValueType::Expr(ast::Expr::Error), + generictypes: generics, + abi, + }, + loc: ident_span, + warnings, + errors, + }; + } + + let mut ty = if let Some((Token::Colon, _)) = self.stream.clone().next() { + let _ = self.stream.next(); + let ty = self.collect_type(); + warnings.extend(ty.warnings); + errors.extend(ty.errors); + let ty = ty.ast; + Some(ty) + } else { + None + }; + + let op = match self.stream.next() { + Some((Token::Op(op), _)) => op, + Some((Token::Seq, _)) => { + if !abi.is_some() { + errors.push(ParseError { + span: ident_span, + reason: ParseErrorReason::DeclarationError, + }); + return ParserReturns { + ast: ValueDeclaration { + loc: ident_span, + is_op, + target: ast::Pattern::Read(ident, ident_span), + args, + ty, + value: ValueType::Expr(Expr::Error), + generictypes: generics, + abi, + }, + loc: ident_span, + warnings, + errors, + }; + } else if ty.is_none() || args.len() != 0 { + errors.push(ParseError { + span: ident_span, + reason: ParseErrorReason::DeclarationError, + }); + return ParserReturns { + ast: ValueDeclaration { + loc: ident_span, + is_op, + target: ast::Pattern::Read(ident, ident_span), + args, + ty, + value: ValueType::Expr(Expr::Error), + generictypes: generics, + abi, + }, + loc: ident_span, + warnings, + errors, + }; + } else { + return ParserReturns { + ast: ValueDeclaration { + loc: ident_span, + is_op, + target: ast::Pattern::Read(ident, ident_span), + args, + ty, + value: ValueType::External, + generictypes: generics, + abi, + }, + loc: ident_span, + warnings, + errors, + }; + } + } + _ => { + //TODO! progress next_toplevel valid point. + errors.push(ParseError { + span: ident_span, + reason: ParseErrorReason::DeclarationError, + }); + return ParserReturns { + ast: ValueDeclaration { + loc: ident_span, + is_op, + target: ast::Pattern::Read(ident, ident_span), + args, + ty, + value: ValueType::Expr(Expr::Error), + generictypes: generics, + abi, + }, + loc: ident_span, + warnings, + errors, + }; + } + }; + + if op != "=" { + //TODO! progress next_toplevel until valid point. + errors.push(ParseError { + span: ident_span, + reason: ParseErrorReason::DeclarationError, + }); + return ParserReturns { + ast: ValueDeclaration { + loc: ident_span, + is_op, + target: ast::Pattern::Read(ident, ident_span), + args, + ty, + value: ValueType::Expr(Expr::Error), + generictypes: generics, + abi, + }, + loc: ident_span, + warnings, + errors, + }; + } + + let value = match self.stream.clone().next() { + Some((Token::BeginBlock, _)) => ValueType::Function({ + let block = self.collect_block(); + warnings.extend(block.warnings); + errors.extend(block.errors); + block.ast + }), + Some((_, _)) => { + let ParserReturns { + ast, + loc: _, + warnings: expr_warnings, + errors: expr_errors, + } = self.next_expr(); + warnings.extend(expr_warnings); + errors.extend(expr_errors); + ValueType::Expr(ast) + } + _ => { + errors.push(ParseError { + span: ident_span, + reason: ParseErrorReason::UnexpectedEndOfFile, + }); + return ParserReturns { + ast: ValueDeclaration { + loc: ident_span, + is_op, + target: ast::Pattern::Read(ident, ident_span), + args, + ty, + value: ValueType::Expr(Expr::Error), + generictypes: generics, + abi, + }, + loc: ident_span, + warnings, + errors, + }; + } + }; + if let Some(generics) = &generics { + for arg in &mut args { + generics + .decls + .iter() + .map(|(_, it)| it) + .for_each(|name| arg.apply_generic(name)); + } + + if let Some(ty) = &mut ty { + *ty = generics + .decls + .iter() + .map(|(_, it)| it) + .fold(ty.clone(), |ty, name| ty.replace_user_with_generic(name)); + } + } + + return ParserReturns { + ast: ValueDeclaration { + loc: ident_span, + is_op, + target: ast::Pattern::Read(ident, ident_span), + args, + ty, + value, + generictypes: generics, + abi, + }, + loc: ident_span, + warnings, + errors, + }; + } + return ParserReturns { + ast: ValueDeclaration { + loc: (0, 0), + is_op: false, + target: ast::Pattern::Read("".to_string(), (0, 0)), + args: vec![ArgDeclaration::Simple { + loc: (0, 0), + ident: "".to_string(), + ty: Some(types::ERROR), + }], + ty: Some(types::ERROR), + value: ValueType::Expr(Expr::Error), + generictypes: generics, + abi, + }, + loc: (0, 0), + warnings: Vec::new(), + errors: vec![ParseError { + span: (0, 0), + reason: ParseErrorReason::UnknownError, + }], + }; + } + + fn collect_block(&mut self) -> ParserReturns> { + let mut warnings = Vec::new(); + let mut errors = Vec::new(); + let sub = if let Some((Token::BeginBlock, _)) = self.stream.next() { + let mut sub_expr = Vec::new(); + loop { + let next = self.stream.peek(); + if let Some((Token::EndBlock, _)) = next { + self.stream.next(); + break; + } else if let Some((Token::EoF, _)) = next { + break; + } + let stmnt = self.next_statement(); + warnings.extend(stmnt.warnings); + errors.extend(stmnt.errors); + sub_expr.push(stmnt.ast); + } + sub_expr + } else { + errors.push(ParseError { + span: (0, 0), + reason: ParseErrorReason::UnknownError, + }); + Vec::new() + }; + ParserReturns { + ast: sub, + loc: (0, 0), + warnings, + errors, + } + } + + fn binary_op(&mut self) -> ParserReturns { + let op_loc = self.stream.clone().nth(2).unwrap().1; + let mut warnings = Vec::new(); + let mut errors = Vec::new(); + let mut group_opens = 0; + let tokens = self + .stream + .clone() + .take_while(|(t, _)| match t { + Token::GroupOpen => { + group_opens += 1; + true + } + Token::Ident(_) + | Token::FloatingPoint(_, _) + | Token::Integer(_, _) + | Token::Op(_) => true, + Token::GroupClose => { + group_opens -= 1; + group_opens >= 0 + } + _ => false, + }) + .collect_vec(); + for _ in 0..tokens.len() { + self.stream.next(); + } + + // (name,weight,right associative) + const PRECIDENCE: [(&'static str, usize, bool); 12] = [ + (".", usize::MAX, true), + ("**", 7, false), + ("*", 5, true), + ("/", 5, true), + ("+", 4, true), + ("-", 4, true), + ("<", 2, true), + ("<=", 2, true), + (">", 2, true), + (">=", 2, true), + ("&&", 1, true), + ("||", 1, true), + ]; + let mut output = Vec::with_capacity(tokens.len()); + let mut op_stack = Vec::with_capacity(tokens.len() / 3); + let mut token_iter = tokens.into_iter().peekable(); + while let Some((token, _)) = token_iter.peek() { + match token { + Token::GroupOpen => { + let _ = token_iter.next(); + let mut group_opens = 0; + let sub_tokens = token_iter + .clone() + .take_while(|(t, _)| match t { + Token::GroupClose => { + group_opens -= 1; + group_opens >= 0 + } + Token::GroupOpen => { + group_opens += 1; + true + } + Token::Ident(_) + | Token::FloatingPoint(_, _) + | Token::Integer(_, _) + | Token::Op(_) => true, + _ => false, + }) + .collect_vec(); + for _ in 0..sub_tokens.len() { + token_iter.next(); + } + let ParserReturns { + ast: result, + loc, + warnings: expr_warnings, + errors: expr_errors, + } = Parser::from_stream(sub_tokens.into_iter()).next_expr(); + warnings.extend(expr_warnings); + errors.extend(expr_errors); + output.push(ShuntingYardOptions::Expr((result, loc))); + } + Token::GroupClose => { + let _ = token_iter.next(); + } + Token::Ident(_) => { + if let Some(( + Token::Ident(_) + | Token::CharLiteral(_) + | Token::StringLiteral(_) + | Token::FloatingPoint(_, _) + | Token::Integer(_, _) + | Token::GroupOpen, + _, + )) = token_iter.clone().nth(1) + { + let sub_tokens = token_iter + .clone() + .take_while(|(t, _)| match t { + Token::GroupClose => { + group_opens -= 1; + group_opens >= 0 + } + Token::GroupOpen => { + group_opens += 1; + true + } + Token::Ident(_) + | Token::FloatingPoint(_, _) + | Token::Integer(_, _) => true, + Token::Op(_) => group_opens >= 0, + _ => false, + }) + .collect_vec(); + for _ in 0..sub_tokens.len() { + token_iter.next(); + } + let ParserReturns { + ast: result, + loc, + warnings: expr_warnings, + errors: expr_errors, + } = Parser::from_stream(sub_tokens.into_iter()).next_expr(); + warnings.extend(expr_warnings); + errors.extend(expr_errors); + + output.push(ShuntingYardOptions::Expr((result, loc))); + } else { + let Some((Token::Ident(ident), loc)) = token_iter.next() else { + unreachable!() + }; + output.push(ShuntingYardOptions::Expr(( + Expr::ValueRead(ident, loc), + loc, + ))); + } + } + Token::Integer(_, _) + | Token::FloatingPoint(_, _) + | Token::CharLiteral(_) + | Token::StringLiteral(_) => output.push(ShuntingYardOptions::Expr({ + let Some((token, span)) = token_iter.next() else { + return ParserReturns { + ast: Expr::Error, + loc: (0, 0), + warnings: Vec::new(), + errors: vec![ParseError { + span: (0, 0), + reason: ParseErrorReason::UnknownError, + }], + }; + }; + + let result = match make_literal(token, span) { + Ok(r) => r, + Err(e) => { + errors.push(e); + ast::Expr::Error + } + }; + (result, span) + })), + Token::Op(_) => { + let Some((Token::Op(ident), loc)) = token_iter.next() else { + unreachable!() + }; + let (prec, left) = PRECIDENCE + .iter() + .find_map(|(op, weight, assc)| { + if op == &ident { + Some((*weight, *assc)) + } else { + None + } + }) + .unwrap_or((1, false)); + if op_stack.is_empty() { + op_stack.push((ident, loc)); + continue; + } + while let Some(op_back) = op_stack.last() { + let back_prec = PRECIDENCE + .iter() + .find_map(|(op, weight, _)| { + if op == &op_back.0 { + Some(*weight) + } else { + None + } + }) + .unwrap_or(1); + if back_prec > prec || (back_prec == prec && left) { + let Some(op_back) = op_stack.pop() else { + unreachable!() + }; + output.push(ShuntingYardOptions::Op(op_back)); + } else { + op_stack.push((ident.clone(), loc)); + break; + } + } + if op_stack.last().is_none() { + op_stack.push((ident, loc)); + } + } + _ => break, + } + } + output.extend(op_stack.into_iter().rev().map(ShuntingYardOptions::Op)); + let mut final_expr = Vec::<(ast::Expr, crate::Location)>::new(); + for expr in output { + match expr { + ShuntingYardOptions::Expr(expr) => final_expr.push(expr), + ShuntingYardOptions::Op((op, loc)) => { + let Some((rhs, _)) = final_expr.pop() else { + unreachable!() + }; + let Some((lhs, _)) = final_expr.pop() else { + unreachable!() + }; + final_expr.push(( + ast::Expr::BinaryOpCall(BinaryOpCall { + loc, + operator: op, + lhs: lhs.into(), + rhs: rhs.into(), + }), + loc, + )) + } + } + } + + if final_expr.len() != 1 { + errors.push(ParseError { + span: op_loc, + reason: ParseErrorReason::UnknownError, + }); + ParserReturns { + ast: Expr::Error, + loc: op_loc, + warnings, + errors, + } + } else { + let (expr, _loc) = final_expr.into_iter().next().unwrap(); + + ParserReturns { + ast: expr, + loc: op_loc, + warnings, + errors, + } + } + } + + fn match_(&mut self) -> ParserReturns { + let Some((Token::Match, match_loc)) = self.stream.next() else { + unreachable!() + }; + let ParserReturns { + ast: on, + loc: _, + mut warnings, + mut errors, + } = self.next_expr(); + if let Some((Token::Where, _)) = self.stream.clone().next() { + let _ = self.stream.next(); + } else { + //TODO? recovery? + let loc = if let Some((_, loc)) = self.stream.clone().next() { + loc + } else { + (0, 0) + }; + errors.push(ParseError { + span: loc, + reason: ParseErrorReason::UnexpectedToken, + }) + }; + let expect_block = if let Some((Token::BeginBlock, _)) = self.stream.clone().next() { + let _ = self.stream.next(); + true + } else { + false + }; + let mut arms = Vec::new(); + while let Some((Token::Op(op), _)) = self.stream.peek() { + if op != "|" { + break; + } + let _ = self.stream.next(); + let pattern = self.collect_pattern(); + warnings.extend(pattern.warnings); + errors.extend(pattern.errors); + let loc = pattern.loc; + let cond = pattern.ast; + if let Some((Token::Arrow, _)) = self.stream.peek() { + self.stream.next(); + } else { + let Some((t, loc)) = self.stream.peek() else { + unreachable!() + }; + println!( + "expected -> but got {:?} at line: {}, col: {}", + t, loc.0, loc.1 + ); + } + let (block, ret) = match self.stream.peek() { + Some((Token::BeginBlock, _)) => { + let _ = self.stream.next(); + let mut body = Vec::new(); + while self + .stream + .clone() + .skip_while(|(it, _)| it != &Token::Seq && it != &Token::EndBlock) + .next() + .map(|a| a.0 != Token::EndBlock && a.0 != Token::EoF) + .unwrap_or(false) + { + let stmnt = self.next_statement(); + warnings.extend(stmnt.warnings); + errors.extend(stmnt.errors); + body.push(stmnt.ast); + } + match self.stream.peek() { + Some((Token::EndBlock, _)) => { + let _ = self.stream.next(); + (body, None) + } + _ => { + let ParserReturns { + ast: ret, + warnings: ret_warnings, + errors: ret_errors, + loc: _, + } = self.next_expr(); + warnings.extend(ret_warnings); + errors.extend(ret_errors); + if let Some((Token::EndBlock, _)) = self.stream.peek() { + let _ = self.stream.next(); + } else { + println!("did you mean next_toplevel move back a block?"); + } + (body, Some(ret.into())) + } + } + } + _ => { + let ParserReturns { + ast: expr, + warnings: ret_warnings, + errors: ret_errors, + loc: _, + } = self.next_expr(); + warnings.extend(ret_warnings); + errors.extend(ret_errors); + + if let Some((Token::Comma, _)) = self.stream.peek() { + let _ = self.stream.next(); + } else { + let Some((peeked, loc)) = self.stream.peek() else { + unreachable!() + }; + println!( + "expected `,` but got {:?} at line : {}, col: {}", + peeked, loc.0, loc.1 + ) + } + (Vec::new(), Some(expr.into())) + } + }; + arms.push(ast::MatchArm { + block, + ret, + cond, + loc, + }); + } + + if expect_block { + if let Some((Token::EndBlock, _)) = self.stream.peek() { + let _ = self.stream.next(); + } else { + println!( + "did you mean next_toplevel go back next_toplevel the containing block level?" + ); + } + } + + ParserReturns { + ast: Match { + loc: match_loc, + on: on.into(), + arms, + }, + loc: match_loc, + warnings, + errors, + } + } + + fn collect_pattern(&mut self) -> ParserReturns { + let mut warnings = Vec::new(); + let mut errors = Vec::new(); + // op should poped beffore this. + let (pattern, loc) = match self.stream.clone().next() { + Some((Token::CurlOpen, loc)) => { + let _curl = self.stream.next(); + let mut fields = HashMap::new(); + while let Some((Token::Ident(_), _)) = self.stream.clone().next() { + let Some((Token::Ident(field_name), loc)) = self.stream.next() else { + unreachable!() + }; + if let Some((Token::Colon, _)) = self.stream.clone().next() { + let Some((Token::Colon, _)) = self.stream.next() else { + unreachable!() + }; + let sub_pattern = self.collect_pattern(); + warnings.extend(sub_pattern.warnings); + errors.extend(sub_pattern.errors); + fields.insert(field_name, sub_pattern.ast); + } else { + fields.insert(field_name.clone(), Pattern::Read(field_name, loc)); + } + if let Some((Token::Comma, _)) = self.stream.clone().next() { + let _comma = self.stream.next(); + } else { + break; + } + } + if let Some((Token::CurlClose, _)) = self.stream.clone().next() { + let _curl = self.stream.next(); + } else { + //todo! recovery. + } + ( + Pattern::Destructure(PatternDestructure::Struct { + base_ty: None, + fields, + }), + loc, + ) + } + Some((Token::Ident(_), _)) => { + let Some((Token::Ident(name), loc)) = self.stream.next() else { + unreachable!() + }; + match self.stream.clone().next() { + Some((Token::Scope, _)) => { + let enum_name = name; + let Some((_scope, scope_loc)) = self.stream.next() else { + unreachable!() + }; + if let Some((Token::Ident(_), _)) = self.stream.clone().next() { + let Some((Token::Ident(variant), _)) = self.stream.next() else { + unreachable!() + }; + let pattern = match self.stream.clone().next() { + Some(( + Token::CurlOpen + | Token::GroupOpen + | Token::Ident(_) + | Token::BracketOpen + | Token::Integer(_, _) + | Token::FloatingPoint(_, _), + _, + )) => { + let sub_pattern = self.collect_pattern(); + warnings.extend(sub_pattern.warnings); + errors.extend(sub_pattern.errors); + Some(sub_pattern.ast.into()) + } + _ => None, + }; + ( + Pattern::EnumVariant { + ty: Some(enum_name), + variant, + pattern, + loc, + }, + loc, + ) + } else { + errors.push(ParseError { + span: scope_loc, + reason: ParseErrorReason::UnexpectedToken, + }); + (Pattern::Error, loc) + } + } + Some((Token::CurlOpen, _)) => { + let mut sub_pattern = self.collect_pattern(); + warnings.extend(sub_pattern.warnings); + errors.extend(sub_pattern.errors); + let Pattern::Destructure(PatternDestructure::Struct { base_ty, .. }) = + &mut sub_pattern.ast + else { + unreachable!() + }; + *base_ty = Some(name); + (sub_pattern.ast, loc) + } + Some(( + Token::GroupOpen + | Token::Ident(_) + | Token::BracketOpen + | Token::Integer(_, _) + | Token::FloatingPoint(_, _), + _, + )) => { + let sub_pattern = self.collect_pattern(); + warnings.extend(sub_pattern.warnings); + errors.extend(sub_pattern.errors); + ( + Pattern::EnumVariant { + ty: None, + variant: name, + pattern: Some(sub_pattern.ast.into()), + loc, + }, + loc, + ) + } + _ => { + if name == "_" { + (Pattern::Default, loc) + } else { + // TODO! pattern detection of enum varaints. + (Pattern::Read(name, loc), loc) + } + } + } + } + Some((Token::Integer(_, _), _)) => { + let Some((Token::Integer(signed, value), loc)) = self.stream.next() else { + unreachable!() + }; + ( + Pattern::ConstNumber(format!("{}{}", if signed { "-" } else { "" }, value)), + loc, + ) + } + Some((Token::FloatingPoint(_, _), _)) => { + let Some((Token::FloatingPoint(signed, value), loc)) = self.stream.next() else { + unreachable!() + }; + + ( + Pattern::ConstNumber(format!("{}{}", if signed { "-" } else { "" }, value)), + loc, + ) + } + Some((Token::CharLiteral(_), _)) => { + let Some((Token::CharLiteral(c), loc)) = self.stream.next() else { + unreachable!() + }; + (Pattern::ConstChar(c), loc) + } + Some((Token::StringLiteral(_), _)) => { + let Some((Token::StringLiteral(c), loc)) = self.stream.next() else { + unreachable!() + }; + (Pattern::ConstStr(c), loc) + } + Some((Token::True, _)) => { + let Some((_, loc)) = self.stream.next() else { + unreachable!() + }; + (Pattern::ConstBool(true), loc) + } + Some((Token::False, _)) => { + let Some((_, loc)) = self.stream.next() else { + unreachable!() + }; + (Pattern::ConstBool(false), loc) + } + + Some((Token::GroupOpen, _)) => { + let Some((Token::GroupOpen, loc)) = self.stream.next() else { + unreachable!() + }; + if let Some((Token::GroupClose, _)) = self.stream.clone().next() { + let _ = self.stream.next(); + (Pattern::Destructure(PatternDestructure::Unit), loc) + } else { + let first = self.collect_pattern(); + warnings.extend(first.warnings); + errors.extend(first.errors); + let first_loc = first.loc; + let mut patterns = vec![first.ast]; + loop { + match self.stream.clone().next() { + Some((Token::Comma, _)) => { + let _ = self.stream.next(); + let next = self.collect_pattern(); + warnings.extend(next.warnings); + errors.extend(next.errors); + patterns.push(next.ast); + } + Some((Token::GroupClose, _)) => { + break; + } + Some((Token::EoF, _)) | None => { + let _ = self.stream.next(); + errors.push(ParseError { + span: loc, + reason: ParseErrorReason::UnexpectedEndOfFile, + }); + break; + } + Some((t, loc)) => { + let _ = self.stream.next(); + errors.push(ParseError { + span: loc, + reason: ParseErrorReason::UnexpectedToken, + }); + break; + } + } + } + match self.stream.clone().next() { + Some((Token::GroupClose, _)) => { + let _ = self.stream.next(); + } + Some((Token::EoF, _)) | None => { + let _ = self.stream.next(); + errors.push(ParseError { + span: loc, + reason: ParseErrorReason::UnexpectedEndOfFile, + }); + } + Some((t, loc)) => { + let n = self + .stream + .clone() + .peeking_take_while(|(t, _)| match t { + Token::Comma | Token::EndBlock => false, + Token::Op(op) => op != "|", + _ => true, + }) + .collect_vec() + .len(); + for _ in 0..n { + let _ = self.stream.next(); + } + errors.push(ParseError { + span: loc, + reason: ParseErrorReason::UnexpectedToken, + }); + } + } + if patterns.len() == 1 { + (patterns.pop().unwrap(), first_loc) + } else { + ( + Pattern::Destructure(PatternDestructure::Tuple(patterns)), + loc, + ) + } + } + } + Some((Token::EoF, _)) | None => { + let _ = self.stream.next(); + errors.push(ParseError { + span: (0, 0), + reason: ParseErrorReason::UnexpectedEndOfFile, + }); + (Pattern::Error, (0, 0)) + } + Some((t, loc)) => { + errors.push(ParseError { + span: loc, + reason: ParseErrorReason::UnexpectedToken, + }); + let n = self + .stream + .clone() + .peeking_take_while(|(t, _)| match t { + Token::Comma | Token::EndBlock => false, + Token::Op(op) => op != "|", + _ => true, + }) + .collect_vec() + .len(); + for _ in 0..n { + let _ = self.stream.next(); + } + (Pattern::Error, loc) + } + }; + let pattern = if let Some((Token::Op(op), _)) = self.stream.peek() { + if op == "|" { + let _ = self.stream.next(); + let next = self.collect_pattern(); + warnings.extend(next.warnings); + errors.extend(next.errors); + Pattern::Or(pattern.into(), next.ast.into()) + } else { + pattern + } + } else { + pattern + }; + ParserReturns { + ast: pattern, + loc, + warnings, + errors, + } + } + + fn array_literal(&mut self) -> ParserReturns { + let Some((Token::BracketOpen, loc)) = self.stream.next() else { + unreachable!() + }; + let mut values = Vec::new(); + let mut warnings = Vec::new(); + let mut errors = Vec::new(); + let expect_block = if let Some((Token::BeginBlock, _)) = self.stream.peek() { + let _ = self.stream.next(); + true + } else { + false + }; + loop { + let ParserReturns { + ast: expr, + loc: _, + warnings: new_warnings, + errors: new_errors, + } = self.next_expr(); + warnings.extend(new_warnings); + errors.extend(new_errors); + values.push(expr); + match self.stream.clone().next() { + Some((Token::Comma, _)) => { + let _ = self.stream.next(); + continue; + } + Some(_) => break, + None => { + unreachable!("somehow not even got EoF"); + } + } + } + + if expect_block { + if let Some((Token::EndBlock, _)) = self.stream.peek() { + let _ = self.stream.next(); + } else { + println!("did you mean next_toplevel have the closing ] on the same level as the opening?") + } + } + + if let Some((Token::BracketClose, _)) = self.stream.peek() { + let _ = self.stream.next(); + } else { + errors.push(ParseError { + span: loc, + reason: ParseErrorReason::UnbalancedBraces, + }); + values.push(ast::Expr::Error); + } + ParserReturns { + ast: ast::Expr::ArrayLiteral { + contents: values, + loc, + }, + loc, + warnings, + errors, + } + } +} + +fn make_literal(token: Token, span: (usize, usize)) -> Result { + match token { + Token::CharLiteral(ch) => Ok(ast::Expr::CharLiteral(ch)), + Token::StringLiteral(src) => { + let mut value = String::with_capacity(src.len()); + let mut s = src.chars(); + while let Some(c) = s.next() { + if c == '\\' { + let next = match s.next() { + Some('n') => '\n', + Some('\\') => '\\', + Some('r') => '\r', + Some('t') => '\t', + Some('"') => '"', + Some('\'') => '\'', + Some(_) => { + return Err(ParseError { + span, + reason: ParseErrorReason::UnsupportedEscape, + }) + } + None => unreachable!(), + }; + value.push(next); + } else { + value.push(c); + } + } + Ok(ast::Expr::StringLiteral(value)) + } + Token::Integer(is_neg, value) | Token::FloatingPoint(is_neg, value) => { + Ok(Expr::NumericLiteral { + value: if is_neg { + "-".to_owned() + &value + } else { + value + }, + }) + } + Token::True => Ok(Expr::BoolLiteral(true, span)), + Token::False => Ok(Expr::BoolLiteral(false, span)), + _ => Err(ParseError { + span, + reason: ParseErrorReason::UnknownError, + }), + } +} +fn type_from_string(name: &str, generics: Vec, loc: crate::Location) -> ResolvedType { + match name { + "str" => types::STR, + "char" => types::CHAR, + "bool" => types::BOOL, + ty if ty.starts_with("int") => { + let size = ty.strip_prefix("int"); + match size { + Some("8") => types::INT8, + Some("16") => types::INT16, + Some("32") => types::INT32, + Some("64") => types::INT64, + _ => ResolvedType::User { + name: ty.to_string(), + generics: Vec::new(), + loc, + }, + } + } + ty if ty.starts_with("float") => { + let size = ty.strip_prefix("float"); + match size { + Some("32") => types::FLOAT32, + Some("64") => types::FLOAT64, + _ => ResolvedType::User { + name: ty.to_string(), + generics: Vec::new(), + loc, + }, + } + } + _ => ResolvedType::User { + name: name.to_string(), + generics, + loc, + }, + } +} +#[allow(unused)] +// TODO use for generating [`crate::ast::Expr::PipeExpr`] +fn is_pipe_op(op: &str) -> bool { + op.ends_with('>') && op[..op.len() - 2].chars().all(|c| c == '|') +} + +enum ShuntingYardOptions { + Expr((ast::Expr, crate::Location)), + Op((String, crate::Location)), +} +impl std::fmt::Debug for ShuntingYardOptions { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Expr(arg0) => f.debug_tuple("Expr").field(&arg0.0).finish(), + Self::Op(arg0) => f.debug_tuple("Op").field(&arg0.0).finish(), + } + } +} + +#[cfg(test)] +mod tests { + use crate::{ + ast::{ + ArgDeclaration, EnumDeclaration, EnumVariant, IfBranching, IfExpr, MatchArm, + StructDefinition, TopLevelDeclaration, + }, + types::ResolvedType, + }; + use pretty_assertions::assert_eq; + + #[test] + fn types() { + assert_eq!( + Parser::from_source("int64").collect_type().ast, + types::INT64 + ); + assert_eq!( + Parser::from_source("int32").collect_type().ast, + types::INT32 + ); + assert_eq!( + Parser::from_source("int16").collect_type().ast, + types::INT16 + ); + assert_eq!(Parser::from_source("int8").collect_type().ast, types::INT8); + assert_eq!(Parser::from_source("str").collect_type().ast, types::STR); + assert_eq!(Parser::from_source("char").collect_type().ast, types::CHAR); + assert_eq!( + Parser::from_source("float64").collect_type().ast, + types::FLOAT64 + ); + assert_eq!( + Parser::from_source("float32").collect_type().ast, + types::FLOAT32 + ); + assert_eq!(Parser::from_source("()").collect_type().ast, types::UNIT); + + assert_eq!( + Parser::from_source("[int32;5]").collect_type().ast, + ResolvedType::Array { + underlining: types::INT32.into(), + size: 5 + } + ); + + //fuctions + assert_eq!( + Parser::from_source("int32->int32").collect_type().ast, + ResolvedType::Function { + arg: types::INT32.into(), + returns: types::INT32.into(), + loc: (0, 0), + } + ); + assert_eq!( + Parser::from_source("int32->int32->int32") + .collect_type() + .ast, + ResolvedType::Function { + arg: types::INT32.into(), + returns: ResolvedType::Function { + arg: types::INT32.into(), + returns: types::INT32.into(), + loc: (0, 0), + } + .into(), + loc: (0, 0), + } + ); + assert_eq!( + Parser::from_source("int32->(int32->int32)") + .collect_type() + .ast, + ResolvedType::Function { + arg: types::INT32.into(), + returns: ResolvedType::Function { + arg: types::INT32.into(), + returns: types::INT32.into(), + loc: (0, 0), + } + .into(), + loc: (0, 0), + } + ); + assert_eq!( + Parser::from_source("(int32->int32)->int32") + .collect_type() + .ast, + ResolvedType::Function { + arg: ResolvedType::Function { + arg: types::INT32.into(), + returns: types::INT32.into(), + loc: (0, 0), + } + .into(), + returns: types::INT32.into(), + loc: (0, 0), + } + ); + } + + use super::*; + #[test] + #[ignore = "This is for singled out tests"] + fn for_debugging_only() { + let mut parser = Parser::from_source( + "enum Testing = | One (int8,int8) | Two +let fun test = match test where +| Testing::One (0,1) -> 0, +| Testing::One ((1|0),a) -> a, +| Testing::One _ -> -1, +| Testing::Two -> -2, ", + ); + let module = parser.module("".to_string()); + println!("{module:#?}") + } + #[test] + fn individual_simple_expressions() { + let mut parser = Parser::from_source("let foo : int32 = 5;"); + + assert_eq!( + Statement::Declaration(ValueDeclaration { + loc: (0, 4), + is_op: false, + target: ast::Pattern::Read("foo".to_owned(), (0, 4)), + ty: Some(types::INT32), + args: Vec::new(), + value: ValueType::Expr(Expr::NumericLiteral { + value: "5".to_string(), + }), + generictypes: None, + abi: None + }), + parser.next_statement().ast + ); + let mut parser = Parser::from_source( + r#"let foo _ : int32 -> int32 = + return 5; +"#, + ); + assert_eq!( + ast::TopLevelDeclaration::Value(TopLevelValue { + loc: (0, 4), + is_op: false, + ident: "foo".to_owned(), + ty: Some(ResolvedType::Function { + arg: types::INT32.into(), + returns: types::INT32.into(), + loc: (0, 18) + }), + args: vec![ArgDeclaration::Discard { + ty: None, + loc: (0, 8) + }], + value: ValueType::Function(vec![Statement::Return( + Expr::NumericLiteral { + value: "5".to_string(), + }, + (1, 4) + )]), + generics: None, + abi: None, + }), + parser.next_toplevel().ast + ) + } + + #[test] + fn higher_kinded() { + const ARG: &'static str = r#" +let foo _ : ( int32 -> int32 ) -> int32 = + return 0; +"#; + let mut parser = Parser::from_source(ARG); + assert_eq!( + Statement::Declaration(ValueDeclaration { + loc: (1, 4), + is_op: false, + target: ast::Pattern::Read("foo".to_owned(), (1, 4)), + ty: Some(ResolvedType::Function { + arg: ResolvedType::Function { + arg: types::INT32.into(), + returns: types::INT32.into(), + loc: (1, 20) + } + .into(), + returns: types::INT32.into(), + loc: (1, 31) + }), + args: vec![ast::ArgDeclaration::Discard { + ty: None, + loc: (1, 8) + }], + value: ValueType::Function(vec![Statement::Return( + Expr::NumericLiteral { + value: "0".to_string(), + }, + (2, 4) + )]), + generictypes: None, + abi: None, + }), + parser.next_statement().ast, + "function as arg" + ); + const RT: &'static str = r#" +let foo _ : int32 -> ( int32 -> int32 ) = + return 0; +"#; + let mut parser = Parser::from_source(RT); + assert_eq!( + Statement::Declaration(ValueDeclaration { + loc: (1, 4), + is_op: false, + target: ast::Pattern::Read("foo".to_owned(), (1, 4)), + ty: Some(ResolvedType::Function { + arg: types::INT32.into(), + returns: ResolvedType::Function { + arg: types::INT32.into(), + returns: types::INT32.into(), + loc: (1, 29) + } + .into(), + loc: (1, 18) + }), + args: vec![ast::ArgDeclaration::Discard { + ty: None, + loc: (1, 8) + }], + value: ValueType::Function(vec![Statement::Return( + Expr::NumericLiteral { + value: "0".to_owned(), + }, + (2, 4) + )]), + generictypes: None, + abi: None, + }), + parser.next_statement().ast, + "function as rt" + ); + } + + #[test] + fn multiple_statements() { + const SRC: &'static str = include_str!("../../samples/test.fb"); + let mut parser = Parser::from_source(SRC); + assert_eq!( + ast::TopLevelDeclaration::Value(TopLevelValue { + loc: (0, 4), + is_op: false, + ident: "foo".to_owned(), + ty: Some(types::INT32), + args: Vec::new(), + value: ValueType::Expr(Expr::NumericLiteral { + value: "3".to_owned(), + }), + generics: None, + abi: None, + }), + parser.next_toplevel().ast, + "simple declaration" + ); + assert_eq!( + ast::TopLevelDeclaration::Value(TopLevelValue { + loc: (2, 4), + is_op: false, + ident: "bar".to_owned(), + ty: Some(ResolvedType::Function { + arg: types::INT32.into(), + returns: types::INT32.into(), + loc: (2, 20) + }), + args: vec![ast::ArgDeclaration::Simple { + ident: "quz".to_string(), + loc: (2, 8), + ty: None, + }], + value: ValueType::Function(vec![ + Statement::Declaration(ValueDeclaration { + loc: (3, 8), + is_op: false, + target: Pattern::Read("baz".to_owned(), (3, 8)), + ty: Some(types::STR), + args: Vec::new(), + value: ValueType::Expr(Expr::StringLiteral(r#"merp " yes"#.to_string())), + generictypes: None, + abi: None, + }), + Statement::Return( + Expr::NumericLiteral { + value: "2".to_owned(), + }, + (4, 4) + ) + ]), + generics: None, + abi: None, + }), + parser.next_toplevel().ast, + "declaration with block" + ); + assert_eq!( + ast::TopLevelDeclaration::Value(TopLevelValue { + loc: (6, 4), + is_op: true, + + ident: "^^".to_owned(), + ty: Some(ResolvedType::Function { + arg: types::INT32.into(), + returns: ResolvedType::Function { + arg: types::INT32.into(), + returns: types::INT32.into(), + loc: (6, 32) + } + .into(), + loc: (6, 23) + }), + args: vec![ + ast::ArgDeclaration::Simple { + ident: "lhs".to_string(), + loc: (6, 7), + ty: None, + }, + ast::ArgDeclaration::Simple { + ident: "rhs".to_string(), + loc: (6, 11), + ty: None, + }, + ], + value: ValueType::Function(vec![ + Statement::FnCall(FnCall { + loc: (7, 4), + value: Expr::ValueRead("bar".to_string(), (7, 4)).into(), + arg: Some(Expr::ValueRead("foo".to_string(), (7, 8)).into()), + }), + Statement::Return( + Expr::NumericLiteral { + value: "1".to_owned(), + }, + (8, 4) + ) + ]), + generics: None, + abi: None, + }), + parser.next_toplevel().ast, + "operator declaration w/ function call", + ); + } + + #[test] + fn fn_chain() { + const SRC: &'static str = r#" +let main _ : int32 -> int32 = + put_int32 100; + print_str "v"; + return 32; +"#; + let mut parser = Parser::from_source(SRC); + assert_eq!( + Statement::Declaration(ValueDeclaration { + loc: (1, 4), + is_op: false, + + target: Pattern::Read("main".to_owned(), (1, 4)), + ty: Some(ResolvedType::Function { + arg: types::INT32.into(), + returns: types::INT32.into(), + loc: (1, 19) + }), + args: vec![ast::ArgDeclaration::Discard { + ty: None, + loc: (1, 9) + }], + value: ValueType::Function(vec![ + Statement::FnCall(FnCall { + loc: (2, 4), + value: Expr::ValueRead("put_int32".to_string(), (2, 4)).into(), + arg: Some( + Expr::NumericLiteral { + value: "100".to_owned(), + } + .into() + ) + }), + Statement::FnCall(FnCall { + loc: (3, 4), + value: Expr::ValueRead("print_str".to_string(), (3, 4)).into(), + arg: Some(Expr::StringLiteral("v".to_string()).into()) + }), + Statement::Return( + Expr::NumericLiteral { + value: "32".to_string(), + }, + (4, 4) + ) + ]), + generictypes: None, + abi: None, + }), + parser.next_statement().ast, + ) + } + + #[test] + fn ops() { + const SRC_S: &'static str = "100 + 100 * foo * ( 10 - 1 )"; + let mut parser = Parser::from_source(SRC_S); + + assert_eq!( + Expr::BinaryOpCall(BinaryOpCall { + loc: (0, 4), + lhs: Expr::NumericLiteral { + value: "100".to_string(), + } + .into(), + rhs: Expr::BinaryOpCall(BinaryOpCall { + loc: (0, 16), + lhs: Expr::BinaryOpCall(BinaryOpCall { + loc: (0, 10), + lhs: Expr::NumericLiteral { + value: "100".to_string(), + } + .into(), + rhs: Expr::ValueRead("foo".to_string(), (0, 12)).into(), + operator: "*".to_string() + }) + .into(), + rhs: Expr::BinaryOpCall(BinaryOpCall { + loc: (0, 23), + lhs: Expr::NumericLiteral { + value: "10".to_string(), + } + .into(), + rhs: Expr::NumericLiteral { + value: "1".to_string(), + } + .into(), + operator: "-".to_string() + }) + .into(), + operator: "*".to_string() + }) + .into(), + operator: "+".to_string() + }), + parser.next_expr().ast + ); + const SRC: &'static str = r#"let main _ = + print_int32 100 + 100; + return 0;"#; + let mut parser = Parser::from_source(SRC); + assert_eq!( + Statement::Declaration(ValueDeclaration { + loc: (0, 4), + is_op: false, + target: Pattern::Read("main".to_owned(), (0, 4)), + ty: None, + args: vec![ast::ArgDeclaration::Discard { + ty: None, + loc: (0, 9) + }], + value: ValueType::Function(vec![ + Statement::FnCall(FnCall { + loc: (1, 4), + value: Expr::ValueRead("print_int32".to_owned(), (1, 4)).into(), + arg: Some( + Expr::BinaryOpCall(BinaryOpCall { + loc: (1, 20), + operator: "+".to_owned(), + lhs: Expr::NumericLiteral { + value: "100".to_owned(), + } + .into(), + rhs: Expr::NumericLiteral { + value: "100".to_owned(), + } + .into() + }) + .into() + ) + }), + Statement::Return( + Expr::NumericLiteral { + value: "0".to_owned(), + }, + (2, 4) + ) + ]), + generictypes: None, + abi: None, + }), + parser.next_statement().ast + ); + //a b . 2 + c d . - + const SRC_MEMBER_ACCESS: &'static str = "a.b + 2 - c.d"; + let mut parser = Parser::from_source(SRC_MEMBER_ACCESS); + assert_eq!( + ast::Expr::BinaryOpCall(BinaryOpCall { + loc: (0, 8), + lhs: ast::Expr::BinaryOpCall(BinaryOpCall { + loc: (0, 4), + lhs: ast::Expr::BinaryOpCall(BinaryOpCall { + loc: (0, 1), + lhs: ast::Expr::ValueRead("a".to_string(), (0, 0)).into(), + rhs: ast::Expr::ValueRead("b".to_string(), (0, 2)).into(), + operator: ".".to_string() + }) + .into(), + rhs: ast::Expr::NumericLiteral { + value: "2".to_string(), + } + .into(), + operator: "+".to_string() + }) + .into(), + rhs: ast::Expr::BinaryOpCall(BinaryOpCall { + loc: (0, 11), + lhs: ast::Expr::ValueRead("c".to_string(), (0, 10)).into(), + rhs: ast::Expr::ValueRead("d".to_string(), (0, 12)).into(), + operator: ".".to_string() + }) + .into(), + operator: "-".to_string() + }), + parser.next_expr().ast, + ); + + let mut parser = Parser::from_source("(foo bar) && (baz quz)"); + assert_eq!( + ast::Expr::BinaryOpCall(BinaryOpCall { + loc: (0, 10), + lhs: ast::Expr::FnCall(FnCall { + loc: (0, 1), + value: ast::Expr::ValueRead("foo".to_string(), (0, 1)).into(), + arg: Some(ast::Expr::ValueRead("bar".to_string(), (0, 5)).into()) + }) + .into(), + rhs: ast::Expr::FnCall(FnCall { + loc: (0, 14), + value: ast::Expr::ValueRead("baz".to_string(), (0, 14)).into(), + arg: Some(ast::Expr::ValueRead("quz".to_string(), (0, 18)).into()) + }) + .into(), + operator: "&&".to_string() + }), + parser.next_expr().ast, + "(foo bar) && (baz quz)" + ); + } + + #[test] + fn generics() { + let mut parser = Parser::from_source("for let test a : T -> T = a"); + assert_eq!( + ast::TopLevelDeclaration::Value(TopLevelValue { + loc: (0, 11), + is_op: false, + ident: "test".to_owned(), + args: vec![ast::ArgDeclaration::Simple { + loc: (0, 16), + ident: "a".to_string(), + ty: None, + }], + ty: Some(ResolvedType::Function { + arg: ResolvedType::Generic { + name: "T".to_string(), + loc: (0, 20) + } + .into(), + returns: ResolvedType::Generic { + name: "T".to_string(), + loc: (0, 25) + } + .into(), + loc: (0, 22) + }), + value: ast::ValueType::Expr(ast::Expr::ValueRead("a".to_string(), (0, 29))), + generics: Some(ast::GenericsDecl { + for_loc: (0, 0), + decls: [((0, 4), "T".to_string())].into_iter().collect(), + }), + abi: None, + }), + parser.next_toplevel().ast, + ) + } + + #[test] + fn struct_decl() { + const SRC: &'static str = r#"type Foo = { + a : int32 +} +for type Tuple = { + first : T, + second : U +}"#; + let mut parser = Parser::from_source(SRC); + assert_eq!( + ast::TopLevelDeclaration::TypeDefinition(ast::TypeDefinition::Struct( + StructDefinition { + ident: "Foo".to_string(), + generics: None, + values: vec![ast::FieldDecl { + name: "a".to_string(), + ty: types::INT32, + loc: (1, 4), + }], + loc: (0, 5) + }, + )), + parser.next_toplevel().ast, + "basic" + ); + assert_eq!( + ast::TopLevelDeclaration::TypeDefinition(ast::TypeDefinition::Struct( + StructDefinition { + ident: "Tuple".to_string(), + generics: Some(ast::GenericsDecl { + for_loc: (3, 0), + decls: vec![((3, 4), "T".to_string()), ((3, 6), "U".to_string())], + }), + values: vec![ + ast::FieldDecl { + name: "first".to_string(), + ty: ResolvedType::Generic { + name: "T".to_string(), + loc: (4, 12), + }, + loc: (4, 4) + }, + ast::FieldDecl { + name: "second".to_string(), + ty: ResolvedType::Generic { + name: "U".to_string(), + loc: (5, 13) + }, + loc: (5, 4) + }, + ], + loc: (3, 14) + } + )), + parser.next_toplevel().ast, + "generic" + ) + } + + #[test] + fn generic_use_types() { + const SRC: &'static str = r"let foo a b : Bar -> Baz -> int32 = + return 0 +"; + let mut parser = Parser::from_source(SRC); + assert_eq!( + ast::TopLevelDeclaration::Value(TopLevelValue { + loc: (0, 4), + is_op: false, + ident: "foo".to_owned(), + args: vec![ + ArgDeclaration::Simple { + loc: (0, 8), + ident: "a".to_string(), + ty: None, + }, + ArgDeclaration::Simple { + loc: (0, 10), + ident: "b".to_string(), + ty: None, + }, + ], + ty: Some(ResolvedType::Function { + arg: ResolvedType::User { + name: "Bar".to_string(), + generics: vec![types::INT32], + loc: (0, 14) + } + .into(), + returns: ResolvedType::Function { + arg: ResolvedType::User { + name: "Baz".to_string(), + generics: vec![types::INT32, types::FLOAT64], + loc: (0, 28) + } + .into(), + returns: types::INT32.into(), + loc: (0, 47) + } + .into(), + loc: (0, 25) + }), + value: ValueType::Function(vec![Statement::Return( + Expr::NumericLiteral { + value: "0".to_string(), + }, + (1, 4) + )]), + generics: None, + abi: None, + }), + parser.next_toplevel().ast + ) + } + + #[test] + fn struct_construction() { + const SRC: &'static str = "Foo { a : 0 }"; + let mut parser = Parser::from_source(SRC); + assert_eq!( + ast::Expr::StructConstruction(StructConstruction { + loc: (0, 4), + fields: HashMap::from([( + "a".to_string(), + ( + Expr::NumericLiteral { + value: "0".to_string(), + }, + (0, 6) + ) + )]), + generics: Vec::new(), + ident: "Foo".to_string() + }), + parser.next_expr().ast + ); + assert_eq!( + ast::Expr::StructConstruction(StructConstruction { + loc: (0, 14), + fields: HashMap::from([( + "a".to_string(), + ( + Expr::NumericLiteral { + value: "0".to_string(), + }, + (0, 16) + ) + )]), + generics: vec![types::INT32], + ident: "Generic".to_string() + }), + Parser::from_source("Generic{ a:0 }").next_expr().ast + ) + } + + #[test] + fn control_flow_if() { + let mut parser = Parser::from_source(include_str!("../../samples/control_flow_if.fb")); + assert_eq!( + ast::TopLevelDeclaration::Value(TopLevelValue { + loc: (0, 4), + is_op: false, + ident: "inline_expr".to_owned(), + args: vec![ast::ArgDeclaration::Simple { + ident: "a".to_string(), + loc: (0, 16), + ty: None, + }], + ty: Some(ResolvedType::Function { + arg: types::BOOL.into(), + returns: types::INT32.into(), + loc: (0, 25) + }), + value: ast::ValueType::Expr(ast::Expr::If(IfExpr { + cond: ast::Expr::ValueRead("a".to_string(), (0, 39)).into(), + true_branch: ( + Vec::new(), + ast::Expr::NumericLiteral { + value: "0".to_string(), + } + .into() + ), + else_ifs: Vec::new(), + else_branch: ( + Vec::new(), + ast::Expr::NumericLiteral { + value: "1".to_string(), + } + .into() + ), + loc: (0, 36) + })), + generics: None, + abi: None, + }), + parser.next_toplevel().ast, + "inline_expr" + ); + + assert_eq!( + ast::TopLevelDeclaration::Value(TopLevelValue { + loc: (2, 4), + is_op: false, + ident: "out_of_line_expr".to_owned(), + args: vec![ast::ArgDeclaration::Simple { + ident: "a".to_string(), + loc: (2, 21), + ty: None, + }], + ty: Some(ResolvedType::Function { + arg: types::BOOL.into(), + returns: types::INT32.into(), + loc: (2, 30) + }), + value: ast::ValueType::Expr(ast::Expr::If(IfExpr { + cond: ast::Expr::ValueRead("a".to_string(), (2, 44)).into(), + true_branch: ( + Vec::new(), + ast::Expr::FnCall(ast::FnCall { + loc: (3, 8), + value: ast::Expr::ValueRead("fun".to_string(), (3, 8)).into(), + arg: Some( + ast::Expr::NumericLiteral { + value: "0".to_string(), + } + .into() + ), + }) + .into() + ), + else_ifs: Vec::new(), + else_branch: ( + Vec::new(), + ast::Expr::NumericLiteral { + value: "1".to_string(), + } + .into() + ), + loc: (2, 41) + })), + generics: None, + abi: None, + }), + parser.next_toplevel().ast, + "out_of_line_expr" + ); + + assert_eq!( + ast::TopLevelDeclaration::Value(TopLevelValue { + loc: (7, 4), + is_op: false, + ident: "expr_with_statement".to_owned(), + args: vec![ast::ArgDeclaration::Simple { + loc: (7, 24), + ident: "a".to_string(), + ty: None, + }], + ty: Some(ResolvedType::Function { + arg: types::BOOL.into(), + returns: types::INT32.into(), + loc: (7, 33) + }), + value: ast::ValueType::Expr(ast::Expr::If(IfExpr { + cond: ast::Expr::ValueRead("a".to_string(), (7, 47)).into(), + true_branch: ( + vec![ast::Statement::FnCall(FnCall { + loc: (8, 8), + value: ast::Expr::ValueRead("bar".to_string(), (8, 8)).into(), + arg: Some( + ast::Expr::NumericLiteral { + value: "3".to_string(), + } + .into() + ), + })], + ast::Expr::NumericLiteral { + value: "0".to_string(), + } + .into() + ), + else_ifs: Vec::new(), + else_branch: ( + vec![ast::Statement::FnCall(FnCall { + loc: (11, 8), + value: ast::Expr::ValueRead("baz".to_string(), (11, 8)).into(), + arg: Some( + ast::Expr::NumericLiteral { + value: "4".to_string(), + } + .into() + ), + })], + ast::Expr::NumericLiteral { + value: "1".to_string(), + } + .into() + ), + loc: (7, 44) + })), + generics: None, + abi: None, + }), + parser.next_toplevel().ast, + "expr_with_statement" + ); + + assert_eq!( + ast::TopLevelDeclaration::Value(TopLevelValue { + loc: (14, 4), + is_op: false, + ident: "expr_with_else_if".to_owned(), + args: vec![ + ast::ArgDeclaration::Simple { + loc: (14, 22), + ident: "a".to_string(), + ty: None, + }, + ast::ArgDeclaration::Simple { + loc: (14, 24), + ident: "b".to_string(), + ty: None, + }, + ], + ty: Some(ResolvedType::Function { + arg: types::BOOL.into(), + returns: ResolvedType::Function { + arg: types::BOOL.into(), + returns: types::INT32.into(), + loc: (14, 41) + } + .into(), + loc: (14, 33) + }), + value: ValueType::Expr(ast::Expr::If(IfExpr { + cond: ast::Expr::ValueRead("a".to_string(), (14, 55)).into(), + true_branch: ( + Vec::new(), + ast::Expr::NumericLiteral { + value: "0".to_string(), + } + .into() + ), + else_ifs: vec![( + ast::Expr::ValueRead("b".to_string(), (14, 72)).into(), + Vec::new(), + ast::Expr::NumericLiteral { + value: "1".to_string(), + } + .into() + ),], + else_branch: ( + Vec::new(), + ast::Expr::NumericLiteral { + value: "2".to_string(), + } + .into() + ), + loc: (14, 52) + })), + generics: None, + abi: None, + }), + parser.next_toplevel().ast, + "expr with else if" + ); + + assert_eq!( + ast::TopLevelDeclaration::Value(TopLevelValue { + loc: (16, 4), + is_op: false, + ident: "statement".to_owned(), + args: vec![ast::ArgDeclaration::Simple { + loc: (16, 14), + ident: "a".to_string(), + ty: None, + }], + ty: Some(ResolvedType::Function { + arg: types::BOOL.into(), + returns: types::INT32.into(), + loc: (16, 23) + }), + value: ast::ValueType::Function(vec![ast::Statement::IfStatement(IfBranching { + cond: ast::Expr::ValueRead("a".to_string(), (17, 7)).into(), + true_branch: vec![ + ast::Statement::FnCall(FnCall { + loc: (18, 8), + value: ast::Expr::ValueRead("foo".to_string(), (18, 8)).into(), + arg: Some( + ast::Expr::NumericLiteral { + value: "3".to_string(), + } + .into() + ) + }), + ast::Statement::Return( + ast::Expr::NumericLiteral { + value: "0".to_string(), + }, + (19, 8) + ), + ], + else_ifs: Vec::new(), + else_branch: vec![ + ast::Statement::FnCall(FnCall { + loc: (21, 8), + value: ast::Expr::ValueRead("bar".to_string(), (21, 8)).into(), + arg: Some( + ast::Expr::NumericLiteral { + value: "4".to_string(), + } + .into() + ) + }), + ast::Statement::Return( + ast::Expr::NumericLiteral { + value: "1".to_string(), + }, + (22, 8) + ), + ], + loc: (17, 4) + })]), + generics: None, + abi: None, + }), + parser.next_toplevel().ast, + "statement" + ); + + assert_eq!( + ast::TopLevelDeclaration::Value(TopLevelValue { + loc: (24, 4), + is_op: false, + ident: "statement_with_else_if".to_owned(), + args: vec![ + ast::ArgDeclaration::Simple { + loc: (24, 27), + ident: "a".to_string(), + ty: None, + }, + ast::ArgDeclaration::Simple { + loc: (24, 29), + ident: "b".to_string(), + ty: None, + }, + ], + ty: Some(ResolvedType::Function { + arg: types::BOOL.into(), + returns: ResolvedType::Function { + arg: types::BOOL.into(), + returns: types::INT32.into(), + loc: (24, 46) + } + .into(), + loc: (24, 38) + }), + value: ast::ValueType::Function(vec![ast::Statement::IfStatement(IfBranching { + cond: ast::Expr::ValueRead("a".to_string(), (25, 7)).into(), + true_branch: vec![ast::Statement::Return( + ast::Expr::NumericLiteral { + value: "0".to_string(), + }, + (26, 8) + )], + else_ifs: vec![( + ast::Expr::ValueRead("b".to_string(), (27, 12)).into(), + vec![ast::Statement::Return( + ast::Expr::NumericLiteral { + value: "1".to_string(), + }, + (28, 8) + )] + )], + else_branch: vec![ast::Statement::Return( + ast::Expr::NumericLiteral { + value: "2".to_string(), + }, + (30, 8) + )], + loc: (25, 4), + })]), + generics: None, + abi: None, + }), + parser.next_toplevel().ast, + "statement_with_else_if" + ); + + assert_eq!( + ast::TopLevelDeclaration::Value(TopLevelValue { + loc: (32, 4), + is_op: false, + ident: "expr_multi_with_elseif".to_owned(), + args: vec![ + ast::ArgDeclaration::Simple { + loc: (32, 27), + ident: "a".to_string(), + ty: None, + }, + ast::ArgDeclaration::Simple { + loc: (32, 29), + ident: "b".to_string(), + ty: None, + }, + ], + ty: Some(ResolvedType::Function { + arg: types::BOOL.into(), + returns: ResolvedType::Function { + arg: types::BOOL.into(), + returns: types::INT32.into(), + loc: (32, 46) + } + .into(), + loc: (32, 38) + }), + value: ValueType::Expr(ast::Expr::If(IfExpr { + cond: ast::Expr::ValueRead("a".to_string(), (32, 60)).into(), + true_branch: ( + Vec::new(), + ast::Expr::NumericLiteral { + value: "0".to_string(), + } + .into(), + ), + else_ifs: vec![( + ast::Expr::ValueRead("b".to_string(), (34, 12)).into(), + Vec::new(), + ast::Expr::NumericLiteral { + value: "1".to_string(), + } + .into(), + )], + else_branch: ( + Vec::new(), + ast::Expr::NumericLiteral { + value: "2".to_string(), + } + .into(), + ), + loc: (32, 57) + })), + generics: None, + abi: None, + }), + parser.next_toplevel().ast, + "multi line expr with else if" + ); + } + + #[test] + fn control_flow_match() { + let mut parser = Parser::from_source(include_str!("../../samples/control_flow_match.fb")); + assert_eq!( + ast::TopLevelDeclaration::Value(TopLevelValue { + loc: (0, 4), + is_op: false, + ident: "match_expr_ints".to_owned(), + args: vec![ast::ArgDeclaration::Simple { + loc: (0, 20), + ident: "x".to_string(), + ty: None, + }], + ty: Some(ResolvedType::Function { + arg: types::INT32.into(), + returns: types::INT32.into(), + loc: (0, 30) + }), + value: ast::ValueType::Expr(ast::Expr::Match(Match { + loc: (0, 41), + on: ast::Expr::ValueRead("x".to_string(), (0, 47)).into(), + arms: vec![ + MatchArm { + block: Vec::new(), + ret: Some( + ast::Expr::NumericLiteral { + value: "1".to_string(), + } + .into() + ), + cond: Pattern::ConstNumber("1".to_string()), + loc: (1, 6) + }, + MatchArm { + block: Vec::new(), + ret: Some( + ast::Expr::NumericLiteral { + value: "3".to_string(), + } + .into() + ), + cond: Pattern::ConstNumber("2".to_string()), + loc: (2, 6) + }, + MatchArm { + block: Vec::new(), + ret: Some( + ast::Expr::NumericLiteral { + value: "4".to_string(), + } + .into() + ), + cond: Pattern::Default, + loc: (3, 6) + }, + ] + })), + generics: None, + abi: None, + }), + parser.next_toplevel().ast, + "match_expr_ints" + ); + + assert_eq!( + ast::TopLevelDeclaration::Value(TopLevelValue { + loc: (5, 4), + is_op: false, + ident: "match_expr_with_block".to_owned(), + args: vec![ArgDeclaration::Simple { + loc: (5, 26), + ident: "x".to_string(), + ty: None, + },], + ty: Some(ResolvedType::Function { + arg: types::INT32.into(), + returns: types::INT32.into(), + loc: (5, 36) + }), + value: ValueType::Expr(ast::Expr::Match(Match { + loc: (5, 47), + on: ast::Expr::ValueRead("x".to_string(), (5, 53)).into(), + arms: vec![ + MatchArm { + loc: (6, 6), + block: vec![ast::Statement::Declaration(ValueDeclaration { + loc: (7, 12), + is_op: false, + target: Pattern::Read("a".to_owned(), (7, 12)), + args: Vec::new(), + ty: Some(types::INT32), + value: ValueType::Expr(ast::Expr::NumericLiteral { + value: "2".to_string(), + }), + generictypes: None, + abi: None, + })], + ret: Some( + ast::Expr::BinaryOpCall(BinaryOpCall { + loc: (8, 9), + lhs: ast::Expr::ValueRead("a".to_string(), (8, 8)).into(), + rhs: ast::Expr::NumericLiteral { + value: "3".to_string(), + } + .into(), + operator: "*".to_string() + }) + .into() + ), + cond: Pattern::ConstNumber("1".to_string()), + }, + MatchArm { + block: Vec::new(), + ret: Some( + ast::Expr::NumericLiteral { + value: "2".to_string(), + } + .into() + ), + cond: Pattern::ConstNumber("2".to_string()), + loc: (9, 6) + }, + MatchArm { + loc: (10, 6), + block: Vec::new(), + ret: Some( + ast::Expr::BinaryOpCall(BinaryOpCall { + loc: (10, 12), + lhs: ast::Expr::ValueRead("a".to_string(), (10, 11)).into(), + rhs: ast::Expr::NumericLiteral { + value: "2".to_string(), + } + .into(), + operator: "/".to_string() + }) + .into() + ), + cond: Pattern::Read("a".to_string(), (10, 6)), + }, + ] + })), + generics: None, + abi: None, + }), + parser.next_toplevel().ast, + "match_expr_with_block" + ); + assert_eq!( + ast::TopLevelDeclaration::Value(TopLevelValue { + loc: (12, 4), + is_op: false, + ident: "match_statement".to_owned(), + args: vec![ArgDeclaration::Simple { + loc: (12, 20), + ident: "x".to_string(), + ty: None, + },], + ty: Some(ResolvedType::Function { + arg: types::INT32.into(), + returns: types::UNIT.into(), + loc: (12, 30) + }), + value: ValueType::Function(vec![ast::Statement::Match(Match { + loc: (13, 4), + on: ast::Expr::ValueRead("x".to_string(), (13, 10)).into(), + arms: vec![ + MatchArm { + block: vec![ast::Statement::FnCall(FnCall { + loc: (15, 8), + value: ast::Expr::ValueRead("foo".to_string(), (15, 8)).into(), + arg: Some( + ast::Expr::NumericLiteral { + value: "0".to_string(), + } + .into() + ) + })], + ret: None, + cond: Pattern::ConstNumber("1".to_string()), + loc: (14, 6), + }, + MatchArm { + block: vec![ast::Statement::FnCall(FnCall { + loc: (17, 8), + value: ast::Expr::ValueRead("bar".to_string(), (17, 8)).into(), + arg: Some( + ast::Expr::NumericLiteral { + value: "1".to_string(), + } + .into() + ) + })], + ret: None, + cond: Pattern::ConstNumber("2".to_string()), + loc: (16, 6), + }, + MatchArm { + block: Vec::new(), + ret: Some( + ast::Expr::FnCall(FnCall { + loc: (18, 11), + value: ast::Expr::ValueRead("baz".to_string(), (18, 11)).into(), + arg: Some( + ast::Expr::NumericLiteral { + value: "2".to_string(), + } + .into() + ) + }) + .into() + ), + cond: Pattern::ConstNumber("3".to_string()), + loc: (18, 6), + }, + ] + })]), + generics: None, + abi: None, + }), + parser.next_toplevel().ast, + "match_statement", + ); + } + #[test] + fn arrays() { + const SRC: &'static str = r#" +let arr = [0,0,0,0]; +"#; + let arr = Parser::from_source(SRC).next_toplevel().ast; + assert_eq!( + ast::TopLevelDeclaration::Value(TopLevelValue { + loc: (1, 4), + is_op: false, + ident: "arr".to_owned(), + args: Vec::new(), + ty: None, + value: ast::ValueType::Expr(ast::Expr::ArrayLiteral { + contents: vec![ + ast::Expr::NumericLiteral { + value: "0".to_string() + }, + ast::Expr::NumericLiteral { + value: "0".to_string() + }, + ast::Expr::NumericLiteral { + value: "0".to_string() + }, + ast::Expr::NumericLiteral { + value: "0".to_string() + }, + ], + loc: (1, 10) + }), + generics: None, + abi: None, + }), + arr, + "arrays" + ) + } + + #[test] + fn abi() { + const SRC: &'static str = r#" +extern "C" let putchar : int32 -> int32; +extern "C" let ex (a:int32) b = a + b; +"#; + let mut parser = Parser::from_source(SRC); + let putchar = parser.next_toplevel().ast; + let ex = parser.next_toplevel().ast; + assert_eq!( + ast::TopLevelDeclaration::Value(TopLevelValue { + loc: (1, 15), + is_op: false, + ident: "putchar".to_owned(), + args: Vec::new(), + ty: Some(types::INT32.fn_ty(&types::INT32)), + value: ValueType::External, + generics: None, + abi: Some(ast::Abi { + loc: (1, 0), + identifier: "C".to_string(), + }), + }), + putchar, + "input function" + ); + assert_eq!( + ast::TopLevelDeclaration::Value(TopLevelValue { + loc: (2, 15), + is_op: false, + ident: "ex".to_owned(), + args: vec![ + ast::ArgDeclaration::Simple { + loc: (2, 19), + ident: "a".to_string(), + ty: Some(types::INT32), + }, + ast::ArgDeclaration::Simple { + loc: (2, 28), + ident: "b".to_string(), + ty: None, + }, + ], + ty: None, + value: ValueType::Expr(Expr::BinaryOpCall(BinaryOpCall { + loc: (2, 34), + lhs: Expr::ValueRead("a".to_string(), (2, 32)).into(), + rhs: Expr::ValueRead("b".to_string(), (2, 36)).into(), + operator: "+".to_string() + })), + generics: None, + abi: Some(ast::Abi { + loc: (2, 0), + identifier: "C".to_string(), + }), + }), + ex, + "output function." + ) + } + + #[test] + fn tuples() { + const SRC: &'static str = " +let ty _ : (int32,int32)->int32 = 0 + +let cons a : int32 -> (int32,int32) = (a,0) +"; + + let module = Parser::from_source(SRC).module("".to_string()).ast; + let [ty, cons] = &module.declarations[..] else { + unreachable!() + }; + assert_eq!( + &ast::TopLevelDeclaration::Value(TopLevelValue { + loc: (1, 4), + is_op: false, + ident: "ty".to_owned(), + args: vec![ArgDeclaration::Discard { + ty: None, + loc: (1, 7) + }], + ty: Some( + ResolvedType::Tuple { + underlining: vec![types::INT32, types::INT32], + loc: (0, 0) + } + .fn_ty(&types::INT32) + ), + value: ValueType::Expr(Expr::NumericLiteral { + value: "0".to_string() + }), + generics: None, + abi: None, + }), + ty + ); + + assert_eq!( + &ast::TopLevelDeclaration::Value(TopLevelValue { + loc: (3, 4), + is_op: false, + ident: "cons".to_owned(), + args: vec![ArgDeclaration::Simple { + loc: (3, 9), + ident: "a".to_string(), + ty: None + }], + ty: Some(types::INT32.fn_ty(&ResolvedType::Tuple { + underlining: vec![types::INT32, types::INT32], + loc: (0, 0) + })), + value: ValueType::Expr(Expr::TupleLiteral { + contents: vec![ + Expr::ValueRead("a".to_string(), (3, 39)), + Expr::NumericLiteral { + value: "0".to_string() + } + ], + loc: (3, 38) + }), + generics: None, + abi: None + }), + cons + ); + } + + #[test] + fn match_patterns() { + let pattern = Parser::from_source("a").collect_pattern().ast; + assert_eq!(Pattern::Read("a".to_string(), (0, 0)), pattern, "a"); + let pattern = Parser::from_source("_").collect_pattern().ast; + assert_eq!(Pattern::Default, pattern, "_"); + let pattern = Parser::from_source("(a,b)").collect_pattern().ast; + assert_eq!( + Pattern::Destructure(PatternDestructure::Tuple(vec![ + Pattern::Read("a".to_string(), (0, 1)), + Pattern::Read("b".to_string(), (0, 3)), + ])), + pattern, + "destruct tuple" + ); + let pattern = Parser::from_source("0 | 1").collect_pattern().ast; + assert_eq!( + Pattern::Or( + Pattern::ConstNumber("0".to_string()).into(), + Pattern::ConstNumber("1".to_string()).into(), + ), + pattern, + "or (0 or 1)" + ); + let pattern = Parser::from_source("0 | 1 | 2").collect_pattern().ast; + assert_eq!( + Pattern::Or( + Pattern::ConstNumber("0".to_string()).into(), + Pattern::Or( + Pattern::ConstNumber("1".to_string()).into(), + Pattern::ConstNumber("2".to_string()).into(), + ) + .into() + ), + pattern, + "or (0 or 1 or 2)" + ); + let pattern = Parser::from_source("(0 | 1,b)").collect_pattern().ast; + assert_eq!( + Pattern::Destructure(PatternDestructure::Tuple(vec![ + Pattern::Or( + Pattern::ConstNumber("0".to_string()).into(), + Pattern::ConstNumber("1".to_string()).into(), + ), + Pattern::Read("b".to_string(), (0, 7)), + ])), + pattern, + "destruct tuple" + ); + } + + #[test] + fn arg_types() { + const SRC: &'static str = " +let simple a = (); +let decon_arg (a,b) = (); +let discard _ = (); +let unit () = (); +let annotated_arg_tuple ((x,y):(int32,int32)) = (); +"; + + let ast = Parser::from_source(SRC).module("".to_string()).ast; + let [simple, decon, discard, unit, annotated_decon] = &ast.declarations[..] else { + unreachable!() + }; + assert_eq!( + &TopLevelDeclaration::Value(TopLevelValue { + loc: (1, 4), + is_op: false, + ident: "simple".to_owned(), + args: vec![ArgDeclaration::Simple { + loc: (1, 11), + ident: "a".to_string(), + ty: None, + },], + ty: None, + value: ValueType::Expr(Expr::UnitLiteral), + generics: None, + abi: None, + }), + simple, + "let simple a = ();" + ); + assert_eq!( + &TopLevelDeclaration::Value(TopLevelValue { + loc: (2, 4), + is_op: false, + ident: "decon_arg".to_owned(), + args: vec![ArgDeclaration::DestructureTuple( + vec![ + ArgDeclaration::Simple { + loc: (2, 15), + ident: "a".to_string(), + ty: None, + }, + ArgDeclaration::Simple { + loc: (2, 17), + ident: "b".to_string(), + ty: None, + }, + ], + None, + (2, 14) + ),], + ty: None, + value: ValueType::Expr(Expr::UnitLiteral), + generics: None, + abi: None, + }), + decon, + "let decon_arg (a,b) = ()" + ); + assert_eq!( + &TopLevelDeclaration::Value(TopLevelValue { + loc: (3, 4), + is_op: false, + ident: "discard".to_owned(), + args: vec![ArgDeclaration::Discard { + loc: (3, 12), + ty: None, + },], + ty: None, + value: ValueType::Expr(Expr::UnitLiteral), + generics: None, + abi: None, + }), + discard, + "let discard _ = ();" + ); + assert_eq!( + &TopLevelDeclaration::Value(TopLevelValue { + loc: (4, 4), + is_op: false, + ident: "unit".to_owned(), + args: vec![ArgDeclaration::Unit { + loc: (4, 9), + ty: None, + },], + ty: None, + value: ValueType::Expr(Expr::UnitLiteral), + generics: None, + abi: None, + }), + unit, + "let unit () = ();" + ); + assert_eq!( + &TopLevelDeclaration::Value(TopLevelValue { + loc: (5, 4), + is_op: false, + ident: "annotated_arg_tuple".to_owned(), + args: vec![ArgDeclaration::DestructureTuple( + vec![ + ArgDeclaration::Simple { + loc: (5, 26), + ident: "x".to_string(), + ty: None, + }, + ArgDeclaration::Simple { + loc: (5, 28), + ident: "y".to_string(), + ty: None, + }, + ], + Some(ResolvedType::Tuple { + underlining: vec![types::INT32, types::INT32,], + loc: (5, 31) + }), + (5, 25) + ),], + ty: None, + value: ValueType::Expr(Expr::UnitLiteral), + generics: None, + abi: None, + }), + annotated_decon, + "let annotated_arg_tuple ((x,y):(int32,int32)) = ();" + ); + } + #[test] + fn destructuring_statement() { + let mut parser = super::Parser::from_source( + " +let (x,y) = v; +let ((x,y),z) = v; +let (x,y,z) = v; +let (x,y):(int32,int32) = v; +//yes this will all fail typecheking. +", + ); + assert_eq!( + Statement::Declaration(ValueDeclaration { + loc: (1, 4), + is_op: false, + target: Pattern::Destructure(PatternDestructure::Tuple(vec![ + Pattern::Read("x".to_string(), (1, 5)), + Pattern::Read("y".to_string(), (1, 7)), + ])), + args: Vec::new(), + ty: None, + value: ValueType::Expr(ast::Expr::ValueRead("v".to_string(), (1, 12))), + generictypes: None, + abi: None, + }), + parser.next_statement().ast + ); + + assert_eq!( + Statement::Declaration(ValueDeclaration { + loc: (2, 4), + is_op: false, + target: Pattern::Destructure(PatternDestructure::Tuple(vec![ + Pattern::Destructure(PatternDestructure::Tuple(vec![ + Pattern::Read("x".to_string(), (2, 6)), + Pattern::Read("y".to_string(), (2, 8)), + ])), + Pattern::Read("z".to_string(), (2, 11)) + ])), + args: Vec::new(), + ty: None, + value: ValueType::Expr(ast::Expr::ValueRead("v".to_string(), (2, 16))), + generictypes: None, + abi: None, + }), + parser.next_statement().ast + ); + assert_eq!( + Statement::Declaration(ValueDeclaration { + loc: (3, 4), + is_op: false, + target: Pattern::Destructure(PatternDestructure::Tuple(vec![ + Pattern::Read("x".to_string(), (3, 5)), + Pattern::Read("y".to_string(), (3, 7)), + Pattern::Read("z".to_string(), (3, 9)), + ])), + args: Vec::new(), + ty: None, + value: ValueType::Expr(ast::Expr::ValueRead("v".to_string(), (3, 14))), + generictypes: None, + abi: None, + }), + parser.next_statement().ast + ); + assert_eq!( + Statement::Declaration(ValueDeclaration { + loc: (4, 4), + is_op: false, + target: Pattern::Destructure(PatternDestructure::Tuple(vec![ + Pattern::Read("x".to_string(), (4, 5)), + Pattern::Read("y".to_string(), (4, 7)), + ])), + args: Vec::new(), + ty: Some(ResolvedType::Tuple { + underlining: vec![types::INT32, types::INT32], + loc: (4, 10), + }), + value: ValueType::Expr(ast::Expr::ValueRead("v".to_string(), (4, 26))), + generictypes: None, + abi: None, + }), + parser.next_statement().ast + ); + } + + #[test] + fn enums() { + const SRC: &'static str = " +enum Basic = | None | AnInt int32 | Struct { a: int32 } +for enum Option = | Some T | None +for enum Result = | Ok T | Err E +"; + let mut parser = Parser::from_source(SRC); + let basic = parser.next_toplevel().ast; + assert_eq!( + TopLevelDeclaration::TypeDefinition(TypeDefinition::Enum(EnumDeclaration { + ident: "Basic".to_string(), + generics: None, + values: vec![ + EnumVariant::Unit { + ident: "None".to_string(), + loc: (1, 15) + }, + EnumVariant::Tuple { + ident: "AnInt".to_string(), + loc: (1, 22), + ty: types::INT32 + }, + EnumVariant::Struct { + ident: "Struct".to_string(), + fields: vec![FieldDecl { + name: "a".to_string(), + ty: types::INT32, + loc: (1, 45) + }], + loc: (1, 36) + } + ], + loc: (1, 5), + })), + basic, + "basic: enum Basic = | None | AnInt int32 | Struct {{ a: int32 }}" + ); + let option = parser.next_toplevel().ast; + assert_eq!( + TopLevelDeclaration::TypeDefinition(TypeDefinition::Enum(EnumDeclaration { + ident: "Option".to_string(), + generics: Some(GenericsDecl { + for_loc: (2, 0), + decls: vec![((2, 4), "T".to_string())] + }), + values: vec![ + EnumVariant::Tuple { + ident: "Some".to_string(), + ty: ResolvedType::Generic { + name: "T".to_string(), + loc: (2, 28) + }, + loc: (2, 23) + }, + EnumVariant::Unit { + ident: "None".to_string(), + loc: (2, 32) + } + ], + loc: (2, 12) + })), + option, + "option: for enum Option = | Some T | None" + ); + + let result = parser.next_toplevel().ast; + assert_eq!( + TopLevelDeclaration::TypeDefinition(TypeDefinition::Enum(EnumDeclaration { + ident: "Result".to_string(), + generics: Some(GenericsDecl { + for_loc: (3, 0), + decls: vec![((3, 4), "T".to_string()), ((3, 6), "E".to_string()),] + }), + values: vec![ + EnumVariant::Tuple { + ident: "Ok".to_string(), + ty: ResolvedType::Generic { + name: "T".to_string(), + loc: (3, 28) + }, + loc: (3, 25) + }, + EnumVariant::Tuple { + ident: "Err".to_string(), + ty: ResolvedType::Generic { + name: "E".to_string(), + loc: (3, 35) + }, + loc: (3, 32) + }, + ], + loc: (3, 14) + })), + result, + "result: for enum Result = | Ok T | Err E" + ); + + assert!(!parser.has_next()); + } + + #[test] + fn enum_patterns() { + const SRC: &'static str = r#" +match a where +| Enum::Complex { a: 0, b } -> b, // TODO! struct patterns +// | Enum::Complex c -> c.a // TODO! struct access. +| Enum::Simple (0 | 1) -> 0, +| Simple a -> a, +"#; + let ast = Parser::from_source(SRC).match_().ast; + + assert_eq!( + ast::Match { + loc: (1, 0), + on: ast::Expr::ValueRead("a".to_string(), (1, 6)).into(), + arms: vec![ + MatchArm { + block: Vec::new(), + ret: Some(ast::Expr::ValueRead("b".to_string(), (2, 31)).into()), + cond: Pattern::EnumVariant { + ty: Some("Enum".to_string()), + variant: "Complex".to_string(), + pattern: Some( + Pattern::Destructure(PatternDestructure::Struct { + base_ty: None, + fields: [ + ("a".to_string(), Pattern::ConstNumber("0".to_string())), + ("b".to_string(), Pattern::Read("b".to_string(), (2, 24))), + ] + .into(), + }) + .into() + ), + loc: (2, 2) + }, + loc: (2, 2), + }, + MatchArm { + block: Vec::new(), + ret: Some( + ast::Expr::NumericLiteral { + value: "0".to_string() + } + .into() + ), + cond: Pattern::EnumVariant { + ty: Some("Enum".to_string()), + variant: "Simple".to_string(), + pattern: Some( + Pattern::Or( + Pattern::ConstNumber("0".to_string()).into(), + Pattern::ConstNumber("1".to_string()).into(), + ) + .into() + ), + loc: (4, 2) + }, + loc: (4, 2), + }, + MatchArm { + block: Vec::new(), + ret: Some(ast::Expr::ValueRead("a".to_string(), (5, 14)).into()), + cond: Pattern::EnumVariant { + ty: None, + variant: "Simple".to_string(), + pattern: Some(Pattern::Read("a".to_string(), (5, 9)).into()), + loc: (5, 2) + }, + loc: (5, 2), + }, + ], + }, + ast, + "match" + ); + } +} diff --git a/compiler/src/parser.rs b/compiler/src/parser.rs index 584214e..6095321 100644 --- a/compiler/src/parser.rs +++ b/compiler/src/parser.rs @@ -1,4015 +1,1487 @@ -use std::{ - collections::{HashMap, HashSet}, - fmt::Error, - iter::Peekable, - str::Chars, +use crate::{ast, tokens::Token, types}; +use std::borrow::Cow; +use winnow::{ + ascii, combinator, + error::{AddContext, ContextError, ErrMode, ParserError, StrContext}, + stream::{AsChar, Located, Location, Stream as WStream, StreamIsPartial}, + token, PResult, Parser, Stateful, }; -use ast::{GenericsDecl, TypeDefinition}; -use itertools::Itertools; - -use crate::{ - ast::{ - self, ArgDeclaration, BinaryOpCall, Expr, FieldDecl, FnCall, Match, Pattern, - PatternDestructure, Statement, StructConstruction, StructDefinition, TopLevelDeclaration, - TopLevelValue, ValueDeclaration, ValueType, - }, - lexer::TokenStream, - tokens::Token, - types::{self, ResolvedType}, -}; +type Stream<'input> = Stateful>,OuterState<'input>>; -use thiserror::Error; +#[derive(Default,Clone,Debug)] +struct State { + in_line_comment:bool, + multiline_comment_depth:usize,//depth to allow for nesting multiline comments + changed_multiline_comment_status:bool, + in_str_lit:bool, + in_char_lit:bool, + escaping:bool, +} -#[derive(Error, Debug)] -#[error("")] -pub enum Warning {} +#[derive(Default,Debug)] +struct OuterState<'input> { -#[allow(unused)] -#[derive(Error, Debug)] -#[error("{reason:?} at {span:?}")] -pub struct ParseError { - span: (usize, usize), - reason: ParseErrorReason, + prefix: Cow<'input, str>, + just_consumed_line:bool, + multi_line_expr:bool, } -#[derive(Debug)] -#[allow(unused)] -enum ParseErrorReason { - UnbalancedBraces, - InvalidIdent, - IndentError, - TypeError, - ArgumentError, - DeclarationError, - UnexpectedEndOfFile, - UnsupportedEscape, - UnsupportedFeature, - UnexpectedToken, - NoElseBlock, - UnknownError, //internal use. should basically never be hit. + +#[derive(Clone)] +struct StrippedParser<'input> { + state : State, + src : &'input str, } -#[derive(Debug)] -pub struct ParserReturns { - pub ast: T, - pub loc: crate::Location, - pub warnings: Vec, //TODO! add warnings and a way next_toplevel treat warnings as errors - pub errors: Vec, +impl StrippedParser<'_> { + fn is_empty(&self) -> bool { + self.src.is_empty() + } } -pub(crate) struct Parser -where - T: Iterator, -{ - stream: Peekable, +impl std::fmt::Debug for StrippedParser<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.src.fmt(f) + + } } -impl<'str> Parser>>> { - #[cfg(test)] - pub(crate) fn from_source(source: &'str str) -> Self { - Self { - stream: TokenStream::from_source(source).peekable(), - } +#[derive(Clone)] +struct StrippedParserCheckpoint<'a> { + inner : <&'a str as WStream>::Checkpoint, +} + +impl std::fmt::Debug for StrippedParserCheckpoint<'_> { + fn fmt(&self, f:&mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.inner.fmt(f) } } -impl Parser -where - T: Iterator + Clone, -{ - pub fn from_stream(stream: T) -> Self { - Self { - stream: stream.peekable(), - } +impl winnow::stream::Offset for StrippedParserCheckpoint<'_> { + fn offset_from(&self, other:&Self) -> usize { + self.inner.offset_from(&other.inner) } +} - pub fn has_next(&mut self) -> bool { - let _ = self - .stream - .peeking_take_while(|(token, _)| match token { - Token::Seq | Token::EndBlock => true, - _ => false, - }) - .collect_vec(); - self.stream - .peek() - .map_or(false, |(token, _)| !token.is_eof()) +#[derive(Clone)] +struct StrippedParserIterator<'a> { + base : StrippedParser<'a>, +} + +impl<'a> std::iter::Iterator for StrippedParserIterator<'a> { + type Item = as WStream>::Token; + + fn next(&mut self) -> Option { + self.base.next_token() } - pub(crate) fn module(mut self, name: String) -> ParserReturns { - let mut decls = Vec::new(); - let mut warnings = Vec::new(); - let mut errors = Vec::new(); - while self.has_next() { - let decl = self.next_toplevel(); - warnings.extend(decl.warnings); - errors.extend(decl.errors); - decls.push(decl.ast); - } - ParserReturns { - ast: ast::ModuleDeclaration { - loc: None, - name, - declarations: decls, - }, - loc: (0, 0), - warnings, - errors, - } +} + +impl<'a> WStream for StrippedParser<'a> { + type Token = <&'a str as WStream>::Token; + + type Slice=<&'a str as WStream>::Slice; + + type IterOffsets=std::iter::Enumerate>; + + type Checkpoint= StrippedParserCheckpoint<'a>; + + fn iter_offsets(&self) -> Self::IterOffsets { + StrippedParserIterator { base:self.clone() }.enumerate() } - pub fn next_toplevel(&mut self) -> ParserReturns { - let ParserReturns { - ast: abi, - loc: extern_loc, - mut warnings, - mut errors, - } = self.abi(); - let ParserReturns { - ast: generics, - loc: for_loc, - warnings: for_warnings, - errors: for_errors, - } = self.collect_generics(); - warnings.extend(for_warnings); - errors.extend(for_errors); - if abi.is_some() && generics.is_some() { - errors.push(ParseError { - span: for_loc, - reason: ParseErrorReason::DeclarationError, - }); - } - match self.stream.clone().next() { - Some((Token::For, loc)) => { - errors.push(ParseError { - span: loc, - reason: ParseErrorReason::DeclarationError, - }); - ParserReturns { - ast: ast::TopLevelDeclaration::Value(TopLevelValue { - loc, - is_op: false, - ident: "".to_string(), - args: vec![ArgDeclaration::Simple { - loc, - ident: "".to_string(), - ty: Some(types::ERROR), - }], - ty: Some(types::ERROR), - value: ValueType::Expr(Expr::Error), - generics: generics, - abi: None, - }), - loc, - warnings, - errors, - } - } - Some((Token::Type | Token::Enum, loc)) => { - if abi.is_some() { - errors.push(ParseError { - span: extern_loc, - reason: ParseErrorReason::DeclarationError, - }); - } - let decl = self.type_decl(generics); - warnings.extend(decl.warnings); - errors.extend(decl.errors); - ParserReturns { - ast: ast::TopLevelDeclaration::TypeDefinition(decl.ast), - loc, - warnings, - errors, - } - } - Some((Token::Let, _)) => { - let _ = self.stream.next(); - let (token, ident_span) = self.stream.next().unwrap(); - let (ident, is_op) = match token { - Token::Ident(ident) => (ident, false), - Token::Op(ident) => (ident, true), - _ => { - return ParserReturns { - ast: TopLevelDeclaration::Value(TopLevelValue { - loc: ident_span, - is_op: false, - ident: "".to_string(), - args: vec![ArgDeclaration::Simple { - loc: (0, 0), - ident: "".to_string(), - ty: Some(types::ERROR), - }], - ty: Some(types::ERROR), - value: ValueType::Expr(Expr::Error), - generics, - abi, - }), - loc: ident_span, - warnings: Vec::new(), - errors: vec![ParseError { - span: ident_span, - reason: ParseErrorReason::DeclarationError, - }], - } - } - }; - let args = self.collect_args(); - warnings.extend(args.warnings); - errors.extend(args.errors); - let mut args = args.ast; - if is_op && (args.len() > 2 || args.len() == 0) { - errors.push(ParseError { - span: ident_span, - reason: ParseErrorReason::ArgumentError, - }); - } - let mut ty = if let Some((Token::Colon, _)) = self.stream.peek() { - let _ = self.stream.next(); - let ty = self.collect_type(); - warnings.extend(ty.warnings); - errors.extend(ty.errors); - Some(ty.ast) - } else { - if is_op { - errors.push(ParseError { - span: ident_span, - reason: ParseErrorReason::DeclarationError, - }); - } - None - }; - let value = match self.stream.peek() { - Some((Token::Op(op), _)) if op == "=" => { - let _ = self.stream.next(); - match self.stream.peek() { - Some((Token::BeginBlock, _)) => { - let block = self.collect_block(); - warnings.extend(block.warnings); - errors.extend(block.errors); - ValueType::Function(block.ast) - } - Some(_) => { - let expr = self.next_expr(); - warnings.extend(expr.warnings); - errors.extend(expr.errors); - ValueType::Expr(expr.ast) - } - None => { - errors.push(ParseError { - span: (0, 0), - reason: ParseErrorReason::UnexpectedEndOfFile, - }); - ValueType::Expr(Expr::Error) - } - } - } - Some((Token::Seq, _)) if abi.is_some() => { - let _ = self.stream.next(); - ValueType::External - } - Some((_, loc)) => { - errors.push(ParseError { - span: *loc, - reason: ParseErrorReason::UnexpectedToken, - }); - ValueType::Expr(Expr::Error) - } - None => { - errors.push(ParseError { - span: (0, 0), - reason: ParseErrorReason::UnexpectedEndOfFile, - }); - ValueType::Expr(Expr::Error) - } - }; - if let Some(generics) = &generics { - for arg in &mut args { - generics - .decls - .iter() - .map(|(_, it)| it) - .for_each(|name| arg.apply_generic(name)); - } - if let Some(ty) = &mut ty { - *ty = generics - .decls - .iter() - .map(|(_, it)| it) - .fold(ty.clone(), |ty, name| ty.replace_user_with_generic(name)); - } - } - ParserReturns { - ast: TopLevelDeclaration::Value(TopLevelValue { - loc: ident_span, - is_op, - ident, - args, - ty, - value, - generics, - abi, - }), - loc: ident_span, - warnings, - errors, - } - } - Some((Token::EoF, loc)) => { - errors.push(ParseError { - span: loc, - reason: ParseErrorReason::UnexpectedEndOfFile, - }); - ParserReturns { - ast: ast::TopLevelDeclaration::Value(TopLevelValue { - loc, - is_op: false, - ident: "".to_string(), - args: vec![ArgDeclaration::Simple { - loc, - ident: "".to_string(), - ty: Some(types::ERROR), - }], - ty: Some(types::ERROR), - value: ValueType::Expr(Expr::Error), - generics: generics, - abi: None, - }), - loc, - warnings, - errors, - } - } - Some((_, loc)) => { - errors.push(ParseError { - span: (0, 0), - reason: ParseErrorReason::UnexpectedToken, - }); - ParserReturns { - ast: ast::TopLevelDeclaration::Value(TopLevelValue { - loc, - is_op: false, - ident: "".to_string(), - args: vec![ArgDeclaration::Simple { - loc, - ident: "".to_string(), - ty: Some(types::ERROR), - }], - ty: Some(types::ERROR), - value: ValueType::Expr(Expr::Error), - generics: generics, - abi: None, - }), - loc, - warnings, - errors, - } - } - None => { - errors.push(ParseError { - span: (0, 0), - reason: ParseErrorReason::UnexpectedEndOfFile, - }); - ParserReturns { - ast: ast::TopLevelDeclaration::Value(TopLevelValue { - loc: (0, 0), - is_op: false, - ident: "".to_string(), - args: vec![ArgDeclaration::Simple { - loc: (0, 0), - ident: "".to_string(), - ty: Some(types::ERROR), - }], - ty: Some(types::ERROR), - value: ValueType::Expr(Expr::Error), - generics: generics, - abi: None, - }), - loc: (0, 0), - warnings, - errors, - } - } - } + fn eof_offset(&self) -> usize { + self.src.eof_offset() } - pub fn next_statement(&mut self) -> ParserReturns { - match self.stream.clone().next() { - Some((Token::For, _)) => { - let ParserReturns { - ast: generics, - loc, - mut warnings, - mut errors, - } = self.collect_generics(); - let inner = self.fn_declaration(None, generics); - warnings.extend(inner.warnings); - errors.extend(inner.errors); - if let Some((Token::Seq, _)) = self.stream.clone().next() { - self.stream.next(); - } else { - // TODO generated error here. - println!("expected ; on line {}", inner.loc.0); - } - ParserReturns { - ast: Statement::Declaration(inner.ast), - loc, - warnings, - errors, - } - } - Some((Token::Let, _)) => { - let inner = match self.stream.clone().nth(1) { - Some((Token::GroupOpen, _)) => self.destructuring_declaration(), - Some((Token::Ident(_), _)) - if self.stream.clone().nth(2).map(|(a, _)| a) == Some(Token::CurlOpen) => - { - self.destructuring_declaration() - } - _ => self.fn_declaration(None, None), - }; - if let Some((Token::Seq, _)) = self.stream.clone().next() { - self.stream.next(); - } else { - // TODO generated error here. - println!("expected ; on line {}", inner.loc.0); - } - ParserReturns { - ast: Statement::Declaration(inner.ast), - loc: inner.loc, - warnings: inner.warnings, - errors: inner.errors, - } - } - Some((Token::Return, _)) => { - let inner = self.ret(); - if let Some((Token::Seq, _)) = self.stream.clone().next() { - self.stream.next(); + fn next_token(&mut self) -> Option { + let token= self.src.next_token()?; + let out = match token { + '\n' if self.state.in_line_comment => { + self.state.in_line_comment = false; + Some('\n') + }, + '"' if !self.state.in_str_lit && !(self.state.in_line_comment || self.state.multiline_comment_depth>0) => { + self.state.in_str_lit = true; + Some('"') + }, + '"' if !self.state.escaping && !(self.state.in_line_comment || self.state.multiline_comment_depth>0) => { + self.state.in_str_lit = false; + Some('"') + }, + '\'' if !self.state.in_char_lit && !(self.state.in_line_comment || self.state.multiline_comment_depth>0) =>{ + self.state.in_char_lit = true; + Some('\'') + }, + '\'' if !self.state.escaping && !(self.state.in_line_comment || self.state.multiline_comment_depth>0) => { + self.state.in_char_lit = false; + Some('\'') + }, + '\\' if (self.state.in_char_lit || self.state.in_str_lit) && !(self.state.in_line_comment || self.state.multiline_comment_depth>0)=> { + self.state.escaping = !self.state.escaping; + Some('\\') + } + '#' if !self.state.in_str_lit && !self.state.in_char_lit => { + if Some('/') == self.src.peek_token().map(|(_,it)| it) { + self.state.multiline_comment_depth+=1; + self.state.changed_multiline_comment_status = true; + Some(' ') + } else if self.state.changed_multiline_comment_status { + self.state.changed_multiline_comment_status =false; + Some(' ') + } else if Some('!') == self.src.peek_token().map(|(_,it)| it) { + self.state.in_line_comment = true; + Some(' ') } else { - println!("expected ; on line {}", inner.loc.0); - //TODO! convert next_toplevel an error that is added and returned as part of the ast. + Some('#') } - inner } - // hmmm should handle if it's actually a binary op call esp and/or compose. - Some((Token::Ident(_), _)) => - // for now last statement in a block is not treated as return though will allow for that soon. - { - let ParserReturns { - ast, - loc, - warnings, - errors, - } = self.function_call(); - let inner = Statement::FnCall(ast); - if let Some((Token::Seq, _)) = self.stream.clone().next() { - self.stream.next(); + '/' if self.state.multiline_comment_depth>0 => { + if Some('#') == self.src.peek_token().map(|(_,it)| it) { + self.state.changed_multiline_comment_status = true; + self.state.multiline_comment_depth -= 1; + Some(' ') + } else if self.state.changed_multiline_comment_status { + self.state.changed_multiline_comment_status = false; + Some(' ') } else { - println!("expected ; on line {}", inner.get_loc().0); - //TODO! convert next_toplevel a warning that is added and returned as part of the ast. - } - ParserReturns { - ast: inner, - loc, - warnings, - errors, - } - } - Some((Token::If, _)) => { - let inner = self.ifstatement(); - - ParserReturns { - ast: Statement::IfStatement(inner.ast), - loc: inner.loc, - warnings: inner.warnings, - errors: inner.errors, + Some('/') } } - Some((Token::Match, _)) => { - let ParserReturns { - ast: match_, - loc, - warnings, - errors, - } = self.match_(); - let ast = Statement::Match(match_); - ParserReturns { - ast, - loc, - warnings, - errors, - } + _ if self.state.in_line_comment || self.state.multiline_comment_depth > 0 => Some(' '), + _ => { + self.state.escaping=false; + + Some(token) + }, + }; + // println!("token {token:?} state {:?} out {out:?}", &self.state); + out + } + + fn offset_for

(&self, predicate: P) -> Option + where + P: Fn(Self::Token) -> bool { + for (o,c) in self.iter_offsets() { + if predicate(c) { + return Some(o); } - _ => unreachable!("how?"), } + None } - pub fn next_expr(&mut self) -> ParserReturns { - match self.stream.clone().next() { - Some((Token::If, loc)) => { - let ParserReturns { - ast, - loc: _, - warnings, - errors, - } = self.ifexpr(); - ParserReturns { - ast: Expr::If(ast), - loc, - warnings, - errors, - } - } - Some((Token::BracketOpen, _)) => self.array_literal(), - Some((Token::GroupOpen, loc)) - if matches!(self.stream.clone().nth(1), Some((Token::GroupClose, _))) => - { - self.stream.next(); - self.stream.next(); - return ParserReturns { - ast: Expr::UnitLiteral, - loc, - warnings: Vec::new(), - errors: Vec::new(), - }; - } - Some((Token::GroupOpen, group_loc)) => { - let mut group_opens = 0; - if let Some((Token::Op(_), _)) = self - .stream - .clone() - .skip(1) - .skip_while(|(it, _)| match it { - //skip this whole expression next_toplevel examine what's after it. - Token::GroupOpen => { - group_opens += 1; - true - } - Token::Ident(_) - | Token::FloatingPoint(_, _) - | Token::Integer(_, _) - | Token::Op(_) => true, - Token::GroupClose => { - group_opens -= 1; - group_opens >= 0 - } - _ => false, - }) - .skip(1) - .next() - { - self.binary_op() - } else { - self.stream.next(); - let mut out = self.next_expr(); + fn offset_at(&self, tokens: usize) -> Result { + self.src.offset_at(tokens) + } - match self.stream.peek() { - Some((Token::GroupClose, _)) => { - let _ = self.stream.next(); - } - Some((Token::Comma, _)) => { - let _ = self.stream.next(); - let mut ast = vec![out.ast]; - loop { - let ParserReturns { - ast: expr, - loc, - warnings, - errors, - } = self.next_expr(); - out.errors.extend(errors); - out.warnings.extend(warnings); - ast.push(expr); - match self.stream.clone().next() { - Some((Token::Comma, _)) => { - self.stream.next(); - continue; - } - Some((Token::GroupClose, _)) => { - self.stream.next(); - break; - } - Some((Token::EoF, _)) | None => { - out.errors.push(ParseError { - span: (0, 0), - reason: ParseErrorReason::UnexpectedEndOfFile, - }); - break; - } - // TODO better error reporting. - Some((_other, loc)) => { - out.errors.push(ParseError { - span: loc, - reason: ParseErrorReason::UnexpectedToken, - }); - ast.push(ast::Expr::Error); - break; - } - } - } + fn next_slice(&mut self, offset: usize) -> Self::Slice { - out.ast = if ast.len() == 1 { - ast.pop().unwrap() - } else { - Expr::TupleLiteral { - contents: ast, - loc: group_loc, - } - } - } - _ => (), - } - return out; - } - } - Some((Token::Ident(_), _)) - if match self.stream.clone().nth(1) { - Some((Token::Op(s), _)) => s == "<", - _ => false, - } => - { - let mut angle_depth = 1; - let mut skipped = self.stream.clone().skip(2).skip_while(|(it, _)| { - if angle_depth == 0 { - false - } else { - match it { - Token::Op(op) if op.chars().all_equal_value() == Ok('>') => { - if angle_depth <= op.len() { - angle_depth -= op.len(); - true - } else { - false - } - } - _ => true, - } - } - }); - if let Some((Token::CurlOpen, _)) = skipped.next() { - let ParserReturns { - ast, - loc, - warnings, - errors, - } = self.struct_construct(); - ParserReturns { - ast: Expr::StructConstruction(ast), - loc, - warnings, - errors, - } - } else { - self.binary_op() - } - } - Some(( - Token::Integer(_, _) - | Token::FloatingPoint(_, _) - | Token::CharLiteral(_) - | Token::StringLiteral(_) - | Token::Ident(_) - | Token::True - | Token::False, - _, - )) if match self.stream.clone().nth(1) { - Some((Token::Op(_), _)) => true, - _ => false, - } => - { - self.binary_op() - } - Some(( - Token::CharLiteral(_) - | Token::StringLiteral(_) - | Token::FloatingPoint(_, _) - | Token::Integer(_, _), - _, - )) => self.literal(), - Some((Token::Ident(_), _)) => { - if let Some(( - Token::Ident(_) - | Token::GroupOpen - | Token::StringLiteral(_) - | Token::CharLiteral(_) - | Token::FloatingPoint(_, _) - | Token::Integer(_, _), - _, - )) = self.stream.clone().nth(1) - { - let ParserReturns { - ast, - loc, - warnings, - errors, - } = self.function_call(); - ParserReturns { - ast: Expr::FnCall(ast), - loc, - warnings, - errors, - } - } else if let Some((Token::CurlOpen, _)) = self - .stream - .clone() - .skip(1) - .skip_while(|(it, _)| matches!(it, Token::BeginBlock)) - .next() - { - let ParserReturns { - ast, - loc, - warnings, - errors, - } = self.struct_construct(); - ParserReturns { - ast: Expr::StructConstruction(ast), - loc, - warnings, - errors, - } - } else { - self.value() - } - } - Some((Token::True, loc)) => { - let _ = self.stream.next(); - ParserReturns { - ast: Expr::BoolLiteral(true, loc), - loc, - warnings: Vec::new(), - errors: Vec::new(), - } - } - Some((Token::False, loc)) => { - let _ = self.stream.next(); - ParserReturns { - ast: Expr::BoolLiteral(false, loc), - loc, - warnings: Vec::new(), - errors: Vec::new(), - } - } - Some((Token::Match, _)) => { - let ParserReturns { - ast, - loc, - warnings, - errors, - } = self.match_(); - ParserReturns { - ast: Expr::Match(ast), - loc, - warnings, - errors, - } - } - _ => ParserReturns { - ast: Expr::Error, - loc: (0, 0), - warnings: Vec::new(), - errors: vec![ParseError { - span: (0, 0), - reason: ParseErrorReason::UnknownError, - }], - }, - } + self.src.next_slice(offset) } - fn ifexpr(&mut self) -> ParserReturns { - let Some((Token::If, if_loc)) = self.stream.next() else { - unreachable!() - }; - let ParserReturns { - ast: root_cond, - loc: _, - mut warnings, - mut errors, - } = self.next_expr(); - if let Some((Token::Then, _)) = self.stream.peek() { - let _ = self.stream.next(); - } else { - let (_token, loc) = self.stream.next().unwrap(); - // TODO! recovery? - errors.push(ParseError { - span: loc, - reason: ParseErrorReason::UnexpectedToken, - }); - } - let true_body = match self.stream.clone().next() { - Some((Token::BeginBlock, _)) => { - let _ = self.stream.next(); - let mut body = Vec::new(); - while self - .stream - .clone() - .skip_while(|(it, _)| it != &Token::Seq && it != &Token::EndBlock) - .next() - .map(|a| a.0) - != Some(Token::EndBlock) - { - let stmnt = self.next_statement(); - warnings.extend(stmnt.warnings); - errors.extend(stmnt.errors); - body.push(stmnt.ast); - } - let ret = self.next_expr(); - errors.extend(ret.errors); - warnings.extend(ret.warnings); - let _ = self.stream.next(); - (body, ret.ast) - } - _ => (Vec::new(), { - let ret = self.next_expr(); - warnings.extend(ret.warnings); - errors.extend(ret.errors); - ret.ast - }), - }; - if let Some((Token::Else, _)) = self.stream.peek() { - let _ = self.stream.next(); - let mut else_ifs = Vec::new(); + fn checkpoint(&self) -> Self::Checkpoint { + StrippedParserCheckpoint { inner:self.src.checkpoint() } + } - while let Some((Token::If, _)) = self.stream.peek() { - let Some((Token::If, loc)) = self.stream.next() else { - unreachable!() - }; - let cond = self.next_expr(); - warnings.extend(cond.warnings); - errors.extend(cond.errors); - let cond = cond.ast.into(); + fn reset(&mut self, checkpoint: &Self::Checkpoint) { + self.src.reset(&checkpoint.inner) + } - if let Some((Token::Then, _)) = self.stream.peek() { - let _ = self.stream.next(); - } else { - let (_token, loc) = self.stream.next().unwrap(); - // TODO! recovery? - errors.push(ParseError { - span: loc, - reason: ParseErrorReason::UnexpectedToken, - }); - } - let (body, ret) = match self.stream.clone().next() { - Some((Token::BeginBlock, _)) => { - let _ = self.stream.next(); - let mut body = Vec::new(); - while self - .stream - .clone() - .skip_while(|(it, _)| it != &Token::Seq && it != &Token::EndBlock) - .next() - .map(|a| a.0) - != Some(Token::EndBlock) - { - let stmnt = self.next_statement(); - warnings.extend(stmnt.warnings); - errors.extend(stmnt.errors); - body.push(stmnt.ast); - } - let ret = self.next_expr(); - errors.extend(ret.errors); - warnings.extend(ret.warnings); - let _ = self.stream.next(); - (body, ret.ast) - } - _ => { - let ret = self.next_expr(); - warnings.extend(ret.warnings); - errors.extend(ret.errors); - (Vec::new(), ret.ast) - } - }; - else_ifs.push((cond, body, ret.into())); + fn raw(&self) -> &dyn std::fmt::Debug { + self + } +} - if let Some((Token::Else, _loc)) = self.stream.clone().next() { - let _else_token = self.stream.next(); - } else { - //todo! recovery? - errors.push(ParseError { - span: loc, - reason: ParseErrorReason::UnexpectedToken, - }); - return ParserReturns { - ast: ast::IfExpr { - cond: root_cond.into(), - loc: if_loc, - true_branch: (true_body.0, true_body.1.into()), - else_ifs, - else_branch: (Vec::new(), ast::Expr::Error.into()), - }, - loc: if_loc, - warnings, - errors, - }; - }; - } - let else_branch = match self.stream.clone().next() { - Some((Token::BeginBlock, _)) => { - let _ = self.stream.next(); - - let mut body = Vec::new(); - while self - .stream - .clone() - .skip_while(|(it, _)| it != &Token::Seq && it != &Token::EndBlock) - .next() - .map(|a| a.0 != Token::EndBlock && a.0 != Token::EoF) - .unwrap_or(false) - { - let stmnt = self.next_statement(); - warnings.extend(stmnt.warnings); - errors.extend(stmnt.errors); - body.push(stmnt.ast); - } - let ret = self.next_expr(); - warnings.extend(ret.warnings); - errors.extend(ret.errors); - let _ = self.stream.next(); - (body, ret.ast.into()) - } - _ => { - let ret = self.next_expr(); - warnings.extend(ret.warnings); - errors.extend(ret.errors); - (Vec::new(), ret.ast.into()) - } - }; - - ParserReturns { - ast: ast::IfExpr { - cond: root_cond.into(), - true_branch: (true_body.0, true_body.1.into()), - else_ifs, - else_branch, - loc: if_loc, - }, - loc: if_loc, - warnings, - errors, - } - } else { - if let Some((_, loc)) = self.stream.clone().next() { - errors.push(ParseError { - span: loc, - reason: ParseErrorReason::UnexpectedToken, - }); - } - // TODO! recover - ParserReturns { - ast: ast::IfExpr { - cond: root_cond.into(), - true_branch: (true_body.0, true_body.1.into()), - else_ifs: Vec::new(), - else_branch: (Vec::new(), Expr::Error.into()), - loc: if_loc, - }, - loc: if_loc, - warnings, - errors, - } - } +impl winnow::stream::Offset for StrippedParser<'_> { + fn offset_from(&self, other:&Self) ->usize { + self.src.offset_from(&other.src.checkpoint()) } +} - fn value(&mut self) -> ParserReturns { - if let Some((Token::Ident(ident), loc)) = self.stream.clone().next() { - let _ = self.stream.next(); - ParserReturns { - ast: ast::Expr::ValueRead(ident, loc), - loc, - warnings: Vec::new(), - errors: Vec::new(), - } - } else { - let loc = if let Some((_, loc)) = self.stream.peek() { - *loc - } else { - return ParserReturns { - ast: Expr::Error, - loc: (0, 0), - warnings: Vec::new(), - errors: vec![ParseError { - span: (0, 0), - reason: ParseErrorReason::UnexpectedEndOfFile, - }], - }; - }; - ParserReturns { - ast: Expr::Error, - loc: loc, - warnings: Vec::new(), - errors: vec![ParseError { - span: loc, - reason: ParseErrorReason::UnknownError, - }], - } - } +impl<'a> winnow::stream::Offset> for StrippedParser<'a> { + fn offset_from(&self, checkpoint:&StrippedParserCheckpoint<'a>) -> usize { + self.src.offset_from(&checkpoint.inner) } +} - fn function_call(&mut self) -> ParserReturns { - let mut errors = Vec::new(); - let mut warnings = Vec::new(); - if let Some((Token::Ident(ident), value_loc)) = self.stream.next() { - let mut values = Vec::<(ast::Expr, (usize, usize))>::new(); - while let Some(( - | Token::GroupOpen - | Token::Ident(_) - // | Token::Op(_) // TODO! this will need some special handling. ie for `foo bar >>> baz` should that be parsed as `(foo bar) >>> baz` or `foo (bar >>> baz)` - | Token::Integer(_,_) - | Token::FloatingPoint(_, _) - | Token::CharLiteral(_) - | Token::StringLiteral(_) - | Token::True - | Token::False - | Token::BracketOpen - ,_ - )) = self.stream.peek() { - match self.stream.peek().map(|(a,_)| a) { - Some(Token::Ident(_)) => { - let test = self.stream.clone().nth(1); - if let Some((Token::Op(_),_)) = test { - let ParserReturns { ast:expr, loc, warnings:expr_warnings, errors:expr_errors } =self.binary_op(); - values.push((expr,loc)); - warnings.extend(expr_warnings); - errors.extend(expr_errors); - } else { - let ParserReturns { ast:expr, loc, warnings:expr_warnings, errors:expr_errors } =self.value(); - values.push((expr,loc)); - warnings.extend(expr_warnings); - errors.extend(expr_errors); - } - } - Some(Token::GroupOpen | Token::BracketOpen) =>{ - let value = self.next_expr(); - errors.extend(value.errors); - warnings.extend(value.warnings); - values.push((value.ast,value.loc)) - }, - Some( - | Token::Integer(_,_) - | Token::FloatingPoint(_, _) - | Token::CharLiteral(_) - | Token::StringLiteral(_) - | Token::True - | Token::False - ) => { - let test = self.stream.clone().nth(1); - if let Some(( - | Token::Ident(_) - | Token::Integer(_,_) - | Token::FloatingPoint(_, _) - | Token::CharLiteral(_) - | Token::StringLiteral(_) - ,loc)) = test { - let ParserReturns { ast, loc:_, warnings:lit_warnings, errors:lit_errors, }= self.literal(); - warnings.extend(lit_warnings); - errors.extend(lit_errors); - values.push((ast,loc)) - } else if let Some((Token::Op(_),_)) = test { - let ParserReturns { ast:expr, loc, warnings:expr_warnings, errors:expr_errors } =self.binary_op(); - values.push((expr,loc)); - warnings.extend(expr_warnings); - errors.extend(expr_errors); - } else { - let ParserReturns { ast, loc:_, warnings:lit_warnings, errors:lit_errors, }= self.literal(); - warnings.extend(lit_warnings); - errors.extend(lit_errors); - values.push((ast,value_loc)) - } - }, - _ => unreachable!() - // TODO! add in operator case special handling - } - } - let (ast, _loc) = values.into_iter().fold( - ( - FnCall { - loc: value_loc, - value: ast::Expr::ValueRead(ident, value_loc).into(), - arg: None, - }, - value_loc, - ), - |(inner, loc), (next, next_loc)| { - if let FnCall { - value, arg: None, .. - } = inner - { - ( - FnCall { - loc, - value, - arg: Some(next.into()), - }, - next_loc, - ) - } else { - ( - FnCall { - loc, - value: Expr::FnCall(inner).into(), - arg: Some(next.into()), - }, - next_loc, - ) - } - }, - ); - ParserReturns { - ast, - loc: value_loc, - warnings, - errors, - } - } else { - errors.push(ParseError { - span: (0, 0), - reason: ParseErrorReason::UnknownError, - }); - ParserReturns { - ast: FnCall { - value: Expr::Error.into(), - arg: Some(Expr::Error.into()), - loc: (0, 0), - }, - loc: (0, 0), - warnings, - errors, - } - } +impl<'a,T> winnow::stream::Compare for StrippedParser<'a> +where &'a str : winnow::stream::Compare { + fn compare(&self, t: T) -> winnow::stream::CompareResult { + self.src.compare(t) } +} - fn struct_construct(&mut self) -> ParserReturns { - let mut warnings = Vec::new(); - let mut errors = Vec::new(); - let Some((_, loc)) = self.stream.clone().next() else { - unreachable!("ICE: somehow reached struct construction with no token?") - }; +impl<'a> winnow::stream::StreamIsPartial for StrippedParser<'a>{ + type PartialState = <&'a str as winnow::stream::StreamIsPartial>::PartialState; - let ty = self.collect_type(); - warnings.extend(ty.warnings); - errors.extend(ty.errors); - let (name, generics) = if let ResolvedType::User { name, generics, .. } = ty.ast { - (name, generics) - } else { - ("".to_string(), vec![types::ERROR]) - }; - let Some((Token::CurlOpen, loc)) = self.stream.next() else { - /* TODO? handle blocks? - EG: ``` - let x = Foo - { - y:0 - } - ``` - though idomatic would be the following or inline. - ``` - let x = Foo { - y:0 - } - ``` - */ - unreachable!("ICE: reached struct construction with no braces?") - }; - let mut fields = HashMap::new(); - while let Some((Token::Ident(_), _)) = self.stream.peek() { - let Some((Token::Ident(ident), loc)) = self.stream.next() else { - unreachable!() - }; - let Some((Token::Colon, _)) = self.stream.next() else { - todo!("handle infered assignment") - }; - let ParserReturns { - ast: expr, - loc: _, - warnings: expr_warnings, - errors: expr_errors, - } = self.next_expr(); - warnings.extend(expr_warnings); - errors.extend(expr_errors); - if fields.contains_key(&ident) { - let (_, loc): &(_, crate::Location) = &fields[&ident]; - errors.push(ParseError { - span: *loc, - reason: ParseErrorReason::DeclarationError, - }) - } else { - fields.insert(ident, (expr, loc)); - } - if let Some((Token::Comma, _)) = self.stream.peek() { - self.stream.next(); - } - } - let _: Vec<_> = self - .stream - .peeking_take_while(|(t, _)| matches!(t, Token::EndBlock)) - .collect(); - let Some((Token::CurlClose, _)) = self.stream.next() else { - errors.push(ParseError { - span: loc, - reason: ParseErrorReason::UnbalancedBraces, - }); - fields.insert("".to_string(), (Expr::Error, (0, 0))); - return ParserReturns { - ast: StructConstruction { - loc, - fields, - generics, - ident: "".to_string(), - }, - loc, - warnings, - errors, - }; - }; - ParserReturns { - ast: StructConstruction { - loc, - fields, - generics, - ident: name, - }, - loc, - warnings, - errors, - } + fn complete(&mut self) -> Self::PartialState { + self.src.complete() } - fn ret(&mut self) -> ParserReturns { - let (token, span) = self.stream.next().unwrap(); - if token == Token::Return { - let ParserReturns { - ast: expr, - loc: _, - warnings, - errors, - } = self.next_expr(); - ParserReturns { - ast: ast::Statement::Return(expr, span), - loc: span, - warnings, - errors, - } - } else { - ParserReturns { - ast: Statement::Error, - loc: span, - warnings: Vec::new(), - errors: vec![ParseError { - span, - reason: ParseErrorReason::UnknownError, - }], - } - } + fn restore_partial(&mut self, state: Self::PartialState) { + self.src.restore_partial(state) } - fn literal(&mut self) -> ParserReturns { - let (token, span) = self.stream.next().unwrap(); - match make_literal(token, span) { - Ok(lit) => ParserReturns { - ast: lit, - loc: span, - warnings: Vec::new(), - errors: Vec::new(), - }, - Err(e) => ParserReturns { - ast: Expr::Error, - loc: span, - warnings: Vec::new(), - errors: vec![e], - }, - } + fn is_partial_supported() -> bool { + as winnow::stream::StreamIsPartial>::is_partial_supported() } +} - fn ifstatement(&mut self) -> ParserReturns { - let Some((Token::If, if_loc)) = self.stream.next() else { - unreachable!() - }; - let ParserReturns { - ast: cond, - mut warnings, - mut errors, - loc: _, - } = self.next_expr(); - let cond = cond.into(); - if let Some((Token::Then, _)) = self.stream.peek() { - let _ = self.stream.next(); - } else { - let (token, loc) = self.stream.next().unwrap(); - println!( - "Expected then but got {:?} at line:{} col:{}", - token, loc.0, loc.1 - ); - errors.push(ParseError { - span: loc, - reason: ParseErrorReason::UnexpectedToken, - }); - //TODO? more recovery? - return ParserReturns { - ast: ast::IfBranching { - cond, - true_branch: vec![Statement::Error], - else_ifs: Vec::new(), - else_branch: Vec::new(), - loc: if_loc, - }, - loc: if_loc, - warnings, - errors, - }; - }; - let body = match self.stream.peek() { - Some((Token::BeginBlock, _)) => { - let block = self.collect_block(); - warnings.extend(block.warnings); - errors.extend(block.errors); - block.ast - } - _ => { - let stmnt = self.next_statement(); - warnings.extend(stmnt.warnings); - errors.extend(stmnt.errors); - vec![stmnt.ast] - } - }; +impl winnow::stream::AsBStr for StrippedParser<'_> { + fn as_bstr(&self) -> &[u8] { + self.src.as_bstr() + } +} - if let Some((Token::Else, _)) = self.stream.peek() { - let mut else_ifs = Vec::new(); - while let Some((Token::If, _)) = self.stream.clone().nth(1) { - let Some((Token::Else, _)) = self.stream.next() else { - unreachable!() - }; - let Some((Token::If, _loc)) = self.stream.next() else { - unreachable!() - }; +pub(crate) fn file(file_name:&str, src :&str) ->ast::ModuleDeclaration{ + let src = Stream { + input: Located::new(StrippedParser{ + src, + state:Default::default(), + }), + state: Default::default(), + }; - let ParserReturns { - ast: cond, - warnings: new_warnings, - errors: new_errors, - loc: _, - } = self.next_expr(); - warnings.extend(new_warnings); - errors.extend(new_errors); - let cond = cond.into(); - if let Some((Token::Then, _)) = self.stream.peek() { - let _ = self.stream.next(); - } else { - let (token, loc) = self.stream.next().unwrap(); - println!( - "Expected then but got {:?} at line:{} col:{}", - token, loc.0, loc.1 - ); - errors.push(ParseError { - span: loc, - reason: ParseErrorReason::UnexpectedToken, - }); - }; - let body = match self.stream.peek() { - Some((Token::BeginBlock, _)) => { - let block = self.collect_block(); - warnings.extend(block.warnings); - errors.extend(block.errors); - block.ast - } - _ => { - let stmnt = self.next_statement(); - warnings.extend(stmnt.warnings); - errors.extend(stmnt.errors); - vec![stmnt.ast] - } - }; - else_ifs.push((cond, body)); - } + let decls = combinator::delimited(ignore_blank_lines, top_level_block,(ascii::space0,ignore_blank_lines)).parse(src).unwrap(); - let else_branch = if let Some((Token::Else, _)) = self.stream.clone().next() { - let _ = self.stream.next(); + ast::ModuleDeclaration{ loc: None, name: file_name.into(), declarations: decls } +} - match self.stream.peek() { - Some((Token::BeginBlock, _)) => { - let block = self.collect_block(); - warnings.extend(block.warnings); - errors.extend(block.errors); - block.ast - } - _ => { - let stmnt = self.next_statement(); - warnings.extend(stmnt.warnings); - errors.extend(stmnt.errors); - vec![stmnt.ast] - } - } - } else { - Vec::new() - }; - ParserReturns { - ast: ast::IfBranching { - cond, - true_branch: body, - else_ifs, - else_branch, - loc: if_loc, - }, - loc: if_loc, - warnings, - errors, - } - } else { - ParserReturns { - ast: ast::IfBranching { - cond, - true_branch: body, - else_ifs: Vec::new(), - else_branch: Vec::new(), - loc: if_loc, - }, - loc: if_loc, - warnings, - errors, - } - } - } +fn parens< I, O, E>( + parser: impl Parser +) -> impl Parser +where I : winnow::stream::Stream + winnow::stream::StreamIsPartial + winnow::stream::Compare, + E : ParserError +{ + combinator::delimited( + (ascii::space0,'(',ascii::space0), + parser, + (ascii::space0,')'), + + ) +} +// (name,weight,right associative) +const PRECIDENCE: [(&'static str, usize, bool); 12] = [ + (".", usize::MAX, true), + ("**", 7, false), + ("*", 5, true), + ("/", 5, true), + ("+", 4, true), + ("-", 4, true), + ("<", 2, true), + ("<=", 2, true), + (">", 2, true), + (">=", 2, true), + ("&&", 1, true), + ("||", 1, true), +]; - pub(crate) fn collect_type(&mut self) -> ParserReturns { - let mut warnings = Vec::new(); - let mut errors = Vec::new(); - let ty = self.stream.next(); - match ty { - Some((Token::Ident(ty), loc)) => { - let mut generic_args = Vec::new(); - if self.stream.peek().map(|(a, _)| a) == Some(&Token::Op("<".to_string())) { - self.stream.next(); - while { - let ty = self.collect_type(); - warnings.extend(ty.warnings); - errors.extend(ty.errors); - generic_args.push(ty.ast); - #[cfg(debug_assertions)] - let _peek = self.stream.peek(); - if self.stream.peek().map(|(a, _)| a) == Some(&Token::Comma) { - let _ = self.stream.next(); - true - } else { - false - } - } {} - if !generic_args.is_empty() { - let mut should_pop = false; - if let Some((Token::Op(s), _)) = self.stream.peek_mut() { - if s.chars().all_equal_value() == Ok('>') { - s.pop(); - if s.len() == 0 { - should_pop = true; - } - } else { - errors.push(ParseError { - span: loc, - reason: ParseErrorReason::UnbalancedBraces, - }); - return ParserReturns { - ast: types::ERROR, - loc, - warnings, - errors, - }; - } - } - if should_pop { - let _ = self.stream.next(); - } - } - } - if let Some((Token::Arrow, fn_loc)) = self.stream.clone().next() { - self.stream.next(); - let result = self.collect_type(); - let ty = type_from_string(&ty, generic_args, loc); - warnings.extend(result.warnings); - errors.extend(result.errors); - ParserReturns { - ast: ResolvedType::Function { - arg: ty.into(), - returns: result.ast.into(), - loc: fn_loc, - }, - loc: fn_loc, - warnings, - errors, - } - } else { - let ty = type_from_string(&ty, generic_args, loc); - ParserReturns { - ast: ty, - loc, - warnings, - errors, - } - } - } - Some((Token::GroupOpen, span)) => { - if let Some((Token::GroupClose, _)) = self.stream.peek() { - self.stream.next(); - return if let Some((Token::Arrow, arr_loc)) = self.stream.clone().next() { - self.stream.next(); - let returns = self.collect_type(); - warnings.extend(returns.warnings); - errors.extend(returns.errors); - ParserReturns { - ast: ResolvedType::Function { - arg: types::UNIT.into(), - returns: returns.ast.into(), - loc: arr_loc, - }, - loc: span, - warnings, - errors, - } - } else { - ParserReturns { - ast: types::UNIT, - loc: span, - warnings, - errors, - } - }; - } - let ty = self.collect_type(); - warnings.extend(ty.warnings); - errors.extend(ty.errors); - let loc = ty.loc; - let mut tys = vec![ty.ast]; - loop { - if let Some((Token::Comma, _)) = self.stream.clone().next() { - let _ = self.stream.next(); - let ty = self.collect_type(); - warnings.extend(ty.warnings); - errors.extend(ty.errors); - tys.push(ty.ast); - match self.stream.clone().next() { - Some((Token::GroupClose, _)) => { - break; - } - Some((Token::Comma, _)) => continue, - _ => { - errors.push(ParseError { - span: span, - reason: ParseErrorReason::TypeError, - }); - return ParserReturns { - ast: types::ERROR, - loc: (0, 0), - warnings, - errors, - }; - } - } - } else { - break; - //TODO! error reporting? - } - } - let ty = if tys.len() == 1 { - tys.pop().unwrap() - } else { - ResolvedType::Tuple { - underlining: tys, - loc: span, - } - }; - if let Some((Token::GroupClose, _)) = self.stream.clone().next() { - let _ = self.stream.next(); - } else { - errors.push(ParseError { - span, - reason: ParseErrorReason::UnbalancedBraces, - }); - } - if let Some((Token::Arrow, arr_loc)) = self.stream.clone().next() { - self.stream.next(); - let result = self.collect_type(); - warnings.extend(result.warnings); - errors.extend(result.errors); - ParserReturns { - ast: ResolvedType::Function { - arg: ty.into(), - returns: result.ast.into(), - loc: arr_loc, - }, - loc: arr_loc, - warnings, - errors, - } - } else { - ParserReturns { - ast: ty, - loc, - warnings, - errors, - } - } - } - Some((Token::BracketOpen, loc)) => { - let ty = self.collect_type(); - warnings.extend(ty.warnings); - errors.extend(ty.errors); - let ty = ty.ast; - match self.stream.clone().next() { - Some((Token::Seq, _)) => { - let _ = self.stream.next(); - match self.stream.clone().next() { - Some((Token::Integer(false, _), _)) => { - let Some((Token::Integer(_, value), _)) = self.stream.next() else { - unreachable!() - }; - match self.stream.peek() { - Some((Token::BracketClose, _)) => { - let _ = self.stream.next(); - ParserReturns { - ast: ResolvedType::Array { - underlining: ty.into(), - size: value.parse().unwrap(), - }, - loc, - warnings, - errors, - } - } - Some((t, loc)) => { - println!( - "unexpected token:{t:?} at line:{}, col:{}", - loc.0, loc.1 - ); - errors.push(ParseError { - span: *loc, - reason: ParseErrorReason::UnbalancedBraces, - }); - ParserReturns { - ast: types::ERROR, - loc: *loc, - warnings, - errors, - } - } - None => { - unreachable!("how did this happen. this is an ice please report it."); - } - } - } - Some((t, loc)) => { - println!("unexpected token:{t:?} at line:{}, col:{}", loc.0, loc.1); - errors.push(ParseError { - span: loc, - reason: ParseErrorReason::UnbalancedBraces, - }); - ParserReturns { - ast: types::ERROR, - loc, - warnings, - errors, - } - } - None => { - unreachable!( - "how did this happen. this is an ice please report it." - ); - } - } - } - Some((Token::BracketClose, _)) => { - let _ = self.stream.next(); - ParserReturns { - ast: ResolvedType::Slice { - underlining: ty.into(), - }, - loc, - warnings, - errors, - } - } - Some((t, loc)) => { - println!("unexpected token:{t:?} at line:{}, col:{}", loc.0, loc.1); - errors.push(ParseError { - span: loc, - reason: ParseErrorReason::UnbalancedBraces, - }); - ParserReturns { - ast: types::ERROR, - loc, - warnings, - errors, - } - } - None => { - unreachable!("how did this happen. this is an ICE please report it."); - } - } - } - Some((_, span)) => { - errors.push(ParseError { - span, - reason: ParseErrorReason::TypeError, - }); - ParserReturns { - ast: types::ERROR, - loc: span, - warnings, - errors, - } - } - None => { - errors.push(ParseError { - span: (0, 0), - reason: ParseErrorReason::TypeError, - }); - ParserReturns { - ast: types::ERROR, - loc: (0, 0), - warnings, - errors, - } - } +enum ShuntingYardOptions { + Expr(ast::Expr), + Op((String, crate::Location)), +} + +fn expect_line(input : &mut Stream<'_>) -> PResult<()> { + combinator::trace("expect line",|input : &mut Stream<'_>| { + + if input.state.just_consumed_line { + return Ok(()); } - } - #[allow(unused)] - fn pipe(&mut self) -> Result { - todo!("pipes") - } - #[allow(unused)] - /// will probably remove as it can easily be defined in lang? - fn compose(&mut self) -> Result { - todo!("compose") - } + let _ = ascii::space0(input)?; + let _ = ascii::line_ending(input)?; + input.state.just_consumed_line = true; + Ok(()) + }).parse_next(input) +} - fn abi(&mut self) -> ParserReturns> { - match self.stream.clone().next() { - Some((Token::Extern, loc)) => { - let _ = self.stream.next(); - let mut errors = Vec::new(); - let abi = if let Some((Token::StringLiteral(_), _)) = self.stream.clone().next() { - let Some((Token::StringLiteral(name), _)) = self.stream.next() else { - unreachable!() - }; - name - } else { - errors.push(ParseError { - span: loc, - reason: ParseErrorReason::UnexpectedToken, - }); - "".to_string() - }; - ParserReturns { - ast: Some(ast::Abi { - loc, - identifier: abi, - }), - loc, - warnings: Vec::new(), - errors, - } - } - _ => ParserReturns { - ast: None, - loc: (0, 0), - warnings: Vec::new(), - errors: Vec::new(), - }, +fn reset_line(input:&mut Stream<'_>) -> PResult<()> { + combinator::trace("reset line",|input : &mut Stream<'_>| { + input.state.just_consumed_line=false; + Ok(()) + }).parse_next(input) +} + +fn ignore_blank_lines(input: &mut Stream<'_>) -> PResult<()> { + combinator::trace("blank lines",|input : &mut Stream<'_>| { + + let mut checkpoint = input.checkpoint(); + let _ = ascii::space0(input)?; + while let Some(_) = combinator::opt(ascii::line_ending).parse_next(input)? { + checkpoint = input.checkpoint(); + ascii::space0(input)?; } + input.reset(&checkpoint); + Ok(()) + }).parse_next(input) +} + + +fn char_lit(input: &mut Stream<'_>) -> PResult { + combinator::delimited( + '\'', + escaper('\''), + combinator::preceded(combinator::not('\\'), '\''), + ) + .parse_next(input) +} + +fn string_lit(input: &mut Stream<'_>) -> PResult { + combinator::trace( + "string_lit", + combinator::delimited( + '"', + escaper('"'), + /* combinator::preceded(combinator::not('\\'), */ + combinator::cut_err('"') //) + .context(winnow::error::StrContext::Label("string terminator".into())), + ), + ) + .parse_next(input) +} + +fn escaper<'a, E: ParserError>>(surronding: char) -> impl Parser, String, E> { + ascii::escaped_transform::<_, _, _, _, String>( + token::take_till(1.., ['\n', '\r', '\\', surronding]), + '\\', + combinator::alt(( + "n".value("\n"), + //todo ocatal and hex escapes. + "t".value("\t"), + "\\".value("\\"), + "\"".value("\""), + "\'".value("\'"), + "r".value("\r"), //don't expect this to be common. + //more escapes? + )), + + ) +} + + +fn simple_ident<'input>(input: &mut Stream<'input>) -> PResult> { + token::take_while(1.., |c: char| c.is_alphanumeric() || c == '_') + .verify(|s: &str| !s.starts_with(char::is_numeric)) + .context(winnow::error::StrContext::Expected( + "indentifers can't start with numbers".into(), + )) + .verify(|s| !KEYWORDS.contains(s)) + .context(winnow::error::StrContext::Expected( + "identifiers can't be a keyword".into(), + )) + .map(Into::into) + .parse_next(input) +} + +fn ident(input:&mut Stream<'_>) -> PResult { + combinator::separated_foldl1( + simple_ident.map(Into::into), + (ascii::space0,"::",ascii::space0), + |left,_,right| format!("{left}::{right}") + ).parse_next(input) +} + +fn top_level_block(input: &mut Stream<'_>) -> PResult> { + ignore_blank_lines(input)?; + let old_prefix = input.state.prefix.clone(); + let checkpoint = input.checkpoint(); + let new_prefix = ascii::space0(input)?; + input.reset(&checkpoint); + if !new_prefix.starts_with(old_prefix.as_ref()) { + Ok(Vec::new()) + } else { + + input.state.prefix = new_prefix.into(); + let result = combinator::repeat(0..,combinator::preceded((ignore_blank_lines,ascii::space0.verify(|it:&str| it == new_prefix)), top_level_decl)).parse_next(input); + input.state.prefix = old_prefix; + result } +} - fn declaration(&mut self) -> ParserReturns { - let ParserReturns { - ast: abi, - loc: extern_loc, - mut warnings, - mut errors, - } = self.abi(); - let ParserReturns { - ast: generics, - loc: for_loc, - warnings: for_warnings, - errors: for_errors, - } = self.collect_generics(); - warnings.extend(for_warnings); - errors.extend(for_errors); - if abi.is_some() && generics.is_some() { - errors.push(ParseError { - span: for_loc, - reason: ParseErrorReason::DeclarationError, - }); - } - let next = self.stream.clone().next(); - match next { - Some((Token::Let, _)) => self.fn_declaration(abi, generics), - Some((Token::Seq, _)) => { - let _ = self.stream.next(); - self.declaration() - } - _ => unimplemented!(), + + + +fn top_level_decl(input: &mut Stream<'_>) -> PResult { + + + let result = combinator::alt(( + mod_decl.map(ast::TopLevelDeclaration::Mod), + top_level_value.map(ast::TopLevelDeclaration::Value), + type_decl.map(ast::TopLevelDeclaration::TypeDefinition), + )) + .parse_next(input)?; + + Ok(result) +} + + +fn type_decl(input: &mut Stream<'_>) -> PResult { + combinator::trace("type declaration", |input: &mut Stream<'_>| { + let generics = combinator::opt(generics).parse_next(input)?; + + combinator::alt(( + combinator::preceded( + (ascii::space0,"type",ascii::space1), + combinator::cut_err(struct_or_alias_def(generics.clone())), + ), + enum_decl(generics).map(ast::TypeDefinition::Enum), + )) + .parse_next(input) + }) + .map(|mut decl| { + decl.bind_generics(); + decl + }) + .parse_next(input) +} + +const EQ_OP : Token<'static> = Token::Op("="); + +fn enum_decl<'input>( + generics: Option, +) -> impl Parser, ast::EnumDeclaration, ContextError> { + combinator::trace("enum declaration", move |input: &mut Stream<'_>| { + let (ident, loc) = + combinator::preceded( + (ascii::space0,"enum",ascii::space1), + simple_ident.with_span()) + .parse_next(input)?; + let values = combinator::preceded( + (ascii::space0,'=',ascii::space0), + combinator::repeat( + 1.., + combinator::preceded( + (ascii::space0,'|', ascii::space0), + |input: &mut Stream<'_>| { + let (ident, loc) = simple_ident.with_span().parse_next(input)?; + let _ = ascii::space0(input)?; + let loc = (loc.start, loc.end); + let struct_ident = ident.clone(); + let tuple_ident = ident.clone(); + combinator::alt(( + struct_body.map(move |fields| ast::EnumVariant::Struct { + ident: struct_ident.clone().into(), + fields, + loc, + }), + type_.map(move |ty| ast::EnumVariant::Tuple { + ident: tuple_ident.clone().into(), + ty, + loc, + }), + combinator::empty.value(ast::EnumVariant::Unit { + ident: ident.into(), + loc, + }), + )) + .parse_next(input) + }, + ), + ), + ) + .parse_next(input)?; + Ok(ast::EnumDeclaration { + ident: ident.into(), + generics: generics.clone(), + values, + loc: (loc.start, loc.end), + }) + }) +} + + + +fn struct_body(input: &mut Stream<'_>) -> PResult> { + combinator::delimited( + (ascii::space0,'{',ascii::multispace0), + combinator::separated( + 0.., + combinator::separated_pair( + simple_ident.with_span(), + (ascii::multispace0,':',ascii::multispace0), + type_ + ).map(|((ident, loc), ty)| ast::FieldDecl { + name: ident.into(), + ty, + loc: (loc.start, loc.end), + }), + (ascii::multispace0, ',',ascii::multispace0), + ), + (ascii::multispace0,combinator::opt((',',ascii::multispace0)),'}'), + ) + .parse_next(input) +} + +fn struct_or_alias_def<'input>( + generics: Option, +) -> impl Parser, ast::TypeDefinition, ContextError> { + combinator::trace( + "struct or alias", + move |input: &mut Stream<'_>| -> PResult { + let (ident, loc) = simple_ident.with_span().parse_next(input)?; + + let _ = (ascii::space0,'=',ascii::space0).void().parse_next(input)?; + let result = combinator::alt(( + combinator::trace("struct", struct_body).map(|fields| { + ast::TypeDefinition::Struct(ast::StructDefinition { + ident: ident.clone().into(), + generics: generics.clone(), + values: fields, + loc: (loc.start, loc.end), + }) + }), + combinator::trace("alias", type_) + .verify(|_| generics.is_none()) + .context(winnow::error::StrContext::Label( + "generic aliases are not yet implemented", + )) + .map(|ty| ast::TypeDefinition::Alias(ident.clone().into(), ty)), + )) + .parse_next(input)?; + Ok(result) + }, + ) +} + + +fn op<'input>(input: &mut Stream<'input>) -> PResult> { + token::take_while( + 1.., + [ + '|', '>', '<', '!', '@', '=', '&', '+', '-', '\\', '/', '*', '^', '.', + ], + ) + .map(Into::into) + .parse_next(input) +} + +fn mod_decl<'input>(input: &mut Stream<'input>) -> PResult { + //TODO! + combinator::fail.context(StrContext::Label("submoules not yet supported")).parse_next(input) +} + +fn unit(input:&mut Stream<'_>) -> PResult<()> { + ( + '(', + ascii::space0, + ')' + ).void() + .parse_next(input) +} + +fn block(input: &mut Stream) -> PResult { +combinator::trace("block", |input: &mut Stream<'_>|{ + // let _ = (ascii::space0,ascii::line_ending).void().parse_next(input)?; + let old_prefix = input.state.prefix.clone(); + let checkpoint= input.checkpoint(); + let new_prefix = ascii::space0(input)?; + if !new_prefix.starts_with(old_prefix.as_ref()) { + return Err(ErrMode::Cut(ContextError::new().add_context(input, &checkpoint, StrContext::Expected(winnow::error::StrContextValue::Description("expected the body to be an ident deeper"))))) } + input.reset(&checkpoint); + input.state.prefix=new_prefix.into(); + let result = ( + combinator::repeat( + 0.., + combinator::preceded( + ignore_blank_lines, + combinator::delimited( + combinator::trace("prefix",(new_prefix,reset_line)), + combinator::trace(format!("block statement prefix {:?}",new_prefix),combinator::repeat(1..,statement)), + combinator::trace("ending",combinator::alt((expect_line,(ascii::space0,combinator::eof).void()))) + ) + ) + ).map(|statements : Vec>| { + statements.into_iter().flat_map(Vec::into_iter).collect() + }) + , + combinator::opt(combinator::preceded((ignore_blank_lines,new_prefix,reset_line),expr).map(Into::into)) + ).map(|(statements,implicit_ret)| ast::Block { statements, implicit_ret }) + .parse_next(input); + input.state.prefix=old_prefix; + result } +).parse_next(input) +} - fn type_decl( - &mut self, - generics: Option, - ) -> ParserReturns { - let mut warnings = Vec::new(); - let mut errors = Vec::new(); - let Some((t, loc)) = self.stream.next() else { - unreachable!() - }; - match t { - Token::Type => { - let (ident, loc) = match self.stream.next() { - Some((Token::Ident(ident), loc)) => (ident, loc), - _ => { - // todo recover? - errors.push(ParseError { - span: loc, - reason: ParseErrorReason::DeclarationError, - }); - return ParserReturns { - ast: TypeDefinition::Alias("".to_string(), types::ERROR), - loc, - warnings, - errors, - }; - } - }; - let Some((Token::Op(op), _)) = self.stream.next() else { - errors.push(ParseError { - span: loc, - reason: ParseErrorReason::DeclarationError, - }); - return ParserReturns { - ast: TypeDefinition::Alias("".to_string(), types::ERROR), - loc, - warnings, - errors, - }; - }; - if op != "=" { - errors.push(ParseError { - span: loc, - reason: ParseErrorReason::DeclarationError, - }); - return ParserReturns { - ast: TypeDefinition::Alias("".to_string(), types::ERROR), - loc, - warnings, - errors, - }; - } - match self.stream.peek() { - Some((Token::Ident(_), _)) => { - let ty = self.collect_type(); - warnings.extend(ty.warnings); - errors.extend(ty.errors); - ParserReturns { - ast: ast::TypeDefinition::Alias(ident, ty.ast), - loc, - warnings, - errors, - } - } - Some((Token::CurlOpen, _)) => { - let strct = self.struct_declaration(ident, generics, loc); - warnings.extend(strct.warnings); - errors.extend(strct.errors); - ParserReturns { - ast: ast::TypeDefinition::Struct(strct.ast), - loc, - warnings, - errors, - } - } - // Some((Token::Op(op), _)) if op == "|" => Ok(ast::TypeDefinition::Enum( - // ident, - // self.enum_declaration(generics)?, - // loc, - // )), - _ => { - errors.push(ParseError { - span: loc, - reason: ParseErrorReason::DeclarationError, - }); - ParserReturns { - ast: ast::TypeDefinition::Alias("".to_string(), types::ERROR), - loc, - warnings, - errors, - } - } +fn comma(input:&mut Stream<'_>) -> PResult<()> { + (ascii::space0,',',ascii::space0).void().parse_next(input) +} + +fn type_<'input>(input: &mut Stream<'input>) -> PResult { + let result = combinator::trace( + "type", + combinator::alt(( + "int8".value(types::INT8), + "int16".value(types::INT16), + "int32".value(types::INT32), + "int64".value(types::INT64), + "float32".value(types::FLOAT32), + "float64".value(types::FLOAT64), + unit.value(types::UNIT), + "str".value(types::STR), + "char".value(types::CHAR), + "bool".value(types::BOOL), + (ident,combinator::opt(combinator::delimited((ascii::space0,'<',ascii::space0), combinator::separated(0.., type_, comma),(ascii::space0,'>',ascii::space0)))).with_span().map(|((ident,generics),span)| { + types::ResolvedType::User{ + name: ident.into(), + generics:generics.unwrap_or_default(), + loc: (span.start,span.end), } - } - Token::Enum => { - let enum_ = self.enum_declaration(generics); - ParserReturns { - ast: ast::TypeDefinition::Enum(enum_.ast), - loc, - warnings: enum_.warnings, - errors: enum_.errors, + }), + //array + combinator::delimited( + (ascii::space0, '[', ascii::space0), + combinator::separated_pair( + type_, + (ascii::space0, ';', ascii::space0), + ascii::dec_uint, + ), + (ascii::space0, ']', ascii::space0), + ) + .map(|(underlining, count)| types::ResolvedType::Array { + underlining: underlining.into(), + size: count, + }), + combinator::delimited( + (ascii::space0, '[', ascii::space0), + type_, + (ascii::space0, ']', ascii::space0), + ) + .map(|underlining| types::ResolvedType::Slice { + underlining: underlining.into(), + }), + combinator::preceded((ascii::space0, '&', ascii::space0), type_).map(|underlining| { + types::ResolvedType::Ref { + underlining: underlining.into(), } - } - _ => unreachable!(), - } + }), + parens(combinator::separated( + 2.., + type_, + (ascii::space0, ',', ascii::space0), + )) + .with_span() + .map(|(underlining, loc)| types::ResolvedType::Tuple { + underlining, + loc: (loc.start, loc.end), + }), + parens(type_), + )), + ) + .parse_next(input)?; + if let Some((loc, ret)) = combinator::trace( + "type (function)", + combinator::opt(( + combinator::delimited(ascii::space0, "->".span(), ascii::space0), + type_, + )), + ) + .parse_next(input)? + { + Ok(types::ResolvedType::Function { + arg: result.into(), + returns: ret.into(), + loc: (loc.start, loc.end), + }) + } else { + Ok(result) } +} - #[allow(unused)] - fn enum_declaration( - &mut self, - generics: Option, - ) -> ParserReturns { - let mut errors = Vec::new(); - let mut warnings = Vec::new(); - let (ident, loc) = match self.stream.clone().next() { - Some((Token::Ident(_), _)) => { - let Some((Token::Ident(ident), loc)) = self.stream.next() else { - unreachable!() - }; - (ident, loc) - } - Some((Token::EoF, loc)) => { - errors.push(ParseError { - span: loc, - reason: ParseErrorReason::UnexpectedEndOfFile, - }); - return ParserReturns { - ast: ast::EnumDeclaration { - ident: "".to_string(), - generics, - values: Vec::new(), - loc: (0, 0), - }, - loc: (0, 0), - warnings, - errors, - }; - } - Some((_, loc)) => { - let _ = self - .stream - .peeking_take_while(|(token, _)| match token { - Token::Op(op) if op == "=" || op == "|" => false, - _ => true, - }) - .collect_vec(); - errors.push(ParseError { - span: loc, - reason: ParseErrorReason::UnexpectedToken, - }); - ("".to_string(), loc) - } - None => { - errors.push(ParseError { - span: (0, 0), - reason: ParseErrorReason::UnexpectedEndOfFile, - }); - return ParserReturns { - ast: ast::EnumDeclaration { - ident: "".to_string(), - generics, - values: Vec::new(), - loc: (0, 0), - }, - loc: (0, 0), - warnings, - errors, - }; - } - }; - let op = match self.stream.next() { - Some((Token::Op(op), _)) => op, - _ => { - //TODO! progress next_toplevel valid point. - errors.push(ParseError { - span: loc, - reason: ParseErrorReason::DeclarationError, - }); - return ParserReturns { - ast: ast::EnumDeclaration { - ident, - generics, - values: vec![ast::EnumVariant::Tuple { - ident: "".to_string(), - ty: types::ERROR, - loc: (0, 0), - }], - loc, - }, - loc, - warnings, - errors, - }; - } - }; - - if op != "=" { - //TODO! progress next_toplevel until valid point. - errors.push(ParseError { - span: loc, - reason: ParseErrorReason::DeclarationError, - }); - return ParserReturns { - ast: ast::EnumDeclaration { - ident, - generics, - values: vec![ast::EnumVariant::Tuple { - ident: "".to_string(), - ty: types::ERROR, - loc: (0, 0), - }], - loc, - }, +fn arg<'input>(input: &mut Stream<'input>) -> PResult { + let apply_ty = combinator::delimited( + ('(', ascii::space0), + combinator::separated_pair(arg, (ascii::space0, ':', ascii::space0), type_), + (ascii::space0, ')'), + ) + .map(|(mut arg, real_ty)| { + match &mut arg { + ast::ArgDeclaration::Simple { ty, .. } + | ast::ArgDeclaration::DestructureTuple(_, ty, _) + | ast::ArgDeclaration::Discard { ty, .. } + | ast::ArgDeclaration::Unit { ty, .. } => { + ty.replace(real_ty); + } + ast::ArgDeclaration::DestructureStruct { loc, - warnings, - errors, - }; + struct_ident, + fields, + renamed_fields, + } => todo!("not a common case. (StructType {{ ... }} : StructType)"), } - let mut values = Vec::new(); - while let Some((Token::Op(op), _)) = self.stream.peek() { - if op == "|" { - let _ = self.stream.next(); - let (ident, variant_loc) = match self.stream.clone().next() { - Some((Token::Ident(_), _)) => { - let Some((Token::Ident(ident), loc)) = self.stream.next() else { - unreachable!() - }; - (ident, loc) - } - Some((Token::EoF, loc)) => { - errors.push(ParseError { - span: loc, - reason: ParseErrorReason::UnexpectedEndOfFile, - }); - return ParserReturns { - ast: ast::EnumDeclaration { - ident, - generics, - values: vec![ast::EnumVariant::Tuple { - ident: "".to_string(), - ty: types::ERROR, - loc: (0, 0), - }], - loc, - }, - loc, - warnings, - errors, - }; - } - Some((_, loc)) => { - let _ = self - .stream - .peeking_take_while(|(token, _)| match token { - Token::Op(op) if op == "=" || op == "|" => false, - _ => true, - }) - .collect_vec(); - errors.push(ParseError { - span: loc, - reason: ParseErrorReason::UnexpectedToken, - }); - ("".to_string(), loc) - } - None => { - errors.push(ParseError { - span: (0, 0), - reason: ParseErrorReason::UnexpectedEndOfFile, - }); - return ParserReturns { - ast: ast::EnumDeclaration { - ident, - generics, - values: vec![ast::EnumVariant::Tuple { - ident: "".to_string(), - ty: types::ERROR, - loc: (0, 0), - }], - loc, - }, - loc, - warnings, - errors, - }; - } - }; - match self.stream.peek() { - Some((Token::CurlOpen, _)) => { - let fields = self.struct_declaration("".to_string(), generics.clone(), loc); - warnings.extend(fields.warnings); - errors.extend(fields.errors); - values.push(ast::EnumVariant::Struct { - ident, - fields: fields.ast.values, - loc: variant_loc, - }); - } - Some((Token::Op(op), _)) if op == "|" => { - values.push(ast::EnumVariant::Unit { - ident, - loc: variant_loc, - }); - } - Some((Token::Ident(_) | Token::BracketOpen | Token::GroupOpen, _)) => { - let ty = self.collect_type(); - warnings.extend(ty.warnings); - errors.extend(ty.errors); - let ty = ty.ast; - let ty = if let Some(generics) = &generics { - generics - .decls - .iter() - .map(|(_, name)| name) - .fold(ty, |accum, name| accum.replace_user_with_generic(name)) - } else { - ty - }; - values.push(ast::EnumVariant::Tuple { - ident, - ty, - loc: variant_loc, - }); - } - _ => { - values.push(ast::EnumVariant::Unit { - ident, - loc: variant_loc, - }); - break; - } - } - } else { - break; - } - } - ParserReturns { - ast: ast::EnumDeclaration { - ident, - generics, - values, - loc, - }, - loc, - warnings, - errors, - } - } - - fn struct_declaration( - &mut self, - ident: String, - generics: Option, - loc: crate::Location, - ) -> ParserReturns { - let Some((Token::CurlOpen, _)) = self.stream.next() else { - unreachable!() - }; - while let Some((Token::BeginBlock, _)) = self.stream.clone().next() { - self.stream.next(); - } - let mut errors = Vec::new(); - #[allow(unused_mut)] - let mut warnings = Vec::new(); - let mut fields = Vec::::new(); - while let Some((Token::Ident(_), _)) = self.stream.clone().next() { - let Some((Token::Ident(name), loc)) = self.stream.next() else { - unreachable!(); - }; - let Some((Token::Colon, _)) = self.stream.next() else { - errors.push(ParseError { - span: (0, 10000), - reason: ParseErrorReason::DeclarationError, - }); - fields.push(FieldDecl { - name, - ty: ResolvedType::Error, - loc, - }); - let ts = self - .stream - .clone() - .take_while(|(it, _)| match it { - Token::Comma | Token::CurlClose | Token::EndBlock => false, - _ => true, - }) - .collect_vec(); - for _ in ts { - let _ = self.stream.next(); - } - continue; - }; - let ty = self.collect_type(); - warnings.extend(ty.warnings); - errors.extend(ty.errors); - let ty = ty.ast; - let ty = if let Some(generics) = &generics { - generics - .decls - .iter() - .map(|(_, it)| it) - .fold(ty, |result, it| result.replace_user_with_generic(it)) - } else { - ty - }; - if let Some((Token::Comma, _)) = self.stream.clone().next() { - self.stream.next(); - } else { - if let Some((Token::Ident(_), loc)) = self.stream.clone().next() { - println!("expected comma at line:{},col:{}", loc.0, loc.1); - while let Some((token, _)) = self.stream.clone().next() { - match token { - Token::CurlClose => { - self.stream.next(); - break; - } - _ => { - self.stream.next(); - } - } - } - errors.push(ParseError { - span: loc, - reason: ParseErrorReason::DeclarationError, - }); - } - } - while let Some((Token::EndBlock, _)) = self.stream.clone().next() { - self.stream.next(); - } - fields.push(ast::FieldDecl { name, ty, loc }); - } - while let Some((Token::EndBlock | Token::Comma, _)) = self.stream.clone().next() { - self.stream.next(); - } - let Some((Token::CurlClose, _)) = self.stream.next() else { - errors.push(ParseError { - span: (0, 11111), - reason: ParseErrorReason::DeclarationError, - }); - return ParserReturns { - ast: StructDefinition { - ident, - generics, - values: fields, - loc, - }, - loc, - warnings, - errors, - }; - }; - ParserReturns { - ast: StructDefinition { - ident, - generics, - values: fields, - loc, - }, - loc, - warnings, - errors, - } - } - - fn collect_generics(&mut self) -> ParserReturns> { - #[allow(unused_mut)] - let mut warnings = Vec::new(); - let mut errors = Vec::new(); - let generics = if let Some((Token::For, _)) = self.stream.clone().next() { - let Some((_, for_loc)) = self.stream.next() else { - unreachable!() - }; - match self.stream.next() { - Some((Token::Op(op), _)) if op == "<" => { - let mut out = self - .stream - .clone() - .filter(|(token, _)| &Token::Comma != token) - .take_while(|(token, _)| &Token::Op(">".to_string()) != token) - .collect_vec(); - // TODO should probably fold next_toplevel ensure that it is comma seperated. - let first_span = out.first().unwrap().1; - let num = out.len(); - out.dedup_by_key(|(it, _)| it.clone()); - if out.len() == num { - Some(ast::GenericsDecl { - for_loc, - decls: out - .into_iter() - .filter_map(|(t, loc)| { - let Token::Ident(name) = t else { return None }; - Some((loc, name)) - }) - .collect(), - }) - } else { - errors.push(ParseError { - span: first_span, - reason: ParseErrorReason::DeclarationError, - }); - return ParserReturns { - ast: None, - loc: first_span, - warnings, - errors, - }; - } - } - _ => { - errors.push(ParseError { - span: for_loc, - reason: ParseErrorReason::DeclarationError, - }); - return ParserReturns { - ast: None, - loc: for_loc, - warnings, - errors, - }; - } - } - } else { - None - }; - if generics.is_some() { - while let Some((token, _)) = self.stream.clone().next() { - match token { - Token::Op(op) if op == ">" => { - self.stream.next(); - break; - } - _ => { - self.stream.next(); - } - } - } - } - ParserReturns { - loc: generics.as_ref().map(|it| it.for_loc).unwrap_or_default(), - ast: generics, - warnings, - errors, - } - } - - fn parse_arg(&mut self) -> ParserReturns { - #[allow(unused_mut)] - let mut warnings = Vec::new(); - let mut errors = Vec::new(); - match self.stream.clone().next() { - Some((Token::GroupOpen, _)) => { - //( - let Some((Token::GroupOpen, open_loc)) = self.stream.next() else { - unreachable!() - }; - match self.stream.clone().next() { - Some((Token::GroupClose, _)) => { - //() - let _ = self.stream.next(); // ) - let ty = if let Some((Token::Colon, _)) = self.stream.clone().next() { - let _ = self.stream.next(); // : - let ty = self.collect_type(); - warnings.extend(ty.warnings); - errors.extend(ty.errors); - // will error at type checking/inference phase if not a unit type. - Some(ty.ast) - } else { - None - }; - ParserReturns { - ast: ArgDeclaration::Unit { loc: open_loc, ty }, - loc: open_loc, - warnings, - errors, - } - } - Some((Token::Ident(_), _)) => { - // ( - let Some((Token::Ident(name), loc)) = self.stream.next() else { - unreachable!() - }; - match self.stream.clone().next() { - Some((Token::Colon, _)) => { - //(: - let _ = self.stream.next(); // : - let ty = self.collect_type(); - warnings.extend(ty.warnings); - errors.extend(ty.errors); - let ty = ty.ast; - match self.stream.clone().next() { - Some((Token::GroupClose, _)) => { - let _ = self.stream.next(); - } - Some((_, loc)) => { - errors.push(ParseError { - span: loc, - reason: ParseErrorReason::UnbalancedBraces, - }); - } - None => { - errors.push(ParseError { - span: (0, 0), - reason: ParseErrorReason::UnbalancedBraces, - }); - } - } - ParserReturns { - ast: if name == "_" { - ArgDeclaration::Discard { loc, ty: Some(ty) } - } else { - ArgDeclaration::Simple { - loc, - ident: name, - ty: Some(ty), - } - }, - loc, - warnings, - errors, - } - } - Some((Token::Comma, _)) => { - //(, - let mut contents = vec![if name == "_" { - ArgDeclaration::Discard { loc, ty: None } - } else { - ArgDeclaration::Simple { - loc, - ident: name, - ty: None, - } - }]; - let _ = self.stream.next(); //, - while let Some((Token::Ident(_) | Token::GroupOpen, _)) = - self.stream.clone().next() - { - let arg = self.parse_arg(); - warnings.extend(arg.warnings); - errors.extend(arg.errors); - contents.push(arg.ast); - } - let ty = if let Some((Token::Colon, _)) = self.stream.clone().next() - { - let _ = self.stream.next(); - let ty = self.collect_type(); - warnings.extend(ty.warnings); - errors.extend(ty.errors); - Some(ty.ast) - } else { - None - }; - if let Some((Token::GroupClose, _)) = self.stream.clone().next() { - let _ = self.stream.next(); - } else { - errors.push(ParseError { - span: loc, - reason: ParseErrorReason::UnbalancedBraces, - }); - } - ParserReturns { - ast: ArgDeclaration::DestructureTuple(contents, ty, open_loc), - loc: open_loc, - warnings, - errors, - } - } - Some((Token::GroupClose, _)) => { - //() - let _ = self.stream.next(); - ParserReturns { - ast: if name == "_" { - ArgDeclaration::Discard { loc, ty: None } - } else { - ArgDeclaration::Simple { - loc, - ident: name, - ty: None, - } - }, - loc: open_loc, - warnings, - errors, - } - } - Some((_, loc)) => { - errors.push(ParseError { - span: loc, - reason: ParseErrorReason::UnbalancedBraces, - }); - ParserReturns { - ast: ArgDeclaration::Simple { - loc, - ident: "".to_string(), - ty: Some(types::ERROR), - }, - loc, - warnings, - errors, - } - } - None => { - errors.push(ParseError { - span: (0, 0), - reason: ParseErrorReason::UnbalancedBraces, - }); - ParserReturns { - ast: ArgDeclaration::Simple { - loc: (0, 0), - ident: "".to_string(), - ty: Some(types::ERROR), - }, - loc: (0, 0), - warnings, - errors, - } - } - } - } - _ => { - //( - let inner = self.parse_arg(); - warnings.extend(inner.warnings); - errors.extend(inner.errors); - let mut inner = inner.ast; - if let Some((Token::Colon, _)) = self.stream.clone().next() { - let _ = self.stream.next(); - let ty = self.collect_type(); - warnings.extend(ty.warnings); - errors.extend(ty.errors); - let new_ty = ty.ast; - match &mut inner { - ArgDeclaration::DestructureStruct { - loc, - struct_ident, - fields, - renamed_fields, - } => (), //generate warning. - ArgDeclaration::Discard { ty, .. } - | ArgDeclaration::DestructureTuple(_, ty, _) - | ArgDeclaration::Unit { ty, .. } - | ArgDeclaration::Simple { ty, .. } => *ty = Some(new_ty), - } - } - if let Some((Token::GroupClose, _)) = self.stream.clone().next() { - let _ = self.stream.next(); - } else { - errors.push(ParseError { - span: open_loc, - reason: ParseErrorReason::UnbalancedBraces, - }); - } - ParserReturns { - ast: inner, - loc: open_loc, - warnings, - errors, - } - } - } - } - Some((Token::Ident(_), _)) => { - let Some((Token::Ident(ident), loc)) = self.stream.next() else { - unreachable!() - }; - ParserReturns { - loc, - ast: if ident == "_" { - ArgDeclaration::Discard { loc, ty: None } - } else { - ArgDeclaration::Simple { - loc, - ident, - ty: None, - } - }, - warnings, - errors, - } - } - Some((Token::EoF, loc)) => { - errors.push(ParseError { - span: loc, - reason: ParseErrorReason::UnexpectedEndOfFile, - }); - ParserReturns { - ast: ArgDeclaration::Simple { - loc, - ident: "".to_string(), - ty: Some(types::ERROR), - }, - loc, - warnings, - errors, - } - } - Some((_token, loc)) => { - errors.push(ParseError { - span: loc, - reason: ParseErrorReason::UnexpectedToken, - }); - ParserReturns { - loc, - ast: ArgDeclaration::Simple { - loc, - ident: "".to_string(), - ty: Some(types::ERROR), - }, - warnings, - errors, - } - } - None => { - errors.push(ParseError { - span: (0, 0), - reason: ParseErrorReason::UnexpectedEndOfFile, - }); - ParserReturns { - ast: ArgDeclaration::Simple { - loc: (0, 0), - ident: "".to_string(), - ty: Some(types::ERROR), - }, - loc: (0, 0), - warnings, - errors, - } - } - } - } - - fn collect_args(&mut self) -> ParserReturns> { - let mut out = Vec::new(); - let mut warnings = Vec::new(); - let mut errors = Vec::new(); - while let Some((t, _)) = self.stream.clone().next() { - if let Token::Op(eq) = &t { - if eq == "=" { - break; - } - } - if t == Token::Colon { - break; - } - let arg = self.parse_arg(); - warnings.extend(arg.warnings); - errors.extend(arg.errors); - out.push(arg.ast) - } - ParserReturns { - ast: out, - loc: (0, 0), //this is discarded. - warnings, - errors, - } - } - - fn destructuring_declaration(&mut self) -> ParserReturns { - let Some((Token::Let, _)) = self.stream.next() else { - unreachable!() - }; - let ParserReturns { - ast: kind, - loc, - mut warnings, - mut errors, - } = self.collect_pattern(); - let ty = if let Some((Token::Colon, _)) = self.stream.peek() { - let _ = self.stream.next(); - let ty = self.collect_type(); - warnings.extend(ty.warnings); - errors.extend(ty.errors); - Some(ty.ast) - } else { - None - }; - if let Some((Token::Op(eq), loc)) = self.stream.peek() { - if eq != "=" { - errors.push(ParseError { - span: *loc, - reason: ParseErrorReason::UnexpectedToken, - }); - } else { - let _ = self.stream.next(); - } - } else { - errors.push(ParseError { - span: loc, - reason: ParseErrorReason::UnexpectedToken, - }); - } - let expr = match self.stream.peek() { - Some((Token::BeginBlock, loc)) => { - errors.push(ParseError { - span: *loc, - reason: ParseErrorReason::UnsupportedFeature, - }); - let result = self.collect_block(); - warnings.extend(result.warnings); - errors.extend(result.errors); - ast::Expr::Error - } - Some(_) => { - let result = self.next_expr(); - warnings.extend(result.warnings); - errors.extend(result.errors); - result.ast - } - _ => { - errors.push(ParseError { - span: (0, 0), - reason: ParseErrorReason::UnexpectedEndOfFile, - }); - ast::Expr::Error - } - }; - ParserReturns { - ast: ValueDeclaration { - loc, - is_op: false, - target: kind, - args: Vec::new(), - ty, - value: ValueType::Expr(expr), - generictypes: None, - abi: None, - }, - loc, - warnings, - errors, - } - } - - fn fn_declaration( - &mut self, - abi: Option, - generics: Option, - ) -> ParserReturns { - if let Some((Token::Let, _start)) = self.stream.next() { - let (token, ident_span) = self.stream.next().unwrap(); - let (ident, is_op) = match token { - Token::Ident(ident) => (ident, false), - Token::Op(ident) => (ident, true), - _ => { - return ParserReturns { - ast: ValueDeclaration { - loc: ident_span, - is_op: false, - target: ast::Pattern::Read("".to_string(), ident_span), - args: vec![ArgDeclaration::Simple { - loc: (0, 0), - ident: "".to_string(), - ty: Some(types::ERROR), - }], - ty: Some(types::ERROR), - value: ValueType::Expr(Expr::Error), - generictypes: generics, - abi, - }, - loc: ident_span, - warnings: Vec::new(), - errors: vec![ParseError { - span: ident_span, - reason: ParseErrorReason::DeclarationError, - }], - } - } - }; - let ParserReturns { - ast: mut args, - loc: _, - mut warnings, - mut errors, - } = self.collect_args(); - if is_op && (args.len() > 2 || args.len() == 0) { - if let Some((Token::Colon, _)) = self.stream.clone().next() { - let _ = self.stream.next(); - let _ = self.collect_type(); - } - if let Some((Token::Op(op), _)) = self.stream.clone().next() { - if op == "=" { - let _ = self.stream.next(); - match self.stream.clone().next() { - Some((Token::BeginBlock, _)) => { - let _ = self.collect_block(); - } - Some(_) => { - let _ = self.next_expr(); - } - _ => (), - } - } - } - errors.push(ParseError { - span: ident_span, - reason: ParseErrorReason::DeclarationError, - }); - return ParserReturns { - ast: ValueDeclaration { - loc: ident_span, - is_op, - target: ast::Pattern::Read(ident, ident_span), - args, - ty: Some(types::ERROR), - value: ValueType::Expr(ast::Expr::Error), - generictypes: generics, - abi, - }, - loc: ident_span, - warnings, - errors, - }; - } - - let mut ty = if let Some((Token::Colon, _)) = self.stream.clone().next() { - let _ = self.stream.next(); - let ty = self.collect_type(); - warnings.extend(ty.warnings); - errors.extend(ty.errors); - let ty = ty.ast; - Some(ty) - } else { - None - }; - - let op = match self.stream.next() { - Some((Token::Op(op), _)) => op, - Some((Token::Seq, _)) => { - if !abi.is_some() { - errors.push(ParseError { - span: ident_span, - reason: ParseErrorReason::DeclarationError, - }); - return ParserReturns { - ast: ValueDeclaration { - loc: ident_span, - is_op, - target: ast::Pattern::Read(ident, ident_span), - args, - ty, - value: ValueType::Expr(Expr::Error), - generictypes: generics, - abi, - }, - loc: ident_span, - warnings, - errors, - }; - } else if ty.is_none() || args.len() != 0 { - errors.push(ParseError { - span: ident_span, - reason: ParseErrorReason::DeclarationError, - }); - return ParserReturns { - ast: ValueDeclaration { - loc: ident_span, - is_op, - target: ast::Pattern::Read(ident, ident_span), - args, - ty, - value: ValueType::Expr(Expr::Error), - generictypes: generics, - abi, - }, - loc: ident_span, - warnings, - errors, - }; - } else { - return ParserReturns { - ast: ValueDeclaration { - loc: ident_span, - is_op, - target: ast::Pattern::Read(ident, ident_span), - args, - ty, - value: ValueType::External, - generictypes: generics, - abi, - }, - loc: ident_span, - warnings, - errors, - }; - } - } - _ => { - //TODO! progress next_toplevel valid point. - errors.push(ParseError { - span: ident_span, - reason: ParseErrorReason::DeclarationError, - }); - return ParserReturns { - ast: ValueDeclaration { - loc: ident_span, - is_op, - target: ast::Pattern::Read(ident, ident_span), - args, - ty, - value: ValueType::Expr(Expr::Error), - generictypes: generics, - abi, - }, - loc: ident_span, - warnings, - errors, - }; - } - }; - - if op != "=" { - //TODO! progress next_toplevel until valid point. - errors.push(ParseError { - span: ident_span, - reason: ParseErrorReason::DeclarationError, - }); - return ParserReturns { - ast: ValueDeclaration { - loc: ident_span, - is_op, - target: ast::Pattern::Read(ident, ident_span), - args, - ty, - value: ValueType::Expr(Expr::Error), - generictypes: generics, - abi, - }, - loc: ident_span, - warnings, - errors, - }; - } - - let value = match self.stream.clone().next() { - Some((Token::BeginBlock, _)) => ValueType::Function({ - let block = self.collect_block(); - warnings.extend(block.warnings); - errors.extend(block.errors); - block.ast - }), - Some((_, _)) => { - let ParserReturns { - ast, - loc: _, - warnings: expr_warnings, - errors: expr_errors, - } = self.next_expr(); - warnings.extend(expr_warnings); - errors.extend(expr_errors); - ValueType::Expr(ast) - } - _ => { - errors.push(ParseError { - span: ident_span, - reason: ParseErrorReason::UnexpectedEndOfFile, - }); - return ParserReturns { - ast: ValueDeclaration { - loc: ident_span, - is_op, - target: ast::Pattern::Read(ident, ident_span), - args, - ty, - value: ValueType::Expr(Expr::Error), - generictypes: generics, - abi, - }, - loc: ident_span, - warnings, - errors, - }; - } - }; - if let Some(generics) = &generics { - for arg in &mut args { - generics - .decls - .iter() - .map(|(_, it)| it) - .for_each(|name| arg.apply_generic(name)); - } - - if let Some(ty) = &mut ty { - *ty = generics - .decls - .iter() - .map(|(_, it)| it) - .fold(ty.clone(), |ty, name| ty.replace_user_with_generic(name)); - } - } - - return ParserReturns { - ast: ValueDeclaration { - loc: ident_span, - is_op, - target: ast::Pattern::Read(ident, ident_span), - args, - ty, - value, - generictypes: generics, - abi, - }, - loc: ident_span, - warnings, - errors, - }; - } - return ParserReturns { - ast: ValueDeclaration { - loc: (0, 0), - is_op: false, - target: ast::Pattern::Read("".to_string(), (0, 0)), - args: vec![ArgDeclaration::Simple { - loc: (0, 0), - ident: "".to_string(), - ty: Some(types::ERROR), - }], - ty: Some(types::ERROR), - value: ValueType::Expr(Expr::Error), - generictypes: generics, - abi, - }, - loc: (0, 0), - warnings: Vec::new(), - errors: vec![ParseError { - span: (0, 0), - reason: ParseErrorReason::UnknownError, - }], - }; - } - - fn collect_block(&mut self) -> ParserReturns> { - let mut warnings = Vec::new(); - let mut errors = Vec::new(); - let sub = if let Some((Token::BeginBlock, _)) = self.stream.next() { - let mut sub_expr = Vec::new(); - loop { - let next = self.stream.peek(); - if let Some((Token::EndBlock, _)) = next { - self.stream.next(); - break; - } else if let Some((Token::EoF, _)) = next { - break; - } - let stmnt = self.next_statement(); - warnings.extend(stmnt.warnings); - errors.extend(stmnt.errors); - sub_expr.push(stmnt.ast); - } - sub_expr - } else { - errors.push(ParseError { - span: (0, 0), - reason: ParseErrorReason::UnknownError, - }); - Vec::new() - }; - ParserReturns { - ast: sub, - loc: (0, 0), - warnings, - errors, - } - } - - fn binary_op(&mut self) -> ParserReturns { - let op_loc = self.stream.clone().nth(2).unwrap().1; - let mut warnings = Vec::new(); - let mut errors = Vec::new(); - let mut group_opens = 0; - let tokens = self - .stream - .clone() - .take_while(|(t, _)| match t { - Token::GroupOpen => { - group_opens += 1; - true - } - Token::Ident(_) - | Token::FloatingPoint(_, _) - | Token::Integer(_, _) - | Token::Op(_) => true, - Token::GroupClose => { - group_opens -= 1; - group_opens >= 0 - } - _ => false, - }) - .collect_vec(); - for _ in 0..tokens.len() { - self.stream.next(); - } - - // (name,weight,right associative) - const PRECIDENCE: [(&'static str, usize, bool); 12] = [ - (".", usize::MAX, true), - ("**", 7, false), - ("*", 5, true), - ("/", 5, true), - ("+", 4, true), - ("-", 4, true), - ("<", 2, true), - ("<=", 2, true), - (">", 2, true), - (">=", 2, true), - ("&&", 1, true), - ("||", 1, true), - ]; - let mut output = Vec::with_capacity(tokens.len()); - let mut op_stack = Vec::with_capacity(tokens.len() / 3); - let mut token_iter = tokens.into_iter().peekable(); - while let Some((token, _)) = token_iter.peek() { - match token { - Token::GroupOpen => { - let _ = token_iter.next(); - let mut group_opens = 0; - let sub_tokens = token_iter - .clone() - .take_while(|(t, _)| match t { - Token::GroupClose => { - group_opens -= 1; - group_opens >= 0 - } - Token::GroupOpen => { - group_opens += 1; - true - } - Token::Ident(_) - | Token::FloatingPoint(_, _) - | Token::Integer(_, _) - | Token::Op(_) => true, - _ => false, - }) - .collect_vec(); - for _ in 0..sub_tokens.len() { - token_iter.next(); - } - let ParserReturns { - ast: result, - loc, - warnings: expr_warnings, - errors: expr_errors, - } = Parser::from_stream(sub_tokens.into_iter()).next_expr(); - warnings.extend(expr_warnings); - errors.extend(expr_errors); - output.push(ShuntingYardOptions::Expr((result, loc))); - } - Token::GroupClose => { - let _ = token_iter.next(); - } - Token::Ident(_) => { - if let Some(( - Token::Ident(_) - | Token::CharLiteral(_) - | Token::StringLiteral(_) - | Token::FloatingPoint(_, _) - | Token::Integer(_, _) - | Token::GroupOpen, - _, - )) = token_iter.clone().nth(1) - { - let sub_tokens = token_iter - .clone() - .take_while(|(t, _)| match t { - Token::GroupClose => { - group_opens -= 1; - group_opens >= 0 - } - Token::GroupOpen => { - group_opens += 1; - true - } - Token::Ident(_) - | Token::FloatingPoint(_, _) - | Token::Integer(_, _) => true, - Token::Op(_) => group_opens >= 0, - _ => false, - }) - .collect_vec(); - for _ in 0..sub_tokens.len() { - token_iter.next(); - } - let ParserReturns { - ast: result, - loc, - warnings: expr_warnings, - errors: expr_errors, - } = Parser::from_stream(sub_tokens.into_iter()).next_expr(); - warnings.extend(expr_warnings); - errors.extend(expr_errors); - - output.push(ShuntingYardOptions::Expr((result, loc))); - } else { - let Some((Token::Ident(ident), loc)) = token_iter.next() else { - unreachable!() - }; - output.push(ShuntingYardOptions::Expr(( - Expr::ValueRead(ident, loc), - loc, - ))); - } - } - Token::Integer(_, _) - | Token::FloatingPoint(_, _) - | Token::CharLiteral(_) - | Token::StringLiteral(_) => output.push(ShuntingYardOptions::Expr({ - let Some((token, span)) = token_iter.next() else { - return ParserReturns { - ast: Expr::Error, - loc: (0, 0), - warnings: Vec::new(), - errors: vec![ParseError { - span: (0, 0), - reason: ParseErrorReason::UnknownError, - }], - }; - }; - - let result = match make_literal(token, span) { - Ok(r) => r, - Err(e) => { - errors.push(e); - ast::Expr::Error - } - }; - (result, span) - })), - Token::Op(_) => { - let Some((Token::Op(ident), loc)) = token_iter.next() else { - unreachable!() - }; - let (prec, left) = PRECIDENCE - .iter() - .find_map(|(op, weight, assc)| { - if op == &ident { - Some((*weight, *assc)) - } else { - None - } - }) - .unwrap_or((1, false)); - if op_stack.is_empty() { - op_stack.push((ident, loc)); - continue; - } - while let Some(op_back) = op_stack.last() { - let back_prec = PRECIDENCE - .iter() - .find_map(|(op, weight, _)| { - if op == &op_back.0 { - Some(*weight) - } else { - None - } - }) - .unwrap_or(1); - if back_prec > prec || (back_prec == prec && left) { - let Some(op_back) = op_stack.pop() else { - unreachable!() - }; - output.push(ShuntingYardOptions::Op(op_back)); - } else { - op_stack.push((ident.clone(), loc)); - break; - } - } - if op_stack.last().is_none() { - op_stack.push((ident, loc)); - } - } - _ => break, - } - } - output.extend(op_stack.into_iter().rev().map(ShuntingYardOptions::Op)); - let mut final_expr = Vec::<(ast::Expr, crate::Location)>::new(); - for expr in output { - match expr { - ShuntingYardOptions::Expr(expr) => final_expr.push(expr), - ShuntingYardOptions::Op((op, loc)) => { - let Some((rhs, _)) = final_expr.pop() else { - unreachable!() - }; - let Some((lhs, _)) = final_expr.pop() else { - unreachable!() - }; - final_expr.push(( - ast::Expr::BinaryOpCall(BinaryOpCall { - loc, - operator: op, - lhs: lhs.into(), - rhs: rhs.into(), - }), - loc, - )) - } - } - } - - if final_expr.len() != 1 { - errors.push(ParseError { - span: op_loc, - reason: ParseErrorReason::UnknownError, - }); - ParserReturns { - ast: Expr::Error, - loc: op_loc, - warnings, - errors, - } - } else { - let (expr, _loc) = final_expr.into_iter().next().unwrap(); - - ParserReturns { - ast: expr, - loc: op_loc, - warnings, - errors, - } - } - } - - fn match_(&mut self) -> ParserReturns { - let Some((Token::Match, match_loc)) = self.stream.next() else { - unreachable!() - }; - let ParserReturns { - ast: on, - loc: _, - mut warnings, - mut errors, - } = self.next_expr(); - if let Some((Token::Where, _)) = self.stream.clone().next() { - let _ = self.stream.next(); - } else { - //TODO? recovery? - let loc = if let Some((_, loc)) = self.stream.clone().next() { - loc - } else { - (0, 0) - }; - errors.push(ParseError { - span: loc, - reason: ParseErrorReason::UnexpectedToken, - }) - }; - let expect_block = if let Some((Token::BeginBlock, _)) = self.stream.clone().next() { - let _ = self.stream.next(); - true - } else { - false - }; - let mut arms = Vec::new(); - while let Some((Token::Op(op), _)) = self.stream.peek() { - if op != "|" { - break; - } - let _ = self.stream.next(); - let pattern = self.collect_pattern(); - warnings.extend(pattern.warnings); - errors.extend(pattern.errors); - let loc = pattern.loc; - let cond = pattern.ast; - if let Some((Token::Arrow, _)) = self.stream.peek() { - self.stream.next(); - } else { - let Some((t, loc)) = self.stream.peek() else { - unreachable!() - }; - println!( - "expected -> but got {:?} at line: {}, col: {}", - t, loc.0, loc.1 - ); - } - let (block, ret) = match self.stream.peek() { - Some((Token::BeginBlock, _)) => { - let _ = self.stream.next(); - let mut body = Vec::new(); - while self - .stream - .clone() - .skip_while(|(it, _)| it != &Token::Seq && it != &Token::EndBlock) - .next() - .map(|a| a.0 != Token::EndBlock && a.0 != Token::EoF) - .unwrap_or(false) - { - let stmnt = self.next_statement(); - warnings.extend(stmnt.warnings); - errors.extend(stmnt.errors); - body.push(stmnt.ast); - } - match self.stream.peek() { - Some((Token::EndBlock, _)) => { - let _ = self.stream.next(); - (body, None) - } - _ => { - let ParserReturns { - ast: ret, - warnings: ret_warnings, - errors: ret_errors, - loc: _, - } = self.next_expr(); - warnings.extend(ret_warnings); - errors.extend(ret_errors); - if let Some((Token::EndBlock, _)) = self.stream.peek() { - let _ = self.stream.next(); - } else { - println!("did you mean next_toplevel move back a block?"); - } - (body, Some(ret.into())) - } - } - } - _ => { - let ParserReturns { - ast: expr, - warnings: ret_warnings, - errors: ret_errors, - loc: _, - } = self.next_expr(); - warnings.extend(ret_warnings); - errors.extend(ret_errors); - - if let Some((Token::Comma, _)) = self.stream.peek() { - let _ = self.stream.next(); - } else { - let Some((peeked, loc)) = self.stream.peek() else { - unreachable!() - }; - println!( - "expected `,` but got {:?} at line : {}, col: {}", - peeked, loc.0, loc.1 - ) - } - (Vec::new(), Some(expr.into())) - } - }; - arms.push(ast::MatchArm { - block, - ret, - cond, - loc, - }); - } - - if expect_block { - if let Some((Token::EndBlock, _)) = self.stream.peek() { - let _ = self.stream.next(); - } else { - println!( - "did you mean next_toplevel go back next_toplevel the containing block level?" - ); - } - } - - ParserReturns { - ast: Match { - loc: match_loc, - on: on.into(), - arms, - }, - loc: match_loc, - warnings, - errors, - } - } - - fn collect_pattern(&mut self) -> ParserReturns { - let mut warnings = Vec::new(); - let mut errors = Vec::new(); - // op should poped beffore this. - let (pattern, loc) = match self.stream.clone().next() { - Some((Token::CurlOpen, loc)) => { - let _curl = self.stream.next(); - let mut fields = HashMap::new(); - while let Some((Token::Ident(_), _)) = self.stream.clone().next() { - let Some((Token::Ident(field_name), loc)) = self.stream.next() else { - unreachable!() - }; - if let Some((Token::Colon, _)) = self.stream.clone().next() { - let Some((Token::Colon, _)) = self.stream.next() else { - unreachable!() - }; - let sub_pattern = self.collect_pattern(); - warnings.extend(sub_pattern.warnings); - errors.extend(sub_pattern.errors); - fields.insert(field_name, sub_pattern.ast); - } else { - fields.insert(field_name.clone(), Pattern::Read(field_name, loc)); - } - if let Some((Token::Comma, _)) = self.stream.clone().next() { - let _comma = self.stream.next(); - } else { - break; - } - } - if let Some((Token::CurlClose, _)) = self.stream.clone().next() { - let _curl = self.stream.next(); - } else { - //todo! recovery. - } - ( - Pattern::Destructure(PatternDestructure::Struct { - base_ty: None, - fields, - }), - loc, - ) - } - Some((Token::Ident(_), _)) => { - let Some((Token::Ident(name), loc)) = self.stream.next() else { - unreachable!() - }; - match self.stream.clone().next() { - Some((Token::Scope, _)) => { - let enum_name = name; - let Some((_scope, scope_loc)) = self.stream.next() else { - unreachable!() - }; - if let Some((Token::Ident(_), _)) = self.stream.clone().next() { - let Some((Token::Ident(variant), _)) = self.stream.next() else { - unreachable!() - }; - let pattern = match self.stream.clone().next() { - Some(( - Token::CurlOpen - | Token::GroupOpen - | Token::Ident(_) - | Token::BracketOpen - | Token::Integer(_, _) - | Token::FloatingPoint(_, _), - _, - )) => { - let sub_pattern = self.collect_pattern(); - warnings.extend(sub_pattern.warnings); - errors.extend(sub_pattern.errors); - Some(sub_pattern.ast.into()) - } - _ => None, - }; - ( - Pattern::EnumVariant { - ty: Some(enum_name), - variant, - pattern, - loc, - }, - loc, - ) - } else { - errors.push(ParseError { - span: scope_loc, - reason: ParseErrorReason::UnexpectedToken, - }); - (Pattern::Error, loc) - } - } - Some((Token::CurlOpen, _)) => { - let mut sub_pattern = self.collect_pattern(); - warnings.extend(sub_pattern.warnings); - errors.extend(sub_pattern.errors); - let Pattern::Destructure(PatternDestructure::Struct { base_ty, .. }) = - &mut sub_pattern.ast - else { - unreachable!() - }; - *base_ty = Some(name); - (sub_pattern.ast, loc) - } - Some(( - Token::GroupOpen - | Token::Ident(_) - | Token::BracketOpen - | Token::Integer(_, _) - | Token::FloatingPoint(_, _), - _, - )) => { - let sub_pattern = self.collect_pattern(); - warnings.extend(sub_pattern.warnings); - errors.extend(sub_pattern.errors); - ( - Pattern::EnumVariant { - ty: None, - variant: name, - pattern: Some(sub_pattern.ast.into()), - loc, - }, - loc, - ) - } - _ => { - if name == "_" { - (Pattern::Default, loc) - } else { - // TODO! pattern detection of enum varaints. - (Pattern::Read(name, loc), loc) - } - } - } - } - Some((Token::Integer(_, _), _)) => { - let Some((Token::Integer(signed, value), loc)) = self.stream.next() else { - unreachable!() - }; - ( - Pattern::ConstNumber(format!("{}{}", if signed { "-" } else { "" }, value)), - loc, - ) - } - Some((Token::FloatingPoint(_, _), _)) => { - let Some((Token::FloatingPoint(signed, value), loc)) = self.stream.next() else { - unreachable!() - }; - - ( - Pattern::ConstNumber(format!("{}{}", if signed { "-" } else { "" }, value)), - loc, - ) - } - Some((Token::CharLiteral(_), _)) => { - let Some((Token::CharLiteral(c), loc)) = self.stream.next() else { - unreachable!() - }; - (Pattern::ConstChar(c), loc) - } - Some((Token::StringLiteral(_), _)) => { - let Some((Token::StringLiteral(c), loc)) = self.stream.next() else { - unreachable!() - }; - (Pattern::ConstStr(c), loc) - } - Some((Token::True, _)) => { - let Some((_, loc)) = self.stream.next() else { - unreachable!() - }; - (Pattern::ConstBool(true), loc) - } - Some((Token::False, _)) => { - let Some((_, loc)) = self.stream.next() else { - unreachable!() - }; - (Pattern::ConstBool(false), loc) - } - - Some((Token::GroupOpen, _)) => { - let Some((Token::GroupOpen, loc)) = self.stream.next() else { - unreachable!() - }; - if let Some((Token::GroupClose, _)) = self.stream.clone().next() { - let _ = self.stream.next(); - (Pattern::Destructure(PatternDestructure::Unit), loc) - } else { - let first = self.collect_pattern(); - warnings.extend(first.warnings); - errors.extend(first.errors); - let first_loc = first.loc; - let mut patterns = vec![first.ast]; - loop { - match self.stream.clone().next() { - Some((Token::Comma, _)) => { - let _ = self.stream.next(); - let next = self.collect_pattern(); - warnings.extend(next.warnings); - errors.extend(next.errors); - patterns.push(next.ast); - } - Some((Token::GroupClose, _)) => { - break; - } - Some((Token::EoF, _)) | None => { - let _ = self.stream.next(); - errors.push(ParseError { - span: loc, - reason: ParseErrorReason::UnexpectedEndOfFile, - }); - break; - } - Some((t, loc)) => { - let _ = self.stream.next(); - errors.push(ParseError { - span: loc, - reason: ParseErrorReason::UnexpectedToken, - }); - break; - } - } - } - match self.stream.clone().next() { - Some((Token::GroupClose, _)) => { - let _ = self.stream.next(); - } - Some((Token::EoF, _)) | None => { - let _ = self.stream.next(); - errors.push(ParseError { - span: loc, - reason: ParseErrorReason::UnexpectedEndOfFile, - }); - } - Some((t, loc)) => { - let n = self - .stream - .clone() - .peeking_take_while(|(t, _)| match t { - Token::Comma | Token::EndBlock => false, - Token::Op(op) => op != "|", - _ => true, - }) - .collect_vec() - .len(); - for _ in 0..n { - let _ = self.stream.next(); - } - errors.push(ParseError { - span: loc, - reason: ParseErrorReason::UnexpectedToken, - }); - } - } - if patterns.len() == 1 { - (patterns.pop().unwrap(), first_loc) - } else { - ( - Pattern::Destructure(PatternDestructure::Tuple(patterns)), - loc, - ) - } - } - } - Some((Token::EoF, _)) | None => { - let _ = self.stream.next(); - errors.push(ParseError { - span: (0, 0), - reason: ParseErrorReason::UnexpectedEndOfFile, - }); - (Pattern::Error, (0, 0)) + arg + }); + let unit = ('(', ascii::space0, ')') + .with_span() + .map(|((_, _space, _), loc)| { + //todo generate warnings?? + ast::ArgDeclaration::Unit { + loc: (loc.start, loc.end), + ty: None, } - Some((t, loc)) => { - errors.push(ParseError { - span: loc, - reason: ParseErrorReason::UnexpectedToken, - }); - let n = self - .stream - .clone() - .peeking_take_while(|(t, _)| match t { - Token::Comma | Token::EndBlock => false, - Token::Op(op) => op != "|", - _ => true, + }); + combinator::alt(( + unit, + apply_ty, + "_".span().map(|loc| ast::ArgDeclaration::Discard { + loc: (loc.start, loc.end), + ty: None, + }), + combinator::delimited(('(', ascii::space0), arg, (ascii::space0, ')')), + combinator::delimited( + ('(', ascii::space0), + combinator::separated(1.., arg, (ascii::space0, ',', ascii::space0)), + (ascii::space0, ')'), + ) + .with_span() + .map(|(args, loc)| ast::ArgDeclaration::DestructureTuple(args, None, (loc.start, loc.end))), + simple_ident + .with_span() + .map(|(ident, loc)| ast::ArgDeclaration::Simple { + loc: (loc.start, loc.end), + ident: ident.into(), + ty: None, + }), + // todo! other destrctures + )) + .parse_next(input) +} + +fn top_level_value(input: &mut Stream<'_>) -> PResult { + let generics = combinator::opt(generics).parse_next(input)?; + let abi = combinator::opt( + combinator::preceded( + ("extern", ascii::space1), + combinator::alt(( + r#""C""#.span().map(|span| ast::Abi { + loc: (span.start, span.end), + identifier: "C".into(), + }), + r#""intrinsic""#.span().map(|span| ast::Abi { + loc: (span.start, span.end), + identifier: "interinsic".into(), + }), + )), + ) + .verify(|_| generics.is_none()) + .context(StrContext::Expected( + "can not combine an abi with generics".into(), + )), + ) + .parse_next(input)?; + + (ascii::multispace0, "let").void().parse_next(input)?; + ascii::space1(input)?; + let ((ident, loc), is_op) = combinator::alt(( + parens(op).with_span().map(|it| (it, true)), + simple_ident.with_span().map(|it| (it, false)), + )) + .parse_next(input)?; + let args = combinator::opt(combinator::preceded( + ascii::space1, + combinator::separated(1.., arg, ascii::space1), + )) + .parse_next(input)? + .unwrap_or_default(); + let ty = combinator::opt(combinator::preceded( + (ascii::space0, ':', ascii::space0), + type_, + )) + .parse_next(input)?; + if let Some(_) = combinator::opt((ascii::space0, '=').void()).parse_next(input)? { + let mut value = ast::TopLevelValue { + loc: (loc.start, loc.end), + is_op, + ident: ident.into(), + args, + ty, + value: combinator::trace( + "value", + combinator::alt(( + combinator::preceded((ascii::space0, ascii::line_ending), block) + .map(ast::ValueType::Function), + combinator::delimited(ascii::space0, expr, |input:&mut Stream<'_>| { + if input.state.multi_line_expr { + input.state.multi_line_expr=false; + Ok(()) + } else { + (ascii::space0,';').void().parse_next(input) + } }) - .collect_vec() - .len(); - for _ in 0..n { - let _ = self.stream.next(); - } - (Pattern::Error, loc) - } - }; - let pattern = if let Some((Token::Op(op), _)) = self.stream.peek() { - if op == "|" { - let _ = self.stream.next(); - let next = self.collect_pattern(); - warnings.extend(next.warnings); - errors.extend(next.errors); - Pattern::Or(pattern.into(), next.ast.into()) - } else { - pattern - } - } else { - pattern + .map(ast::ValueType::Expr), + )), + ) + .parse_next(input)?, + generics, + abi, }; - ParserReturns { - ast: pattern, - loc, - warnings, - errors, - } + value.bind_generics(); + Ok(value) + } else { + (ascii::space0, ';') + .void() + .verify(|_| abi.is_some() && ty.is_some() && generics.is_none()) + .parse_next(input)?; + Ok(ast::TopLevelValue { + loc: (loc.start, loc.end), + is_op, + ident: ident.into(), + args, + ty, + value: ast::ValueType::External, + generics, + abi, + }) } +} - fn array_literal(&mut self) -> ParserReturns { - let Some((Token::BracketOpen, loc)) = self.stream.next() else { - unreachable!() - }; - let mut values = Vec::new(); - let mut warnings = Vec::new(); - let mut errors = Vec::new(); - let expect_block = if let Some((Token::BeginBlock, _)) = self.stream.peek() { - let _ = self.stream.next(); - true - } else { - false - }; - loop { - let ParserReturns { - ast: expr, - loc: _, - warnings: new_warnings, - errors: new_errors, - } = self.next_expr(); - warnings.extend(new_warnings); - errors.extend(new_errors); - values.push(expr); - match self.stream.clone().next() { - Some((Token::Comma, _)) => { - let _ = self.stream.next(); - continue; - } - Some(_) => break, - None => { - unreachable!("somehow not even got EoF"); - } - } - } +fn generics<'input>(input: &mut Stream<'input>) -> PResult { + let for_loc = "for".span().parse_next(input)?; + let decls = combinator::delimited( + (ascii::space0, '<'), + combinator::separated( + 1.., + combinator::delimited( + ascii::space0, + simple_ident + .with_span() + .map(|(a, b)| ((b.start, b.end), a.into())), + ascii::space0, + ), + ',', + ), + (ascii::space0, '>'), + ) + .parse_next(input)?; + Ok(ast::GenericsDecl { + for_loc: (for_loc.start, for_loc.end), + decls, + }) +} - if expect_block { - if let Some((Token::EndBlock, _)) = self.stream.peek() { - let _ = self.stream.next(); - } else { - println!("did you mean next_toplevel have the closing ] on the same level as the opening?") - } - } +fn if_statement(input :&mut Stream<'_>) -> PResult { + let prefix = input.state.prefix.clone(); + combinator::trace("if",winnow::combinator::seq! { ast::If{ + loc:"if".span().map(|loc| (loc.start,loc.end)), + cond : combinator::delimited(ascii::multispace1,combinator::cut_err(expr).map(Into::into),(ascii::multispace1,"then")), + true_branch : combinator::alt(( + combinator::preceded((ascii::space0,ascii::line_ending),block), + expr.map(|expr| ast::Block { statements:Vec::new(), implicit_ret:Some(expr.into())}) + )), + _:ignore_blank_lines, + else_branch : combinator::opt( + combinator::preceded( + combinator::preceded(&*prefix, "else"), + combinator::alt(( + combinator::preceded(ascii::space1,if_statement).map(|if_|ast::Block { statements : vec![ast::Statement::IfStatement(if_)], implicit_ret:None}), + combinator::preceded((ascii::space0,ascii::line_ending),block), + expr.map(|expr| ast::Block { statements:Vec::new(), implicit_ret:Some(expr.into())}) + )) + ) + ), + } + }).parse_next(input) +} - if let Some((Token::BracketClose, _)) = self.stream.peek() { - let _ = self.stream.next(); - } else { - errors.push(ParseError { - span: loc, - reason: ParseErrorReason::UnbalancedBraces, - }); - values.push(ast::Expr::Error); - } - ParserReturns { - ast: ast::Expr::ArrayLiteral { - contents: values, - loc, - }, - loc, - warnings, - errors, - } +fn statement(input: &mut Stream<'_>) -> PResult { + let declaration = combinator::preceded( + ("let", ascii::space1), + combinator::cut_err(( + pattern + .verify(|pat| { + !matches!( + pat, + ast::Pattern::Or(_, _) + | ast::Pattern::EnumVariant { .. } + | ast::Pattern::ConstNumber(_) + | ast::Pattern::ConstStr(_) + | ast::Pattern::ConstChar(_) + | ast::Pattern::ConstBool(_) + + ) + }) + .with_span() + .map(|(pat, loc)| ((loc.start, loc.end), pat)), + combinator::opt(combinator::preceded( + (ascii::space0, ':', ascii::space0), + type_, + )), + combinator::preceded( + (ascii::space0, "=", ascii::space0), + combinator::alt(( + combinator::preceded((ascii::space0, ascii::line_ending), block) + .map(ast::ValueType::Function), + combinator::terminated(expr,(ascii::space0,';')).map(ast::ValueType::Expr), + )), + ), + )), + ) + .map(|((loc, target), ty, value)| ast::ValueDeclaration { + loc, + is_op: false, + target, + args: Vec::new(), + ty, + value, + generictypes: None, + abi: None, + }); + let multiline_context = input.state.multi_line_expr; + let result = combinator::trace( + "statement", + combinator::alt(( + + declaration.map(ast::Statement::Declaration), + match_.map(ast::Statement::Match), + if_statement.map(ast::Statement::IfStatement), + combinator::terminated(combinator::alt(( + + ("return".span(), + combinator::cut_err(combinator::preceded(ascii::space1, expr)), + + ).map(|(loc, expr)| ast::Statement::Return(expr.into(), (loc.start, loc.end))), + expr.map(ast::Statement::Expr), + + )), + (ascii::multispace0,';') + ), + combinator::fail.context(StrContext::Label("Invalid statement"))//this should never be reached??? + )), + ) + .parse_next(input); + input.state.multi_line_expr=multiline_context; + // ignore_blank_lines(input)?; + result +} + + + +fn simple_expr(input:&mut Stream<'_>) -> PResult { + + + if input.is_empty() { + return Err(ErrMode::Backtrack(ContextError::new())); + } + + let if_ = combinator::trace("if",winnow::combinator::seq! { ast::If{ + loc:"if".span().map(|loc| (loc.start,loc.end)), + cond : combinator::delimited(ascii::multispace1,expr.map(Into::into),(ascii::multispace1,"then")), + true_branch : combinator::alt(( + combinator::preceded((ascii::space0,ascii::line_ending,|input:&mut Stream<'_>| { + input.state.multi_line_expr=true; + Ok(()) + }),block), + expr.map(|expr| ast::Block { statements:Vec::new(), implicit_ret:Some(expr.into())}) + )), + _:(ascii::multispace0,"else"),//TODO! need to check indent level or if inline then space preceded. + else_branch : combinator::alt(( + combinator::preceded((ascii::space0,ascii::line_ending,|input:&mut Stream<'_>| { + input.state.multi_line_expr=true; + Ok(()) + }),block), + expr.map(|expr| ast::Block { statements:Vec::new(), implicit_ret:Some(expr.into())}) + )).map(Into::into), } + }); + let struct_con = ( + type_.with_span(), + combinator::delimited( + (ascii::space0, '{', ascii::multispace0), + combinator::separated( + 0.., + combinator::alt(( + combinator::separated_pair( + simple_ident, + (ascii::space0, ':', ascii::space0), + expr, + ) + .map(|(ident, expr)| { + let loc = expr.get_loc(); + (ident, (expr, loc)) + }), + simple_ident.with_span().map(|(ident, loc)| { + ( + ident.clone(), + ( + ast::Expr::ValueRead(ident.into(), (loc.start, loc.end)), + (loc.start, loc.end), + ), + ) + }), + )), + (ascii::multispace0, ',', ascii::multispace0), + ), + (ascii::space0, '}', ascii::multispace0), + ), + ) + .map(|((ty, loc), fields): (_, Vec<_>)| { + if let types::ResolvedType::User { name, generics, .. } = ty { + ast::Expr::StructConstruction(ast::StructConstruction { + loc: (loc.start, loc.end), + fields: fields + .into_iter() + .map(|(ident, value)| (ident.into(), value)) + .collect(), + generics, + ident: name, + }) + } else { + ast::Expr::Error + } + }); + + ascii::space0(input)?; + combinator::trace( + "simple expr", + combinator::alt(( + //axioms + "()".map(|_| ast::Expr::UnitLiteral), + "true" + .span() + .map(|loc| ast::Expr::BoolLiteral(true, (loc.start, loc.end))), + "false" + .span() + .map(|loc| ast::Expr::BoolLiteral(false, (loc.start, loc.end))), + combinator::trace("struct construction",struct_con), + ascii::dec_int.map(|it: i128| ast::Expr::NumericLiteral { + value: it.to_string(), + }), + ascii::float.map(|it: f64| ast::Expr::NumericLiteral { + value: it.to_string(), + }), + string_lit.map(ast::Expr::StringLiteral), + char_lit.map(ast::Expr::CharLiteral), + // todo! operator read. important for passing operators to functions + // parens(op).map(ast::Expr::OpRead) + //dependents. + parens(expr), + //tuple + combinator::trace("tuple",parens(combinator::separated( + 1.., + expr, + (ascii::multispace0, ',', ascii::multispace0), + ))) + .with_span() + .map(|(contents, loc)| ast::Expr::TupleLiteral { + contents, + loc: (loc.start, loc.end), + }), + //array + combinator::trace("array construction",combinator::delimited( + ('[', ascii::multispace0), + combinator::cut_err(combinator::separated( + 1.., + expr, + (ascii::multispace0, ',', ascii::multispace0), + )), + (ascii::multispace0, ']'), + )).with_span() + .map(|(contents, loc)| ast::Expr::ArrayLiteral { + contents, + loc: (loc.start, loc.end), + }), + if_.map(ast::Expr::If), + match_.map(ast::Expr::Match), + ident + .with_span() + .map(|(name, loc)| ast::Expr::ValueRead(name.into(), (loc.start, loc.end))), + + // combinator::separated(expr,combinator::delimited(ascii::multispace0,op,ascii::multispace0)) + )), + ).parse_next(input) } -fn make_literal(token: Token, span: (usize, usize)) -> Result { - match token { - Token::CharLiteral(ch) => Ok(ast::Expr::CharLiteral(ch)), - Token::StringLiteral(src) => { - let mut value = String::with_capacity(src.len()); - let mut s = src.chars(); - while let Some(c) = s.next() { - if c == '\\' { - let next = match s.next() { - Some('n') => '\n', - Some('\\') => '\\', - Some('r') => '\r', - Some('t') => '\t', - Some('"') => '"', - Some('\'') => '\'', - Some(_) => { - return Err(ParseError { - span, - reason: ParseErrorReason::UnsupportedEscape, +fn expr(input: &mut Stream<'_>) -> PResult { + combinator::trace("expr",|input:&mut Stream<'_>| { + + + let out = simple_expr(input)?; + let out = if let Some(args) = combinator::opt(combinator::preceded( + ascii::multispace1, + combinator::separated::<_, _, Vec<_>, _, _, _, _>(1.., simple_expr, ascii::multispace1), + )) + .parse_next(input)? + { + std::iter::once(out) + .chain(args) + .reduce(|value, arg| { + let loc = value.get_loc(); + ast::Expr::FnCall(ast::FnCall { + value: value.into(), + arg: Some(arg.into()), + loc, + }) + }) + .unwrap() + } else { + out + }; + if let Some(op_ident) = combinator::opt(combinator::preceded( + ascii::space0, + op.with_span() + .map(|(op, loc)| (op.to_string(), (loc.start, loc.end))), + )) + .parse_next(input)? + { + let mut output = vec![ShuntingYardOptions::Expr(out)]; + let mut op_stack = vec![op_ident]; + let op = combinator::delimited(ascii::space0, op.with_span(), ascii::space0) + .map(|(op, loc)| (op.to_string(), (loc.start, loc.end))) + .map(ShuntingYardOptions::Op); + let mut opts = combinator::opt(combinator::preceded( + ascii::space0, + combinator::alt((simple_expr.map(ShuntingYardOptions::Expr), op)), + )); + + //todo! move to just before inference for + while let Some(opts) = opts.parse_next(input)? { + match opts { + ShuntingYardOptions::Expr(_) => { + output.push(opts); + } + ShuntingYardOptions::Op((op_ident, loc)) => { + let (prec, left) = PRECIDENCE + .iter() + .find_map(|(op, weight, assc)| { + if op == &op_ident { + Some((*weight, *assc)) + } else { + None + } + }) + .unwrap_or((1, false)); + if op_stack.is_empty() { + op_stack.push((op_ident, loc)); + continue; + } + while let Some(op_back) = op_stack.last() { + let back_prec = PRECIDENCE + .iter() + .find_map(|(op, weight, _)| { + if op == &op_back.0 { + Some(*weight) + } else { + None + } }) + .unwrap_or(1); + if back_prec > prec || (back_prec == prec && left) { + let Some(op_back) = op_stack.pop() else { + unreachable!() + }; + output.push(ShuntingYardOptions::Op(op_back)); + } else { + op_stack.push((op_ident.clone(), loc)); + break; } - None => unreachable!(), - }; - value.push(next); - } else { - value.push(c); + } + if op_stack.last().is_none() { + op_stack.push((op_ident, loc)); + } } } - Ok(ast::Expr::StringLiteral(value)) - } - Token::Integer(is_neg, value) | Token::FloatingPoint(is_neg, value) => { - Ok(Expr::NumericLiteral { - value: if is_neg { - "-".to_owned() + &value - } else { - value - }, - }) } - Token::True => Ok(Expr::BoolLiteral(true, span)), - Token::False => Ok(Expr::BoolLiteral(false, span)), - _ => Err(ParseError { - span, - reason: ParseErrorReason::UnknownError, - }), - } -} -fn type_from_string(name: &str, generics: Vec, loc: crate::Location) -> ResolvedType { - match name { - "str" => types::STR, - "char" => types::CHAR, - "bool" => types::BOOL, - ty if ty.starts_with("int") => { - let size = ty.strip_prefix("int"); - match size { - Some("8") => types::INT8, - Some("16") => types::INT16, - Some("32") => types::INT32, - Some("64") => types::INT64, - _ => ResolvedType::User { - name: ty.to_string(), - generics: Vec::new(), - loc, - }, + output.extend(op_stack.into_iter().rev().map(ShuntingYardOptions::Op)); + let mut final_expr = Vec::new(); + for expr in output { + match expr { + ShuntingYardOptions::Expr(expr) => final_expr.push(expr), + ShuntingYardOptions::Op((op, loc)) => { + let Some(rhs) = final_expr.pop() else { + unreachable!() + }; + let Some(lhs) = final_expr.pop() else { + unreachable!() + }; + final_expr.push(ast::Expr::BinaryOpCall(ast::BinaryOpCall { + loc, + operator: op, + lhs: lhs.into(), + rhs: rhs.into(), + })); + } } } - ty if ty.starts_with("float") => { - let size = ty.strip_prefix("float"); - match size { - Some("32") => types::FLOAT32, - Some("64") => types::FLOAT64, - _ => ResolvedType::User { - name: ty.to_string(), - generics: Vec::new(), - loc, - }, - } + if final_expr.len() == 1 { + Ok(final_expr.pop().unwrap()) + } else { + Err(ErrMode::Cut(ContextError::new().add_context( + input, + &input.checkpoint(), + winnow::error::StrContext::Label("Incomplete binary op expression"), + ))) } - _ => ResolvedType::User { - name: name.to_string(), - generics, - loc, - }, + } else { + Ok(out) } + }).parse_next(input) } -#[allow(unused)] -// TODO use for generating [`crate::ast::Expr::PipeExpr`] -fn is_pipe_op(op: &str) -> bool { - op.ends_with('>') && op[..op.len() - 2].chars().all(|c| c == '|') + +fn match_(input: &mut Stream<'_>) -> PResult { + let loc = "match" + .span() + .map(|loc| (loc.start, loc.end)) + .parse_next(input)?; + let on = combinator::delimited(ascii::multispace1, expr, (ascii::multispace1, "where")) + .parse_next(input)?; + let _spaces = ascii::space0(input)?; + let arms = if ascii::line_ending::<_, ErrMode>(input).is_ok() { + input.state.multi_line_expr=true; + // on another line. + let prefix = input.state.prefix.clone(); + let checkpoint = input.checkpoint(); + let new_prefix = ascii::space0(input)?; + input.reset(&checkpoint); + input.state.prefix = new_prefix.into(); + let arms = combinator::repeat(1.., combinator::preceded(new_prefix, arm)) + .parse_next(input)?; + input.state.prefix = prefix; + arms + } else { + // on same line. + todo!() + }; + Ok(ast::Match { + loc, + on: on.into(), + arms, + }) } -enum ShuntingYardOptions { - Expr((ast::Expr, crate::Location)), - Op((String, crate::Location)), +fn arm(input: &mut Stream<'_>) -> PResult { + combinator::trace("match arm",|input: &mut Stream<'_>| { + + let (loc, _, pat) = ("|".span(), ascii::space0.void(), pattern).parse_next(input)?; + let block = combinator::preceded( + (ascii::space0, "->", ascii::space0), + combinator::alt(( + combinator::preceded((ascii::space0, ascii::line_ending), block), + combinator::terminated( + expr, + (ascii::space0, ',', ascii::space0, ascii::line_ending), + ) + .map(|expr| ast::Block { + statements: Vec::new(), + implicit_ret: Some(expr.into()), + }), + )), + ) + .parse_next(input)?; + Ok(ast::MatchArm { + block, + cond: pat, + loc: (loc.start, loc.end), + }) + }).parse_next(input) } -impl std::fmt::Debug for ShuntingYardOptions { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Self::Expr(arg0) => f.debug_tuple("Expr").field(&arg0.0).finish(), - Self::Op(arg0) => f.debug_tuple("Op").field(&arg0.0).finish(), + +fn pattern(input: &mut Stream<'_>) -> PResult { + combinator::trace("pattern", |input: &mut Stream<'_>| { + let base = combinator::alt(( + // axioms + "_".map(|_| ast::Pattern::Default), + ascii::dec_int.map(|it: i128| ast::Pattern::ConstNumber(it.to_string())), + ascii::float.map(|it: f64| ast::Pattern::ConstNumber(it.to_string())), + "true".map(|_| ast::Pattern::ConstBool(true)), + "false".map(|_| ast::Pattern::ConstBool(false)), + string_lit.map(ast::Pattern::ConstStr), + char_lit.map(ast::Pattern::ConstChar), + combinator::separated_pair( + ident.with_span(), + ascii::space1, + pattern + ).map(|((ident,span),pat)| { + let (ty, variant) = if let Some((ty,variant)) = ident.rsplit_once("::") { + (Some(ty.into()),variant.into()) + } else { + (None,ident) + }; + ast::Pattern::EnumVariant { ty, variant, pattern: Some(pat.into()), loc: (span.start,span.end) } + }), + // todo struct destructureing + ( + ident, + combinator::delimited( + (ascii::space0, '{', ascii::multispace0), + combinator::separated( + 0.., + combinator::alt(( + combinator::separated_pair( + simple_ident.map(Into::into), + (ascii::space0, ':', ascii::space0), + combinator::cut_err(pattern), + ), + simple_ident.with_span().map(|(ident, span)| { + ( + ident.clone().into(), + ast::Pattern::Read(ident.into(), (span.start, span.end)), + ) + }), + )), + (ascii::multispace0, ',', ascii::multispace0), + ), + (ascii::multispace0, '}'), + ), + ) + .map(|(ident, fields)| { + ast::Pattern::Destructure(ast::PatternDestructure::Struct { + base_ty: Some(ident), + fields, + }) + }), + ident.with_span().verify(|(it,_)| it.contains("::")).map(|(ident,span)| { + let Some((ty,variant)) = ident.rsplit_once("::") else {unreachable!()}; + ast::Pattern::EnumVariant { ty: Some(ty.into()), variant: variant.into(), pattern:None, loc: (span.start,span.end) } + }), + simple_ident + .with_span() + .map(|(ident, loc)| ast::Pattern::Read(ident.into(), (loc.start, loc.end))), + // more complex + parens(combinator::separated( + 2.., + pattern, + (ascii::space0, ',', ascii::space0), + )) + .map(|contents| ast::Pattern::Destructure(ast::PatternDestructure::Tuple(contents))), + parens(pattern), + )) + .parse_next(input)?; + if let Some(rhs) = combinator::opt(combinator::preceded( + (ascii::space0, "|", ascii::space0), + pattern, + )) + .parse_next(input)? + { + Ok(ast::Pattern::Or(base.into(), rhs.into())) + } else { + Ok(base) } - } + }) + .parse_next(input) } +const KEYWORDS: &[&'static str] = &[ + "for", + "let", + "true", + "false", + "type", + "mod", + "implements", + "enum", + "return", + "where", + "if", + "then", + "else", +]; #[cfg(test)] mod tests { - use crate::{ - ast::{ - ArgDeclaration, EnumDeclaration, EnumVariant, IfBranching, IfExpr, MatchArm, - StructDefinition, TopLevelDeclaration, - }, - types::ResolvedType, - }; + use std::collections::HashMap; + + use super::*; use pretty_assertions::assert_eq; + use winnow::error::InputError; + + fn from_source(src: &'static str) -> Stream<'static> { + Stateful { + input:Located::new(StrippedParser { + src, + + state: Default::default(), + }), + + state: Default::default(), + } + } #[test] - fn types() { - assert_eq!( - Parser::from_source("int64").collect_type().ast, - types::INT64 - ); - assert_eq!( - Parser::from_source("int32").collect_type().ast, - types::INT32 - ); + fn if_statements() { + let mut src = from_source(r#" +if a then + return 0;"#); + ignore_blank_lines(&mut src).unwrap(); assert_eq!( - Parser::from_source("int16").collect_type().ast, - types::INT16 - ); - assert_eq!(Parser::from_source("int8").collect_type().ast, types::INT8); - assert_eq!(Parser::from_source("str").collect_type().ast, types::STR); - assert_eq!(Parser::from_source("char").collect_type().ast, types::CHAR); - assert_eq!( - Parser::from_source("float64").collect_type().ast, - types::FLOAT64 - ); - assert_eq!( - Parser::from_source("float32").collect_type().ast, - types::FLOAT32 - ); - assert_eq!(Parser::from_source("()").collect_type().ast, types::UNIT); + Ok(ast::If { + loc: (1,3), + cond: ast::Expr::ValueRead("a".into(), (4,5)).into(), + true_branch: ast::Block { + statements:vec![ + ast::Statement::Return(ast::Expr::NumericLiteral { value: "0".into() }, (15,21)), + ], + implicit_ret:None, + }, + else_branch: None, + }), + if_statement(&mut src), + ) + } + + #[test] + #[ignore = "for debuging small test cases"] + fn debugging() { + let mut src = from_source(r#"if a then 0 else 1;"#); + + let x = expr(&mut src); + println!("{x:#?}"); + // println!("{src}"); + assert!(false); + } + #[test] + fn type_parsing() { + use types::ResolvedType; + let mut src = from_source("int64"); + assert_eq!(type_(&mut src).unwrap(), types::INT64); + let mut src = from_source("int32"); + assert_eq!(type_(&mut src).unwrap(), types::INT32); + let mut src = from_source("int16"); + assert_eq!(type_(&mut src).unwrap(), types::INT16); + let mut src = from_source("int8"); + assert_eq!(type_(&mut src).unwrap(), types::INT8); + let mut src = from_source("str"); + assert_eq!(type_(&mut src).unwrap(), types::STR); + let mut src = from_source("char"); + assert_eq!(type_(&mut src).unwrap(), types::CHAR); + let mut src = from_source("float64"); + assert_eq!(type_(&mut src).unwrap(), types::FLOAT64); + let mut src = from_source("float32"); + assert_eq!(type_(&mut src).unwrap(), types::FLOAT32); + let mut src = from_source("()"); + assert_eq!(type_(&mut src).unwrap(), types::UNIT); + let mut src = from_source("[int32;5]"); assert_eq!( - Parser::from_source("[int32;5]").collect_type().ast, + type_(&mut src).unwrap(), ResolvedType::Array { underlining: types::INT32.into(), size: 5 } ); + let mut src = from_source("(int32,int32)"); + assert_eq!( + type_(&mut src), + Ok(ResolvedType::Tuple { + underlining: vec![types::INT32, types::INT32], + loc: (0, 0) + }) + ); + //fuctions + let mut src = from_source("int32->int32"); assert_eq!( - Parser::from_source("int32->int32").collect_type().ast, + type_(&mut src).unwrap(), ResolvedType::Function { arg: types::INT32.into(), returns: types::INT32.into(), loc: (0, 0), } ); + let mut src = from_source("int32->int32->int32"); assert_eq!( - Parser::from_source("int32->int32->int32") - .collect_type() - .ast, + type_(&mut src).unwrap(), ResolvedType::Function { arg: types::INT32.into(), returns: ResolvedType::Function { @@ -4021,368 +1493,127 @@ mod tests { loc: (0, 0), } ); + let mut src = from_source("int32->(int32->int32)"); assert_eq!( - Parser::from_source("int32->(int32->int32)") - .collect_type() - .ast, + type_(&mut src).unwrap(), ResolvedType::Function { arg: types::INT32.into(), returns: ResolvedType::Function { - arg: types::INT32.into(), - returns: types::INT32.into(), - loc: (0, 0), - } - .into(), - loc: (0, 0), - } - ); - assert_eq!( - Parser::from_source("(int32->int32)->int32") - .collect_type() - .ast, - ResolvedType::Function { - arg: ResolvedType::Function { - arg: types::INT32.into(), - returns: types::INT32.into(), - loc: (0, 0), - } - .into(), - returns: types::INT32.into(), - loc: (0, 0), - } - ); - } - - use super::*; - #[test] - #[ignore = "This is for singled out tests"] - fn for_debugging_only() { - let mut parser = Parser::from_source( - "enum Testing = | One (int8,int8) | Two -let fun test = match test where -| Testing::One (0,1) -> 0, -| Testing::One ((1|0),a) -> a, -| Testing::One _ -> -1, -| Testing::Two -> -2, ", - ); - let module = parser.module("".to_string()); - println!("{module:#?}") - } - #[test] - fn individual_simple_expressions() { - let mut parser = Parser::from_source("let foo : int32 = 5;"); - - assert_eq!( - Statement::Declaration(ValueDeclaration { - loc: (0, 4), - is_op: false, - target: ast::Pattern::Read("foo".to_owned(), (0, 4)), - ty: Some(types::INT32), - args: Vec::new(), - value: ValueType::Expr(Expr::NumericLiteral { - value: "5".to_string(), - }), - generictypes: None, - abi: None - }), - parser.next_statement().ast - ); - let mut parser = Parser::from_source( - r#"let foo _ : int32 -> int32 = - return 5; -"#, - ); - assert_eq!( - ast::TopLevelDeclaration::Value(TopLevelValue { - loc: (0, 4), - is_op: false, - ident: "foo".to_owned(), - ty: Some(ResolvedType::Function { - arg: types::INT32.into(), - returns: types::INT32.into(), - loc: (0, 18) - }), - args: vec![ArgDeclaration::Discard { - ty: None, - loc: (0, 8) - }], - value: ValueType::Function(vec![Statement::Return( - Expr::NumericLiteral { - value: "5".to_string(), - }, - (1, 4) - )]), - generics: None, - abi: None, - }), - parser.next_toplevel().ast - ) - } - - #[test] - fn higher_kinded() { - const ARG: &'static str = r#" -let foo _ : ( int32 -> int32 ) -> int32 = - return 0; -"#; - let mut parser = Parser::from_source(ARG); - assert_eq!( - Statement::Declaration(ValueDeclaration { - loc: (1, 4), - is_op: false, - target: ast::Pattern::Read("foo".to_owned(), (1, 4)), - ty: Some(ResolvedType::Function { - arg: ResolvedType::Function { - arg: types::INT32.into(), - returns: types::INT32.into(), - loc: (1, 20) - } - .into(), + arg: types::INT32.into(), returns: types::INT32.into(), - loc: (1, 31) - }), - args: vec![ast::ArgDeclaration::Discard { - ty: None, - loc: (1, 8) - }], - value: ValueType::Function(vec![Statement::Return( - Expr::NumericLiteral { - value: "0".to_string(), - }, - (2, 4) - )]), - generictypes: None, - abi: None, - }), - parser.next_statement().ast, - "function as arg" + loc: (0, 0), + } + .into(), + loc: (0, 0), + } ); - const RT: &'static str = r#" -let foo _ : int32 -> ( int32 -> int32 ) = - return 0; -"#; - let mut parser = Parser::from_source(RT); + let mut src = from_source("(int32->int32)->int32"); assert_eq!( - Statement::Declaration(ValueDeclaration { - loc: (1, 4), - is_op: false, - target: ast::Pattern::Read("foo".to_owned(), (1, 4)), - ty: Some(ResolvedType::Function { + type_(&mut src).unwrap(), + ResolvedType::Function { + arg: ResolvedType::Function { arg: types::INT32.into(), - returns: ResolvedType::Function { - arg: types::INT32.into(), - returns: types::INT32.into(), - loc: (1, 29) - } - .into(), - loc: (1, 18) - }), - args: vec![ast::ArgDeclaration::Discard { - ty: None, - loc: (1, 8) - }], - value: ValueType::Function(vec![Statement::Return( - Expr::NumericLiteral { - value: "0".to_owned(), - }, - (2, 4) - )]), - generictypes: None, - abi: None, - }), - parser.next_statement().ast, - "function as rt" + returns: types::INT32.into(), + loc: (0, 0), + } + .into(), + returns: types::INT32.into(), + loc: (0, 0), + } ); + let mut src = from_source("Generic"); + assert_eq!( + type_(&mut src).unwrap(), + ResolvedType::User{ + name: "Generic".into(), + generics: vec![types::INT32], + loc: (0,0), + } + ) } #[test] - fn multiple_statements() { - const SRC: &'static str = include_str!("../../samples/test.fb"); - let mut parser = Parser::from_source(SRC); + fn expressions() { + let mut src = from_source("1"); assert_eq!( - ast::TopLevelDeclaration::Value(TopLevelValue { - loc: (0, 4), - is_op: false, - ident: "foo".to_owned(), - ty: Some(types::INT32), - args: Vec::new(), - value: ValueType::Expr(Expr::NumericLiteral { - value: "3".to_owned(), - }), - generics: None, - abi: None, - }), - parser.next_toplevel().ast, - "simple declaration" + ast::Expr::NumericLiteral { value: "1".into() }, + expr(&mut src).unwrap() ); + let mut src = from_source("a"); + + let read_a = expr(&mut src).unwrap(); + assert_eq!(ast::Expr::ValueRead("a".into(), (0, 1)), read_a); + + let mut src = from_source("(a)"); assert_eq!( - ast::TopLevelDeclaration::Value(TopLevelValue { - loc: (2, 4), - is_op: false, - ident: "bar".to_owned(), - ty: Some(ResolvedType::Function { - arg: types::INT32.into(), - returns: types::INT32.into(), - loc: (2, 20) - }), - args: vec![ast::ArgDeclaration::Simple { - ident: "quz".to_string(), - loc: (2, 8), - ty: None, - }], - value: ValueType::Function(vec![ - Statement::Declaration(ValueDeclaration { - loc: (3, 8), - is_op: false, - target: Pattern::Read("baz".to_owned(), (3, 8)), - ty: Some(types::STR), - args: Vec::new(), - value: ValueType::Expr(Expr::StringLiteral(r#"merp " yes"#.to_string())), - generictypes: None, - abi: None, - }), - Statement::Return( - Expr::NumericLiteral { - value: "2".to_owned(), - }, - (4, 4) - ) - ]), - generics: None, - abi: None, - }), - parser.next_toplevel().ast, - "declaration with block" + expr(&mut src).unwrap(), + ast::Expr::ValueRead("a".into(), (1, 2)), + "`(a)` should be the same `a`" ); - assert_eq!( - ast::TopLevelDeclaration::Value(TopLevelValue { - loc: (6, 4), - is_op: true, - ident: "^^".to_owned(), - ty: Some(ResolvedType::Function { - arg: types::INT32.into(), - returns: ResolvedType::Function { - arg: types::INT32.into(), - returns: types::INT32.into(), - loc: (6, 32) - } - .into(), - loc: (6, 23) - }), - args: vec![ - ast::ArgDeclaration::Simple { - ident: "lhs".to_string(), - loc: (6, 7), - ty: None, - }, - ast::ArgDeclaration::Simple { - ident: "rhs".to_string(), - loc: (6, 11), - ty: None, - }, - ], - value: ValueType::Function(vec![ - Statement::FnCall(FnCall { - loc: (7, 4), - value: Expr::ValueRead("bar".to_string(), (7, 4)).into(), - arg: Some(Expr::ValueRead("foo".to_string(), (7, 8)).into()), - }), - Statement::Return( - Expr::NumericLiteral { - value: "1".to_owned(), - }, - (8, 4) - ) - ]), - generics: None, - abi: None, - }), - parser.next_toplevel().ast, - "operator declaration w/ function call", + let mut src = from_source(r#""merp\"\\""#); + assert_eq!( + r#"merp"\"#, + string_lit(&mut src).unwrap(), + "string literal with escapes" ); - } - #[test] - fn fn_chain() { - const SRC: &'static str = r#" -let main _ : int32 -> int32 = - put_int32 100; - print_str "v"; - return 32; -"#; - let mut parser = Parser::from_source(SRC); + let mut src = from_source("a b c"); assert_eq!( - Statement::Declaration(ValueDeclaration { - loc: (1, 4), - is_op: false, + expr(&mut src), + Ok(ast::Expr::FnCall(ast::FnCall{ + loc: (0,1), + value: ast::Expr::FnCall(ast::FnCall{ + loc: (0,1), + value: ast::Expr::ValueRead("a".into(), (0,1)).into(), + arg: Some(ast::Expr::ValueRead("b".into(), (2,3)).into()) + }).into(), + arg: Some(ast::Expr::ValueRead("c".into(), (4,5)).into()) + })) + ); - target: Pattern::Read("main".to_owned(), (1, 4)), - ty: Some(ResolvedType::Function { - arg: types::INT32.into(), - returns: types::INT32.into(), - loc: (1, 19) - }), - args: vec![ast::ArgDeclaration::Discard { - ty: None, - loc: (1, 9) - }], - value: ValueType::Function(vec![ - Statement::FnCall(FnCall { - loc: (2, 4), - value: Expr::ValueRead("put_int32".to_string(), (2, 4)).into(), - arg: Some( - Expr::NumericLiteral { - value: "100".to_owned(), - } - .into() - ) - }), - Statement::FnCall(FnCall { - loc: (3, 4), - value: Expr::ValueRead("print_str".to_string(), (3, 4)).into(), - arg: Some(Expr::StringLiteral("v".to_string()).into()) - }), - Statement::Return( - Expr::NumericLiteral { - value: "32".to_string(), - }, - (4, 4) - ) - ]), - generictypes: None, - abi: None, - }), - parser.next_statement().ast, - ) - } + let mut src = from_source("a (b c)"); + assert_eq!( + expr(&mut src), + Ok(ast::Expr::FnCall(ast::FnCall{ + loc: (0,1), + value: ast::Expr::ValueRead("a".into(), (0,1)).into(), + arg: Some(ast::Expr::FnCall(ast::FnCall{ + loc: (3,4), + value: (ast::Expr::ValueRead("b".into(), (3,4)).into()), + arg: Some(ast::Expr::ValueRead("c".into(), (5,6)).into()) + }).into()), + })) + ); + } #[test] fn ops() { + use ast::*; const SRC_S: &'static str = "100 + 100 * foo * ( 10 - 1 )"; - let mut parser = Parser::from_source(SRC_S); + let mut parser = from_source(SRC_S); assert_eq!( Expr::BinaryOpCall(BinaryOpCall { - loc: (0, 4), + loc: (4, 5), lhs: Expr::NumericLiteral { value: "100".to_string(), } .into(), rhs: Expr::BinaryOpCall(BinaryOpCall { - loc: (0, 16), + loc: (16, 17), lhs: Expr::BinaryOpCall(BinaryOpCall { - loc: (0, 10), + loc: (10, 11), lhs: Expr::NumericLiteral { value: "100".to_string(), } .into(), - rhs: Expr::ValueRead("foo".to_string(), (0, 12)).into(), + rhs: Expr::ValueRead("foo".to_string(), (12, 15)).into(), operator: "*".to_string() }) .into(), rhs: Expr::BinaryOpCall(BinaryOpCall { - loc: (0, 23), + loc: (23, 24), lhs: Expr::NumericLiteral { value: "10".to_string(), } @@ -4399,66 +1630,70 @@ let main _ : int32 -> int32 = .into(), operator: "+".to_string() }), - parser.next_expr().ast + expr(&mut parser).unwrap() ); const SRC: &'static str = r#"let main _ = - print_int32 100 + 100; - return 0;"#; - let mut parser = Parser::from_source(SRC); + print_int32 (100 + 100); + return 0; +"#; + let mut parser = from_source(SRC); assert_eq!( - Statement::Declaration(ValueDeclaration { - loc: (0, 4), + TopLevelValue { + loc: (4, 8), is_op: false, - target: Pattern::Read("main".to_owned(), (0, 4)), + ident: "main".to_owned(), ty: None, args: vec![ast::ArgDeclaration::Discard { ty: None, - loc: (0, 9) + loc: (9, 10) }], - value: ValueType::Function(vec![ - Statement::FnCall(FnCall { - loc: (1, 4), - value: Expr::ValueRead("print_int32".to_owned(), (1, 4)).into(), - arg: Some( - Expr::BinaryOpCall(BinaryOpCall { - loc: (1, 20), - operator: "+".to_owned(), - lhs: Expr::NumericLiteral { - value: "100".to_owned(), - } - .into(), - rhs: Expr::NumericLiteral { - value: "100".to_owned(), - } + value: ValueType::Function(Block { + statements: vec![ + Statement::Expr(Expr::FnCall(FnCall { + loc: (17, 28), + value: Expr::ValueRead("print_int32".to_owned(), (17, 28)).into(), + arg: Some( + Expr::BinaryOpCall(BinaryOpCall { + loc: (34, 35), + operator: "+".to_owned(), + lhs: Expr::NumericLiteral { + value: "100".to_owned(), + } + .into(), + rhs: Expr::NumericLiteral { + value: "100".to_owned(), + } + .into() + }) .into() - }) - .into() + ) + })), + Statement::Return( + Expr::NumericLiteral { + value: "0".to_owned(), + }, + (46, 52) ) - }), - Statement::Return( - Expr::NumericLiteral { - value: "0".to_owned(), - }, - (2, 4) - ) - ]), - generictypes: None, + ], + implicit_ret: None + }), + generics: None, abi: None, - }), - parser.next_statement().ast + }, + top_level_value(&mut parser).unwrap() ); //a b . 2 + c d . - const SRC_MEMBER_ACCESS: &'static str = "a.b + 2 - c.d"; - let mut parser = Parser::from_source(SRC_MEMBER_ACCESS); + let mut parser = from_source(SRC_MEMBER_ACCESS); assert_eq!( ast::Expr::BinaryOpCall(BinaryOpCall { - loc: (0, 8), + loc: (8, 9), lhs: ast::Expr::BinaryOpCall(BinaryOpCall { - loc: (0, 4), + loc: (4, 5), lhs: ast::Expr::BinaryOpCall(BinaryOpCall { - loc: (0, 1), - lhs: ast::Expr::ValueRead("a".to_string(), (0, 0)).into(), - rhs: ast::Expr::ValueRead("b".to_string(), (0, 2)).into(), + loc: (1, 2), + lhs: ast::Expr::ValueRead("a".to_string(), (0, 1)).into(), + rhs: ast::Expr::ValueRead("b".to_string(), (2, 3)).into(), operator: ".".to_string() }) .into(), @@ -4470,74 +1705,275 @@ let main _ : int32 -> int32 = }) .into(), rhs: ast::Expr::BinaryOpCall(BinaryOpCall { - loc: (0, 11), - lhs: ast::Expr::ValueRead("c".to_string(), (0, 10)).into(), - rhs: ast::Expr::ValueRead("d".to_string(), (0, 12)).into(), + loc: (11, 12), + lhs: ast::Expr::ValueRead("c".to_string(), (10, 11)).into(), + rhs: ast::Expr::ValueRead("d".to_string(), (12, 13)).into(), operator: ".".to_string() }) .into(), operator: "-".to_string() }), - parser.next_expr().ast, + expr(&mut parser).unwrap(), ); - let mut parser = Parser::from_source("(foo bar) && (baz quz)"); + let mut parser = from_source("(foo bar) && (baz quz)"); assert_eq!( ast::Expr::BinaryOpCall(BinaryOpCall { - loc: (0, 10), + loc: (10, 12), lhs: ast::Expr::FnCall(FnCall { - loc: (0, 1), - value: ast::Expr::ValueRead("foo".to_string(), (0, 1)).into(), - arg: Some(ast::Expr::ValueRead("bar".to_string(), (0, 5)).into()) + loc: (1, 4), + value: ast::Expr::ValueRead("foo".to_string(), (1, 4)).into(), + arg: Some(ast::Expr::ValueRead("bar".to_string(), (5, 8)).into()) }) .into(), rhs: ast::Expr::FnCall(FnCall { - loc: (0, 14), - value: ast::Expr::ValueRead("baz".to_string(), (0, 14)).into(), - arg: Some(ast::Expr::ValueRead("quz".to_string(), (0, 18)).into()) + loc: (14, 17), + value: ast::Expr::ValueRead("baz".to_string(), (14, 17)).into(), + arg: Some(ast::Expr::ValueRead("quz".to_string(), (18, 21)).into()) }) .into(), operator: "&&".to_string() }), - parser.next_expr().ast, + expr(&mut parser).unwrap(), "(foo bar) && (baz quz)" ); } + #[test] + fn block_() { + let mut src = from_source( + r" + let x = 0; + x", + ); + ignore_blank_lines(&mut src).unwrap(); + assert_eq!( + block(&mut src).unwrap(), + ast::Block { + statements: vec![ast::Statement::Declaration(ast::ValueDeclaration { + loc: (9, 10), + is_op: false, + target: ast::Pattern::Read("x".into(), (9, 10)), + args: Vec::new(), + ty: None, + value: ast::ValueType::Expr(ast::Expr::NumericLiteral { value: "0".into() }), + generictypes: None, + abi: None + }),], + implicit_ret: Some(ast::Expr::ValueRead("x".into(), (20, 21)).into()) + } + ) + } + + #[test] + fn statements() { + const SRC: &'static str = include_str!("../../samples/test.fb"); + let mut input = from_source(SRC); + assert_eq!( + ast::TopLevelValue { + loc: (4, 7), + is_op: false, + ident: "foo".to_owned(), + ty: Some(types::INT32), + args: Vec::new(), + value: ast::ValueType::Expr(ast::Expr::NumericLiteral { + value: "3".to_owned(), + }), + generics: None, + abi: None, + }, + top_level_value(&mut input).unwrap(), + "simple declaration" + ); + ignore_blank_lines(&mut input).unwrap(); + assert_eq!( + ast::TopLevelValue { + loc: (26, 29), + is_op: false, + ident: "bar".to_owned(), + ty: Some(types::ResolvedType::Function { + arg: types::INT32.into(), + returns: types::INT32.into(), + loc: (2, 20) + }), + args: vec![ast::ArgDeclaration::Simple { + ident: "quz".to_string(), + loc: (30, 33), + ty: None, + }], + value: ast::ValueType::Function(ast::Block { + statements: vec![ + ast::Statement::Declaration(ast::ValueDeclaration { + loc: (62, 65), + is_op: false, + target: ast::Pattern::Read("baz".to_owned(), (62, 65)), + ty: Some(types::STR), + args: Vec::new(), + value: ast::ValueType::Expr(ast::Expr::StringLiteral( + r#"merp " yes"#.to_string() + )), + generictypes: None, + abi: None, + }), + ast::Statement::Return( + ast::Expr::NumericLiteral { + value: "2".to_owned(), + }, + (93, 99) + ) + ], + implicit_ret: None + }), + generics: None, + abi: None, + }, + top_level_value(&mut input).unwrap(), + "declaration with block" + ); + ignore_blank_lines(&mut input).unwrap(); + assert_eq!( + ast::TopLevelValue { + loc: (108, 112), + is_op: true, + + ident: "^^".to_owned(), + ty: Some(types::ResolvedType::Function { + arg: types::INT32.into(), + returns: types::ResolvedType::Function { + arg: types::INT32.into(), + returns: types::INT32.into(), + loc: (6, 32) + } + .into(), + loc: (6, 23) + }), + args: vec![ + ast::ArgDeclaration::Simple { + ident: "lhs".to_string(), + loc: (113, 116), + ty: None, + }, + ast::ArgDeclaration::Simple { + ident: "rhs".to_string(), + loc: (117, 120), + ty: None, + }, + ], + value: ast::ValueType::Function(ast::Block { + statements: vec![ + ast::Statement::Expr(ast::Expr::FnCall(ast::FnCall { + loc: (153, 156), + value: ast::Expr::ValueRead("bar".to_string(), (153, 156)).into(), + arg: Some(ast::Expr::ValueRead("foo".to_string(), (157, 160)).into()), + })), + ast::Statement::Return( + ast::Expr::NumericLiteral { + value: "1".to_owned(), + }, + (166, 172) + ) + ], + implicit_ret: None, + }), + generics: None, + abi: None, + }, + top_level_value(&mut input).unwrap(), + "operator declaration w/ function call", + ); + } + + #[test] + fn fn_chain() { + const SRC: &'static str = r#"let main _ : int32 -> int32 = + put_int32 100; + print_str "v"; + return 32; +"#; + let mut parser = from_source(SRC); + + assert_eq!( + ast::TopLevelValue { + loc: (4, 8), + is_op: false, + + ident: "main".to_owned(), + ty: Some(types::ResolvedType::Function { + arg: types::INT32.into(), + returns: types::INT32.into(), + loc: (19, 21) + }), + args: vec![ast::ArgDeclaration::Discard { + ty: None, + loc: (9, 10) + }], + value: ast::ValueType::Function(ast::Block { + statements: vec![ + ast::Statement::Expr(ast::Expr::FnCall(ast::FnCall { + loc: (35, 44), + value: ast::Expr::ValueRead("put_int32".to_string(), (35, 44)).into(), + arg: Some( + ast::Expr::NumericLiteral { + value: "100".to_owned(), + } + .into() + ) + })), + ast::Statement::Expr(ast::Expr::FnCall(ast::FnCall { + loc: (54, 63), + value: ast::Expr::ValueRead("print_str".to_string(), (54, 63)).into(), + arg: Some(ast::Expr::StringLiteral("v".to_string()).into()) + })), + ast::Statement::Return( + ast::Expr::NumericLiteral { + value: "32".to_string(), + }, + (73, 79) + ) + ], + implicit_ret: None + }), + generics: None, + abi: None, + }, + top_level_value(&mut parser).unwrap(), + ); + } + #[test] fn generics() { - let mut parser = Parser::from_source("for let test a : T -> T = a"); + let mut parser = from_source("for let test a : T -> T = a;"); assert_eq!( - ast::TopLevelDeclaration::Value(TopLevelValue { - loc: (0, 11), + ast::TopLevelValue { + loc: (11, 15), is_op: false, ident: "test".to_owned(), args: vec![ast::ArgDeclaration::Simple { - loc: (0, 16), + loc: (16, 17), ident: "a".to_string(), ty: None, }], - ty: Some(ResolvedType::Function { - arg: ResolvedType::Generic { + ty: Some(types::ResolvedType::Function { + arg: types::ResolvedType::Generic { name: "T".to_string(), - loc: (0, 20) + loc: (20, 21) } .into(), - returns: ResolvedType::Generic { + returns: types::ResolvedType::Generic { name: "T".to_string(), - loc: (0, 25) + loc: (25, 26) } .into(), - loc: (0, 22) + loc: (22, 24) }), - value: ast::ValueType::Expr(ast::Expr::ValueRead("a".to_string(), (0, 29))), + value: ast::ValueType::Expr(ast::Expr::ValueRead("a".to_string(), (29, 30))), generics: Some(ast::GenericsDecl { - for_loc: (0, 0), - decls: [((0, 4), "T".to_string())].into_iter().collect(), + for_loc: (0, 3), + decls: [((4, 5), "T".to_string())].into_iter().collect(), }), abi: None, - }), - parser.next_toplevel().ast, + }, + top_level_value(&mut parser).unwrap(), ) } @@ -4550,53 +1986,54 @@ for type Tuple = { first : T, second : U }"#; - let mut parser = Parser::from_source(SRC); + let mut parser = from_source(SRC); assert_eq!( ast::TopLevelDeclaration::TypeDefinition(ast::TypeDefinition::Struct( - StructDefinition { + ast::StructDefinition { ident: "Foo".to_string(), generics: None, values: vec![ast::FieldDecl { name: "a".to_string(), ty: types::INT32, - loc: (1, 4), + loc: (17, 18), }], - loc: (0, 5) + loc: (5, 8) }, )), - parser.next_toplevel().ast, + top_level_decl(&mut parser).unwrap(), "basic" ); + ignore_blank_lines(&mut parser).unwrap(); assert_eq!( ast::TopLevelDeclaration::TypeDefinition(ast::TypeDefinition::Struct( - StructDefinition { + ast::StructDefinition { ident: "Tuple".to_string(), generics: Some(ast::GenericsDecl { - for_loc: (3, 0), - decls: vec![((3, 4), "T".to_string()), ((3, 6), "U".to_string())], + for_loc: (29, 32), + decls: vec![((33, 34), "T".to_string()), ((35, 36), "U".to_string())], }), values: vec![ ast::FieldDecl { name: "first".to_string(), - ty: ResolvedType::Generic { + ty: types::ResolvedType::Generic { name: "T".to_string(), - loc: (4, 12), + loc: (65, 66), }, - loc: (4, 4) + loc: (57, 62) }, ast::FieldDecl { name: "second".to_string(), - ty: ResolvedType::Generic { + ty: types::ResolvedType::Generic { name: "U".to_string(), - loc: (5, 13) + loc: (81, 82) }, - loc: (5, 4) + loc: (72, 78) }, ], - loc: (3, 14) + loc: (43, 48) } )), - parser.next_toplevel().ast, + top_level_decl(&mut parser).unwrap(), "generic" ) } @@ -4604,774 +2041,124 @@ for type Tuple = { #[test] fn generic_use_types() { const SRC: &'static str = r"let foo a b : Bar -> Baz -> int32 = - return 0 + return 0; "; - let mut parser = Parser::from_source(SRC); + let mut parser = from_source(SRC); assert_eq!( - ast::TopLevelDeclaration::Value(TopLevelValue { - loc: (0, 4), + ast::TopLevelDeclaration::Value(ast::TopLevelValue { + loc: (4, 7), is_op: false, ident: "foo".to_owned(), - args: vec![ - ArgDeclaration::Simple { - loc: (0, 8), - ident: "a".to_string(), - ty: None, - }, - ArgDeclaration::Simple { - loc: (0, 10), - ident: "b".to_string(), - ty: None, - }, - ], - ty: Some(ResolvedType::Function { - arg: ResolvedType::User { - name: "Bar".to_string(), - generics: vec![types::INT32], - loc: (0, 14) - } - .into(), - returns: ResolvedType::Function { - arg: ResolvedType::User { - name: "Baz".to_string(), - generics: vec![types::INT32, types::FLOAT64], - loc: (0, 28) - } - .into(), - returns: types::INT32.into(), - loc: (0, 47) - } - .into(), - loc: (0, 25) - }), - value: ValueType::Function(vec![Statement::Return( - Expr::NumericLiteral { - value: "0".to_string(), - }, - (1, 4) - )]), - generics: None, - abi: None, - }), - parser.next_toplevel().ast - ) - } - - #[test] - fn struct_construction() { - const SRC: &'static str = "Foo { a : 0 }"; - let mut parser = Parser::from_source(SRC); - assert_eq!( - ast::Expr::StructConstruction(StructConstruction { - loc: (0, 4), - fields: HashMap::from([( - "a".to_string(), - ( - Expr::NumericLiteral { - value: "0".to_string(), - }, - (0, 6) - ) - )]), - generics: Vec::new(), - ident: "Foo".to_string() - }), - parser.next_expr().ast - ); - assert_eq!( - ast::Expr::StructConstruction(StructConstruction { - loc: (0, 14), - fields: HashMap::from([( - "a".to_string(), - ( - Expr::NumericLiteral { - value: "0".to_string(), - }, - (0, 16) - ) - )]), - generics: vec![types::INT32], - ident: "Generic".to_string() - }), - Parser::from_source("Generic{ a:0 }").next_expr().ast - ) - } - - #[test] - fn control_flow_if() { - let mut parser = Parser::from_source(include_str!("../../samples/control_flow_if.fb")); - assert_eq!( - ast::TopLevelDeclaration::Value(TopLevelValue { - loc: (0, 4), - is_op: false, - ident: "inline_expr".to_owned(), - args: vec![ast::ArgDeclaration::Simple { - ident: "a".to_string(), - loc: (0, 16), - ty: None, - }], - ty: Some(ResolvedType::Function { - arg: types::BOOL.into(), - returns: types::INT32.into(), - loc: (0, 25) - }), - value: ast::ValueType::Expr(ast::Expr::If(IfExpr { - cond: ast::Expr::ValueRead("a".to_string(), (0, 39)).into(), - true_branch: ( - Vec::new(), - ast::Expr::NumericLiteral { - value: "0".to_string(), - } - .into() - ), - else_ifs: Vec::new(), - else_branch: ( - Vec::new(), - ast::Expr::NumericLiteral { - value: "1".to_string(), - } - .into() - ), - loc: (0, 36) - })), - generics: None, - abi: None, - }), - parser.next_toplevel().ast, - "inline_expr" - ); - - assert_eq!( - ast::TopLevelDeclaration::Value(TopLevelValue { - loc: (2, 4), - is_op: false, - ident: "out_of_line_expr".to_owned(), - args: vec![ast::ArgDeclaration::Simple { - ident: "a".to_string(), - loc: (2, 21), - ty: None, - }], - ty: Some(ResolvedType::Function { - arg: types::BOOL.into(), - returns: types::INT32.into(), - loc: (2, 30) - }), - value: ast::ValueType::Expr(ast::Expr::If(IfExpr { - cond: ast::Expr::ValueRead("a".to_string(), (2, 44)).into(), - true_branch: ( - Vec::new(), - ast::Expr::FnCall(ast::FnCall { - loc: (3, 8), - value: ast::Expr::ValueRead("fun".to_string(), (3, 8)).into(), - arg: Some( - ast::Expr::NumericLiteral { - value: "0".to_string(), - } - .into() - ), - }) - .into() - ), - else_ifs: Vec::new(), - else_branch: ( - Vec::new(), - ast::Expr::NumericLiteral { - value: "1".to_string(), - } - .into() - ), - loc: (2, 41) - })), - generics: None, - abi: None, - }), - parser.next_toplevel().ast, - "out_of_line_expr" - ); - - assert_eq!( - ast::TopLevelDeclaration::Value(TopLevelValue { - loc: (7, 4), - is_op: false, - ident: "expr_with_statement".to_owned(), - args: vec![ast::ArgDeclaration::Simple { - loc: (7, 24), - ident: "a".to_string(), - ty: None, - }], - ty: Some(ResolvedType::Function { - arg: types::BOOL.into(), - returns: types::INT32.into(), - loc: (7, 33) - }), - value: ast::ValueType::Expr(ast::Expr::If(IfExpr { - cond: ast::Expr::ValueRead("a".to_string(), (7, 47)).into(), - true_branch: ( - vec![ast::Statement::FnCall(FnCall { - loc: (8, 8), - value: ast::Expr::ValueRead("bar".to_string(), (8, 8)).into(), - arg: Some( - ast::Expr::NumericLiteral { - value: "3".to_string(), - } - .into() - ), - })], - ast::Expr::NumericLiteral { - value: "0".to_string(), - } - .into() - ), - else_ifs: Vec::new(), - else_branch: ( - vec![ast::Statement::FnCall(FnCall { - loc: (11, 8), - value: ast::Expr::ValueRead("baz".to_string(), (11, 8)).into(), - arg: Some( - ast::Expr::NumericLiteral { - value: "4".to_string(), - } - .into() - ), - })], - ast::Expr::NumericLiteral { - value: "1".to_string(), - } - .into() - ), - loc: (7, 44) - })), - generics: None, - abi: None, - }), - parser.next_toplevel().ast, - "expr_with_statement" - ); - - assert_eq!( - ast::TopLevelDeclaration::Value(TopLevelValue { - loc: (14, 4), - is_op: false, - ident: "expr_with_else_if".to_owned(), - args: vec![ - ast::ArgDeclaration::Simple { - loc: (14, 22), - ident: "a".to_string(), - ty: None, - }, - ast::ArgDeclaration::Simple { - loc: (14, 24), - ident: "b".to_string(), - ty: None, - }, - ], - ty: Some(ResolvedType::Function { - arg: types::BOOL.into(), - returns: ResolvedType::Function { - arg: types::BOOL.into(), - returns: types::INT32.into(), - loc: (14, 41) - } - .into(), - loc: (14, 33) - }), - value: ValueType::Expr(ast::Expr::If(IfExpr { - cond: ast::Expr::ValueRead("a".to_string(), (14, 55)).into(), - true_branch: ( - Vec::new(), - ast::Expr::NumericLiteral { - value: "0".to_string(), - } - .into() - ), - else_ifs: vec![( - ast::Expr::ValueRead("b".to_string(), (14, 72)).into(), - Vec::new(), - ast::Expr::NumericLiteral { - value: "1".to_string(), - } - .into() - ),], - else_branch: ( - Vec::new(), - ast::Expr::NumericLiteral { - value: "2".to_string(), - } - .into() - ), - loc: (14, 52) - })), - generics: None, - abi: None, - }), - parser.next_toplevel().ast, - "expr with else if" - ); - - assert_eq!( - ast::TopLevelDeclaration::Value(TopLevelValue { - loc: (16, 4), - is_op: false, - ident: "statement".to_owned(), - args: vec![ast::ArgDeclaration::Simple { - loc: (16, 14), - ident: "a".to_string(), - ty: None, - }], - ty: Some(ResolvedType::Function { - arg: types::BOOL.into(), - returns: types::INT32.into(), - loc: (16, 23) - }), - value: ast::ValueType::Function(vec![ast::Statement::IfStatement(IfBranching { - cond: ast::Expr::ValueRead("a".to_string(), (17, 7)).into(), - true_branch: vec![ - ast::Statement::FnCall(FnCall { - loc: (18, 8), - value: ast::Expr::ValueRead("foo".to_string(), (18, 8)).into(), - arg: Some( - ast::Expr::NumericLiteral { - value: "3".to_string(), - } - .into() - ) - }), - ast::Statement::Return( - ast::Expr::NumericLiteral { - value: "0".to_string(), - }, - (19, 8) - ), - ], - else_ifs: Vec::new(), - else_branch: vec![ - ast::Statement::FnCall(FnCall { - loc: (21, 8), - value: ast::Expr::ValueRead("bar".to_string(), (21, 8)).into(), - arg: Some( - ast::Expr::NumericLiteral { - value: "4".to_string(), - } - .into() - ) - }), - ast::Statement::Return( - ast::Expr::NumericLiteral { - value: "1".to_string(), - }, - (22, 8) - ), - ], - loc: (17, 4) - })]), - generics: None, - abi: None, - }), - parser.next_toplevel().ast, - "statement" - ); - - assert_eq!( - ast::TopLevelDeclaration::Value(TopLevelValue { - loc: (24, 4), - is_op: false, - ident: "statement_with_else_if".to_owned(), args: vec![ ast::ArgDeclaration::Simple { - loc: (24, 27), + loc: (8, 9), ident: "a".to_string(), ty: None, }, ast::ArgDeclaration::Simple { - loc: (24, 29), + loc: (10, 11), ident: "b".to_string(), ty: None, }, ], - ty: Some(ResolvedType::Function { - arg: types::BOOL.into(), - returns: ResolvedType::Function { - arg: types::BOOL.into(), - returns: types::INT32.into(), - loc: (24, 46) + ty: Some(types::ResolvedType::Function { + arg: types::ResolvedType::User { + name: "Bar".to_string(), + generics: vec![types::INT32], + loc: (14, 25) } - .into(), - loc: (24, 38) - }), - value: ast::ValueType::Function(vec![ast::Statement::IfStatement(IfBranching { - cond: ast::Expr::ValueRead("a".to_string(), (25, 7)).into(), - true_branch: vec![ast::Statement::Return( - ast::Expr::NumericLiteral { - value: "0".to_string(), - }, - (26, 8) - )], - else_ifs: vec![( - ast::Expr::ValueRead("b".to_string(), (27, 12)).into(), - vec![ast::Statement::Return( - ast::Expr::NumericLiteral { - value: "1".to_string(), - }, - (28, 8) - )] - )], - else_branch: vec![ast::Statement::Return( - ast::Expr::NumericLiteral { - value: "2".to_string(), - }, - (30, 8) - )], - loc: (25, 4), - })]), - generics: None, - abi: None, - }), - parser.next_toplevel().ast, - "statement_with_else_if" - ); - - assert_eq!( - ast::TopLevelDeclaration::Value(TopLevelValue { - loc: (32, 4), - is_op: false, - ident: "expr_multi_with_elseif".to_owned(), - args: vec![ - ast::ArgDeclaration::Simple { - loc: (32, 27), - ident: "a".to_string(), - ty: None, - }, - ast::ArgDeclaration::Simple { - loc: (32, 29), - ident: "b".to_string(), - ty: None, - }, - ], - ty: Some(ResolvedType::Function { - arg: types::BOOL.into(), - returns: ResolvedType::Function { - arg: types::BOOL.into(), + .into(), + returns: types::ResolvedType::Function { + arg: types::ResolvedType::User { + name: "Baz".to_string(), + generics: vec![types::INT32, types::FLOAT64], + loc: (28, 47) + } + .into(), returns: types::INT32.into(), - loc: (32, 46) + loc: (47, 49) } .into(), - loc: (32, 38) + loc: (25, 27) }), - value: ValueType::Expr(ast::Expr::If(IfExpr { - cond: ast::Expr::ValueRead("a".to_string(), (32, 60)).into(), - true_branch: ( - Vec::new(), + value: ast::ValueType::Function(ast::Block { + statements: vec![ast::Statement::Return( ast::Expr::NumericLiteral { value: "0".to_string(), - } - .into(), - ), - else_ifs: vec![( - ast::Expr::ValueRead("b".to_string(), (34, 12)).into(), - Vec::new(), - ast::Expr::NumericLiteral { - value: "1".to_string(), - } - .into(), + }, + (62, 68) )], - else_branch: ( - Vec::new(), - ast::Expr::NumericLiteral { - value: "2".to_string(), - } - .into(), - ), - loc: (32, 57) - })), + implicit_ret: None + }), generics: None, abi: None, }), - parser.next_toplevel().ast, - "multi line expr with else if" + top_level_decl(&mut parser).unwrap() ); } #[test] - fn control_flow_match() { - let mut parser = Parser::from_source(include_str!("../../samples/control_flow_match.fb")); - assert_eq!( - ast::TopLevelDeclaration::Value(TopLevelValue { - loc: (0, 4), - is_op: false, - ident: "match_expr_ints".to_owned(), - args: vec![ast::ArgDeclaration::Simple { - loc: (0, 20), - ident: "x".to_string(), - ty: None, - }], - ty: Some(ResolvedType::Function { - arg: types::INT32.into(), - returns: types::INT32.into(), - loc: (0, 30) - }), - value: ast::ValueType::Expr(ast::Expr::Match(Match { - loc: (0, 41), - on: ast::Expr::ValueRead("x".to_string(), (0, 47)).into(), - arms: vec![ - MatchArm { - block: Vec::new(), - ret: Some( - ast::Expr::NumericLiteral { - value: "1".to_string(), - } - .into() - ), - cond: Pattern::ConstNumber("1".to_string()), - loc: (1, 6) - }, - MatchArm { - block: Vec::new(), - ret: Some( - ast::Expr::NumericLiteral { - value: "3".to_string(), - } - .into() - ), - cond: Pattern::ConstNumber("2".to_string()), - loc: (2, 6) - }, - MatchArm { - block: Vec::new(), - ret: Some( - ast::Expr::NumericLiteral { - value: "4".to_string(), - } - .into() - ), - cond: Pattern::Default, - loc: (3, 6) - }, - ] - })), - generics: None, - abi: None, - }), - parser.next_toplevel().ast, - "match_expr_ints" - ); - - assert_eq!( - ast::TopLevelDeclaration::Value(TopLevelValue { - loc: (5, 4), - is_op: false, - ident: "match_expr_with_block".to_owned(), - args: vec![ArgDeclaration::Simple { - loc: (5, 26), - ident: "x".to_string(), - ty: None, - },], - ty: Some(ResolvedType::Function { - arg: types::INT32.into(), - returns: types::INT32.into(), - loc: (5, 36) - }), - value: ValueType::Expr(ast::Expr::Match(Match { - loc: (5, 47), - on: ast::Expr::ValueRead("x".to_string(), (5, 53)).into(), - arms: vec![ - MatchArm { - loc: (6, 6), - block: vec![ast::Statement::Declaration(ValueDeclaration { - loc: (7, 12), - is_op: false, - target: Pattern::Read("a".to_owned(), (7, 12)), - args: Vec::new(), - ty: Some(types::INT32), - value: ValueType::Expr(ast::Expr::NumericLiteral { - value: "2".to_string(), - }), - generictypes: None, - abi: None, - })], - ret: Some( - ast::Expr::BinaryOpCall(BinaryOpCall { - loc: (8, 9), - lhs: ast::Expr::ValueRead("a".to_string(), (8, 8)).into(), - rhs: ast::Expr::NumericLiteral { - value: "3".to_string(), - } - .into(), - operator: "*".to_string() - }) - .into() - ), - cond: Pattern::ConstNumber("1".to_string()), - }, - MatchArm { - block: Vec::new(), - ret: Some( - ast::Expr::NumericLiteral { - value: "2".to_string(), - } - .into() - ), - cond: Pattern::ConstNumber("2".to_string()), - loc: (9, 6) - }, - MatchArm { - loc: (10, 6), - block: Vec::new(), - ret: Some( - ast::Expr::BinaryOpCall(BinaryOpCall { - loc: (10, 12), - lhs: ast::Expr::ValueRead("a".to_string(), (10, 11)).into(), - rhs: ast::Expr::NumericLiteral { - value: "2".to_string(), - } - .into(), - operator: "/".to_string() - }) - .into() - ), - cond: Pattern::Read("a".to_string(), (10, 6)), - }, - ] - })), - generics: None, - abi: None, - }), - parser.next_toplevel().ast, - "match_expr_with_block" - ); + fn struct_construction() { + const SRC: &'static str = "Foo { a : 0 }"; + let mut parser = from_source(SRC); assert_eq!( - ast::TopLevelDeclaration::Value(TopLevelValue { - loc: (12, 4), - is_op: false, - ident: "match_statement".to_owned(), - args: vec![ArgDeclaration::Simple { - loc: (12, 20), - ident: "x".to_string(), - ty: None, - },], - ty: Some(ResolvedType::Function { - arg: types::INT32.into(), - returns: types::UNIT.into(), - loc: (12, 30) - }), - value: ValueType::Function(vec![ast::Statement::Match(Match { - loc: (13, 4), - on: ast::Expr::ValueRead("x".to_string(), (13, 10)).into(), - arms: vec![ - MatchArm { - block: vec![ast::Statement::FnCall(FnCall { - loc: (15, 8), - value: ast::Expr::ValueRead("foo".to_string(), (15, 8)).into(), - arg: Some( - ast::Expr::NumericLiteral { - value: "0".to_string(), - } - .into() - ) - })], - ret: None, - cond: Pattern::ConstNumber("1".to_string()), - loc: (14, 6), - }, - MatchArm { - block: vec![ast::Statement::FnCall(FnCall { - loc: (17, 8), - value: ast::Expr::ValueRead("bar".to_string(), (17, 8)).into(), - arg: Some( - ast::Expr::NumericLiteral { - value: "1".to_string(), - } - .into() - ) - })], - ret: None, - cond: Pattern::ConstNumber("2".to_string()), - loc: (16, 6), - }, - MatchArm { - block: Vec::new(), - ret: Some( - ast::Expr::FnCall(FnCall { - loc: (18, 11), - value: ast::Expr::ValueRead("baz".to_string(), (18, 11)).into(), - arg: Some( - ast::Expr::NumericLiteral { - value: "2".to_string(), - } - .into() - ) - }) - .into() - ), - cond: Pattern::ConstNumber("3".to_string()), - loc: (18, 6), + ast::Expr::StructConstruction(ast::StructConstruction { + loc: (0, 3), + fields: HashMap::from([( + "a".to_string(), + ( + ast::Expr::NumericLiteral { + value: "0".to_string(), }, - ] - })]), - generics: None, - abi: None, + (0, 0) + ) + )]), + generics: Vec::new(), + ident: "Foo".to_string() }), - parser.next_toplevel().ast, - "match_statement", + expr(&mut parser).unwrap() ); - } - #[test] - fn arrays() { - const SRC: &'static str = r#" -let arr = [0,0,0,0]; -"#; - let arr = Parser::from_source(SRC).next_toplevel().ast; + let mut parser = from_source("Generic{ a:0 }"); assert_eq!( - ast::TopLevelDeclaration::Value(TopLevelValue { - loc: (1, 4), - is_op: false, - ident: "arr".to_owned(), - args: Vec::new(), - ty: None, - value: ast::ValueType::Expr(ast::Expr::ArrayLiteral { - contents: vec![ - ast::Expr::NumericLiteral { - value: "0".to_string() - }, - ast::Expr::NumericLiteral { - value: "0".to_string() - }, - ast::Expr::NumericLiteral { - value: "0".to_string() - }, + ast::Expr::StructConstruction(ast::StructConstruction { + loc: (0, 14), + fields: HashMap::from([( + "a".to_string(), + ( ast::Expr::NumericLiteral { - value: "0".to_string() + value: "0".to_string(), }, - ], - loc: (1, 10) - }), - generics: None, - abi: None, + (0, 0) + ) + )]), + generics: vec![types::INT32], + ident: "Generic".to_string() }), - arr, - "arrays" + expr(&mut parser).unwrap() ) } #[test] fn abi() { - const SRC: &'static str = r#" -extern "C" let putchar : int32 -> int32; + const SRC: &'static str = r#"extern "C" let putchar : int32 -> int32; extern "C" let ex (a:int32) b = a + b; "#; - let mut parser = Parser::from_source(SRC); - let putchar = parser.next_toplevel().ast; - let ex = parser.next_toplevel().ast; + let mut parser = from_source(SRC); + let putchar = top_level_decl(&mut parser).unwrap(); + + ignore_blank_lines(&mut parser).unwrap(); + let ex = top_level_decl(&mut parser).unwrap(); assert_eq!( - ast::TopLevelDeclaration::Value(TopLevelValue { - loc: (1, 15), + ast::TopLevelDeclaration::Value(ast::TopLevelValue { + loc: (15, 22), is_op: false, ident: "putchar".to_owned(), args: Vec::new(), ty: Some(types::INT32.fn_ty(&types::INT32)), - value: ValueType::External, + value: ast::ValueType::External, generics: None, abi: Some(ast::Abi { - loc: (1, 0), + loc: (7, 10), identifier: "C".to_string(), }), }), @@ -5379,32 +2166,32 @@ extern "C" let ex (a:int32) b = a + b; "input function" ); assert_eq!( - ast::TopLevelDeclaration::Value(TopLevelValue { - loc: (2, 15), + ast::TopLevelDeclaration::Value(ast::TopLevelValue { + loc: (56, 58), is_op: false, ident: "ex".to_owned(), args: vec![ ast::ArgDeclaration::Simple { - loc: (2, 19), + loc: (60, 61), ident: "a".to_string(), ty: Some(types::INT32), }, ast::ArgDeclaration::Simple { - loc: (2, 28), + loc: (69, 70), ident: "b".to_string(), ty: None, }, ], ty: None, - value: ValueType::Expr(Expr::BinaryOpCall(BinaryOpCall { - loc: (2, 34), - lhs: Expr::ValueRead("a".to_string(), (2, 32)).into(), - rhs: Expr::ValueRead("b".to_string(), (2, 36)).into(), + value: ast::ValueType::Expr(ast::Expr::BinaryOpCall(ast::BinaryOpCall { + loc: (75, 76), + lhs: ast::Expr::ValueRead("a".to_string(), (73, 74)).into(), + rhs: ast::Expr::ValueRead("b".to_string(), (77, 78)).into(), operator: "+".to_string() })), generics: None, abi: Some(ast::Abi { - loc: (2, 0), + loc: (48, 51), identifier: "C".to_string(), }), }), @@ -5415,33 +2202,32 @@ extern "C" let ex (a:int32) b = a + b; #[test] fn tuples() { - const SRC: &'static str = " -let ty _ : (int32,int32)->int32 = 0 + const SRC: &'static str = "let ty _ : (int32,int32)->int32 = 0; -let cons a : int32 -> (int32,int32) = (a,0) +let cons a : int32 -> (int32,int32) = (a,0); "; - - let module = Parser::from_source(SRC).module("".to_string()).ast; - let [ty, cons] = &module.declarations[..] else { + let mut src = from_source(SRC); + let module = top_level_block(&mut src).unwrap(); + let [ty, cons] = &module[..] else { unreachable!() }; assert_eq!( - &ast::TopLevelDeclaration::Value(TopLevelValue { - loc: (1, 4), + &ast::TopLevelDeclaration::Value(ast::TopLevelValue { + loc: (4, 6), is_op: false, ident: "ty".to_owned(), - args: vec![ArgDeclaration::Discard { + args: vec![ast::ArgDeclaration::Discard { ty: None, - loc: (1, 7) + loc: (7, 8) }], ty: Some( - ResolvedType::Tuple { + types::ResolvedType::Tuple { underlining: vec![types::INT32, types::INT32], loc: (0, 0) } .fn_ty(&types::INT32) ), - value: ValueType::Expr(Expr::NumericLiteral { + value: ast::ValueType::Expr(ast::Expr::NumericLiteral { value: "0".to_string() }), generics: None, @@ -5451,27 +2237,27 @@ let cons a : int32 -> (int32,int32) = (a,0) ); assert_eq!( - &ast::TopLevelDeclaration::Value(TopLevelValue { - loc: (3, 4), + &ast::TopLevelDeclaration::Value(ast::TopLevelValue { + loc: (42, 46), is_op: false, ident: "cons".to_owned(), - args: vec![ArgDeclaration::Simple { - loc: (3, 9), + args: vec![ast::ArgDeclaration::Simple { + loc: (47, 48), ident: "a".to_string(), ty: None }], - ty: Some(types::INT32.fn_ty(&ResolvedType::Tuple { + ty: Some(types::INT32.fn_ty(&types::ResolvedType::Tuple { underlining: vec![types::INT32, types::INT32], loc: (0, 0) })), - value: ValueType::Expr(Expr::TupleLiteral { + value: ast::ValueType::Expr(ast::Expr::TupleLiteral { contents: vec![ - Expr::ValueRead("a".to_string(), (3, 39)), - Expr::NumericLiteral { + ast::Expr::ValueRead("a".to_string(), (77, 78)), + ast::Expr::NumericLiteral { value: "0".to_string() } ], - loc: (3, 38) + loc: (76, 81) }), generics: None, abi: None @@ -5482,51 +2268,53 @@ let cons a : int32 -> (int32,int32) = (a,0) #[test] fn match_patterns() { - let pattern = Parser::from_source("a").collect_pattern().ast; - assert_eq!(Pattern::Read("a".to_string(), (0, 0)), pattern, "a"); - let pattern = Parser::from_source("_").collect_pattern().ast; - assert_eq!(Pattern::Default, pattern, "_"); - let pattern = Parser::from_source("(a,b)").collect_pattern().ast; + let mut src = from_source("a"); + let pattern_ = pattern(&mut src).unwrap(); + assert_eq!(ast::Pattern::Read("a".to_string(), (0, 1)), pattern_, "a"); + let mut src = from_source("_"); + let pattern_ = pattern(&mut src).unwrap(); + assert_eq!(ast::Pattern::Default, pattern_, "_"); + let mut src = from_source("(a,b)"); assert_eq!( - Pattern::Destructure(PatternDestructure::Tuple(vec![ - Pattern::Read("a".to_string(), (0, 1)), - Pattern::Read("b".to_string(), (0, 3)), + ast::Pattern::Destructure(ast::PatternDestructure::Tuple(vec![ + ast::Pattern::Read("a".to_string(), (1, 2)), + ast::Pattern::Read("b".to_string(), (3, 4)), ])), - pattern, + pattern(&mut src).unwrap(), "destruct tuple" ); - let pattern = Parser::from_source("0 | 1").collect_pattern().ast; + let mut src = from_source("0 | 1"); assert_eq!( - Pattern::Or( - Pattern::ConstNumber("0".to_string()).into(), - Pattern::ConstNumber("1".to_string()).into(), + ast::Pattern::Or( + ast::Pattern::ConstNumber("0".to_string()).into(), + ast::Pattern::ConstNumber("1".to_string()).into(), ), - pattern, + pattern(&mut src).unwrap(), "or (0 or 1)" ); - let pattern = Parser::from_source("0 | 1 | 2").collect_pattern().ast; + let mut src = from_source("0 | 1 | 2"); assert_eq!( - Pattern::Or( - Pattern::ConstNumber("0".to_string()).into(), - Pattern::Or( - Pattern::ConstNumber("1".to_string()).into(), - Pattern::ConstNumber("2".to_string()).into(), + ast::Pattern::Or( + ast::Pattern::ConstNumber("0".to_string()).into(), + ast::Pattern::Or( + ast::Pattern::ConstNumber("1".to_string()).into(), + ast::Pattern::ConstNumber("2".to_string()).into(), ) .into() ), - pattern, + pattern(&mut src).unwrap(), "or (0 or 1 or 2)" ); - let pattern = Parser::from_source("(0 | 1,b)").collect_pattern().ast; + let mut src = from_source("(0 | 1,b)"); assert_eq!( - Pattern::Destructure(PatternDestructure::Tuple(vec![ - Pattern::Or( - Pattern::ConstNumber("0".to_string()).into(), - Pattern::ConstNumber("1".to_string()).into(), + ast::Pattern::Destructure(ast::PatternDestructure::Tuple(vec![ + ast::Pattern::Or( + ast::Pattern::ConstNumber("0".to_string()).into(), + ast::Pattern::ConstNumber("1".to_string()).into(), ), - Pattern::Read("b".to_string(), (0, 7)), + ast::Pattern::Read("b".to_string(), (7, 8)), ])), - pattern, + pattern(&mut src).unwrap(), "destruct tuple" ); } @@ -5541,22 +2329,24 @@ let unit () = (); let annotated_arg_tuple ((x,y):(int32,int32)) = (); "; - let ast = Parser::from_source(SRC).module("".to_string()).ast; - let [simple, decon, discard, unit, annotated_decon] = &ast.declarations[..] else { - unreachable!() - }; + let mut src = from_source(SRC); + let simple = top_level_decl(&mut src).unwrap(); + let decon = top_level_decl(&mut src).unwrap(); + let discard = top_level_decl(&mut src).unwrap(); + let unit = top_level_decl(&mut src).unwrap(); + let annotated_decon = top_level_decl(&mut src).unwrap(); assert_eq!( - &TopLevelDeclaration::Value(TopLevelValue { - loc: (1, 4), + ast::TopLevelDeclaration::Value(ast::TopLevelValue { + loc: (5, 11), is_op: false, ident: "simple".to_owned(), - args: vec![ArgDeclaration::Simple { - loc: (1, 11), + args: vec![ast::ArgDeclaration::Simple { + loc: (12, 13), ident: "a".to_string(), ty: None, },], ty: None, - value: ValueType::Expr(Expr::UnitLiteral), + value: ast::ValueType::Expr(ast::Expr::UnitLiteral), generics: None, abi: None, }), @@ -5564,28 +2354,28 @@ let annotated_arg_tuple ((x,y):(int32,int32)) = (); "let simple a = ();" ); assert_eq!( - &TopLevelDeclaration::Value(TopLevelValue { - loc: (2, 4), + ast::TopLevelDeclaration::Value(ast::TopLevelValue { + loc: (24, 33), is_op: false, ident: "decon_arg".to_owned(), - args: vec![ArgDeclaration::DestructureTuple( + args: vec![ast::ArgDeclaration::DestructureTuple( vec![ - ArgDeclaration::Simple { - loc: (2, 15), + ast::ArgDeclaration::Simple { + loc: (35, 36), ident: "a".to_string(), ty: None, }, - ArgDeclaration::Simple { - loc: (2, 17), + ast::ArgDeclaration::Simple { + loc: (37, 38), ident: "b".to_string(), ty: None, }, ], None, - (2, 14) + (34, 39) ),], ty: None, - value: ValueType::Expr(Expr::UnitLiteral), + value: ast::ValueType::Expr(ast::Expr::UnitLiteral), generics: None, abi: None, }), @@ -5593,16 +2383,16 @@ let annotated_arg_tuple ((x,y):(int32,int32)) = (); "let decon_arg (a,b) = ()" ); assert_eq!( - &TopLevelDeclaration::Value(TopLevelValue { - loc: (3, 4), + ast::TopLevelDeclaration::Value(ast::TopLevelValue { + loc: (50, 57), is_op: false, ident: "discard".to_owned(), - args: vec![ArgDeclaration::Discard { - loc: (3, 12), + args: vec![ast::ArgDeclaration::Discard { + loc: (58, 59), ty: None, },], ty: None, - value: ValueType::Expr(Expr::UnitLiteral), + value: ast::ValueType::Expr(ast::Expr::UnitLiteral), generics: None, abi: None, }), @@ -5610,16 +2400,16 @@ let annotated_arg_tuple ((x,y):(int32,int32)) = (); "let discard _ = ();" ); assert_eq!( - &TopLevelDeclaration::Value(TopLevelValue { - loc: (4, 4), + ast::TopLevelDeclaration::Value(ast::TopLevelValue { + loc: (70, 74), is_op: false, ident: "unit".to_owned(), - args: vec![ArgDeclaration::Unit { - loc: (4, 9), + args: vec![ast::ArgDeclaration::Unit { + loc: (75, 77), ty: None, },], ty: None, - value: ValueType::Expr(Expr::UnitLiteral), + value: ast::ValueType::Expr(ast::Expr::UnitLiteral), generics: None, abi: None, }), @@ -5627,31 +2417,31 @@ let annotated_arg_tuple ((x,y):(int32,int32)) = (); "let unit () = ();" ); assert_eq!( - &TopLevelDeclaration::Value(TopLevelValue { - loc: (5, 4), + ast::TopLevelDeclaration::Value(ast::TopLevelValue { + loc: (88, 107), is_op: false, ident: "annotated_arg_tuple".to_owned(), - args: vec![ArgDeclaration::DestructureTuple( + args: vec![ast::ArgDeclaration::DestructureTuple( vec![ - ArgDeclaration::Simple { - loc: (5, 26), + ast::ArgDeclaration::Simple { + loc: (110, 111), ident: "x".to_string(), ty: None, }, - ArgDeclaration::Simple { - loc: (5, 28), + ast::ArgDeclaration::Simple { + loc: (112, 113), ident: "y".to_string(), ty: None, }, ], - Some(ResolvedType::Tuple { + Some(types::ResolvedType::Tuple { underlining: vec![types::INT32, types::INT32,], - loc: (5, 31) + loc: (115, 128) }), - (5, 25) + (109, 114) ),], ty: None, - value: ValueType::Expr(Expr::UnitLiteral), + value: ast::ValueType::Expr(ast::Expr::UnitLiteral), generics: None, abi: None, }), @@ -5659,91 +2449,130 @@ let annotated_arg_tuple ((x,y):(int32,int32)) = (); "let annotated_arg_tuple ((x,y):(int32,int32)) = ();" ); } + #[test] fn destructuring_statement() { - let mut parser = super::Parser::from_source( - " -let (x,y) = v; + let mut parser = from_source( +r#"let (x,y) = v; let ((x,y),z) = v; let (x,y,z) = v; let (x,y):(int32,int32) = v; -//yes this will all fail typecheking. -", +"#, ); assert_eq!( - Statement::Declaration(ValueDeclaration { - loc: (1, 4), + ast::Statement::Declaration(ast::ValueDeclaration { + loc: (4,9), is_op: false, - target: Pattern::Destructure(PatternDestructure::Tuple(vec![ - Pattern::Read("x".to_string(), (1, 5)), - Pattern::Read("y".to_string(), (1, 7)), + target: ast::Pattern::Destructure(ast::PatternDestructure::Tuple(vec![ + ast::Pattern::Read("x".to_string(), (5, 6)), + ast::Pattern::Read("y".to_string(), (7, 8)), ])), args: Vec::new(), ty: None, - value: ValueType::Expr(ast::Expr::ValueRead("v".to_string(), (1, 12))), + value: ast::ValueType::Expr(ast::Expr::ValueRead("v".to_string(), (12, 13))), generictypes: None, abi: None, }), - parser.next_statement().ast + statement(&mut parser).unwrap() ); - + ascii::line_ending::<_, ContextError>(&mut parser); assert_eq!( - Statement::Declaration(ValueDeclaration { - loc: (2, 4), + ast::Statement::Declaration(ast::ValueDeclaration { + loc: (19, 28), is_op: false, - target: Pattern::Destructure(PatternDestructure::Tuple(vec![ - Pattern::Destructure(PatternDestructure::Tuple(vec![ - Pattern::Read("x".to_string(), (2, 6)), - Pattern::Read("y".to_string(), (2, 8)), + target: ast::Pattern::Destructure(ast::PatternDestructure::Tuple(vec![ + ast::Pattern::Destructure(ast::PatternDestructure::Tuple(vec![ + ast::Pattern::Read("x".to_string(), (21, 22)), + ast::Pattern::Read("y".to_string(), (23, 24)), ])), - Pattern::Read("z".to_string(), (2, 11)) + ast::Pattern::Read("z".to_string(), (26, 27)) ])), args: Vec::new(), ty: None, - value: ValueType::Expr(ast::Expr::ValueRead("v".to_string(), (2, 16))), + value: ast::ValueType::Expr(ast::Expr::ValueRead("v".to_string(), (31, 32))), generictypes: None, abi: None, }), - parser.next_statement().ast + statement(&mut parser).unwrap() ); + + ascii::line_ending::<_, ContextError>(&mut parser); assert_eq!( - Statement::Declaration(ValueDeclaration { - loc: (3, 4), + ast::Statement::Declaration(ast::ValueDeclaration { + loc: (38, 45), is_op: false, - target: Pattern::Destructure(PatternDestructure::Tuple(vec![ - Pattern::Read("x".to_string(), (3, 5)), - Pattern::Read("y".to_string(), (3, 7)), - Pattern::Read("z".to_string(), (3, 9)), + target: ast::Pattern::Destructure(ast::PatternDestructure::Tuple(vec![ + ast::Pattern::Read("x".to_string(), (39, 40)), + ast::Pattern::Read("y".to_string(), (41, 42)), + ast::Pattern::Read("z".to_string(), (43, 44)), ])), args: Vec::new(), ty: None, - value: ValueType::Expr(ast::Expr::ValueRead("v".to_string(), (3, 14))), + value: ast::ValueType::Expr(ast::Expr::ValueRead("v".to_string(), (48, 49))), generictypes: None, abi: None, }), - parser.next_statement().ast + statement(&mut parser).unwrap() ); + ascii::line_ending::<_, ContextError>(&mut parser); assert_eq!( - Statement::Declaration(ValueDeclaration { - loc: (4, 4), + ast::Statement::Declaration(ast::ValueDeclaration { + loc: (55, 60), is_op: false, - target: Pattern::Destructure(PatternDestructure::Tuple(vec![ - Pattern::Read("x".to_string(), (4, 5)), - Pattern::Read("y".to_string(), (4, 7)), + target: ast::Pattern::Destructure(ast::PatternDestructure::Tuple(vec![ + ast::Pattern::Read("x".to_string(), (56, 57)), + ast::Pattern::Read("y".to_string(), (58, 59)), ])), args: Vec::new(), - ty: Some(ResolvedType::Tuple { + ty: Some(types::ResolvedType::Tuple { underlining: vec![types::INT32, types::INT32], loc: (4, 10), }), - value: ValueType::Expr(ast::Expr::ValueRead("v".to_string(), (4, 26))), + value: ast::ValueType::Expr(ast::Expr::ValueRead("v".to_string(), (77, 78))), generictypes: None, abi: None, }), - parser.next_statement().ast + statement(&mut parser).unwrap() ); } + #[test] + fn arrays() { + const SRC: &'static str = r#"let arr = [0,0,0,0]; +"#; + let mut arr = from_source(SRC); + let arr = top_level_decl(&mut arr).unwrap(); + assert_eq!( + ast::TopLevelDeclaration::Value(ast::TopLevelValue { + loc: (4, 7), + is_op: false, + ident: "arr".to_owned(), + args: Vec::new(), + ty: None, + value: ast::ValueType::Expr(ast::Expr::ArrayLiteral { + contents: vec![ + ast::Expr::NumericLiteral { + value: "0".to_string() + }, + ast::Expr::NumericLiteral { + value: "0".to_string() + }, + ast::Expr::NumericLiteral { + value: "0".to_string() + }, + ast::Expr::NumericLiteral { + value: "0".to_string() + }, + ], + loc: (10, 19) + }), + generics: None, + abi: None, + }), + arr, + "arrays" + ) + } #[test] fn enums() { const SRC: &'static str = " @@ -5751,169 +2580,184 @@ enum Basic = | None | AnInt int32 | Struct { a: int32 } for enum Option = | Some T | None for enum Result = | Ok T | Err E "; - let mut parser = Parser::from_source(SRC); - let basic = parser.next_toplevel().ast; + let mut parser = from_source(SRC); + ignore_blank_lines(&mut parser); + let basic = top_level_decl(&mut parser).unwrap(); assert_eq!( - TopLevelDeclaration::TypeDefinition(TypeDefinition::Enum(EnumDeclaration { - ident: "Basic".to_string(), - generics: None, - values: vec![ - EnumVariant::Unit { - ident: "None".to_string(), - loc: (1, 15) - }, - EnumVariant::Tuple { - ident: "AnInt".to_string(), - loc: (1, 22), - ty: types::INT32 - }, - EnumVariant::Struct { - ident: "Struct".to_string(), - fields: vec![FieldDecl { - name: "a".to_string(), - ty: types::INT32, - loc: (1, 45) - }], - loc: (1, 36) - } - ], - loc: (1, 5), - })), + ast::TopLevelDeclaration::TypeDefinition(ast::TypeDefinition::Enum( + ast::EnumDeclaration { + ident: "Basic".to_string(), + generics: None, + values: vec![ + ast::EnumVariant::Unit { + ident: "None".to_string(), + loc: (16, 20) + }, + ast::EnumVariant::Tuple { + ident: "AnInt".to_string(), + loc: (23, 28), + ty: types::INT32 + }, + ast::EnumVariant::Struct { + ident: "Struct".to_string(), + fields: vec![ast::FieldDecl { + name: "a".to_string(), + ty: types::INT32, + loc: (46, 47) + }], + loc: (37, 43) + } + ], + loc: (6, 11), + } + )), basic, "basic: enum Basic = | None | AnInt int32 | Struct {{ a: int32 }}" ); - let option = parser.next_toplevel().ast; + ignore_blank_lines(&mut parser); + let option = top_level_decl(&mut parser).unwrap(); assert_eq!( - TopLevelDeclaration::TypeDefinition(TypeDefinition::Enum(EnumDeclaration { - ident: "Option".to_string(), - generics: Some(GenericsDecl { - for_loc: (2, 0), - decls: vec![((2, 4), "T".to_string())] - }), - values: vec![ - EnumVariant::Tuple { - ident: "Some".to_string(), - ty: ResolvedType::Generic { - name: "T".to_string(), - loc: (2, 28) + ast::TopLevelDeclaration::TypeDefinition(ast::TypeDefinition::Enum( + ast::EnumDeclaration { + ident: "Option".to_string(), + generics: Some(ast::GenericsDecl { + for_loc: (57, 60), + decls: vec![((61, 62), "T".to_string())] + }), + values: vec![ + ast::EnumVariant::Tuple { + ident: "Some".to_string(), + ty: types::ResolvedType::Generic { + name: "T".to_string(), + loc: (85, 86) + }, + loc: (80, 84) }, - loc: (2, 23) - }, - EnumVariant::Unit { - ident: "None".to_string(), - loc: (2, 32) - } - ], - loc: (2, 12) - })), + ast::EnumVariant::Unit { + ident: "None".to_string(), + loc: (89, 93) + } + ], + loc: (69, 75) + } + )), option, "option: for enum Option = | Some T | None" ); - let result = parser.next_toplevel().ast; + ignore_blank_lines(&mut parser); + let result = top_level_decl(&mut parser).unwrap(); assert_eq!( - TopLevelDeclaration::TypeDefinition(TypeDefinition::Enum(EnumDeclaration { - ident: "Result".to_string(), - generics: Some(GenericsDecl { - for_loc: (3, 0), - decls: vec![((3, 4), "T".to_string()), ((3, 6), "E".to_string()),] - }), - values: vec![ - EnumVariant::Tuple { - ident: "Ok".to_string(), - ty: ResolvedType::Generic { - name: "T".to_string(), - loc: (3, 28) + ast::TopLevelDeclaration::TypeDefinition(ast::TypeDefinition::Enum( + ast::EnumDeclaration { + ident: "Result".to_string(), + generics: Some(ast::GenericsDecl { + for_loc: (94, 97), + decls: vec![((98, 99), "T".to_string()), ((100, 101), "E".to_string()),] + }), + values: vec![ + ast::EnumVariant::Tuple { + ident: "Ok".to_string(), + ty: types::ResolvedType::Generic { + name: "T".to_string(), + loc: (122, 123) + }, + loc: (119, 121) }, - loc: (3, 25) - }, - EnumVariant::Tuple { - ident: "Err".to_string(), - ty: ResolvedType::Generic { - name: "E".to_string(), - loc: (3, 35) + ast::EnumVariant::Tuple { + ident: "Err".to_string(), + ty: types::ResolvedType::Generic { + name: "E".to_string(), + loc: (130, 131) + }, + loc: (126, 129) }, - loc: (3, 32) - }, - ], - loc: (3, 14) - })), + ], + loc: (108, 114) + } + )), result, "result: for enum Result = | Ok T | Err E" ); - - assert!(!parser.has_next()); + ignore_blank_lines(&mut parser); + assert!(combinator::eof::<_, ContextError>(&mut parser).is_ok()); } #[test] fn enum_patterns() { const SRC: &'static str = r#" match a where -| Enum::Complex { a: 0, b } -> b, // TODO! struct patterns -// | Enum::Complex c -> c.a // TODO! struct access. +| Enum::Complex { a: 0, b } -> b, | Enum::Simple (0 | 1) -> 0, | Simple a -> a, "#; - let ast = Parser::from_source(SRC).match_().ast; - + // | Enum::Complex c -> c.a // TODO! struct access. + let mut src = from_source(SRC); + ignore_blank_lines(&mut src); + let ast = match_(&mut src).unwrap(); assert_eq!( ast::Match { - loc: (1, 0), - on: ast::Expr::ValueRead("a".to_string(), (1, 6)).into(), + loc: (1, 6), + on: ast::Expr::ValueRead("a".to_string(), (7, 8)).into(), arms: vec![ - MatchArm { - block: Vec::new(), - ret: Some(ast::Expr::ValueRead("b".to_string(), (2, 31)).into()), - cond: Pattern::EnumVariant { - ty: Some("Enum".to_string()), - variant: "Complex".to_string(), - pattern: Some( - Pattern::Destructure(PatternDestructure::Struct { - base_ty: None, - fields: [ - ("a".to_string(), Pattern::ConstNumber("0".to_string())), - ("b".to_string(), Pattern::Read("b".to_string(), (2, 24))), - ] - .into(), - }) - .into() + ast::MatchArm { + block: ast::Block { + statements: Vec::new(), + implicit_ret: Some( + ast::Expr::ValueRead("b".to_string(), (46, 47)).into() ), - loc: (2, 2) }, - loc: (2, 2), + cond: ast::Pattern::Destructure(ast::PatternDestructure::Struct { + base_ty: Some("Enum::Complex".into()), + fields: [ + ("a".to_string(), ast::Pattern::ConstNumber("0".to_string())), + ( + "b".to_string(), + ast::Pattern::Read("b".to_string(), (39, 40)) + ), + ] + .into(), + }), + loc: (15, 16) }, - MatchArm { - block: Vec::new(), - ret: Some( - ast::Expr::NumericLiteral { - value: "0".to_string() - } - .into() - ), - cond: Pattern::EnumVariant { + ast::MatchArm { + block: ast::Block { + statements: Vec::new(), + implicit_ret: Some( + ast::Expr::NumericLiteral { + value: "0".to_string() + } + .into() + ) + }, + cond: ast::Pattern::EnumVariant { ty: Some("Enum".to_string()), variant: "Simple".to_string(), pattern: Some( - Pattern::Or( - Pattern::ConstNumber("0".to_string()).into(), - Pattern::ConstNumber("1".to_string()).into(), + ast::Pattern::Or( + ast::Pattern::ConstNumber("0".to_string()).into(), + ast::Pattern::ConstNumber("1".to_string()).into(), ) .into() ), - loc: (4, 2) + loc: (51, 63) }, - loc: (4, 2), + loc: (49, 50), }, - MatchArm { - block: Vec::new(), - ret: Some(ast::Expr::ValueRead("a".to_string(), (5, 14)).into()), - cond: Pattern::EnumVariant { + ast::MatchArm { + block: ast::Block { + statements: Vec::new(), + implicit_ret: Some( + ast::Expr::ValueRead("a".to_string(), (92, 93)).into() + ), + }, + cond: ast::Pattern::EnumVariant { ty: None, variant: "Simple".to_string(), - pattern: Some(Pattern::Read("a".to_string(), (5, 9)).into()), - loc: (5, 2) + pattern: Some(ast::Pattern::Read("a".to_string(), (87, 88)).into()), + loc: (80, 86), }, - loc: (5, 2), + loc: (78, 79), }, ], }, @@ -5921,4 +2765,37 @@ match a where "match" ); } + + #[test] + fn comments() { + let mut src = from_source(r"#/ unnested #/ nested + /# unnested /#"); + assert!(ascii::space1::<_,ContextError>(&mut src).is_ok()); + assert!(src.is_empty()); + let mut src = from_source("a #/ comment /# b"); + assert_eq!( + expr(&mut src), + Ok(ast::Expr::FnCall(ast::FnCall{ + loc:(0,1), + value:ast::Expr::ValueRead("a".into(),(0,1)).into(), + arg: Some(ast::Expr::ValueRead("b".into(), (16,17)).into()) + })) + ); + assert!(src.is_empty()); + let mut src = from_source("a b #! as;ldkfj;aslkdf +()"); + assert_eq!( + expr(&mut src), + Ok(ast::Expr::FnCall(ast::FnCall{ + loc:(0,1), + value: ast::Expr::FnCall(ast::FnCall { + value:ast::Expr::ValueRead("a".into(),(0,1)).into(), + arg: Some(ast::Expr::ValueRead("b".into(), (2,3)).into()), + loc:(0,1), + }).into(), + arg:Some(ast::Expr::UnitLiteral.into()), + })) + ); + assert!(src.is_empty()); + } } diff --git a/compiler/src/tokens.rs b/compiler/src/tokens.rs index ee483db..c2da295 100644 --- a/compiler/src/tokens.rs +++ b/compiler/src/tokens.rs @@ -1,5 +1,6 @@ +use std::borrow::Cow; #[derive(PartialEq, Eq, Debug, Clone)] -pub enum Token { +pub enum Token<'a> { Let, Return, Arrow, // -> @@ -29,15 +30,15 @@ pub enum Token { // Fn, //to be added latter to distinguish between value and function with 0 args. reality will be syntax sugar for functions with auto unit args //literals - Integer(bool, String), - FloatingPoint(bool, String), + Integer(String), + FloatingPoint(String), StringLiteral(String), CharLiteral(String), #[allow(unused)] //todo implement. Compose, // |, >, <, !, @, $, =, &, +, -, \, /, *, ^, . - Op(String), + Op(&'a str), //meta tokens //TODO! attribute indicatator Extern, @@ -50,8 +51,63 @@ pub enum Token { Error(&'static str /*reason*/), } -impl Token { +impl Token<'_> { pub fn is_eof(&self) -> bool { matches!(self, Self::EoF) } } + +impl winnow::stream::ContainsToken> for Token<'_> { + #[inline(always)] + fn contains_token(&self, token: Token) -> bool { + self == &token + } +} + +impl winnow::stream::ContainsToken> for (Token<'_>,std::ops::Range) { + #[inline(always)] + fn contains_token(&self, token: Token<'_>) -> bool { + self.0 == token + } +} + +impl winnow::stream::ContainsToken> for &'_ [Token<'_>] { + #[inline] + fn contains_token(&self, token: Token<'_>) -> bool { + self.iter().any(|t| *t == token) + } +} + +impl winnow::stream::ContainsToken> for &'_ [Token<'_>; LEN] { + #[inline] + fn contains_token(&self, token: Token<'_>) -> bool { + self.iter().any(|t| t == &token) + } +} + +impl winnow::stream::ContainsToken> for [Token<'_>; LEN] { + #[inline] + fn contains_token(&self, token: Token<'_>) -> bool { + self.iter().any(|t| t == &token) + } +} +impl winnow::stream::ContainsToken> for &'_ [(Token<'_>,std::ops::Range)] { + #[inline] + fn contains_token(&self, token: Token<'_>) -> bool { + self.iter().any(|t| t.0 == token) + } +} + +impl winnow::stream::ContainsToken> for &'_ [(Token<'_>,std::ops::Range); LEN] { + #[inline] + fn contains_token(&self, token: Token<'_>) -> bool { + self.iter().any(|t| t.0 == token) + } +} + +impl winnow::stream::ContainsToken> for [(Token<'_>,std::ops::Range); LEN] { + #[inline] + fn contains_token(&self, token: Token<'_>) -> bool { + self.iter().any(|t| t.0 == token) + } +} diff --git a/compiler/src/typed_ast.rs b/compiler/src/typed_ast.rs index e18dddc..28a1766 100644 --- a/compiler/src/typed_ast.rs +++ b/compiler/src/typed_ast.rs @@ -216,6 +216,55 @@ impl ResolvedGenericsDecl { } } +#[derive(PartialEq, Clone, Debug)] +pub struct TypedBlock { + pub statements: Vec, + pub implicit_ret: Option>, + pub ret_ty: Option, +} + +impl TypedBlock { + fn try_from( + value: ast::Block, + known_externs: &HashMap, + known_values: &HashMap, + known_types: &HashMap, + ) -> Result { + let ast::Block { + statements: untyped_statements, + implicit_ret, + id: _, + ret_ty, + } = value; + let mut known_values = known_values.clone(); + let mut statements = Vec::with_capacity(untyped_statements.len()); + for stmnt in untyped_statements { + match TypedStatement::try_from(stmnt, known_externs, &known_values, known_types) { + Ok(stmnt) => { + if let TypedStatement::Declaration(decl) = &stmnt { + known_values.extend(decl.get_names_with_types()); + } + statements.push(stmnt); + } + Err(err) => return Err(err), + } + } + let implicit_ret = if let Some(ret) = implicit_ret { + Some( + TypedExpr::try_from(*ret, known_externs, &known_values, known_types, Vec::new())? + .into(), + ) + } else { + None + }; + Ok(Self { + statements, + implicit_ret, + ret_ty, + }) + } +} + #[derive(Debug, PartialEq, Clone)] pub enum TypedDeclaration { Value(TypedTopLevelValue), @@ -643,7 +692,7 @@ impl From for TypedEnumDeclaration { values.iter_mut().for_each(|variant| match variant { crate::ast::EnumVariant::Unit { .. } => (), crate::ast::EnumVariant::Tuple { ty, .. } => { - *ty = ty.clone().replace_user_with_generic(generic) + take_mut::take(ty, |ty| ty.replace_user_with_generic(generic)) } crate::ast::EnumVariant::Struct { fields, .. } => { for field in fields { @@ -855,6 +904,20 @@ impl TypedValueDeclaration { TypedValueType::External => (), } } + + fn get_names_with_types(&self) -> HashMap { + match &self.target { + TypedPattern::Read(ident, ty, _) => [(ident.clone(), ty.clone())].into(), + TypedPattern::Destructure(typed_destructure) => { + typed_destructure.get_idents_with_types() + } + TypedPattern::EnumVariant { .. } => { + todo!("not yet supported (`let enum` destructure) ") + } + TypedPattern::Const(_, _) | TypedPattern::Err | TypedPattern::Default => HashMap::new(), + TypedPattern::Or(typed_pattern, typed_pattern1) => todo!("or patterns not supported"), + } + } } #[derive(Debug, PartialEq, Clone)] @@ -1120,9 +1183,11 @@ impl TypedValueType { pub enum TypedStatement { Declaration(TypedValueDeclaration), Return(TypedExpr, crate::Location), + #[deprecated(note = "use expr instead")] FnCall(TypedFnCall), + Expr(TypedExpr), Pipe(TypedPipe), - IfBranching(TypedIfBranching), + IfBranching(TypedIf), Discard(TypedExpr, crate::Location), Match(TypedMatch), Error, @@ -1136,6 +1201,13 @@ impl TypedStatement { known_types: &HashMap, ) -> Result { match statement { + ast::Statement::Expr(expr) => Ok(Self::Expr(TypedExpr::try_from( + expr, + known_externs, + known_values, + known_types, + Vec::new(), + )?)), ast::Statement::Declaration(data) => Ok( match TypedValueDeclaration::try_from( data, @@ -1160,9 +1232,12 @@ impl TypedStatement { known_values, known_types, )?)), - ast::Statement::IfStatement(ifstmnt) => Ok(Self::IfBranching( - TypedIfBranching::try_from(ifstmnt, known_externs, known_values, known_types), - )), + ast::Statement::IfStatement(ifstmnt) => Ok(Self::IfBranching(TypedIf::try_from( + ifstmnt, + known_externs, + known_values, + known_types, + )?)), ast::Statement::Match(match_) => Ok(Self::Match(TypedMatch::as_statement( match_, known_externs, @@ -1188,6 +1263,7 @@ impl TypedStatement { fn lower_generics(&mut self, context: &mut LoweringContext) { match self { + Self::Expr(expr) => expr.lower_generics(context), Self::Declaration(decl) => match &mut decl.value { TypedValueType::Expr(expr) => { expr.lower_generics(context); @@ -1209,6 +1285,7 @@ impl TypedStatement { fn get_ty(&self) -> ResolvedType { match self { + Self::Expr(expr) => expr.get_ty(), Self::Declaration(decl) => decl.ty.clone(), Self::Return(expr, _) => expr.get_ty(), Self::FnCall(call) => call.rt.clone(), @@ -1230,147 +1307,150 @@ pub struct TypedIfBranching { impl TypedIfBranching { fn try_from( - value: ast::IfBranching, + value: ast::If, known_externs: &HashMap, known_values: &HashMap, known_types: &HashMap, ) -> Self { - let ast::IfBranching { - cond, - true_branch, - else_ifs, - else_branch, - loc, - } = value; - let cond = match TypedExpr::try_from( - *cond, - known_externs, - known_values, - known_types, - Vec::new(), - ) { - Ok(cond) if cond.get_ty() == ResolvedType::Bool => cond, - Ok(cond) => { - let loc = cond.get_loc().unwrap_or_default(); - println!( - "condition must be a boolean expresion but got:{} at line:{}, col:{}", - cond.get_ty().to_string(), - loc.0, - loc.1 - ); - TypedExpr::ErrorNode - } - Err(e) => { - println!("{e:?}"); - TypedExpr::ErrorNode - } - } - .into(); - - let true_branch = { - let mut output = Vec::with_capacity(true_branch.len()); - let mut known_values = known_values.clone(); - for stmnt in true_branch { - match TypedStatement::try_from(stmnt, known_externs, &known_values, known_types) { - Ok(stmnt) => { - if let TypedStatement::Declaration(data) = &stmnt { - known_values.extend(data.target.get_idents_with_types()); - } - output.push(stmnt); - } - Err(e) => { - println!("{:?}", e); - output.push(TypedStatement::Error); - } - } - } - output - }; - - let else_ifs = else_ifs - .into_iter() - .map(|(cond, stmnts)| { - let cond = match TypedExpr::try_from( - *cond, - known_externs, - known_values, - known_types, - Vec::new(), - ) { - Ok(cond) if cond.get_ty() == ResolvedType::Bool => cond, - Ok(cond) => { - let loc = cond.get_loc().unwrap_or_default(); - println!( - "condition must be a boolean expresion at line:{}, col:{}", - loc.0, loc.1 - ); - TypedExpr::ErrorNode - } - Err(e) => { - println!("{e:?}"); - TypedExpr::ErrorNode - } - }; - let mut block_known_values = known_values.clone(); - let block = { - let mut block = Vec::new(); - for stmnt in stmnts { - match TypedStatement::try_from( - stmnt, - known_externs, - &block_known_values, - known_types, - ) { - Ok(stmnt) => { - if let TypedStatement::Declaration(data) = &stmnt { - block_known_values.extend(data.target.get_idents_with_types()); - } - block.push(stmnt); - } - Err(e) => { - println!("{:?}", e); - block.push(TypedStatement::Error); - } - } - } - block - }; - (cond.into(), block) - }) - .collect(); - - let else_branch = { - let mut else_block_known_values = known_values.clone(); - let mut block = Vec::new(); - for stmnt in else_branch { - match TypedStatement::try_from( - stmnt, - known_externs, - &else_block_known_values, - known_types, - ) { - Ok(stmnt) => { - if let TypedStatement::Declaration(data) = &stmnt { - else_block_known_values.extend(data.target.get_idents_with_types()); - } - block.push(stmnt); - } - Err(e) => { - println!("{:?}", e); - block.push(TypedStatement::Error); - } - } - } - block - }; - - Self { + let ast::If { cond, true_branch, - else_ifs, else_branch, loc, - } + id: _, + result: _, + } = value; /* + let cond = match TypedExpr::try_from( + *cond, + known_externs, + known_values, + known_types, + Vec::new(), + ) { + Ok(cond) if cond.get_ty() == ResolvedType::Bool => cond, + Ok(cond) => { + let loc = cond.get_loc().unwrap_or_default(); + println!( + "condition must be a boolean expresion but got:{} at line:{}, col:{}", + cond.get_ty().to_string(), + loc.0, + loc.1 + ); + TypedExpr::ErrorNode + } + Err(e) => { + println!("{e:?}"); + TypedExpr::ErrorNode + } + } + .into(); + + let true_branch = { + let mut output = Vec::with_capacity(true_branch.len()); + let mut known_values = known_values.clone(); + for stmnt in true_branch { + match TypedStatement::try_from(stmnt, known_externs, &known_values, known_types) { + Ok(stmnt) => { + if let TypedStatement::Declaration(data) = &stmnt { + known_values.extend(data.target.get_idents_with_types()); + } + output.push(stmnt); + } + Err(e) => { + println!("{:?}", e); + output.push(TypedStatement::Error); + } + } + } + output + }; + + let else_ifs = else_ifs + .into_iter() + .map(|(cond, stmnts)| { + let cond = match TypedExpr::try_from( + *cond, + known_externs, + known_values, + known_types, + Vec::new(), + ) { + Ok(cond) if cond.get_ty() == ResolvedType::Bool => cond, + Ok(cond) => { + let loc = cond.get_loc().unwrap_or_default(); + println!( + "condition must be a boolean expresion at line:{}, col:{}", + loc.0, loc.1 + ); + TypedExpr::ErrorNode + } + Err(e) => { + println!("{e:?}"); + TypedExpr::ErrorNode + } + }; + let mut block_known_values = known_values.clone(); + let block = { + let mut block = Vec::new(); + for stmnt in stmnts { + match TypedStatement::try_from( + stmnt, + known_externs, + &block_known_values, + known_types, + ) { + Ok(stmnt) => { + if let TypedStatement::Declaration(data) = &stmnt { + block_known_values.extend(data.target.get_idents_with_types()); + } + block.push(stmnt); + } + Err(e) => { + println!("{:?}", e); + block.push(TypedStatement::Error); + } + } + } + block + }; + (cond.into(), block) + }) + .collect(); + + let else_branch = { + let mut else_block_known_values = known_values.clone(); + let mut block = Vec::new(); + for stmnt in else_branch { + match TypedStatement::try_from( + stmnt, + known_externs, + &else_block_known_values, + known_types, + ) { + Ok(stmnt) => { + if let TypedStatement::Declaration(data) = &stmnt { + else_block_known_values.extend(data.target.get_idents_with_types()); + } + block.push(stmnt); + } + Err(e) => { + println!("{:?}", e); + block.push(TypedStatement::Error); + } + } + } + block + }; + + Self { + cond, + true_branch, + else_ifs, + else_branch, + loc, + } + */ + todo!() } fn lower_generics(&mut self, context: &mut LoweringContext) { @@ -1685,7 +1765,7 @@ pub enum TypedExpr { StructConstruction(TypedStructConstruction), - IfExpr(TypedIfExpr), + IfExpr(TypedIf), BoolLiteral(bool, crate::Location), @@ -1816,12 +1896,12 @@ impl TypedExpr { Expr::StructConstruction(strct) => Ok(Self::StructConstruction( TypedStructConstruction::from(strct, known_externs, known_values, known_types)?, )), - Expr::If(ifexpr) => Ok(Self::IfExpr(TypedIfExpr::from( + Expr::If(ifexpr) => Ok(Self::IfExpr(TypedIf::try_from( ifexpr, known_externs, known_values, known_types, - ))), + )?)), Expr::BoolLiteral(value, loc, _) => Ok(Self::BoolLiteral(value, loc)), Expr::Match(match_) => Ok(Self::Match(TypedMatch::from( match_, @@ -1892,19 +1972,7 @@ impl TypedExpr { generics: strct.generics.clone(), loc: strct.loc, }, - Self::IfExpr(ifexpr) => { - let expected_ty = ifexpr.true_branch.1.get_ty(); - for (_, _, returned) in &ifexpr.else_ifs { - if expected_ty != returned.get_ty() { - return ResolvedType::Error; - } - } - if ifexpr.else_branch.1.get_ty() != expected_ty { - ResolvedType::Error - } else { - expected_ty - } - } + Self::IfExpr(ifexpr) => ifexpr.result_ty.clone(), Self::MemeberRead(member_read) => member_read.get_ty(), Self::Match(match_) => match_.get_ty(), Self::ErrorNode => types::ERROR, @@ -2044,6 +2112,109 @@ impl TypedExpr { } } +#[derive(PartialEq, Debug, Clone)] +pub struct TypedIf { + pub cond: Box, + pub true_branch: TypedBlock, + pub else_branch: Option, + pub loc: crate::Location, + pub result_ty: ResolvedType, +} + +impl TypedIf { + pub fn try_from( + value: ast::If, + known_externs: &HashMap, + known_values: &HashMap, + known_types: &HashMap, + ) -> Result { + let ast::If { + loc, + cond, + true_branch, + else_branch, + result, + .. + } = value; + let cond = + TypedExpr::try_from(*cond, known_externs, known_values, known_types, Vec::new())? + .into(); + let true_branch = + TypedBlock::try_from(true_branch, known_externs, known_values, known_types)?; + let else_branch = else_branch + .map(|else_branch| { + TypedBlock::try_from(else_branch, known_externs, known_values, known_types) + }) + .transpose()?; + Ok(Self { + cond, + loc, + true_branch, + else_branch, + result_ty: result, + }) + } + + fn replace_type(&mut self, name: &str, new_ty: &ResolvedType) { + self.cond.replace_type(name, new_ty); + for stmnt in &mut self.true_branch.statements { + stmnt.replace_type(name, new_ty); + } + if let Some(ret) = &mut self.true_branch.implicit_ret { + ret.replace_type(name, new_ty); + } + if let Some(ty) = &mut self.true_branch.ret_ty { + take_mut::take(ty, |ty| ty.replace_generic(name, new_ty.clone())); + } + if let Some(branch) = &mut self.else_branch { + for stmnt in &mut branch.statements { + stmnt.replace_type(name, new_ty); + } + if let Some(ret) = &mut branch.implicit_ret { + ret.replace_type(name, new_ty); + } + if let Some(ty) = &mut branch.ret_ty { + take_mut::take(ty, |ty| ty.replace_generic(name, new_ty.clone())); + } + } + take_mut::take(&mut self.result_ty, |ty| { + ty.replace_generic(name, new_ty.clone()) + }); + } + + fn lower_generics(&mut self, context: &mut LoweringContext) { + self.cond.lower_generics(context); + for stmnt in &mut self.true_branch.statements { + stmnt.lower_generics(context); + } + if let Some(ret) = &mut self.true_branch.implicit_ret { + ret.lower_generics(context); + } + if let Some(ty) = &mut self.true_branch.ret_ty { + ty.lower_generics(context); + } + if let Some(branch) = &mut self.else_branch { + for stmnt in &mut branch.statements { + stmnt.lower_generics(context); + } + if let Some(ret) = &mut branch.implicit_ret { + ret.lower_generics(context); + } + if let Some(ty) = &mut branch.ret_ty { + ty.lower_generics(context); + } + } + self.result_ty.lower_generics(context) + } + + fn replace_types(&mut self, replaced: &[(String, ResolvedType)]) { + for (name, new_ty) in replaced { + self.replace_type(name, new_ty); + } + } + +} + #[derive(PartialEq, Debug, Clone)] pub struct TypedIfExpr { pub cond: Box, @@ -3413,7 +3584,7 @@ impl TypedPattern { Self::EnumVariant { pattern, .. } => pattern .as_ref() .map(Box::as_ref) - .map(|it| matches!(it,Self::Default)) + .map(|it| matches!(it, Self::Default)) .unwrap_or(true), } } @@ -3522,7 +3693,7 @@ mod tests { use super::TypedArgDeclaration; use super::TypedExpr; use crate::inference::ast; - use crate::parser::Parser; + use crate::parser::file; use crate::typed_ast::TypedDestructure; use crate::typed_ast::TypedPattern; use crate::typed_ast::TypedTopLevelValue; @@ -3550,8 +3721,7 @@ let b value : (int32,(int32,int32)) -> int32 = match value where | (0, (0,b) | (b,0) ) | (b,_) -> b, | _ -> 0, "#; - let parser = Parser::from_source(SRC); - let mut module = parser.module("foo".to_string()).ast; + let mut module = file("", SRC); module.canonialize(vec!["P".to_string()]); let dependency_graph = module.get_dependencies(); let dependency_tree = dependency_graph @@ -3969,10 +4139,10 @@ let b value : (int32,(int32,int32)) -> int32 = match value where #[test] fn generic_use() { - use crate::parser::Parser; - let parser = Parser::from_source( + let module = file( + "", r#" -for let test a : T -> T = a +for let test a : T -> T = a; let main _ : () -> () = let x : int32 = 3; @@ -3980,7 +4150,6 @@ let main _ : () -> () = "#, // test 3; this will be an inference error of "Unable to determine type of a NumericLiteral" ); - let module = parser.module("test".to_string()).ast; // module.canonialize(vec!["test".to_string()]); let dtree = module.get_dependencies(); let dependency_tree = dtree @@ -4005,11 +4174,11 @@ let main _ : () -> () = }; assert_eq!( &TypedDeclaration::Value(TypedTopLevelValue { - loc: (1, 11), + loc: (12, 16), is_op: false, ident: "test".to_string(), args: vec![TypedArgDeclaration::Simple { - loc: (1, 16), + loc: (17, 18), ident: "a".to_string(), ty: ResolvedType::Generic { name: "T".to_string(), @@ -4020,9 +4189,9 @@ let main _ : () -> () = "a".to_string(), ResolvedType::Generic { name: "T".to_string(), - loc: (1, 20) + loc: (21, 22) }, - (1, 29) + (30, 31) )), ty: ResolvedType::Function { arg: ResolvedType::Generic { @@ -4038,9 +4207,9 @@ let main _ : () -> () = loc: (0, 0) }, generics: Some(ResolvedGenericsDecl { - for_loc: (1, 0), + for_loc: (1, 4), decls: vec![( - (1, 4), + (5, 6), ResolvedType::Generic { name: "T".to_string(), loc: (1, 4) @@ -4054,18 +4223,18 @@ let main _ : () -> () = ); assert_eq!( &TypedDeclaration::Value(TypedTopLevelValue { - loc: (3, 4), + loc: (38, 42), is_op: false, ident: "main".to_string(), args: vec![TypedArgDeclaration::Discard { - loc: (3, 9), + loc: (43, 44), ty: types::UNIT, }], value: TypedValueType::Function(vec![ TypedStatement::Declaration(TypedValueDeclaration { - loc: (4, 8), + loc: (66, 67), is_op: false, - target: TypedPattern::Read("x".to_string(), types::INT32, (4, 8)), + target: TypedPattern::Read("x".to_string(), types::INT32, (66, 67)), args: Vec::new(), value: TypedValueType::Expr(TypedExpr::IntegerLiteral { value: "3".to_string(), @@ -4076,8 +4245,8 @@ let main _ : () -> () = abi: None, is_curried: false, }), - TypedStatement::FnCall(TypedFnCall { - loc: (5, 4), + TypedStatement::Expr(TypedExpr::FnCall(TypedFnCall { + loc: (85, 89), value: TypedExpr::ValueRead( "test".to_string(), ResolvedType::Function { @@ -4093,11 +4262,11 @@ let main _ : () -> () = .into(), loc: (0, 0), }, - (5, 4) + (85, 89) ) .into(), arg: Some( - TypedExpr::ValueRead("x".to_string(), types::INT32, (5, 9)).into() + TypedExpr::ValueRead("x".to_string(), types::INT32, (90, 91)).into() ), rt: ResolvedType::Generic { name: "T".to_string(), @@ -4105,7 +4274,7 @@ let main _ : () -> () = }, arg_t: types::INT32, is_extern: false, - }) + })) ]), ty: ResolvedType::Function { arg: types::UNIT.into(), @@ -4122,20 +4291,18 @@ let main _ : () -> () = #[test] fn structs() { - use crate::Parser; - let parser = Parser::from_source( + let module = file( + "test", r" for type Tuple = { first : T, second : U, } -let first a : Tuple -> int32 = - return 0 +let first a : Tuple -> int32 = 0; ", ); - let module = parser.module("test".to_string()).ast; // module.canonialize(vec!["test".to_string()]); let dtree = module.get_dependencies(); @@ -4161,20 +4328,20 @@ let first a : Tuple -> int32 = StructDefinition { ident: "Tuple".to_string(), generics: Some(ResolvedGenericsDecl { - for_loc: (1, 0), + for_loc: (1, 4), decls: vec![ ( - (1, 4), + (5, 6), ResolvedType::Generic { name: "T".to_string(), - loc: (1, 4), + loc: (5, 6), }, ), ( - (1, 6), + (7, 8), ResolvedType::Generic { name: "U".to_string(), - loc: (1, 6) + loc: (7, 8) } ) ] @@ -4184,9 +4351,9 @@ let first a : Tuple -> int32 = name: "first".to_string(), ty: ResolvedType::Generic { name: "T".to_string(), - loc: (2, 12), + loc: (37, 38), }, - loc: (2, 4) + loc: (29, 34) }, crate::ast::FieldDecl { name: "second".to_string(), @@ -4194,10 +4361,10 @@ let first a : Tuple -> int32 = name: "U".to_string(), loc: (3, 13) }, - loc: (3, 4) + loc: (44, 50) } ], - loc: (1, 14) + loc: (15, 20) } )), strct, @@ -4210,13 +4377,12 @@ let first a : Tuple -> int32 = unreachable!() }; assert_eq!( - fun, &TypedDeclaration::Value(TypedTopLevelValue { - loc: (6, 4), + loc: (63, 68), is_op: false, ident: "first".to_string(), args: vec![TypedArgDeclaration::Simple { - loc: (6, 10), + loc: (69, 70), ident: "a".to_string(), ty: ResolvedType::User { name: "Tuple".to_string(), @@ -4224,13 +4390,10 @@ let first a : Tuple -> int32 = loc: (0, 0) }, }], - value: TypedValueType::Function(vec![TypedStatement::Return( - TypedExpr::IntegerLiteral { - value: "0".to_string(), - size: types::IntWidth::ThirtyTwo - }, - (7, 4) - )]), + value: TypedValueType::Expr(TypedExpr::IntegerLiteral { + value: "0".to_string(), + size: types::IntWidth::ThirtyTwo + },), ty: ResolvedType::Function { arg: ResolvedType::User { name: "Tuple".to_string(), @@ -4244,6 +4407,7 @@ let first a : Tuple -> int32 = generics: None, abi: None, }), + fun, "post lowering function" ); @@ -4255,15 +4419,15 @@ let first a : Tuple -> int32 = crate::ast::FieldDecl { name: "first".to_string(), ty: types::INT32, - loc: (2, 4) + loc: (29, 34) }, crate::ast::FieldDecl { name: "second".to_string(), ty: types::FLOAT64, - loc: (3, 4) + loc: (44, 50) } ], - loc: (1, 14) + loc: (15, 20) })), generated_strct, "generated" @@ -4272,9 +4436,8 @@ let first a : Tuple -> int32 = #[test] fn generic_lowering() { - use crate::parser::Parser; - use crate::TokenStream; - let parser = Parser::from_stream(TokenStream::from_source( + let module = file( + "test", r#" for let test a : T -> T = return a; @@ -4283,8 +4446,7 @@ let main x : int32 -> int32 = test x; return 0; "#, - )); - let module = parser.module("test.fb".to_string()).ast; + ); // module.canonialize(vec!["test".to_string()]); let dtree = module.get_dependencies(); @@ -4309,15 +4471,15 @@ let main x : int32 -> int32 = }; assert_eq!( &TypedDeclaration::Value(TypedTopLevelValue { - loc: (1, 11), + loc: (12, 16), is_op: false, ident: "test".to_string(), args: vec![TypedArgDeclaration::Simple { ident: "a".to_string(), - loc: (1, 16), + loc: (17, 18), ty: ResolvedType::Generic { name: "T".to_string(), - loc: (1, 20) + loc: (0, 0) }, }], value: TypedValueType::Function(vec![TypedStatement::Return( @@ -4325,16 +4487,16 @@ let main x : int32 -> int32 = "a".to_string(), ResolvedType::Generic { name: "T".to_string(), - loc: (1, 20) + loc: (0, 0) }, - (2, 11) + (41, 42) ), - (2, 4) + (34, 40) )]), ty: ResolvedType::Function { arg: ResolvedType::Generic { name: "T".to_string(), - loc: (1, 20), + loc: (0, 0), } .into(), returns: ResolvedType::Generic { @@ -4345,12 +4507,12 @@ let main x : int32 -> int32 = loc: (1, 23), }, generics: Some(ResolvedGenericsDecl { - for_loc: (1, 0), + for_loc: (1, 4), decls: vec![( - (1, 4), + (5, 6), ResolvedType::Generic { name: "T".to_string(), - loc: (1, 4) + loc: (0, 0) } )], }), @@ -4361,46 +4523,46 @@ let main x : int32 -> int32 = ); assert_eq!( &TypedDeclaration::Value(TypedTopLevelValue { - loc: (4, 4), + loc: (49, 53), is_op: false, ident: "main".to_string(), args: vec![TypedArgDeclaration::Simple { ident: "x".to_string(), - loc: (4, 9), + loc: (54, 55), ty: types::INT32, }], value: TypedValueType::Function(vec![ - TypedStatement::FnCall(TypedFnCall { - loc: (5, 4), + TypedStatement::Expr(TypedExpr::FnCall(TypedFnCall { + loc: (79, 83), value: TypedExpr::ValueRead( "test".to_string(), ResolvedType::Function { arg: types::INT32.into(), returns: types::INT32.into(), - loc: (5, 4) + loc: (0, 0) }, - (5, 4) + (79, 83) ) .into(), arg: Some( - TypedExpr::ValueRead("x".to_string(), types::INT32, (5, 9)).into() + TypedExpr::ValueRead("x".to_string(), types::INT32, (84, 85)).into() ), rt: types::INT32, arg_t: types::INT32, is_extern: false, - }), + })), TypedStatement::Return( TypedExpr::IntegerLiteral { value: "0".to_string(), size: types::IntWidth::ThirtyTwo }, - (6, 4) + (91, 97) ) ]), ty: ResolvedType::Function { arg: types::INT32.into(), returns: types::INT32.into(), - loc: (6, 20) + loc: (0, 0) }, generics: None, abi: None, @@ -4410,17 +4572,17 @@ let main x : int32 -> int32 = ); assert_eq!( &TypedDeclaration::Value(TypedTopLevelValue { - loc: (1, 11), + loc: (12, 16), is_op: false, ident: "test".to_string(), args: vec![TypedArgDeclaration::Simple { ident: "a".to_string(), - loc: (1, 16), + loc: (17, 18), ty: types::INT32, }], value: crate::typed_ast::TypedValueType::Function(vec![TypedStatement::Return( - TypedExpr::ValueRead("a".to_string(), types::INT32, (2, 11)), - (2, 4) + TypedExpr::ValueRead("a".to_string(), types::INT32, (41, 42)), + (34, 40) )]), ty: ResolvedType::Function { arg: types::INT32.into(), @@ -4437,7 +4599,8 @@ let main x : int32 -> int32 = #[test] fn control_flow_if() { - let parser = Parser::from_source( + let module = file( + "test", r#" let expr_with_statement a : bool -> int32 = if a then foo 3; @@ -4455,7 +4618,6 @@ let statement_with_else_if a b : bool -> bool -> int32 = return 2; "#, ); - let module = parser.module("test.fb".to_string()).ast; // module.canonialize(vec!["test".to_string()]);//don't really need to do this for tests. let dtree = module.get_dependencies(); let dependency_tree = dtree @@ -4480,19 +4642,21 @@ let statement_with_else_if a b : bool -> bool -> int32 = }; assert_eq!( &TypedDeclaration::Value(TypedTopLevelValue { - loc: (1, 4), + loc: (5,24), is_op: false, ident: "expr_with_statement".to_string(), args: vec![TypedArgDeclaration::Simple { - loc: (1, 24), + loc: (25,26), ident: "a".to_string(), ty: types::BOOL, }], - value: TypedValueType::Expr(TypedExpr::IfExpr(TypedIfExpr { - cond: TypedExpr::ValueRead("a".to_string(), types::BOOL, (1, 47)).into(), - true_branch: ( - vec![TypedStatement::FnCall(TypedFnCall { - loc: (2, 8), + value: TypedValueType::Expr(TypedExpr::IfExpr(super::TypedIf { + cond: TypedExpr::ValueRead("a".to_string(), types::BOOL, (48,49)).into(), + result_ty: types::INT32, + true_branch: super::TypedBlock { + ret_ty: types::INT32.into(), + statements: vec![TypedStatement::Expr(TypedExpr::FnCall(TypedFnCall { + loc: (63,66), value: TypedExpr::ValueRead( "foo".to_string(), ResolvedType::Function { @@ -4500,7 +4664,7 @@ let statement_with_else_if a b : bool -> bool -> int32 = returns: types::INT32.into(), loc: (0, 0) }, - (2, 8) + (63,66) ) .into(), arg: Some( @@ -4513,17 +4677,19 @@ let statement_with_else_if a b : bool -> bool -> int32 = rt: types::INT32, arg_t: types::INT32, is_extern: false, - })], - TypedExpr::IntegerLiteral { - value: "0".to_string(), - size: types::IntWidth::ThirtyTwo - } - .into() - ), - else_ifs: Vec::new(), - else_branch: ( - vec![TypedStatement::FnCall(TypedFnCall { - loc: (5, 8), + }))], + implicit_ret: Some( + TypedExpr::IntegerLiteral { + value: "0".to_string(), + size: types::IntWidth::ThirtyTwo + } + .into() + ) + }, + else_branch: super::TypedBlock { + ret_ty: types::INT32.into(), + statements: vec![TypedStatement::Expr(TypedExpr::FnCall(TypedFnCall { + loc: (97,100), value: TypedExpr::ValueRead( "foo".to_string(), ResolvedType::Function { @@ -4531,7 +4697,7 @@ let statement_with_else_if a b : bool -> bool -> int32 = returns: types::INT32.into(), loc: (0, 0) }, - (5, 8) + (97,100) ) .into(), arg: Some( @@ -4544,14 +4710,17 @@ let statement_with_else_if a b : bool -> bool -> int32 = rt: types::INT32, arg_t: types::INT32, is_extern: false, - })], - TypedExpr::IntegerLiteral { - value: "1".to_string(), - size: types::IntWidth::ThirtyTwo - } - .into() - ), - loc: (1, 44) + }))], + implicit_ret: Some( + TypedExpr::IntegerLiteral { + value: "1".to_string(), + size: types::IntWidth::ThirtyTwo + } + .into() + ) + } + .into(), + loc: (45,47) })), ty: ResolvedType::Function { arg: types::BOOL.into(), @@ -4566,17 +4735,17 @@ let statement_with_else_if a b : bool -> bool -> int32 = ); assert_eq!( &TypedDeclaration::Value(TypedTopLevelValue { - loc: (8, 4), + loc: (119,141), is_op: false, ident: "statement_with_else_if".to_string(), args: vec![ TypedArgDeclaration::Simple { - loc: (8, 27), + loc: (142,143), ident: "a".to_string(), ty: types::BOOL, }, TypedArgDeclaration::Simple { - loc: (8, 29), + loc: (144,145), ident: "b".to_string(), ty: types::BOOL, }, @@ -4591,36 +4760,53 @@ let statement_with_else_if a b : bool -> bool -> int32 = .into(), loc: (0, 0) }, - value: TypedValueType::Function(vec![TypedStatement::IfBranching( - TypedIfBranching { - cond: TypedExpr::ValueRead("a".to_string(), types::BOOL, (9, 7)).into(), - true_branch: vec![TypedStatement::Return( + value: TypedValueType::Function(vec![TypedStatement::IfBranching(super::TypedIf { + cond: TypedExpr::ValueRead("a".to_string(), types::BOOL, (179,180)).into(), + true_branch: super::TypedBlock { + statements: vec![TypedStatement::Return( TypedExpr::IntegerLiteral { value: "0".to_string(), size: types::IntWidth::ThirtyTwo }, - (10, 8) + (194,200) )], - else_ifs: vec![( - TypedExpr::ValueRead("b".to_string(), types::BOOL, (11, 12)).into(), - vec![TypedStatement::Return( - TypedExpr::IntegerLiteral { - value: "1".to_string(), - size: types::IntWidth::ThirtyTwo - }, - (12, 8) - )] - )], - else_branch: vec![TypedStatement::Return( - TypedExpr::IntegerLiteral { - value: "2".to_string(), - size: types::IntWidth::ThirtyTwo + implicit_ret: None, + ret_ty: Some(types::UNIT), + }, + else_branch: Some(super::TypedBlock { + statements: vec![TypedStatement::IfBranching(super::TypedIf { + cond: TypedExpr::ValueRead("b".into(), types::BOOL, (216,217),).into(), + true_branch: super::TypedBlock { + statements: vec![TypedStatement::Return( + TypedExpr::IntegerLiteral { + value: "1".to_string(), + size: types::IntWidth::ThirtyTwo, + }, + (231,237) + )], + implicit_ret: None, + ret_ty: Some(types::UNIT), }, - (14, 8) - )], - loc: (9, 4) - } - )]), + else_branch:super::TypedBlock { + statements: vec![TypedStatement::Return( + TypedExpr::IntegerLiteral { + value: "2".to_string(), + size: types::IntWidth::ThirtyTwo, + }, + (258,264) + )], + implicit_ret: None, + ret_ty: Some(types::UNIT), + }.into(), + loc:(213,215), + result_ty:types::UNIT, + })], + implicit_ret: None, + ret_ty:Some(types::UNIT), + }), + loc:(176,178), + result_ty:types::UNIT, + })]), generics: None, abi: None, }), @@ -4630,17 +4816,18 @@ let statement_with_else_if a b : bool -> bool -> int32 = } #[test] fn control_flow_match() { - let module = Parser::from_source( + let module = file( + "test", " let simple_expr a fun : int32 -> (int32 -> int32) -> int32 = match fun a where -| 1 -> 0, -| 2 -> 3, -| a -> a*3, + | 1 -> 0, + | 2 -> 3, + | a -> a*3, let nest_in_call a fun : int32 -> (int32 -> int32) -> int32 = fun (match a where -| 1 -> 0, -| 2 -> 3, -| _ -> a*3, + | 1 -> 0, + | 2 -> 3, + | _ -> a*3, ) let as_statement a b : int32 -> int32 -> () = @@ -4653,9 +4840,7 @@ let as_statement a b : int32 -> int32 -> () = | 3 -> (), | 2 -> (), ", - ) - .module("test".to_string()) - .ast; + ); // module.canonialize(vec!["test".to_string()]); let dtree = module.get_dependencies(); @@ -4686,25 +4871,25 @@ let as_statement a b : int32 -> int32 -> () = }; assert_eq!( &TypedDeclaration::Value(TypedTopLevelValue { - loc: (1, 4), + loc: (5,16), is_op: false, ident: "simple_expr".to_string(), args: vec![ TypedArgDeclaration::Simple { - loc: (1, 16), + loc: (17,18), ident: "a".to_string(), ty: types::INT32, }, TypedArgDeclaration::Simple { - loc: (1, 18), + loc: (19,22), ident: "fun".to_string(), ty: types::INT32.fn_ty(&types::INT32), }, ], value: TypedValueType::Expr(TypedExpr::Match(TypedMatch { - loc: (1, 61), + loc: (62,67), on: TypedExpr::FnCall(TypedFnCall { - loc: (1, 67), + loc: (68,71), value: TypedExpr::ValueRead( "fun".to_string(), ResolvedType::Function { @@ -4712,11 +4897,11 @@ let as_statement a b : int32 -> int32 -> () = returns: types::INT32.into(), loc: (0, 0) }, - (1, 67) + (68,71) ) .into(), arg: Some( - TypedExpr::ValueRead("a".to_string(), types::INT32, (1, 71)).into() + TypedExpr::ValueRead("a".to_string(), types::INT32, (72,73)).into() ), rt: types::INT32, arg_t: types::INT32, @@ -4725,7 +4910,7 @@ let as_statement a b : int32 -> int32 -> () = .into(), arms: vec![ TypedMatchArm { - loc: (2, 2), + loc: (84,85), cond: crate::typed_ast::TypedPattern::Const( "1".to_string(), types::INT32 @@ -4740,7 +4925,7 @@ let as_statement a b : int32 -> int32 -> () = ) }, TypedMatchArm { - loc: (3, 2), + loc: (98,99), cond: crate::typed_ast::TypedPattern::Const( "2".to_string(), types::INT32 @@ -4755,20 +4940,20 @@ let as_statement a b : int32 -> int32 -> () = ) }, TypedMatchArm { - loc: (4, 2), + loc: (112,113), cond: crate::typed_ast::TypedPattern::Read( "a".to_string(), types::INT32, - (4, 2) + (114,115) ), block: Vec::new(), ret: Some( TypedExpr::BinaryOpCall(TypedBinaryOpCall { - loc: (4, 8), + loc: (120,121), lhs: TypedExpr::ValueRead( "a".to_string(), types::INT32, - (4, 7) + (119,120) ) .into(), rhs: TypedExpr::IntegerLiteral { @@ -4808,23 +4993,23 @@ let as_statement a b : int32 -> int32 -> () = assert_eq!( &TypedDeclaration::Value(TypedTopLevelValue { - loc: (6, 4), + loc: (129,141), is_op: false, ident: "nest_in_call".to_string(), args: vec![ TypedArgDeclaration::Simple { - loc: (6, 17), + loc: (142,143), ident: "a".to_string(), ty: types::INT32, }, TypedArgDeclaration::Simple { - loc: (6, 19), + loc: (144, 147), ident: "fun".to_string(), ty: types::INT32.fn_ty(&types::INT32), }, ], value: TypedValueType::Expr(TypedExpr::FnCall(TypedFnCall { - loc: (6, 62), + loc: (187,190), value: TypedExpr::ValueRead( "fun".to_string(), ResolvedType::Function { @@ -4832,16 +5017,16 @@ let as_statement a b : int32 -> int32 -> () = returns: types::INT32.into(), loc: (0, 0) }, - (6, 62) + (187,190) ) .into(), arg: Some( TypedExpr::Match(TypedMatch { - loc: (6, 67), - on: TypedExpr::ValueRead("a".to_string(), types::INT32, (6, 73)).into(), + loc: (192,197), + on: TypedExpr::ValueRead("a".to_string(), types::INT32, (198,199)).into(), arms: vec![ TypedMatchArm { - loc: (7, 2), + loc: (210,211), cond: crate::typed_ast::TypedPattern::Const( "1".to_string(), types::INT32 @@ -4856,7 +5041,7 @@ let as_statement a b : int32 -> int32 -> () = ) }, TypedMatchArm { - loc: (8, 2), + loc: (224,225), cond: crate::typed_ast::TypedPattern::Const( "2".to_string(), types::INT32 @@ -4871,16 +5056,16 @@ let as_statement a b : int32 -> int32 -> () = ) }, TypedMatchArm { - loc: (9, 2), + loc: (238,239), cond: crate::typed_ast::TypedPattern::Default, block: Vec::new(), ret: Some( TypedExpr::BinaryOpCall(TypedBinaryOpCall { - loc: (9, 8), + loc: (246,247), lhs: TypedExpr::ValueRead( "a".to_string(), types::INT32, - (9, 7) + (245,246) ) .into(), rhs: TypedExpr::IntegerLiteral { @@ -4926,45 +5111,45 @@ let as_statement a b : int32 -> int32 -> () = assert_eq!( &TypedDeclaration::Value(TypedTopLevelValue { - loc: (12, 4), + loc: (257,269), is_op: false, ident: "as_statement".to_string(), args: vec![ TypedArgDeclaration::Simple { - loc: (12, 17), + loc: (270,271), ident: "a".to_string(), ty: types::INT32, }, TypedArgDeclaration::Simple { - loc: (12, 19), + loc: (272,273), ident: "b".to_string(), ty: types::INT32, }, ], value: TypedValueType::Function(vec![TypedStatement::Match(TypedMatch { - loc: (13, 4), - on: TypedExpr::ValueRead("a".to_string(), types::INT32, (13, 10)).into(), + loc: (303,308), + on: TypedExpr::ValueRead("a".to_string(), types::INT32, (309,310)).into(), arms: vec![ TypedMatchArm { - loc: (14, 6), + loc: (321,322), cond: crate::typed_ast::TypedPattern::Const( "1".to_string(), types::INT32 ), block: vec![TypedStatement::Match(TypedMatch { - loc: (15, 8), - on: TypedExpr::ValueRead("b".to_string(), types::INT32, (15, 14)) + loc: (337,342), + on: TypedExpr::ValueRead("b".to_string(), types::INT32, (343,344)) .into(), arms: vec![ TypedMatchArm { - loc: (16, 10), + loc: (359,360), cond: crate::typed_ast::TypedPattern::Const( "1".to_string(), types::INT32 ), block: vec![TypedStatement::Discard( TypedExpr::FnCall(TypedFnCall { - loc: (16, 15), + loc: (366,369), value: TypedExpr::ValueRead( "foo".to_string(), ResolvedType::Function { @@ -4972,7 +5157,7 @@ let as_statement a b : int32 -> int32 -> () = returns: types::UNIT.into(), loc: (0, 0) }, - (16, 15) + (366,369) ) .into(), arg: Some( @@ -4986,18 +5171,18 @@ let as_statement a b : int32 -> int32 -> () = arg_t: types::INT32, is_extern: false, }), - (16, 15) + (366,369) )], ret: None }, TypedMatchArm { - loc: (17, 10), + loc: (381,382), cond: crate::typed_ast::TypedPattern::Const( "2".to_string(), types::INT32 ), - block: vec![TypedStatement::FnCall(TypedFnCall { - loc: (18, 12), + block: vec![TypedStatement::Expr(TypedExpr::FnCall(TypedFnCall { + loc: (401,404), value: TypedExpr::ValueRead( "foo".to_string(), ResolvedType::Function { @@ -5005,7 +5190,7 @@ let as_statement a b : int32 -> int32 -> () = returns: types::UNIT.into(), loc: (0, 0) }, - (18, 12) + (401,404) ) .into(), arg: Some( @@ -5018,11 +5203,11 @@ let as_statement a b : int32 -> int32 -> () = rt: types::UNIT, arg_t: types::INT32, is_extern: false, - })], + }))], ret: None }, TypedMatchArm { - loc: (19, 10), + loc: (416,417), cond: crate::typed_ast::TypedPattern::Const( "3".to_string(), types::INT32 @@ -5035,7 +5220,7 @@ let as_statement a b : int32 -> int32 -> () = ret: None }, TypedMatchArm { - loc: (20, 6), + loc: (431,432), cond: crate::typed_ast::TypedPattern::Const( "2".to_string(), types::INT32 @@ -5064,11 +5249,12 @@ let as_statement a b : int32 -> int32 -> () = } #[test] fn arrays() { - let module = Parser::from_source( + let module = file( + "test", " -let simple _ : () -> [int32;5] = [5,4,3,2,1] +let simple _ : () -> [int32;5] = [5,4,3,2,1]; -let should_fail _ : () -> [int32;5] = [1,2,3,4] +let should_fail _ : () -> [int32;5] = [1,2,3,4]; let not_so_simple a : int32 -> [int32;4] = return [ @@ -5078,9 +5264,7 @@ let not_so_simple a : int32 -> [int32;4] = foo a ]; ", - ) - .module("foo".to_string()) - .ast; + ); let dtree = module.get_dependencies(); let dependency_tree = dtree .into_iter() @@ -5105,11 +5289,11 @@ let not_so_simple a : int32 -> [int32;4] = assert_eq!( &TypedDeclaration::Value(TypedTopLevelValue { - loc: (1, 4), + loc: (5,11), is_op: false, ident: "simple".to_string(), args: vec![TypedArgDeclaration::Discard { - loc: (1, 11), + loc: (12,13), ty: types::UNIT }], value: TypedValueType::Expr(TypedExpr::ArrayLiteral { @@ -5162,7 +5346,7 @@ let main _ : () -> () = return (); "; - let ast = crate::Parser::from_source(USAGE).module(String::new()).ast; + let ast = file("", USAGE); let dtree = ast.get_dependencies(); let dtree = dtree .into_iter() @@ -5183,11 +5367,11 @@ let main _ : () -> () = }; assert_eq!( &TypedDeclaration::Value(TypedTopLevelValue { - loc: (1, 4), + loc: (5,6), is_op: false, ident: "f".to_string(), args: vec![TypedArgDeclaration::Simple { - loc: (1, 7), + loc: (8,9), ident: "a".to_string(), ty: ResolvedType::Array { underlining: types::INT32.into(), @@ -5208,17 +5392,17 @@ let main _ : () -> () = ); assert_eq!( &TypedDeclaration::Value(TypedTopLevelValue { - loc: (3, 4), + loc: (32,36), is_op: false, ident: "main".to_string(), args: vec![TypedArgDeclaration::Discard { - loc: (3, 9), + loc: (37,38), ty: types::UNIT, },], ty: types::UNIT.fn_ty(&types::UNIT), value: TypedValueType::Function(vec![ - TypedStatement::FnCall(TypedFnCall { - loc: (4, 4), + TypedStatement::Expr(TypedExpr::FnCall(TypedFnCall { + loc: (56,57), value: TypedExpr::ValueRead( "f".to_string(), ResolvedType::Array { @@ -5226,7 +5410,7 @@ let main _ : () -> () = size: 5 } .fn_ty(&types::UNIT), - (4, 4) + (56,57) ) .into(), arg: Some( @@ -5263,8 +5447,8 @@ let main _ : () -> () = size: 5 }, is_extern: false, - }), - TypedStatement::Return(TypedExpr::UnitLiteral, (5, 4)) + })), + TypedStatement::Return(TypedExpr::UnitLiteral, (75,81)) ]), generics: None, abi: None, @@ -5275,14 +5459,13 @@ let main _ : () -> () = } #[test] fn destructuring_statement() { - let ast = Parser::from_source( + let ast = file( + "", " let a (v:(int32,int32)) = let (x,y) = v; return ();", - ) - .module("".to_string()) - .ast; + ); let dtree = ast.get_dependencies(); let dtree = dtree .into_iter() @@ -5302,7 +5485,7 @@ let a (v:(int32,int32)) = }; assert_eq!( &TypedDeclaration::Value(TypedTopLevelValue { - loc: (1, 4), + loc: (5,6), is_op: false, ident: "a".to_string(), args: vec![TypedArgDeclaration::Simple { @@ -5311,7 +5494,7 @@ let a (v:(int32,int32)) = underlining: vec![types::INT32, types::INT32,], loc: (0, 0) }, - loc: (1, 7) + loc: (8,9) }], ty: ResolvedType::Tuple { underlining: vec![types::INT32, types::INT32,], @@ -5320,12 +5503,12 @@ let a (v:(int32,int32)) = .fn_ty(&types::UNIT), value: TypedValueType::Function(vec![ TypedStatement::Declaration(TypedValueDeclaration { - loc: (2, 8), + loc: (35,40), is_op: false, is_curried: false, target: TypedPattern::Destructure(TypedDestructure::Tuple(vec![ - TypedPattern::Read("x".to_string(), types::INT32, (2, 9)), - TypedPattern::Read("y".to_string(), types::INT32, (2, 11)), + TypedPattern::Read("x".to_string(), types::INT32, (36,37)), + TypedPattern::Read("y".to_string(), types::INT32, (38,39)), ])), args: Vec::new(), value: TypedValueType::Expr(TypedExpr::ValueRead( @@ -5334,7 +5517,7 @@ let a (v:(int32,int32)) = underlining: vec![types::INT32, types::INT32,], loc: (0, 0) }, - (2, 16) + (43,44) )), ty: ResolvedType::Tuple { underlining: vec![types::INT32, types::INT32,], @@ -5343,7 +5526,7 @@ let a (v:(int32,int32)) = generictypes: None, abi: None, }), - TypedStatement::Return(TypedExpr::UnitLiteral, (3, 4)) + TypedStatement::Return(TypedExpr::UnitLiteral, (50,56)) ]), generics: None, abi: None, @@ -5360,7 +5543,7 @@ let fun a = match a where | Test::A (a,b) -> 1, | Test::B -> 0, "#; - let ast = Parser::from_source(SRC).module("".to_string()).ast; + let ast = file("", SRC); let dtree = ast.get_dependencies(); let dtree = dtree .into_iter() @@ -5382,7 +5565,6 @@ let fun a = match a where }; assert_eq!( - ty, &super::TypedDeclaration::TypeDefinition(super::ResolvedTypeDeclaration::Enum( super::TypedEnumDeclaration { ident: "Test".into(), @@ -5394,26 +5576,26 @@ let fun a = match a where underlining: vec![types::INT8; 2], loc: (0, 0) }, - loc: (1, 14) + loc: (15,16) }, crate::ast::EnumVariant::Unit { ident: "B".into(), - loc: (1, 30) + loc: (31,32) } ], - loc: (1, 5), + loc: (6,10), } - )) + )), + ty, ); assert_eq!( - fun, &super::TypedDeclaration::Value(super::TypedTopLevelValue { - loc: (2, 4), + loc: (37,40), is_op: false, ident: "fun".into(), args: vec![TypedArgDeclaration::Simple { - loc: (2, 8), + loc: (41,42), ident: "a".into(), ty: ResolvedType::User { name: "Test".into(), @@ -5428,20 +5610,20 @@ let fun a = match a where } .fn_ty(&types::INT8), value: TypedValueType::Expr(super::TypedExpr::Match(super::TypedMatch { - loc: (2, 12), + loc: (45,50), on: super::TypedExpr::ValueRead( "a".into(), ResolvedType::User { name: "Test".into(), generics: Vec::new(), - loc: (1, 5) + loc: (6,10) }, - (2, 18) + (51,52) ) .into(), arms: vec![ super::TypedMatchArm { - loc: (3, 2), + loc: (59,60), cond: TypedPattern::EnumVariant { ty: ResolvedType::Dependent { base: ResolvedType::User { @@ -5463,28 +5645,28 @@ let fun a = match a where pattern: Some( TypedPattern::Or( TypedPattern::Destructure(TypedDestructure::Tuple(vec![ - TypedPattern::Read("a".into(), types::INT8, (3, 12)), + TypedPattern::Read("a".into(), types::INT8, (71,72)), TypedPattern::Const("0".into(), types::INT8), ])) .into(), TypedPattern::Destructure(TypedDestructure::Tuple(vec![ TypedPattern::Const("0".into(), types::INT8), - TypedPattern::Read("a".into(), types::INT8, (3, 22)), + TypedPattern::Read("a".into(), types::INT8, (81,82)), ])) .into() ) .into() ), - loc: (3, 2) + loc: (61,68) }, block: Vec::new(), ret: Some( - super::TypedExpr::ValueRead("a".into(), types::INT8, (3, 29)) + super::TypedExpr::ValueRead("a".into(), types::INT8, (88,89)) .into() ) }, super::TypedMatchArm { - loc: (4, 2), + loc: (91,92), cond: TypedPattern::EnumVariant { ty: ResolvedType::Dependent { base: ResolvedType::User { @@ -5504,19 +5686,28 @@ let fun a = match a where }, variant: "Test::A".into(), pattern: Some( - super::TypedPattern::Destructure(TypedDestructure::Tuple(vec![ - TypedPattern::Read("a".into(), types::INT8, (4, 11)), - TypedPattern::Read("b".into(), types::INT8, (4, 13)), - ])).into() + super::TypedPattern::Destructure(TypedDestructure::Tuple( + vec![ + TypedPattern::Read("a".into(), types::INT8, (102,103)), + TypedPattern::Read("b".into(), types::INT8, (104,105)), + ] + )) + .into() ), - loc: (4, 2) + loc: (93,100) }, block: Vec::new(), - ret: Some(super::TypedExpr::IntegerLiteral { value: "1".into(), size: types::IntWidth::Eight }.into()) + ret: Some( + super::TypedExpr::IntegerLiteral { + value: "1".into(), + size: types::IntWidth::Eight + } + .into() + ) }, super::TypedMatchArm { - loc:(5,2), - cond: TypedPattern::EnumVariant { + loc: (113,114), + cond: TypedPattern::EnumVariant { ty: ResolvedType::Dependent { base: ResolvedType::User { name: "Test".into(), @@ -5528,19 +5719,26 @@ let fun a = match a where generics: Vec::new(), ident: "Test::B".into(), loc: (0, 0) - }, variant: "Test::B".into(), - pattern: None, - loc: (5,2) - + }, + variant: "Test::B".into(), + pattern: None, + loc: (115,122) }, - block:Vec::new(), - ret: Some(super::TypedExpr::IntegerLiteral { value: "0".into(), size: types::IntWidth::Eight }.into()) + block: Vec::new(), + ret: Some( + super::TypedExpr::IntegerLiteral { + value: "0".into(), + size: types::IntWidth::Eight + } + .into() + ) } ] })), generics: None, abi: None - }) + }), + fun, ); } } diff --git a/compiler/src/types.rs b/compiler/src/types.rs index 6fb671b..866f68b 100644 --- a/compiler/src/types.rs +++ b/compiler/src/types.rs @@ -1,3 +1,4 @@ + use std::collections::HashSet; use crate::typed_ast; @@ -626,12 +627,34 @@ impl ResolvedType { _ => false, } } + + pub(crate) fn replace_generic_inplace(&mut self, generic: &str) { + match self { + Self::Function {arg,returns,..} => { + arg.replace_generic_inplace(generic); + returns.replace_generic_inplace(generic); + } + Self::Pointer { underlining, .. } + |Self::Array { underlining, .. } + | Self::Ref { underlining } + | Self::Slice { underlining } + => underlining.replace_generic_inplace(generic), + Self::User {name, generics, loc, .. } if name == generic => { + if !generics.is_empty() { + //TODO! generate error if there are generics. + + } + *self = Self::Generic { name: generic.into(), loc: *loc }; + } + _ => (), + } + } } impl ToString for ResolvedType { fn to_string(&self) -> String { match self { - ResolvedType::Dependent { .. } => todo!(), + ResolvedType::Dependent { base, ident,.. } => format!("{}::{ident}",base.to_string()), ResolvedType::Number => "{number}".to_string(), ResolvedType::Bool => "bool".to_string(), ResolvedType::Alias { actual, .. } => actual.to_string(), diff --git a/language_spec.txt b/language_spec.txt new file mode 100644 index 0000000..986fe2f --- /dev/null +++ b/language_spec.txt @@ -0,0 +1,72 @@ +SimpleIdent ::= any sequence of alphanumeric chars or _ but doesn't lead with a number + +Ident ::= + | Ident "::" SimpleIdent + | SimpleIdent\ + +Operator ::= sequence of one of [+-*/!^&| ] + +Expr ::= + | Ident + | "..." + | '...' + | Number + | FnCall + | Match + | If with required else clause + | "[" (comma separated Expr)+ "]" + | "()" + + +FnCall ::= Expr " " Expr + +Match ::= + "match " Expr " where" + ("|" Pattern "->" (Expr | Block))+ + +Block ::= all prefixed with the same leading whitspace. should be longer than containing block. + Statement+ + [Expr] + +If ::= + "if" expr "then" (Expr|Block) + ["else" (Expr|Block)] + +Pattern ::= + | SimpleIdent + | "(" (Pattern",")+ ")" + | Ident " "* Pattern + | Ident "{" (SimpleIdent[":"Pattern])+"}" + | Pattern "|" Pattern + +Statement ::= + | If + | Match + | "let" SimplePattern Arg* [":"Type]"=" (Expr ";"|Block) + | Expr ";" + +Arg ::= + | SimpleIdent + | "()" + | "("Arg[":"Type]")" + | "(" comma separated Arg ")" + +Type ::= + | Ident + | Type "->" Type + | "("Type")" + | "["Type";"Number"]" + | "("(comma separated Type)+")" + | "()" + +GenericDecl::= + "for" "<" (comma separated SimpleIdent)+ ">" + +TopLevelDeclaration ::= + | TopLevelValue + | StructDecl + | EnumDeclaration + | AliasDecl + +TopLevelValue ::= [GenericDecl] "let" (SimpleIdent|"("Operator")") Arg* [":"Type] "=" (Expr ";"|Block) + diff --git a/llvm-codegen/src/code_gen.rs b/llvm-codegen/src/code_gen.rs index f7b81a2..eb8a5c2 100644 --- a/llvm-codegen/src/code_gen.rs +++ b/llvm-codegen/src/code_gen.rs @@ -24,10 +24,7 @@ use itertools::Itertools; use crate::type_resolver::TypeResolver; use compiler::typed_ast::{ - collect_args, ResolvedTypeDeclaration, StructDefinition, TypedArgDeclaration, - TypedBinaryOpCall, TypedDeclaration, TypedDestructure, TypedExpr, TypedFnCall, - TypedIfBranching, TypedIfExpr, TypedMatch, TypedMatchArm, TypedMemberRead, TypedPattern, - TypedStatement, TypedTopLevelValue, TypedValueDeclaration, TypedValueType, + collect_args, ResolvedTypeDeclaration, StructDefinition, TypedArgDeclaration, TypedBinaryOpCall, TypedBlock, TypedDeclaration, TypedDestructure, TypedExpr, TypedFnCall, TypedIf, TypedIfExpr, TypedMatch, TypedMatchArm, TypedMemberRead, TypedPattern, TypedStatement, TypedTopLevelValue, TypedValueDeclaration, TypedValueType }; use compiler::types::{self, ResolvedType}; use multimap::MultiMap; @@ -45,7 +42,7 @@ pub struct CodeGen<'ctx> { locals: HashMap>, current_module: String, target_info: TargetData, - enum_discrims:HashMap>, + enum_discrims: HashMap>, curry_ty: StructType<'ctx>, ret_target: Option>, // debug info starts here @@ -96,7 +93,7 @@ impl<'ctx> CodeGen<'ctx> { locals: HashMap::new(), ret_target: None, current_module: String::new(), - enum_discrims:HashMap::new(), + enum_discrims: HashMap::new(), dibuilder: None, compile_unit: None, difile: None, @@ -144,7 +141,7 @@ impl<'ctx> CodeGen<'ctx> { fields, renamed_fields, } => { - todo!() + todo!("todo destructuring struct args") } TypedArgDeclaration::Discard { loc, ty } | TypedArgDeclaration::Unit { loc, ty } => { //TODO debug info for these args. @@ -412,7 +409,9 @@ impl<'ctx> CodeGen<'ctx> { pat: TypedPattern, ) { match pat { - TypedPattern::EnumVariant { .. } => todo!("enum variant destructure. should be type checked."), + TypedPattern::EnumVariant { .. } => { + todo!("enum variant destructure. should be type checked.") + } TypedPattern::Const(_, _) => { println!("invalid code."); @@ -481,17 +480,18 @@ impl<'ctx> CodeGen<'ctx> { pub fn compile_statement(&mut self, stmnt: TypedStatement) { match stmnt { TypedStatement::IfBranching(ifbranch) => { - let TypedIfBranching { + let TypedIf { cond, true_branch, - else_ifs, else_branch, .. } = ifbranch; - let fun = self - .builder - .get_insert_block() - .unwrap() + let parent_block = self + .builder + .get_insert_block() + .unwrap(); + let fun = + parent_block .get_parent() .unwrap(); let true_block = self.ctx.append_basic_block(fun, ""); @@ -501,161 +501,39 @@ impl<'ctx> CodeGen<'ctx> { AnyValueEnum::IntValue(it) => it, _=> unreachable!("it can only ever be a point which means a value read or an expression resulting in a boolean") }; + //build the true branch. + self.builder.position_at_end(true_block); + for stmnt in true_branch.statements { + self.compile_statement(stmnt); + } + if let Some(true_expr) = true_branch.implicit_ret { + let _ = self.compile_expr(*true_expr); + } + self.builder.build_unconditional_branch(end_block); + self.builder.position_at_end(parent_block);//reset to parent block to build the conditional + if let Some(else_branch) = else_branch { + //if then else + let else_block = self.ctx.append_basic_block(fun, ""); + self.builder + .build_conditional_branch(cond, true_block, else_block) + .unwrap(); - match (else_ifs.is_empty(), else_branch.is_empty()) { - (true, true) => { - // if then - self.builder - .build_conditional_branch(cond, true_block, end_block) - .unwrap(); - self.builder.position_at_end(true_block); - for stmnt in true_branch { - self.compile_statement(stmnt); - } - self.builder.build_unconditional_branch(end_block).unwrap(); - } - (true, false) => { - //if then else - let else_block = self.ctx.append_basic_block(fun, ""); - self.builder - .build_conditional_branch(cond, true_block, else_block) - .unwrap(); - self.builder.position_at_end(true_block); - for stmnt in true_branch { - self.compile_statement(stmnt); - } - self.builder.build_unconditional_branch(end_block).unwrap(); - self.builder.position_at_end(else_block); - for stmnt in else_branch { - self.compile_statement(stmnt); - } - let _ = end_block.move_after(else_block); - self.builder.build_unconditional_branch(end_block).unwrap(); + self.builder.build_unconditional_branch(end_block).unwrap(); + self.builder.position_at_end(else_block); + for stmnt in else_branch.statements { + self.compile_statement(stmnt); } - (false, true) => { - //if then else if then - let cond_blocks = - std::iter::repeat_with(|| self.ctx.append_basic_block(fun, "")) - .take(else_ifs.len()) - .collect_vec(); - - self.builder - .build_conditional_branch( - cond, - true_block, - *cond_blocks.first().unwrap(), - ) - .unwrap(); - self.builder.position_at_end(true_block); - for stmnt in true_branch { - self.compile_statement(stmnt); - } - self.builder.position_at_end(true_block); - - let else_ifs = else_ifs - .into_iter() - .map(|(cond, stmnts)| { - let block = self.ctx.append_basic_block(fun, ""); - self.builder.position_at_end(block); - for stmnt in stmnts { - self.compile_statement(stmnt); - } - self.builder.build_unconditional_branch(end_block).unwrap(); - (cond, block) - }) - .zip(cond_blocks.iter().copied()) - .map(|((cond, block), cond_block)| { - let _ = block.move_after(cond_block); - (cond, block, cond_block) - }) - .collect_vec(); - let blocks = else_ifs - .into_iter() - .zip(cond_blocks.into_iter().skip(1).chain(once(end_block))) - .map(|(it, false_block)| (it.0, it.1, it.2, false_block)) - .collect_vec(); - let _ = end_block.move_after(blocks.last().map(|it| it.1).unwrap()); - for (cond, true_block, cond_block, false_block) in blocks { - self.builder.position_at_end(cond_block); - let cond = match self.compile_expr(*cond) { - AnyValueEnum::PointerValue(p) => self - .builder - .build_load(self.ctx.bool_type(), p, "") - .unwrap() - .into_int_value(), - AnyValueEnum::IntValue(i) => i, - _ => unreachable!(), - }; - self.builder - .build_conditional_branch(cond, true_block, false_block) - .unwrap(); - } - } - (false, false) => { - let cond_blocks = - std::iter::repeat_with(|| self.ctx.append_basic_block(fun, "")) - .take(else_ifs.len()) - .collect_vec(); - - self.builder - .build_conditional_branch( - cond, - true_block, - *cond_blocks.first().unwrap(), - ) - .unwrap(); - self.builder.position_at_end(true_block); - for stmnt in true_branch { - self.compile_statement(stmnt); - } - self.builder.build_unconditional_branch(end_block).unwrap(); - let else_block = self.ctx.append_basic_block(fun, ""); - let else_ifs = else_ifs - .into_iter() - .map(|(cond, stmnts)| { - let block = self.ctx.append_basic_block(fun, ""); - self.builder.position_at_end(block); - for stmnt in stmnts { - self.compile_statement(stmnt); - } - self.builder.build_unconditional_branch(end_block).unwrap(); - (cond, block) - }) - .zip(cond_blocks.iter().copied()) - .map(|((cond, block), cond_block)| { - let _ = block.move_after(cond_block); - (cond, block, cond_block) - }) - .collect_vec(); - let blocks = else_ifs - .into_iter() - .zip(cond_blocks.into_iter().skip(1).chain(once(else_block))) - .map(|(it, false_block)| (it.0, it.1, it.2, false_block)) - .collect_vec(); - let _ = else_block.move_after(blocks.last().map(|it| it.2).unwrap()); - for (cond, true_block, cond_block, false_block) in blocks { - self.builder.position_at_end(cond_block); - let cond = match self.compile_expr(*cond) { - AnyValueEnum::PointerValue(p) => self - .builder - .build_load(self.ctx.bool_type(), p, "") - .unwrap() - .into_int_value(), - AnyValueEnum::IntValue(i) => i, - _ => unreachable!(), - }; - self.builder - .build_conditional_branch(cond, true_block, false_block) - .unwrap(); - } - self.builder.position_at_end(else_block); - for stmnt in else_branch { - self.compile_statement(stmnt); - } - self.builder.build_unconditional_branch(end_block).unwrap(); - let _ = end_block.move_after(else_block); + if let Some(else_expr) = else_branch.implicit_ret { + let _ = self.compile_expr(*else_expr); } + let _ = end_block.move_after(else_block); + self.builder.build_unconditional_branch(end_block).unwrap(); + } else { + + self.builder + .build_conditional_branch(cond, true_block, end_block); } + #[cfg(debug_assertions)] let _ = self.module.print_to_file("./debug.ll"); self.builder.position_at_end(end_block); @@ -736,6 +614,23 @@ impl<'ctx> CodeGen<'ctx> { } } + fn compile_block(&mut self, block : TypedBlock) -> AnyValueEnum<'ctx> { + let TypedBlock { + statements, + implicit_ret, + ret_ty:_, + } = block; + + for stmnt in statements { + self.compile_statement(stmnt); + } + if let Some(ret) = implicit_ret { + self.compile_expr(*ret) + } else { + self.ctx.i8_type().const_zero().into() // in theory this should never matter. could be any value. + } + } + pub fn compile_expr(&mut self, expr: TypedExpr) -> AnyValueEnum<'ctx> { #[cfg(debug_assertions)] let _ = self.module.print_to_file("./debug.ll"); @@ -748,15 +643,15 @@ impl<'ctx> CodeGen<'ctx> { } } TypedExpr::IfExpr(expr) => { - let rt = expr.get_ty(); - let ty = self.type_resolver.resolve_type_as_basic(expr.get_ty()); - let TypedIfExpr { + let TypedIf { cond, true_branch, - else_ifs, else_branch, loc: _, + result_ty:rt } = expr; + let ty = self.type_resolver.resolve_type_as_basic(rt.clone()); + let fun = self .builder .get_insert_block() @@ -775,139 +670,37 @@ impl<'ctx> CodeGen<'ctx> { let result_block = self.ctx.append_basic_block(fun, ""); let then_block = self.ctx.append_basic_block(fun, ""); let else_block = self.ctx.append_basic_block(fun, ""); - if else_ifs.is_empty() { + + self.builder + .build_conditional_branch(root_cond, then_block, else_block) + .unwrap(); + self.builder.position_at_end(then_block); + + let true_value = self.compile_block(true_branch); + let true_value = convert_to_basic_value(true_value); + let true_value = if !rt.is_user() && true_value.is_pointer_value() { self.builder - .build_conditional_branch(root_cond, then_block, else_block) - .unwrap(); - self.builder.position_at_end(then_block); - for stmnt in true_branch.0 { - self.compile_statement(stmnt); - } - let true_value = convert_to_basic_value(self.compile_expr(*true_branch.1)); - let true_value = if !rt.is_user() && true_value.is_pointer_value() { - self.builder - .build_load(ty, true_value.into_pointer_value(), "") - .unwrap() - } else { - true_value - }; - self.builder.position_at_end(else_block); - for stmnt in else_branch.0 { - self.compile_statement(stmnt); - } - let else_value = convert_to_basic_value(self.compile_expr(*else_branch.1)); - let else_value = if !rt.is_user() && else_value.is_pointer_value() { - self.builder - .build_load(ty, else_value.into_pointer_value(), "") - .unwrap() - } else { - else_value - }; - self.builder.position_at_end(result_block); - let phi = self.builder.build_phi(ty, "").unwrap(); - phi.add_incoming(&[(&true_value, then_block), (&else_value, else_block)]); - let _ = result_block.move_after(else_block); - phi.as_any_value_enum() + .build_load(ty, true_value.into_pointer_value(), "") + .unwrap() } else { - let cond_blocks = - std::iter::repeat_with(|| self.ctx.append_basic_block(fun, "")) - .take(else_ifs.len()) - .collect_vec(); - self.builder - .build_conditional_branch( - root_cond, - then_block, - *cond_blocks.first().unwrap(), - ) - .unwrap(); - self.builder.position_at_end(result_block); - let phi = self.builder.build_phi(ty, "").unwrap(); - self.builder.position_at_end(then_block); - for stmnt in true_branch.0 { - self.compile_statement(stmnt); - } - let true_value = convert_to_basic_value(self.compile_expr(*true_branch.1)); - let true_value = if !rt.is_user() && true_value.is_pointer_value() { - self.builder - .build_load(ty, true_value.into_pointer_value(), "") - .unwrap() - } else { - true_value - }; - self.builder - .build_unconditional_branch(result_block) - .unwrap(); - phi.add_incoming(&[(&true_value, then_block)]); - let else_ifs = else_ifs - .into_iter() - .map(|(cond, stmnts, result)| { - let block = self.ctx.append_basic_block(fun, ""); - self.builder.position_at_end(block); - for stmnt in stmnts { - self.compile_statement(stmnt); - } - let result = convert_to_basic_value(self.compile_expr(*result)); - let result = if !rt.is_user() && result.is_pointer_value() { - self.builder - .build_load(ty, result.into_pointer_value(), "") - .unwrap() - } else { - result - }; - phi.add_incoming(&[( - &result, - self.builder.get_insert_block().unwrap(), - )]); - self.builder - .build_unconditional_branch(result_block) - .unwrap(); - (cond, block) - }) - .zip(cond_blocks.iter().copied()) - .map(|((cond, block), cond_block)| { - let _ = block.move_after(cond_block); - (cond, block, cond_block) - }) - .collect_vec(); - let _ = else_block.move_after(else_ifs.last().unwrap().1); - for ((cond, true_block, cond_block), false_block) in else_ifs - .into_iter() - .zip(cond_blocks.into_iter().skip(1).chain(once(else_block))) - { - self.builder.position_at_end(cond_block); - let cond = match self.compile_expr(*cond) { - AnyValueEnum::PointerValue(p) => self - .builder - .build_load(self.ctx.bool_type(), p, "") - .unwrap() - .into_int_value(), - AnyValueEnum::IntValue(i) => i, - _ => unreachable!(), - }; - self.builder - .build_conditional_branch(cond, true_block, false_block) - .unwrap(); - } - let _ = result_block.move_after(else_block); - self.builder.position_at_end(else_block); - for stmnt in else_branch.0 { - self.compile_statement(stmnt); - } - let else_value = convert_to_basic_value(self.compile_expr(*else_branch.1)); + true_value + }; + self.builder.position_at_end(else_block); + let else_value = self.compile_block(else_branch.expect("if expressions require an else")); + let else_value = convert_to_basic_value(else_value); + let else_value = if !rt.is_user() && else_value.is_pointer_value() { self.builder - .build_unconditional_branch(result_block) - .unwrap(); - let else_value = if !rt.is_user() && else_value.is_pointer_value() { - self.builder - .build_load(ty, else_value.into_pointer_value(), "") - .unwrap() - } else { - else_value - }; - phi.add_incoming(&[(&else_value, self.builder.get_insert_block().unwrap())]); - self.builder.position_at_end(result_block); - phi.as_any_value_enum() - } + .build_load(ty, else_value.into_pointer_value(), "") + .unwrap() + } else { + else_value + }; + self.builder.position_at_end(result_block); + let phi = self.builder.build_phi(ty, "").unwrap(); + phi.add_incoming(&[(&true_value, then_block), (&else_value, else_block)]); + let _ = result_block.move_after(else_block); + phi.as_any_value_enum() + } TypedExpr::BinaryOpCall(TypedBinaryOpCall { operator, @@ -2108,7 +1901,7 @@ impl<'ctx> CodeGen<'ctx> { compiler::typed_ast::ResolvedTypeDeclaration::Enum(enum_) => { let i32_t = self.type_resolver.resolve_type_as_basic(types::INT32); let i8_t = self.type_resolver.resolve_type_as_basic(types::INT8); - + if enum_.generics.is_some() { return; } @@ -2130,7 +1923,8 @@ impl<'ctx> CodeGen<'ctx> { enum_.ident.clone(), ResolvedTypeDeclaration::Enum(enum_.clone()), ); - self.enum_discrims.insert(enum_.ident.clone(),enum_discrims); + self.enum_discrims + .insert(enum_.ident.clone(), enum_discrims); let mut max_size = 0; for variant in &enum_.values { let variant_struct = self @@ -2811,27 +2605,72 @@ impl<'ctx> CodeGen<'ctx> { } match pat { - TypedPattern::EnumVariant { variant, pattern:Some(pat), ty, .. } => { - let variant_short = if let Some((_,short)) = variant.rsplit_once("::") { + TypedPattern::EnumVariant { + variant, + pattern: Some(pat), + ty, + .. + } => { + let variant_short = if let Some((_, short)) = variant.rsplit_once("::") { dbg!(short) } else { &variant }; let success_block = self.ctx.append_basic_block(fun, dbg!(&variant)); let _ = success_block.move_after(curr_block); - let ResolvedType::User { name, .. } = cond_ty else { unreachable!() }; - let discrim = dbg!(dbg!(&self.enum_discrims).get(dbg!(name)).unwrap()).iter().position(|it| it==variant_short).unwrap(); - let value = self.builder.build_struct_gep(self.ctx.struct_type(&[self.ctx.i8_type().into()], false), cond_v.into_pointer_value(), 0, "$discrim").unwrap(); - let value = self.builder.build_load(self.ctx.i8_type(),value,"").unwrap(); - let right_variant = self.builder.build_int_compare(IntPredicate::EQ, value.into_int_value(), self.ctx.i8_type().const_int(discrim as _, false), "").unwrap(); - let _ = self.builder.build_conditional_branch(right_variant, success_block, next_block); + let ResolvedType::User { name, .. } = cond_ty else { + unreachable!() + }; + let discrim = dbg!(dbg!(&self.enum_discrims).get(dbg!(name)).unwrap()) + .iter() + .position(|it| it == variant_short) + .unwrap(); + let value = self + .builder + .build_struct_gep( + self.ctx.struct_type(&[self.ctx.i8_type().into()], false), + cond_v.into_pointer_value(), + 0, + "$discrim", + ) + .unwrap(); + let value = self + .builder + .build_load(self.ctx.i8_type(), value, "") + .unwrap(); + let right_variant = self + .builder + .build_int_compare( + IntPredicate::EQ, + value.into_int_value(), + self.ctx.i8_type().const_int(discrim as _, false), + "", + ) + .unwrap(); + let _ = + self.builder + .build_conditional_branch(right_variant, success_block, next_block); self.builder.position_at_end(success_block); - let ResolvedType::Dependent { actual, ident, .. }= ty else { unreachable!() }; + let ResolvedType::Dependent { actual, ident, .. } = ty else { + unreachable!() + }; let variant_data_type = self.ctx.get_struct_type(&ident).unwrap(); - let value = self.builder.build_struct_gep(variant_data_type,cond_v.into_pointer_value(),1,"").unwrap(); - self.compile_complex_pattern(*pat, fun, &value.into(), &actual, success_block, next_block, bindings_block, bindings_phi, bindings_to_make) - - }, + let value = self + .builder + .build_struct_gep(variant_data_type, cond_v.into_pointer_value(), 1, "") + .unwrap(); + self.compile_complex_pattern( + *pat, + fun, + &value.into(), + &actual, + success_block, + next_block, + bindings_block, + bindings_phi, + bindings_to_make, + ) + } TypedPattern::EnumVariant { .. } => unreachable!(), TypedPattern::Destructure(TypedDestructure::Tuple(conds)) => { let ResolvedType::Tuple { underlining, .. } = cond_ty else { @@ -2876,13 +2715,12 @@ impl<'ctx> CodeGen<'ctx> { .remove_entry(&false) .map(|(_, a)| a) .unwrap_or_else(Vec::new); - complex.retain(|(pat,idx,ty)| { - + complex.retain(|(pat, idx, ty)| { let value = self .builder .build_struct_gep(tuple_ty, cond_v.into_pointer_value(), *idx as _, "") .unwrap(); - if let TypedPattern::Read(name,_,_)= pat { + if let TypedPattern::Read(name, _, _) = pat { bindings_to_make.insert(name.clone(), value.as_basic_value_enum()); false } else { diff --git a/other_sample.fb b/other_sample.fb index a966d40..95a8eb1 100644 --- a/other_sample.fb +++ b/other_sample.fb @@ -4,6 +4,6 @@ let fun test = match test where | Testing::One (1|0,a) -> a, | Testing::One _ -> 1, | Testing::Two -> 2, -| _ -> 3 +| _ -> 3, -let main () = () \ No newline at end of file +let main () = (); \ No newline at end of file diff --git a/samples/test.fb b/samples/test.fb index 6d754b6..23937df 100644 --- a/samples/test.fb +++ b/samples/test.fb @@ -1,9 +1,9 @@ -let foo : int32 = 3 +let foo : int32 = 3; let bar quz : int32 -> int32 = let baz : str = "merp \" yes"; return 2; -let ^^ lhs rhs : int32 -> int32 -> int32 = +let (^^) lhs rhs : int32 -> int32 -> int32 = bar foo; return 1; \ No newline at end of file diff --git a/testing.sh b/testing.sh new file mode 100755 index 0000000..9a8d334 --- /dev/null +++ b/testing.sh @@ -0,0 +1,11 @@ +#!/bin/zsh +for i in {1..1000} +do + if cargo test -p compiler -- typed_ast::tests > out.txt 2>&1 + then + echo "$i passed" + else + echo "$i failed" + break + fi +done \ No newline at end of file