From 30668b5ad2942c5ae8dee5677470790586bfddad Mon Sep 17 00:00:00 2001 From: Christoph Hegemann Date: Sun, 18 Aug 2024 07:33:30 +0200 Subject: [PATCH] Basic Modules (#22) --- Cargo.lock | 81 +- README.md | 2 +- crates/backend/src/codegen.rs | 95 +-- crates/backend/src/lib.rs | 22 +- crates/backend/src/wasm_builder.rs | 84 +- crates/frontend/Cargo.toml | 2 + crates/frontend/src/builtins.rs | 19 +- crates/frontend/src/error.rs | 33 +- crates/frontend/src/highlight.rs | 25 +- crates/frontend/src/ir.rs | 45 +- crates/frontend/src/ir/format.rs | 14 +- crates/frontend/src/ir/names.rs | 254 ++++-- crates/frontend/src/lib.rs | 135 ++- crates/frontend/src/module_dag.rs | 48 ++ crates/frontend/src/parser/grammar.rs | 149 +++- crates/frontend/src/parser/lexer.rs | 26 + crates/frontend/src/syntax/nodes.rs | 280 +++++++ crates/frontend/src/syntax/nodes.ungram | 22 +- crates/frontend/src/types.rs | 38 +- crates/frontend/src/types/check.rs | 790 ++++++++++-------- crates/frontend/src/types/error.rs | 70 +- crates/frontend/src/types/module.rs | 256 ++++++ crates/frontend/src/types/names.rs | 61 +- crates/frontend/tests/lib.rs | 13 +- crates/frontend/tests/parsing/modules.nemo | 15 + .../snapshots/lib__parsing@arrays.nemo.snap | 353 ++++---- .../snapshots/lib__parsing@block.nemo.snap | 115 +-- .../snapshots/lib__parsing@closures.nemo.snap | 258 +++--- .../snapshots/lib__parsing@decl.nemo.snap | 345 ++++---- .../lib__parsing@expr_postfix.nemo.snap | 291 +++---- .../lib__parsing@global_annotation.nemo.snap | 431 +++++----- .../tests/snapshots/lib__parsing@if.nemo.snap | 73 +- .../snapshots/lib__parsing@infix_op.nemo.snap | 499 +++++------ .../snapshots/lib__parsing@literals.nemo.snap | 221 ++--- .../snapshots/lib__parsing@modules.nemo.snap | 183 ++++ .../snapshots/lib__parsing@poly.nemo.snap | 267 +++--- .../snapshots/lib__parsing@return.nemo.snap | 45 +- .../snapshots/lib__parsing@structs.nemo.snap | 305 +++---- .../lib__parsing@toplevels.nemo.snap | 483 +++++------ .../snapshots/lib__parsing@variants.nemo.snap | 561 ++++++------- ...pe_errors@operator_type_mismatch.nemo.snap | 3 +- ..._type_errors@unknown_alternative.nemo.snap | 8 +- crates/language-server/src/lib.rs | 43 +- crates/language-server/src/vfs.rs | 5 +- crates/wasm-lib/Cargo.toml | 2 +- crates/wasm-lib/src/lib.rs | 47 +- design/modules.md | 26 + playground/examples/strings.nemo | 64 +- 48 files changed, 4253 insertions(+), 2954 deletions(-) create mode 100644 crates/frontend/src/module_dag.rs create mode 100644 crates/frontend/src/types/module.rs create mode 100644 crates/frontend/tests/parsing/modules.nemo create mode 100644 crates/frontend/tests/snapshots/lib__parsing@modules.nemo.snap diff --git a/Cargo.lock b/Cargo.lock index 6ff122fc..d6543fed 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,18 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy", +] + [[package]] name = "aho-corasick" version = "1.1.3" @@ -279,7 +291,9 @@ dependencies = [ "num-derive", "num-traits", "rowan", + "string-interner", "text-size", + "topological-sort", "yansi", ] @@ -301,6 +315,9 @@ name = "hashbrown" version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +dependencies = [ + "ahash", +] [[package]] name = "heck" @@ -655,6 +672,17 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa42c91313f1d05da9b26f267f931cf178d4aba455b4c4622dd7355eb80c6640" +[[package]] +name = "string-interner" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c6a0d765f5807e98a091107bae0a56ea3799f66a5de47b2c84c94a39c09974e" +dependencies = [ + "cfg-if", + "hashbrown", + "serde", +] + [[package]] name = "strsim" version = "0.11.1" @@ -693,6 +721,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" +[[package]] +name = "topological-sort" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea68304e134ecd095ac6c3574494fc62b909f416c4fca77e440530221e549d3d" + [[package]] name = "ungrammar" version = "1.16.1" @@ -744,6 +778,12 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + [[package]] name = "walkdir" version = "2.5.0" @@ -756,19 +796,20 @@ dependencies = [ [[package]] name = "wasm-bindgen" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" dependencies = [ "cfg-if", + "once_cell", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" dependencies = [ "bumpalo", "log", @@ -781,9 +822,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -791,9 +832,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" dependencies = [ "proc-macro2", "quote", @@ -804,9 +845,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" +checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" [[package]] name = "wasm-encoder" @@ -945,3 +986,23 @@ name = "yansi" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" + +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/README.md b/README.md index 6125199b..79d76b07 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,7 @@ While developing the compiler a couple of other tools are useful/necessary to ha The easiest way I've found to install them is using [cargo-binstall]: ```sh -cargo binstall just wasm-bindgen-cli wasm-tools wasm-opt +cargo binstall just wasm-bindgen-cli wasm-tools wasm-opt watchexec-cli ``` Additionally you'll need a version of Node > 22.0.0 if you'd like to run the generated Wasm code outside of the browser. (You could probably also make Deno work) diff --git a/crates/backend/src/codegen.rs b/crates/backend/src/codegen.rs index 941b71b3..3147ec9f 100644 --- a/crates/backend/src/codegen.rs +++ b/crates/backend/src/codegen.rs @@ -3,14 +3,15 @@ use std::fmt::Write; use crate::wasm_builder::{BodyBuilder, Builder}; use frontend::ir::{ - Callee, Declaration, DeclarationData, Expr, ExprData, Func, Id, Lit, LitData, Name, NameSupply, - Op, OpData, Pattern, PatternData, Program, SetTarget, SetTargetData, Substitution, Ty, TypeDef, + Callee, Ctx, Declaration, DeclarationData, Expr, ExprData, Func, Lit, LitData, ModuleId, Name, + NameTag, Op, OpData, Pattern, PatternData, Program, SetTarget, SetTargetData, Substitution, Ty, + TypeDef, }; use text_size::TextRange; use wasm_encoder::{BlockType, ConstExpr, HeapType, Instruction, RefType, ValType}; -pub fn codegen(program: Program, name_supply: NameSupply) -> (Vec, NameSupply) { - let builder = Builder::new(name_supply); +pub fn codegen(program: Program, ctx: Ctx) -> (Vec, Ctx) { + let builder = Builder::new(ctx); let mut codegen = Codegen { builder, poly_funcs: HashMap::new(), @@ -128,10 +129,10 @@ impl<'a> Codegen<'a> { fn compile_expr(&mut self, body: &mut BodyBuilder, expr: Expr) -> Vec> { match *expr.it { ExprData::Lit { lit } => self.compile_lit(lit), - ExprData::Var { name } => match name { - Name::Local(_) => vec![Instruction::LocalGet(body.lookup_local(&name).unwrap())], - Name::Global(_) => vec![Instruction::GlobalGet(self.builder.lookup_global(&name))], - Name::Func(_) => { + ExprData::Var { name } => match name.tag { + NameTag::Local => vec![Instruction::LocalGet(body.lookup_local(&name).unwrap())], + NameTag::Global => vec![Instruction::GlobalGet(self.builder.lookup_global(&name))], + NameTag::Func => { let Ty::Func(ty) = &expr.ty else { unreachable!("Non-function type for function reference") }; @@ -291,10 +292,11 @@ impl<'a> Codegen<'a> { } => { let mut instrs = vec![]; - let gen_name = self.builder.name_supply.local_idx(Id { - it: "$match_scrutinee".to_string(), - at: scrutinee.at, - }); + let (gen_name, _) = self.builder.name_supply().local_idx( + ModuleId::CODEGEN, + "$match_scrutinee", + scrutinee.at, + ); let scrutinee_ty = self.builder.val_ty(&scrutinee.ty); let scrutinee_local = body.new_local(gen_name, scrutinee_ty); instrs.extend(self.compile_expr(body, scrutinee)); @@ -393,10 +395,11 @@ impl<'a> Codegen<'a> { let (func_name, func_idx) = self .builder .declare_anon_func(expr.at, closure_info.closure_func_ty); - let env_name = self.builder.name_supply.local_idx(Id { - at: TextRange::empty(0.into()), - it: "env".to_string(), - }); + let (env_name, _) = self.builder.name_supply().local_idx( + ModuleId::CODEGEN, + "env", + TextRange::default(), + ); let mut func_params = vec![( env_name, ValType::Ref(RefType { @@ -582,20 +585,18 @@ impl<'a> Codegen<'a> { } SetTargetData::SetVar { name } => { let mut instrs = self.compile_expr(body, expr); - match name { - Name::Global(_) => { + match name.tag { + NameTag::Global => { instrs.push(Instruction::GlobalSet(self.builder.lookup_global(&name))); } - Name::Local(_) => { + NameTag::Local => { instrs.push(Instruction::LocalSet(body.lookup_local(&name).unwrap())); } - Name::Func(_) - | Name::Type(_) - | Name::TypeVar(_) - | Name::Field(_) - | Name::Gen(_) => { - unreachable!("can't set a non local/global variable") - } + NameTag::Func + | NameTag::Type + | NameTag::TypeVar + | NameTag::Field + | NameTag::Gen => unreachable!("can't set a non local/global variable"), }; instrs } @@ -609,24 +610,16 @@ impl<'a> Codegen<'a> { if let Some(existing) = poly_func.instances.get(&tys) { return *existing; } - let definition = self - .builder - .name_supply - .lookup(name) - .expect("Unknown polyfunc"); - let mut it = format!("{}#", definition.it); + let func_name = self.builder.ctx.display_name(name); + let mut it = format!("{}#", func_name); for param in &tys { - write!( - &mut it, - "_{}", - param.display(&self.builder.name_supply.name_map) - ) - .unwrap() + write!(&mut it, "_{}", param.display(&self.builder.ctx)).unwrap() } - let new_name = self.builder.name_supply.func_idx(Id { - it, - at: definition.at, - }); + let (new_name, _) = self.builder.name_supply().func_idx( + ModuleId::CODEGEN, + &func_name, + TextRange::default(), + ); poly_func.instances.insert(tys, new_name); new_name }; @@ -703,10 +696,14 @@ impl<'a> Codegen<'a> { } } } + let (start_fn, _) = self.builder.name_supply().func_idx( + ModuleId::CODEGEN, + "start", + TextRange::default(), + ); let start_locals = start_body.get_locals(); - self.builder.declare_start(program.start_fn); - self.builder - .fill_func(program.start_fn, start_locals, start_instrs); + self.builder.declare_start(start_fn); + self.builder.fill_func(start_fn, start_locals, start_instrs); } for func in program.funcs { @@ -722,14 +719,12 @@ impl<'a> Codegen<'a> { let body = self.compile_expr(&mut body_builder, func.body); let locals = body_builder.get_locals(); self.builder.fill_func(func.name, locals, body); - self.builder.declare_export( - func.name, - self.builder.resolve_name(func.name).it.to_string(), - ); + self.builder + .declare_export(func.name, self.builder.resolve_name(func.name)); } } - pub fn finish(self) -> (Vec, NameSupply) { + pub fn finish(self) -> (Vec, Ctx) { self.builder.finish() } } diff --git a/crates/backend/src/lib.rs b/crates/backend/src/lib.rs index 2093f7bc..8d69589f 100644 --- a/crates/backend/src/lib.rs +++ b/crates/backend/src/lib.rs @@ -7,22 +7,16 @@ use frontend::run_frontend; pub fn compile_program(source: &str) -> Result, String> { let check_result = run_frontend(source); - if !check_result.errors.is_empty() { - for err in &check_result.errors { - eprintln!( - "{}", - err.display(source, &check_result.names.name_map, true) - ); + if check_result.has_errors() { + let mut count = 0; + for err in check_result.errors() { + count += 1; + eprintln!("{}", err.display(source, &check_result.ctx, true)); } - return Err(format!( - "Compiling failed with {} errors", - check_result.errors.len() - )); + return Err(format!("Compiling failed with {} errors", count)); } - let (wasm, _) = codegen( - check_result.ir.expect("No IR despite no check errors"), - check_result.names, - ); + let (ctx, ir) = check_result.consume(); + let (wasm, _) = codegen(ir.expect("No IR despite no check errors"), ctx); Ok(wasm) } diff --git a/crates/backend/src/wasm_builder.rs b/crates/backend/src/wasm_builder.rs index 2c3152a8..8ae31dd6 100644 --- a/crates/backend/src/wasm_builder.rs +++ b/crates/backend/src/wasm_builder.rs @@ -2,7 +2,9 @@ use std::fmt::Write; use std::iter; use std::{collections::HashMap, mem}; -use frontend::ir::{FuncTy, Id, Import, Name, NameSupply, Struct, Substitution, Ty, Variant}; +use frontend::ir::{ + Ctx, FuncTy, Import, ModuleId, Name, NameSupply, Struct, Substitution, Ty, Variant, +}; use text_size::TextRange; use wasm_encoder::{ self, ArrayType, CodeSection, CompositeType, ConstExpr, DataCountSection, DataSection, @@ -95,7 +97,7 @@ pub struct ClosureInfo { #[derive(Debug)] pub struct Builder<'a> { - pub(crate) name_supply: NameSupply, + pub(crate) ctx: Ctx, funcs: HashMap>, globals: HashMap, types: Vec, @@ -119,9 +121,9 @@ pub struct Builder<'a> { } impl<'a> Builder<'a> { - pub fn new(name_supply: NameSupply) -> Builder<'a> { + pub fn new(ctx: Ctx) -> Builder<'a> { Builder { - name_supply, + ctx, funcs: HashMap::new(), globals: HashMap::new(), datas: vec![], @@ -140,17 +142,21 @@ impl<'a> Builder<'a> { } } - fn _print_funcs(&self) { - for (name, id) in self.name_supply.name_map.iter() { - if let Name::Func(n) = name { - eprintln!("$fn:{n} = {id:?}") - } - } + pub fn name_supply(&self) -> &NameSupply { + self.ctx.get_name_supply(ModuleId::CODEGEN) } - pub fn finish(self) -> (Vec, NameSupply) { + // fn _print_funcs(&self) { + // for (name, id) in self.name_supply().name_map.iter() { + // if name.tag == NameTag::Func { + // eprintln!("$fn:{:?}->{} = {id:?}", name.module, name.idx) + // } + // } + // } + + pub fn finish(self) -> (Vec, Ctx) { let mut module = Module::new(); - let names = self.name_supply; + let ctx = self.ctx; // self._print_funcs(); // type_section @@ -167,17 +173,17 @@ impl<'a> Builder<'a> { for (name, info) in self.structs { for (tys, type_idx) in &info.instances { - let mut it = names.lookup(name).unwrap().it.clone(); + let mut it = ctx.display_name(name); if !tys.is_empty() { it.push('#'); } for param in tys { - write!(&mut it, "_{}", param.display(&names.name_map)).unwrap() + write!(&mut it, "_{}", param.display(&ctx)).unwrap() } type_names.append(*type_idx, &it); let mut field_names = WasmNameMap::new(); for (field, _) in info.definition.fields.iter() { - field_names.append(info.field_idx(*field), &names.lookup(name).unwrap().it) + field_names.append(info.field_idx(*field), &ctx.display_name(name)) } all_field_names.append(*type_idx, &field_names); } @@ -185,12 +191,12 @@ impl<'a> Builder<'a> { for (name, info) in self.variants { for (tys, type_idx) in info.instances { - let mut it = names.lookup(name).unwrap().it.clone(); + let mut it = ctx.display_name(name); if !tys.is_empty() { it.push('#'); } for param in tys { - write!(&mut it, "_{}", param.display(&names.name_map)).unwrap() + write!(&mut it, "_{}", param.display(&ctx)).unwrap() } type_names.append(type_idx, &it); } @@ -206,7 +212,7 @@ impl<'a> Builder<'a> { let mut import_indices = vec![]; for (name, data) in imports { import_section.import(&data.ns, &data.func, EntityType::Function(data.ty_idx)); - function_names.append(data.index, &names.lookup(name).unwrap().it); + function_names.append(data.index, &ctx.display_name(name)); import_indices.push(data.index); } // function_section @@ -215,7 +221,7 @@ impl<'a> Builder<'a> { let mut function_indices = vec![]; funcs.sort_by_key(|(_, v)| v.index); for (name, func) in funcs.iter() { - function_names.append(func.index, &names.lookup(*name).unwrap().it); + function_names.append(func.index, &ctx.display_name(*name)); function_section.function(func.ty); function_indices.push(func.index); } @@ -229,7 +235,7 @@ impl<'a> Builder<'a> { let mut global_names = WasmNameMap::new(); for data in globals { global_section.global(data.ty, &data.init); - global_names.append(data.index, &names.lookup(data.name).unwrap().it) + global_names.append(data.index, &ctx.display_name(data.name)) } // export_section let mut export_section = ExportSection::new(); @@ -255,7 +261,7 @@ impl<'a> Builder<'a> { names: local_names, }) = func.locals else { - panic!("No locals for function {}", names.lookup(name).unwrap().it) + panic!("No locals for function {}", ctx.display_name(name)) }; let mut func_body = Function::new_with_locals_types(locals); for instr in func.body.unwrap() { @@ -266,7 +272,7 @@ impl<'a> Builder<'a> { let mut local_names_map = WasmNameMap::new(); for (index, name) in local_names { - local_names_map.append(index, &names.lookup(name).unwrap().it); + local_names_map.append(index, &ctx.display_name(name)); } let ix = (_ix + _import_count) as u32; @@ -302,14 +308,15 @@ impl<'a> Builder<'a> { module.section(&code_section); module.section(&data_section); module.section(&name_section); - (module.finish(), names) + (module.finish(), ctx) } - pub fn resolve_name(&self, name: Name) -> Id { - self.name_supply - .lookup(name) - .cloned() - .unwrap_or_else(|| panic!("Failed to resolve: {name:?}")) + pub fn resolve_name(&self, name: Name) -> String { + self.ctx.display_name(name) + } + + pub fn resolve_name_range(&self, name: Name) -> (String, TextRange) { + self.ctx.resolve(name) } pub fn declare_variant(&mut self, ty: Variant) { @@ -421,7 +428,7 @@ impl<'a> Builder<'a> { } else { panic!( "tried to get heap type {} before declaring it", - self.resolve_name(name).it + self.resolve_name(name) ) } } @@ -436,7 +443,7 @@ impl<'a> Builder<'a> { self.structs.get(&name).unwrap_or_else(|| { panic!( "Tried to get struct type before declaring it: {}", - self.resolve_name(name).it + self.resolve_name(name) ) }) } @@ -685,11 +692,9 @@ impl<'a> Builder<'a> { pub fn declare_anon_func(&mut self, at: TextRange, ty: TypeIdx) -> (Name, FuncIdx) { let index = (self.imports.len() + self.funcs.len()) as u32; - let name = self.name_supply.func_idx(Id { - // TODO: Use surrounding function name or something? - it: format!("closure-{index}"), - at, - }); + let (name, _) = + self.name_supply() + .func_idx(ModuleId::CODEGEN, &format!("closure-{index}"), at); self.funcs.insert( name, FuncData { @@ -727,11 +732,10 @@ impl<'a> Builder<'a> { if let Some(idx) = self.func_refs.get(&name) { return *idx; } - let Id { it, at } = self.resolve_name(name); - let func_name = self.name_supply.func_idx(Id { - it: format!("{it}#ref"), - at, - }); + let (it, at) = self.resolve_name_range(name); + let (func_name, _) = + self.name_supply() + .func_idx(ModuleId::CODEGEN, &format!("{it}#ref"), at); let mut instrs: Vec = (0..ty.arguments.len()) .map(|i| Instruction::LocalGet(i as u32 + 1)) .collect(); diff --git a/crates/frontend/Cargo.toml b/crates/frontend/Cargo.toml index 28aa6faf..6315f0e0 100644 --- a/crates/frontend/Cargo.toml +++ b/crates/frontend/Cargo.toml @@ -15,6 +15,8 @@ text-size = "1.1.1" line-index = "0.1.1" lexpr = "0.2.7" derive_ir = { path = "../derive_ir" } +string-interner = "0.17.0" +topological-sort = "0.2.2" [dev-dependencies] insta = { version = "1.34.0", features = ["glob"] } diff --git a/crates/frontend/src/builtins.rs b/crates/frontend/src/builtins.rs index f7a26bec..f7bc105f 100644 --- a/crates/frontend/src/builtins.rs +++ b/crates/frontend/src/builtins.rs @@ -1,4 +1,4 @@ -use crate::ir::{FuncTy, Name, Ty}; +use crate::ir::{FuncTy, ModuleId, Name, NameTag, Ty}; use std::collections::HashMap; use std::sync::LazyLock; @@ -52,6 +52,13 @@ fn i32_func_binary(name: &'static str) -> Fn { } } +// Should be initialized after namemap/context is created +static TODO_NAME: Name = Name { + tag: NameTag::Gen, + idx: 0, + module: ModuleId::PRIM, +}; + static BUILTINS: LazyLock> = LazyLock::new(|| { let mut m = HashMap::new(); m.insert("f32_neg", f32_func_unary("f32_neg")); @@ -124,9 +131,9 @@ static BUILTINS: LazyLock> = LazyLock::new(|| { "array_len", Fn { name: "array_len", - ty_params: vec![Name::Gen(0)], + ty_params: vec![TODO_NAME], ty: FuncTy { - arguments: vec![Ty::Array(Box::new(Ty::Var(Name::Gen(0))))], + arguments: vec![Ty::Array(Box::new(Ty::Var(TODO_NAME)))], result: Ty::I32, }, }, @@ -135,10 +142,10 @@ static BUILTINS: LazyLock> = LazyLock::new(|| { "array_new", Fn { name: "array_new", - ty_params: vec![Name::Gen(0)], + ty_params: vec![TODO_NAME], ty: FuncTy { - arguments: vec![Ty::Var(Name::Gen(0)), Ty::I32], - result: Ty::Array(Box::new(Ty::Var(Name::Gen(0)))), + arguments: vec![Ty::Var(TODO_NAME), Ty::I32], + result: Ty::Array(Box::new(Ty::Var(TODO_NAME))), }, }, ); diff --git a/crates/frontend/src/error.rs b/crates/frontend/src/error.rs index bab63092..56e533ba 100644 --- a/crates/frontend/src/error.rs +++ b/crates/frontend/src/error.rs @@ -1,27 +1,26 @@ -use crate::ir::NameMap; -use crate::parser::ParseError; use crate::types::TyError; +use crate::{ir::Ctx, parser::ParseError}; use line_index::{LineCol, LineIndex}; use std::fmt; use text_size::TextRange; -#[derive(Debug)] -pub enum CheckError { - ParseError(ParseError), - TypeError(TyError), +#[derive(Debug, Clone)] +pub enum CheckError<'a> { + ParseError(&'a ParseError), + TypeError(&'a TyError), } -impl CheckError { +impl<'a> CheckError<'a> { pub fn display<'src, 'err>( &'err self, source: &'src str, - name_map: &'src NameMap, + ctx: &'src Ctx, colors: bool, ) -> DisplayCheckError<'src, 'err> { DisplayCheckError { source, - error: self, - name_map, + error: self.clone(), + ctx, colors, } } @@ -33,10 +32,10 @@ impl CheckError { } } - pub fn message(&self, name_map: &NameMap) -> String { + pub fn message(&self, ctx: &Ctx) -> String { match self { CheckError::ParseError(err) => err.it.clone(), - CheckError::TypeError(err) => err.message(name_map), + CheckError::TypeError(err) => err.message(ctx), } } @@ -49,9 +48,9 @@ impl CheckError { } pub struct DisplayCheckError<'a, 'b> { - error: &'b CheckError, + error: CheckError<'b>, source: &'a str, - name_map: &'a NameMap, + ctx: &'a Ctx, colors: bool, } @@ -62,11 +61,7 @@ impl fmt::Display for DisplayCheckError<'_, '_> { write!(f, "{}", err.display(self.source, self.colors)) } CheckError::TypeError(err) => { - write!( - f, - "{}", - err.display(self.source, self.name_map, self.colors) - ) + write!(f, "{}", err.display(self.source, self.ctx, self.colors)) } } } diff --git a/crates/frontend/src/highlight.rs b/crates/frontend/src/highlight.rs index dd9fb67b..549663ef 100644 --- a/crates/frontend/src/highlight.rs +++ b/crates/frontend/src/highlight.rs @@ -1,6 +1,6 @@ -use crate::ir::Name; +use crate::ir::NameTag; use crate::parser::SyntaxKind; -use crate::syntax::{AstNode, Root}; +use crate::syntax::{AstNode, Module}; use crate::types::OccurrenceMap; use crate::T; use text_size::TextRange; @@ -24,9 +24,9 @@ pub struct Highlight { pub kind: HighlightKind, } -pub fn highlight(root: &Root, occurrences: &OccurrenceMap) -> Vec { +pub fn highlight(module: &Module, occurrences: &OccurrenceMap) -> Vec { let mut highlights = Vec::new(); - for node in root.syntax().descendants_with_tokens() { + for node in module.syntax().descendants_with_tokens() { match node.kind() { T![let] | T![set] @@ -40,6 +40,9 @@ pub fn highlight(root: &Root, occurrences: &OccurrenceMap) -> Vec { | T![variant] | T![struct] | T![import] + | T![use] + | T![module] + | T![exports] | T![from] => { highlights.push(Highlight { range: node.text_range(), @@ -82,38 +85,38 @@ pub fn highlight(root: &Root, occurrences: &OccurrenceMap) -> Vec { for (ptr, occurrence) in occurrences { let name = *occurrence.name(); - match name { - Name::Global(_) => { + match name.tag { + NameTag::Global => { highlights.push(Highlight { range: ptr.0, kind: HighlightKind::Global, }); } - Name::Local(_) => { + NameTag::Local => { highlights.push(Highlight { range: ptr.0, kind: HighlightKind::Local, }); } - Name::Func(_) => { + NameTag::Func => { highlights.push(Highlight { range: ptr.0, kind: HighlightKind::Function, }); } - Name::Type(_) | Name::TypeVar(_) => { + NameTag::Type | NameTag::TypeVar => { highlights.push(Highlight { range: ptr.0, kind: HighlightKind::Type, }); } - Name::Field(_) => { + NameTag::Field => { highlights.push(Highlight { range: ptr.0, kind: HighlightKind::Property, }); } - Name::Gen(_) => {} + NameTag::Gen => {} } } highlights.sort_by_key(|hl| hl.range.start()); diff --git a/crates/frontend/src/ir.rs b/crates/frontend/src/ir.rs index 26e642c0..942c4ae8 100644 --- a/crates/frontend/src/ir.rs +++ b/crates/frontend/src/ir.rs @@ -3,7 +3,7 @@ mod names; use core::fmt; use derive_ir::IrBuilder; -pub use names::{Id, Name, NameMap, NameSupply}; +pub use names::{CompactId, Ctx, Id, ModuleId, ModuleIdGen, Name, NameSupply, NameTag, Symbol}; use std::{ collections::{BTreeMap, HashMap, HashSet}, fmt::Debug, @@ -29,8 +29,8 @@ pub enum Ty { } impl Ty { - pub fn display<'a>(&'a self, name_map: &'a NameMap) -> TyDisplay<'a> { - TyDisplay { ty: self, name_map } + pub fn display<'a>(&'a self, ctx: &'a Ctx) -> TyDisplay<'a> { + TyDisplay { ty: self, ctx } } fn vars_inner(&self, acc: &mut HashSet) { @@ -63,7 +63,7 @@ impl Ty { pub struct TyDisplay<'a> { ty: &'a Ty, - name_map: &'a NameMap, + ctx: &'a Ctx, } impl fmt::Display for TyDisplay<'_> { @@ -75,26 +75,26 @@ impl fmt::Display for TyDisplay<'_> { Ty::Unit => write!(f, "unit"), Ty::Bytes => write!(f, "bytes"), Ty::Diverge => write!(f, "!"), - Ty::Array(t) => write!(f, "[{}]", t.display(self.name_map)), + Ty::Array(t) => write!(f, "[{}]", t.display(self.ctx)), Ty::Cons { name: t, ty_args: args, } => { - write!(f, "{}", self.name_map.get(t).unwrap().it)?; + self.ctx.fmt_name(f, *t)?; if !args.is_empty() { write!(f, "[")?; for (idx, arg) in args.tys().into_iter().enumerate() { if idx != 0 { write!(f, ", ")? } - write!(f, "{}", arg.display(self.name_map))?; + write!(f, "{}", arg.display(self.ctx))?; } write!(f, "]")?; }; Ok(()) } - Ty::Var(v) => write!(f, "{}", self.name_map.get(v).unwrap().it), - Ty::Func(func_ty) => func_ty.display(self.name_map).fmt(f), + Ty::Var(v) => self.ctx.fmt_name(f, *v), + Ty::Func(func_ty) => func_ty.display(self.ctx).fmt(f), Ty::Error => write!(f, "ERROR"), } } @@ -107,17 +107,14 @@ pub struct FuncTy { } impl FuncTy { - pub fn display<'a>(&'a self, name_map: &'a NameMap) -> FuncTyDisplay<'a> { - FuncTyDisplay { - func_ty: self, - name_map, - } + pub fn display<'a>(&'a self, ctx: &'a Ctx) -> FuncTyDisplay<'a> { + FuncTyDisplay { func_ty: self, ctx } } } pub struct FuncTyDisplay<'a> { func_ty: &'a FuncTy, - name_map: &'a NameMap, + ctx: &'a Ctx, } impl fmt::Display for FuncTyDisplay<'_> { @@ -128,10 +125,10 @@ impl fmt::Display for FuncTyDisplay<'_> { self.func_ty .arguments .iter() - .map(|a| format!("{}", a.display(self.name_map))) + .map(|a| format!("{}", a.display(self.ctx))) .collect::>() .join(", "), - self.func_ty.result.display(self.name_map) + self.func_ty.result.display(self.ctx) ) } } @@ -335,7 +332,7 @@ impl Expr { match &*expr.it { ExprData::Lit { .. } => {} ExprData::Var { name } => { - if let Name::Local(_) = name { + if let NameTag::Local = name.tag { // We don't want to override an existing entry for a variable that gets re-assigned current.entry(*name).or_insert_with(|| FreeVarInfo { ty: &expr.ty, @@ -602,11 +599,19 @@ impl Func { } } -#[derive(Debug, PartialEq, Clone)] +#[derive(Debug, PartialEq, Clone, Default)] pub struct Program { pub imports: Vec, pub types: Vec, pub globals: Vec, pub funcs: Vec, - pub start_fn: Name, +} + +impl Program { + pub fn merge(&mut self, other: Program) { + self.imports.extend(other.imports); + self.types.extend(other.types); + self.globals.extend(other.globals); + self.funcs.extend(other.funcs); + } } diff --git a/crates/frontend/src/ir/format.rs b/crates/frontend/src/ir/format.rs index ce6e75c5..c4cd52e7 100644 --- a/crates/frontend/src/ir/format.rs +++ b/crates/frontend/src/ir/format.rs @@ -1,24 +1,26 @@ use crate::ir::{ - Callee, Declaration, DeclarationData, Expr, ExprData, LitData, Name, NameSupply, Program, - SetTarget, SetTargetData, Ty, + Callee, Declaration, DeclarationData, Expr, ExprData, LitData, Name, Program, SetTarget, + SetTargetData, Ty, }; use lexpr::Value; -pub fn format_ir(names: &NameSupply, ir: &Program) -> String { +use super::Ctx; + +pub fn format_ir(names: &Ctx, ir: &Program) -> String { format!("{}", Formatter { names }.program(ir)) } struct Formatter<'a> { - names: &'a NameSupply, + names: &'a Ctx, } impl Formatter<'_> { fn name(&self, n: &Name) -> Value { - Value::symbol(self.names.lookup(*n).unwrap().it.as_ref()) + Value::symbol(self.names.display_name(*n).as_ref()) } fn ty(&self, ty: &Ty) -> Value { - ty.display(&self.names.name_map).to_string().into() + ty.display(self.names).to_string().into() } fn set_target(&self, set_target: &SetTarget) -> Value { diff --git a/crates/frontend/src/ir/names.rs b/crates/frontend/src/ir/names.rs index fbd1faf0..e5fe6461 100644 --- a/crates/frontend/src/ir/names.rs +++ b/crates/frontend/src/ir/names.rs @@ -1,120 +1,206 @@ -use std::{collections::HashMap, fmt}; +use std::{ + cell::{Cell, RefCell}, + fmt, + num::NonZeroU16, +}; +use string_interner::{DefaultStringInterner, DefaultSymbol}; use text_size::TextRange; +use crate::types::Interface; + +// Indexed by ModuleId +#[derive(Debug)] +pub struct Ctx { + // Indexed by ModuleId + module_names: Vec, + interfaces: Vec, + name_supplies: Vec, +} + +impl Ctx { + pub fn new(module_count: u16) -> Ctx { + // Includes the reserved modules + let all_module_count = (module_count + ModuleId::FIRST_NON_RESERVED.get() - 1) as usize; + + let mut name_supplies = Vec::with_capacity(all_module_count); + let mut module_names = Vec::with_capacity(all_module_count); + let mut interfaces = Vec::with_capacity(all_module_count); + // TODO: Should add proper values for reserved modules + for _ in 0..name_supplies.capacity() { + name_supplies.push(NameSupply::new()); + module_names.push("NOT INITIALIZED".to_string()); + interfaces.push(Interface::default()); + } + Ctx { + module_names, + interfaces, + name_supplies, + } + } + pub fn set_module_name(&mut self, module: ModuleId, name: String) { + self.module_names[(module.0.get() - 1) as usize] = name + } + pub fn set_interface(&mut self, module: ModuleId, interface: Interface) { + self.interfaces[(module.0.get() - 1) as usize] = interface + } + pub fn set_name_supply(&mut self, module: ModuleId, supply: NameSupply) { + self.name_supplies[(module.0.get() - 1) as usize] = supply + } + pub fn get_name_supply(&self, module: ModuleId) -> &NameSupply { + &self.name_supplies[(module.0.get() - 1) as usize] + } + pub fn get_interface(&self, module: ModuleId) -> &Interface { + &self.interfaces[(module.0.get() - 1) as usize] + } + pub fn get_module_name(&self, module: ModuleId) -> &str { + &self.module_names[(module.0.get() - 1) as usize] + } + pub fn resolve(&self, name: Name) -> (String, TextRange) { + let supply = self.get_name_supply(name.module); + let id = supply.lookup(name); + (supply.lookup_symbol(id.it), id.at) + } + pub fn display_name(&self, name: Name) -> String { + self.resolve(name).0 + } + pub fn fmt_name(&self, f: &mut fmt::Formatter<'_>, name: Name) -> fmt::Result { + write!(f, "{}", self.display_name(name)) + } +} + #[derive(Debug, Eq, PartialEq, Clone, Hash)] pub struct Id { pub it: String, pub at: TextRange, } -// Should we have spanned names as well? #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)] -pub enum Name { - Global(u32), - Local(u32), - Func(u32), - Type(u32), - TypeVar(u32), - Field(u32), - Gen(u32), +pub enum NameTag { + Local, + Global, + Func, + Type, + TypeVar, + Field, + Gen, } -impl Name { - pub fn display<'a>(&'a self, name_map: &'a NameMap) -> NameDisplay<'a> { - NameDisplay { - name: self, - name_map, - } +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)] +pub struct ModuleId(NonZeroU16); + +impl ModuleId { + pub fn new(id: u16) -> Self { + debug_assert!(id > 2, "module ids 1 and 2 are reserved"); + Self(NonZeroU16::new(id).expect("ModuleId must be non-zero")) + } + + pub const PRIM: Self = ModuleId(unsafe { NonZeroU16::new_unchecked(1) }); + pub const CODEGEN: Self = ModuleId(unsafe { NonZeroU16::new_unchecked(2) }); + const FIRST_NON_RESERVED: NonZeroU16 = unsafe { NonZeroU16::new_unchecked(3) }; +} + +impl From for u16 { + fn from(val: ModuleId) -> Self { + val.0.get() } } -pub struct NameDisplay<'a> { - name: &'a Name, - name_map: &'a NameMap, +pub struct ModuleIdGen(NonZeroU16); +impl ModuleIdGen { + pub fn new() -> Self { + Self(ModuleId::FIRST_NON_RESERVED) + } + pub fn next_id(&mut self) -> ModuleId { + let tmp = ModuleId(self.0); + self.0 = self.0.checked_add(1).unwrap(); + tmp + } } -impl fmt::Display for NameDisplay<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.name_map.get(self.name).unwrap().it) +impl Default for ModuleIdGen { + fn default() -> Self { + Self::new() } } -pub type NameMap = HashMap; +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)] +pub struct Name { + pub tag: NameTag, + pub module: ModuleId, + pub idx: u32, +} + +pub type Symbol = DefaultSymbol; -#[derive(Debug, Clone, Default)] +#[derive(Debug, Copy, Clone)] +pub struct CompactId { + pub it: Symbol, + pub at: TextRange, +} + +#[derive(Debug)] pub struct NameSupply { - local: u32, - global: u32, - func: u32, - typ: u32, - typ_var: u32, - field: u32, - gen: u32, - pub name_map: HashMap, + supply: Cell, + name_map: RefCell>, + strings: RefCell, +} + +impl Default for NameSupply { + fn default() -> Self { + Self::new() + } } impl NameSupply { pub fn new() -> Self { - Self::default() + Self { + supply: Cell::new(0), + name_map: RefCell::new(Vec::new()), + strings: RefCell::new(DefaultStringInterner::default()), + } } - - pub fn local_idx(&mut self, id: Id) -> Name { - self.local += 1; - let name = Name::Local(self.local); - self.name_map.insert(name, id); - name + pub fn new_name( + &self, + tag: NameTag, + module: ModuleId, + it: &str, + at: TextRange, + ) -> (Name, Symbol) { + let idx = self.supply.get(); + self.supply.set(idx + 1); + let it = self.strings.borrow_mut().get_or_intern(it); + self.name_map.borrow_mut().push(CompactId { it, at }); + (Name { tag, module, idx }, it) } - - pub fn global_idx(&mut self, id: Id) -> Name { - self.global += 1; - let name = Name::Global(self.global); - self.name_map.insert(name, id); - name + pub fn local_idx(&self, module: ModuleId, it: &str, at: TextRange) -> (Name, Symbol) { + self.new_name(NameTag::Local, module, it, at) } - - pub fn func_idx(&mut self, id: Id) -> Name { - self.func += 1; - let name = Name::Func(self.func); - self.name_map.insert(name, id); - name + pub fn global_idx(&self, module: ModuleId, it: &str, at: TextRange) -> (Name, Symbol) { + self.new_name(NameTag::Global, module, it, at) } - - pub fn type_idx(&mut self, id: Id) -> Name { - self.typ += 1; - let name = Name::Type(self.typ); - self.name_map.insert(name, id); - name + pub fn func_idx(&self, module: ModuleId, it: &str, at: TextRange) -> (Name, Symbol) { + self.new_name(NameTag::Func, module, it, at) } - - pub fn type_var(&mut self, id: Id) -> Name { - self.typ_var += 1; - let name = Name::TypeVar(self.typ_var); - self.name_map.insert(name, id); - name + pub fn type_idx(&self, module: ModuleId, it: &str, at: TextRange) -> (Name, Symbol) { + self.new_name(NameTag::Type, module, it, at) } - - pub fn field_idx(&mut self, id: Id) -> Name { - self.field += 1; - let name = Name::Field(self.field); - self.name_map.insert(name, id); - name + pub fn type_var_idx(&self, module: ModuleId, it: &str, at: TextRange) -> (Name, Symbol) { + self.new_name(NameTag::TypeVar, module, it, at) } - - pub fn gen_idx(&mut self) -> Name { - self.gen += 1; - let name = Name::Gen(self.gen); - self.name_map.insert( - name, - Id { - it: format!("gen{}", self.gen), - at: TextRange::default(), - }, - ); - name + pub fn field_idx(&self, module: ModuleId, it: &str, at: TextRange) -> (Name, Symbol) { + self.new_name(NameTag::Field, module, it, at) } - - pub fn lookup(&self, name: Name) -> Option<&Id> { - self.name_map.get(&name) + pub fn gen_idx(&self, module: ModuleId, it: &str) -> (Name, Symbol) { + self.new_name(NameTag::Gen, module, it, TextRange::default()) + } + pub fn get_or_intern(&self, s: &str) -> Symbol { + self.strings.borrow_mut().get_or_intern(s) + } + pub fn lookup(&self, name: Name) -> CompactId { + *self.name_map.borrow().get(name.idx as usize).unwrap() + } + pub fn lookup_symbol(&self, sym: Symbol) -> String { + self.strings.borrow().resolve(sym).unwrap().to_string() } } diff --git a/crates/frontend/src/lib.rs b/crates/frontend/src/lib.rs index cd94a4c5..1c3df494 100644 --- a/crates/frontend/src/lib.rs +++ b/crates/frontend/src/lib.rs @@ -2,39 +2,122 @@ pub mod builtins; mod error; pub mod highlight; pub mod ir; +mod module_dag; pub mod parser; pub mod syntax; pub mod types; -use parser::parse_prog; +use ir::{Ctx, ModuleId, ModuleIdGen, Program}; +use parser::{parse_prog, ParseError}; pub use error::CheckError; +use syntax::Module; pub use types::CheckResult; +use types::{OccurrenceMap, TyError}; + +// TODO: Customizable display for debugging +#[derive(Debug)] +pub struct FrontendModuleResult { + pub id: ModuleId, + // path/offset? + pub ty_errors: Vec, + pub occurrences: OccurrenceMap, + pub ir: Option, + pub parse: Module, +} + +#[derive(Debug)] +pub struct FrontendResult { + pub ctx: Ctx, + pub parse_errors: Vec, + pub modules: Vec, +} + +impl FrontendResult { + pub fn errors(&self) -> impl Iterator { + self.parse_errors.iter().map(CheckError::ParseError).chain( + self.modules + .iter() + .flat_map(|module| module.ty_errors.iter().map(CheckError::TypeError)), + ) + } + + pub fn has_errors(&self) -> bool { + !self.parse_errors.is_empty() + || self + .modules + .iter() + .any(|module| !module.ty_errors.is_empty()) + } + + pub fn display(&self, source: &str) { + for module in &self.modules { + for error in &module.ty_errors { + eprintln!("{}", error.display(source, &self.ctx, true)); + } + } + } + + pub fn consume(self) -> (Ctx, Option) { + let mut ir = Some(ir::Program::default()); + for module in self.modules { + match (&mut ir, module.ir) { + (Some(ir), Some(module_ir)) => { + ir.merge(module_ir); + } + (_, _) => { + ir = None; + break; + } + } + } + (self.ctx, ir) + } +} /// Runs the full frontend on `source` and returns the generated IR and other structures. /// If there are any errors, the generated IR should _not_ be used. It's returned here for /// debugging purposes. -pub fn run_frontend(source: &str) -> CheckResult { +pub fn run_frontend(source: &str) -> FrontendResult { + // TODO multiple files let (parse_root, parse_errors) = parse_prog(source).take(); - let mut errors = vec![]; - let check_result = types::check_prog(parse_root); - for error in parse_errors { - errors.push(CheckError::ParseError(error)); - } - for error in check_result.errors { - errors.push(CheckError::TypeError(error)); - } - if errors.is_empty() && check_result.ir.is_none() { - panic!("No IR generated, despite no errors") + // Special case for single module without module header + let parsed_modules: Vec = parse_root.modules().collect(); + let modules = if parsed_modules.len() == 1 { + vec![( + ModuleIdGen::new().next_id(), + "main".to_owned(), + parsed_modules[0].clone(), + )] + } else { + module_dag::toposort_modules(parse_root.clone()) }; + let mut ctx = Ctx::new(modules.len() as u16); + let mut checked_modules = vec![]; + let mut checked_ids = vec![]; + for (id, name, module) in modules { + let check_result = types::check_module(&ctx, module.clone(), id, &checked_ids); + ctx.set_module_name(id, name); + ctx.set_interface(id, check_result.interface.clone()); + ctx.set_name_supply(id, check_result.names); + if check_result.errors.is_empty() && check_result.ir.is_none() { + panic!("No IR generated, despite no errors") + }; + checked_ids.push(id); + checked_modules.push(FrontendModuleResult { + id, + parse: module, + ty_errors: check_result.errors, + occurrences: check_result.occurrences, + ir: check_result.ir, + }); + } - CheckResult { - errors, - names: check_result.names, - occurrences: check_result.occurrences, - ir: check_result.ir, - parse: check_result.parse, + FrontendResult { + ctx, + parse_errors, + modules: checked_modules, } } @@ -42,17 +125,13 @@ pub fn run_frontend(source: &str) -> CheckResult { /// If there are any errors returns a summary message in Err otherwise Ok. pub fn check_program(source: &str) -> Result<(), String> { let check_result = run_frontend(source); - if !check_result.errors.is_empty() { - for err in &check_result.errors { - eprintln!( - "{}", - err.display(source, &check_result.names.name_map, true) - ); + if check_result.has_errors() { + let mut count = 0; + for err in check_result.errors() { + count += 1; + eprintln!("{}", err.display(source, &check_result.ctx, true)); } - return Err(format!( - "Check failed with {} errors", - check_result.errors.len() - )); + return Err(format!("Check failed with {} errors", count)); } Ok(()) } diff --git a/crates/frontend/src/module_dag.rs b/crates/frontend/src/module_dag.rs new file mode 100644 index 00000000..a667f6e7 --- /dev/null +++ b/crates/frontend/src/module_dag.rs @@ -0,0 +1,48 @@ +use std::collections::HashMap; +use topological_sort::TopologicalSort; + +use crate::{ + ir::{ModuleId, ModuleIdGen}, + syntax::{Module, Root}, +}; + +fn mod_name(module: &Module) -> String { + module + .mod_header() + .and_then(|h| h.ident_token()) + .map(|t| t.text().to_string()) + .unwrap_or("DEFAULT_MODULE_NAME".to_string()) +} + +pub fn toposort_modules(root: Root) -> Vec<(ModuleId, String, Module)> { + let mut id_gen = ModuleIdGen::new(); + let (module_name_map, mut module_id_map) = { + let mut module_name_map = HashMap::new(); + let mut module_id_map = HashMap::new(); + for module in root.modules() { + let id = id_gen.next_id(); + module_name_map.insert(mod_name(&module), id); + module_id_map.insert(id, (mod_name(&module), module.clone())); + } + (module_name_map, module_id_map) + }; + + let mut ts: TopologicalSort = TopologicalSort::new(); + for (_, module) in module_id_map.values() { + let module_id = module_name_map[&mod_name(module)]; + ts.insert(module_id); + let Some(header) = module.mod_header() else { + continue; + }; + for mod_use in header.mod_uses() { + let import_name_tkn = mod_use.ident_token().unwrap(); + let import_id = module_name_map[import_name_tkn.text()]; + ts.add_dependency(import_id, module_id) + } + } + ts.map(|id| { + let (name, module) = module_id_map.remove(&id).unwrap(); + (id, name, module) + }) + .collect() +} diff --git a/crates/frontend/src/parser/grammar.rs b/crates/frontend/src/parser/grammar.rs index 437bea73..fb0fcfd3 100644 --- a/crates/frontend/src/parser/grammar.rs +++ b/crates/frontend/src/parser/grammar.rs @@ -17,6 +17,14 @@ impl Progress { pub fn prog(p: &mut Parser) { while !p.at(SyntaxKind::EOF) { + module(p); + } +} + +fn module(p: &mut Parser) { + let c = p.checkpoint(); + module_header(p); + while !p.at(SyntaxKind::EOF) && !p.at(T![module]) { if !toplevel(p).made_progress() { let c = p.checkpoint(); // RECOVERY @@ -27,9 +35,63 @@ pub fn prog(p: &mut Parser) { p.finish_at(c, SyntaxKind::Error) } } + p.finish_at(c, SyntaxKind::Module) +} + +fn module_header(p: &mut Parser) -> Progress { + let c = p.checkpoint(); + if !p.eat(T![module]) { + return Progress::None; + } + p.expect(T![ident]); + p.expect(T![exports]); + p.expect(T!['(']); + if p.at(T![dotdotdot]) { + let c = p.checkpoint(); + p.bump(T![dotdotdot]); + p.finish_at(c, SyntaxKind::ModExportAll); + p.expect(T![')']); + return Progress::Made; + } + while !p.at(SyntaxKind::EOF) && !p.at(T![')']) { + if !mod_export_item(p).made_progress() { + p.error("expected an export") + } + if !p.eat(T![,]) { + break; + } + } + p.expect(T![')']); + while !p.at(SyntaxKind::EOF) && p.at(T![use]) { + let c = p.checkpoint(); + p.bump(T![use]); + p.expect(T![ident]); + p.finish_at(c, SyntaxKind::ModUse); + } + p.finish_at(c, SyntaxKind::ModHeader); + Progress::Made } -const TOP_LEVEL_FIRST: [SyntaxKind; 4] = [T![global], T![fn], T![import], T![struct]]; +fn mod_export_item(p: &mut Parser) -> Progress { + let c = p.checkpoint(); + if p.eat(T![ident]) { + p.finish_at(c, SyntaxKind::ModExportVal); + } else if p.eat(T![upper_ident]) { + p.finish_at(c, SyntaxKind::ModExportTy); + } else { + return Progress::None; + } + Progress::Made +} + +const TOP_LEVEL_FIRST: [SyntaxKind; 6] = [ + T![global], + T![fn], + T![import], + T![struct], + T![variant], + T![module], +]; fn toplevel(p: &mut Parser) -> Progress { match p.current() { T![global] => { @@ -191,6 +253,18 @@ fn qualifier(p: &mut Parser) -> Progress { } } +fn mod_qualifier(p: &mut Parser) -> Progress { + if p.at(T![ident]) && p.nth_at(1, T![::]) { + let c = p.checkpoint(); + p.bump(T![ident]); + p.bump(T![::]); + p.finish_at(c, SyntaxKind::ModQualifier); + Progress::Made + } else { + Progress::None + } +} + fn typ_annot(p: &mut Parser) -> Progress { if !p.eat(SyntaxKind::COLON) { return Progress::None; @@ -225,14 +299,15 @@ fn typ(p: &mut Parser) -> Progress { p.finish_at(c, SyntaxKind::TyUnit) } T![ident] => { - p.bump(T![ident]); - p.finish_at(c, SyntaxKind::TyVar) + if mod_qualifier(p).made_progress() { + ty_cons(p, c); + } else { + p.bump(T![ident]); + p.finish_at(c, SyntaxKind::TyVar) + } } T![upper_ident] => { - qualifier(p); - p.expect(T![upper_ident]); - ty_arg_list(p); - p.finish_at(c, SyntaxKind::TyCons) + ty_cons(p, c); } T!['['] => { p.bump(T!['[']); @@ -266,6 +341,13 @@ fn typ(p: &mut Parser) -> Progress { Progress::Made } +fn ty_cons(p: &mut Parser, c: Checkpoint) { + qualifier(p); + p.expect(T![upper_ident]); + ty_arg_list(p); + p.finish_at(c, SyntaxKind::TyCons) +} + fn lit(p: &mut Parser) -> Progress { let c = p.checkpoint(); match p.current() { @@ -421,8 +503,13 @@ fn match_branch(p: &mut Parser) -> Progress { fn pattern(p: &mut Parser) -> Progress { let c = p.checkpoint(); + let is_mod_qualified = mod_qualifier(p).made_progress(); match p.current() { T![ident] => { + if is_mod_qualified { + p.error("Can only qualify variant patterns"); + return Progress::Made; + } p.bump(T![ident]); p.finish_at(c, SyntaxKind::PatVar); Progress::Made @@ -547,30 +634,33 @@ fn atom(p: &mut Parser) -> Progress { return Progress::Made; } - match p.current() { - T!['('] => { - p.bump(T!['(']); - if !expr(p).made_progress() { - p.error("expected an expression") - } - p.expect(T![')']); - p.finish_at(c, SyntaxKind::EParen); + if p.eat(T!['(']) { + if !expr(p).made_progress() { + p.error("expected an expression") } - T!['['] => { - p.bump(T!['[']); - while !p.at(SyntaxKind::EOF) && !p.at(T![']']) { - if !expr(p).made_progress() { - break; - } + p.expect(T![')']); + p.finish_at(c, SyntaxKind::EParen); + return Progress::Made; + } - if !p.at(T![']']) && !p.expect(T![,]) { - break; - } + if p.eat(T!['[']) { + while !p.at(SyntaxKind::EOF) && !p.at(T![']']) { + if !expr(p).made_progress() { + break; } - p.expect(T![']']); - p.finish_at(c, SyntaxKind::EArray) + if !p.at(T![']']) && !p.expect(T![,]) { + break; + } } + + p.expect(T![']']); + p.finish_at(c, SyntaxKind::EArray); + return Progress::Made; + } + + let qualified = mod_qualifier(p); + match p.current() { T![upper_ident] => { qualifier(p); p.expect(T![upper_ident]); @@ -599,7 +689,12 @@ fn atom(p: &mut Parser) -> Progress { p.bump(T![ident]); p.finish_at(c, SyntaxKind::EVar) } - _ => return Progress::None, + _ => { + if qualified.made_progress() { + p.error("expected a qualified identifier") + } + return qualified; + } } Progress::Made diff --git a/crates/frontend/src/parser/lexer.rs b/crates/frontend/src/parser/lexer.rs index 54a1193b..5a5af6e6 100644 --- a/crates/frontend/src/parser/lexer.rs +++ b/crates/frontend/src/parser/lexer.rs @@ -121,6 +121,15 @@ pub enum SyntaxKind { #[regex("\n|\r\n")] LINEFEED, + #[token("module")] + MODULE_KW, + + #[token("exports")] + EXPORTS_KW, + + #[token("use")] + USE_KW, + #[token("fn")] FN_KW, @@ -202,6 +211,9 @@ pub enum SyntaxKind { #[regex("\"[^\"]*\"")] BYTES_LIT, + #[token("...")] + DOTDOTDOT, + #[token(".")] DOT, @@ -297,6 +309,7 @@ pub enum SyntaxKind { EArgList, ETyArgList, Qualifier, + ModQualifier, // Types TyInt, @@ -360,6 +373,15 @@ pub enum SyntaxKind { SetStruct, SetArray, + // Modules + Module, + ModHeader, + ModUse, + ModExports, + ModExportVal, + ModExportTy, + ModExportAll, + // Root Root, @@ -410,6 +432,7 @@ macro_rules ! T { [==] => { SyntaxKind::DOUBLE_EQUALS }; [!=] => { SyntaxKind::NOT_EQUALS }; [.] => { SyntaxKind::DOT }; + [dotdotdot] => { SyntaxKind::DOTDOTDOT }; [::] => { SyntaxKind::DOUBLE_COLON }; [:] => { SyntaxKind::COLON }; [=] => { SyntaxKind::EQUALS }; @@ -422,6 +445,9 @@ macro_rules ! T { [bool] => { SyntaxKind::BOOL_BUILTIN }; [bytes] => { SyntaxKind::BYTES_BUILTIN }; [unit] => { SyntaxKind::UNIT_BUILTIN }; + [module] => { SyntaxKind::MODULE_KW }; + [exports] => { SyntaxKind::EXPORTS_KW }; + [use] => { SyntaxKind::USE_KW }; [fn] => { SyntaxKind::FN_KW }; [global] => { SyntaxKind::GLOBAL_KW }; [import] => { SyntaxKind::IMPORT_KW }; diff --git a/crates/frontend/src/syntax/nodes.rs b/crates/frontend/src/syntax/nodes.rs index f1e2da22..93e0069f 100644 --- a/crates/frontend/src/syntax/nodes.rs +++ b/crates/frontend/src/syntax/nodes.rs @@ -9,11 +9,77 @@ pub struct Root { pub(crate) syntax: SyntaxNode, } impl Root { + pub fn modules(&self) -> AstChildren { + support::children(&self.syntax) + } +} +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct Module { + pub(crate) syntax: SyntaxNode, +} +impl Module { + pub fn mod_header(&self) -> Option { + support::child(&self.syntax) + } pub fn top_levels(&self) -> AstChildren { support::children(&self.syntax) } } #[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct ModHeader { + pub(crate) syntax: SyntaxNode, +} +impl ModHeader { + pub fn module_token(&self) -> Option { + support::token(&self.syntax, T![module]) + } + pub fn ident_token(&self) -> Option { + support::token(&self.syntax, T![ident]) + } + pub fn mod_exports(&self) -> AstChildren { + support::children(&self.syntax) + } + pub fn mod_uses(&self) -> AstChildren { + support::children(&self.syntax) + } +} +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct ModUse { + pub(crate) syntax: SyntaxNode, +} +impl ModUse { + pub fn ident_token(&self) -> Option { + support::token(&self.syntax, T![ident]) + } +} +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct ModExportVal { + pub(crate) syntax: SyntaxNode, +} +impl ModExportVal { + pub fn ident_token(&self) -> Option { + support::token(&self.syntax, T![ident]) + } +} +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct ModExportTy { + pub(crate) syntax: SyntaxNode, +} +impl ModExportTy { + pub fn upper_ident_token(&self) -> Option { + support::token(&self.syntax, T![upper_ident]) + } +} +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct ModExportAll { + pub(crate) syntax: SyntaxNode, +} +impl ModExportAll { + pub fn dotdotdot_token(&self) -> Option { + support::token(&self.syntax, T![dotdotdot]) + } +} +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct TopImport { pub(crate) syntax: SyntaxNode, } @@ -288,6 +354,9 @@ pub struct TyCons { pub(crate) syntax: SyntaxNode, } impl TyCons { + pub fn mod_qualifier(&self) -> Option { + support::child(&self.syntax) + } pub fn qualifier(&self) -> Option { support::child(&self.syntax) } @@ -317,6 +386,18 @@ impl TyFn { } } #[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct ModQualifier { + pub(crate) syntax: SyntaxNode, +} +impl ModQualifier { + pub fn ident_token(&self) -> Option { + support::token(&self.syntax, T![ident]) + } + pub fn coloncolon_token(&self) -> Option { + support::token(&self.syntax, T![::]) + } +} +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Qualifier { pub(crate) syntax: SyntaxNode, } @@ -402,6 +483,9 @@ pub struct EVar { pub(crate) syntax: SyntaxNode, } impl EVar { + pub fn mod_qualifier(&self) -> Option { + support::child(&self.syntax) + } pub fn ident_token(&self) -> Option { support::token(&self.syntax, T![ident]) } @@ -426,6 +510,9 @@ pub struct EStruct { pub(crate) syntax: SyntaxNode, } impl EStruct { + pub fn mod_qualifier(&self) -> Option { + support::child(&self.syntax) + } pub fn qualifier(&self) -> Option { support::child(&self.syntax) } @@ -716,6 +803,9 @@ pub struct PatVariant { pub(crate) syntax: SyntaxNode, } impl PatVariant { + pub fn mod_qualifier(&self) -> Option { + support::child(&self.syntax) + } pub fn qualifier(&self) -> Option { support::child(&self.syntax) } @@ -744,6 +834,12 @@ pub enum TopLevel { TopFn(TopFn), } #[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub enum ModExport { + ModExportVal(ModExportVal), + ModExportTy(ModExportTy), + ModExportAll(ModExportAll), +} +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum Type { TyInt(TyInt), TyFloat(TyFloat), @@ -812,6 +908,96 @@ impl AstNode for Root { &self.syntax } } +impl AstNode for Module { + fn can_cast(kind: SyntaxKind) -> bool { + kind == Module + } + fn cast(syntax: SyntaxNode) -> Option { + if Self::can_cast(syntax.kind()) { + Some(Self { syntax }) + } else { + None + } + } + fn syntax(&self) -> &SyntaxNode { + &self.syntax + } +} +impl AstNode for ModHeader { + fn can_cast(kind: SyntaxKind) -> bool { + kind == ModHeader + } + fn cast(syntax: SyntaxNode) -> Option { + if Self::can_cast(syntax.kind()) { + Some(Self { syntax }) + } else { + None + } + } + fn syntax(&self) -> &SyntaxNode { + &self.syntax + } +} +impl AstNode for ModUse { + fn can_cast(kind: SyntaxKind) -> bool { + kind == ModUse + } + fn cast(syntax: SyntaxNode) -> Option { + if Self::can_cast(syntax.kind()) { + Some(Self { syntax }) + } else { + None + } + } + fn syntax(&self) -> &SyntaxNode { + &self.syntax + } +} +impl AstNode for ModExportVal { + fn can_cast(kind: SyntaxKind) -> bool { + kind == ModExportVal + } + fn cast(syntax: SyntaxNode) -> Option { + if Self::can_cast(syntax.kind()) { + Some(Self { syntax }) + } else { + None + } + } + fn syntax(&self) -> &SyntaxNode { + &self.syntax + } +} +impl AstNode for ModExportTy { + fn can_cast(kind: SyntaxKind) -> bool { + kind == ModExportTy + } + fn cast(syntax: SyntaxNode) -> Option { + if Self::can_cast(syntax.kind()) { + Some(Self { syntax }) + } else { + None + } + } + fn syntax(&self) -> &SyntaxNode { + &self.syntax + } +} +impl AstNode for ModExportAll { + fn can_cast(kind: SyntaxKind) -> bool { + kind == ModExportAll + } + fn cast(syntax: SyntaxNode) -> Option { + if Self::can_cast(syntax.kind()) { + Some(Self { syntax }) + } else { + None + } + } + fn syntax(&self) -> &SyntaxNode { + &self.syntax + } +} impl AstNode for TopImport { fn can_cast(kind: SyntaxKind) -> bool { kind == TopImport @@ -1112,6 +1298,21 @@ impl AstNode for TyFn { &self.syntax } } +impl AstNode for ModQualifier { + fn can_cast(kind: SyntaxKind) -> bool { + kind == ModQualifier + } + fn cast(syntax: SyntaxNode) -> Option { + if Self::can_cast(syntax.kind()) { + Some(Self { syntax }) + } else { + None + } + } + fn syntax(&self) -> &SyntaxNode { + &self.syntax + } +} impl AstNode for Qualifier { fn can_cast(kind: SyntaxKind) -> bool { kind == Qualifier @@ -1615,6 +1816,45 @@ impl AstNode for TopLevel { } } } +impl From for ModExport { + fn from(node: ModExportVal) -> ModExport { + ModExport::ModExportVal(node) + } +} +impl From for ModExport { + fn from(node: ModExportTy) -> ModExport { + ModExport::ModExportTy(node) + } +} +impl From for ModExport { + fn from(node: ModExportAll) -> ModExport { + ModExport::ModExportAll(node) + } +} +impl AstNode for ModExport { + fn can_cast(kind: SyntaxKind) -> bool { + match kind { + ModExportVal | ModExportTy | ModExportAll => true, + _ => false, + } + } + fn cast(syntax: SyntaxNode) -> Option { + let res = match syntax.kind() { + ModExportVal => ModExport::ModExportVal(ModExportVal { syntax }), + ModExportTy => ModExport::ModExportTy(ModExportTy { syntax }), + ModExportAll => ModExport::ModExportAll(ModExportAll { syntax }), + _ => return None, + }; + Some(res) + } + fn syntax(&self) -> &SyntaxNode { + match self { + ModExport::ModExportVal(it) => &it.syntax, + ModExport::ModExportTy(it) => &it.syntax, + ModExport::ModExportAll(it) => &it.syntax, + } + } +} impl From for Type { fn from(node: TyInt) -> Type { Type::TyInt(node) @@ -1981,6 +2221,11 @@ impl std::fmt::Display for TopLevel { std::fmt::Display::fmt(self.syntax(), f) } } +impl std::fmt::Display for ModExport { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} impl std::fmt::Display for Type { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) @@ -2016,6 +2261,36 @@ impl std::fmt::Display for Root { std::fmt::Display::fmt(self.syntax(), f) } } +impl std::fmt::Display for Module { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} +impl std::fmt::Display for ModHeader { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} +impl std::fmt::Display for ModUse { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} +impl std::fmt::Display for ModExportVal { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} +impl std::fmt::Display for ModExportTy { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} +impl std::fmt::Display for ModExportAll { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} impl std::fmt::Display for TopImport { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) @@ -2116,6 +2391,11 @@ impl std::fmt::Display for TyFn { std::fmt::Display::fmt(self.syntax(), f) } } +impl std::fmt::Display for ModQualifier { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} impl std::fmt::Display for Qualifier { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) diff --git a/crates/frontend/src/syntax/nodes.ungram b/crates/frontend/src/syntax/nodes.ungram index ef0e9672..b633f7ee 100644 --- a/crates/frontend/src/syntax/nodes.ungram +++ b/crates/frontend/src/syntax/nodes.ungram @@ -1,4 +1,15 @@ -Root = TopLevel* +Root = Module* + +Module = ModHeader TopLevel* + +ModHeader = 'module' 'ident' ModExport* ModUse* + +ModExport = ModExportVal | ModExportTy | ModExportAll +ModExportVal = 'ident' +ModExportTy = 'upper_ident' +ModExportAll = 'dotdotdot' + +ModUse = 'ident' // TopLevel TopLevel @@ -41,9 +52,10 @@ TyBool = 'bool' TyBytes = 'bytes' TyUnit = 'unit' TyArray = '[' elem:Type ']' -TyCons = Qualifier? 'upper_ident' type_args:Type* +TyCons = ModQualifier? Qualifier? 'upper_ident' type_args:Type* TyVar = 'ident' +ModQualifier = 'ident' '::' Qualifier = 'upper_ident' '::' TyFn = 'fn' TyArgList '->' result:Type @@ -75,7 +87,7 @@ Expr | EReturn ELit = Literal -EVar = 'ident' +EVar = ModQualifier? 'ident' EArray = '[' Expr* ']' EParen = '(' Expr ')' EArrayIdx = Expr '[' index:Expr ']' @@ -86,7 +98,7 @@ ETyArgList = Type* EBinary = lhs:Expr op:('+' | '-') rhs:Expr -EStruct = Qualifier? 'upper_ident' ETyArgList? '{' EStructField* '}' +EStruct = ModQualifier? Qualifier? 'upper_ident' ETyArgList? '{' EStructField* '}' EStructField = 'ident' '=' Expr EStructIdx = Expr '.' 'ident' @@ -119,5 +131,5 @@ Pattern = PatVariant | PatVar -PatVariant = Qualifier 'upper_ident' 'ident' +PatVariant = ModQualifier? Qualifier 'upper_ident' 'ident' PatVar = 'ident' diff --git a/crates/frontend/src/types.rs b/crates/frontend/src/types.rs index 816815e9..77831bc1 100644 --- a/crates/frontend/src/types.rs +++ b/crates/frontend/src/types.rs @@ -1,32 +1,50 @@ mod check; mod error; +mod module; mod names; -use crate::ir::{Name, NameSupply, Program}; -use crate::syntax::{token_ptr::SyntaxTokenPtr, Root}; +use crate::ir::{Ctx, ModuleId, Name, NameSupply, Program}; +use crate::syntax::token_ptr::SyntaxTokenPtr; +use crate::syntax::Module; use check::Typechecker; use std::collections::HashMap; pub use check::{Occurrence, OccurrenceMap}; pub use error::TyError; +pub use module::{FuncDef, Interface, StructDef, StructFields, TypeDef, VariantDef}; #[derive(Debug)] -pub struct CheckResult { - pub errors: Vec, +pub struct CheckResult { + pub errors: Vec, pub occurrences: HashMap>, pub names: NameSupply, + pub interface: Interface, pub ir: Option, - pub parse: Root, + pub parse: Module, } -pub fn check_prog(prog: Root) -> CheckResult { - let mut checker = Typechecker::new(); - let (ir, errors) = checker.infer_program(&prog); +pub fn check_module( + ctx: &Ctx, + module: Module, + module_id: ModuleId, + checked_ids: &[ModuleId], +) -> CheckResult { + let mut dependencies: Vec<(String, Interface)> = vec![]; + for id in checked_ids { + dependencies.push(( + ctx.get_module_name(*id).to_owned(), + ctx.get_interface(*id).clone(), + )); + } + let mut checker = Typechecker::new(module_id, dependencies, ctx); + let (ir, interface, errors) = checker.infer_module(&module); + let (names, _) = checker.name_supply.take(); CheckResult { errors, occurrences: checker.occurrences, - names: checker.name_supply.take(), + names, ir, - parse: prog, + interface, + parse: module, } } diff --git a/crates/frontend/src/types/check.rs b/crates/frontend/src/types/check.rs index 6f8c4a48..9f344f4c 100644 --- a/crates/frontend/src/types/check.rs +++ b/crates/frontend/src/types/check.rs @@ -1,111 +1,52 @@ -use super::error::{ - TyError, - TyErrorData::{self, *}, - TyErrors, -}; use super::names::NameSupply; -use crate::builtins::lookup_builtin; +use super::{ + error::{ + TyError, + TyErrorData::{self, *}, + TyErrors, + }, + Interface, +}; +use super::{FuncDef, StructDef, TypeDef, VariantDef}; use crate::ir::{ self, ExprBuilder, FuncTy, LambdaBuilder, LitBuilder, Name, PatVarBuilder, ReturnBuilder, - Substitution, Ty, VarBuilder, + Substitution, Symbol, Ty, VarBuilder, }; use crate::parser::SyntaxKind; use crate::syntax::token_ptr::SyntaxTokenPtr; use crate::syntax::*; use crate::T; +use crate::{ + builtins::lookup_builtin, + ir::{ModuleId, NameTag}, +}; use std::collections::{HashMap, HashSet}; use std::mem; use std::rc::Rc; use text_size::TextRange; -#[derive(Debug, Clone)] -struct StructDef { - name: Name, - span: TextRange, - variant: Option, - ty_params: Vec<(String, Name)>, -} - -#[derive(Debug, Clone)] -struct VariantDef { - name: Name, - span: TextRange, - ty_params: Vec<(String, Name)>, - // TODO: The ordering of these alternatives needs to be deterministic - alternatives: HashMap, -} - -impl VariantDef { - pub fn lookup_alternative(&self, name: &str) -> Option { - self.alternatives.get(name).copied() - } -} - -#[derive(Debug, Clone)] -enum TypeDef { - Struct(Rc), - Variant(Rc), -} -impl TypeDef { - fn name(&self) -> Name { - match self { - TypeDef::Struct(x) => x.name, - TypeDef::Variant(x) => x.name, - } - } - - fn ty_params(&self) -> &[(String, Name)] { - match self { - TypeDef::Struct(x) => &x.ty_params, - TypeDef::Variant(x) => &x.ty_params, - } - } -} - -#[derive(Debug, Clone)] -struct StructFields { - // TODO: The ordering of these fields needs to be deterministic - fields: HashMap, -} - -impl StructFields { - fn to_ir(&self) -> Vec<(Name, Ty)> { - self.fields.values().cloned().collect() - } - - fn names(&self) -> Vec { - self.fields.values().map(|(n, _)| *n).collect() - } -} - -#[derive(Debug, Clone)] -struct FuncDef { - name: Name, - ty_params: Vec<(String, Name)>, - ty: FuncTy, -} - -// NOTE: We could consider passing an explicit Ctx around, -// but we'd need to make it immutable and persistent +// NOTE: We could consider splitting into context and scope +// to split into an immutable and mutable part during expr/decl +// checking #[derive(Debug)] -struct Ctx { - values: Vec>, - type_vars: HashMap, +struct TyCtx { + values: Vec>, + type_vars: HashMap, // We keep track of the return type of the current function // so that we can typecheck early returns return_type: Option>, - // Basically "static" data. Once we've walked all type definitions - // and function headers this data is fixed. - functions: HashMap>, - types_names: HashMap, + // Basically "static" data. Once we've walked all uses, + // type definitions, and function headers this data is fixed. + functions: HashMap>, + types_names: HashMap, type_defs: HashMap, - field_defs: HashMap, + uses: HashMap, } -impl Ctx { - fn new() -> Ctx { - Ctx { +impl TyCtx { + fn new() -> TyCtx { + TyCtx { values: vec![], type_vars: HashMap::new(), return_type: None, @@ -113,23 +54,23 @@ impl Ctx { functions: HashMap::new(), type_defs: HashMap::new(), types_names: HashMap::new(), - field_defs: HashMap::new(), + uses: HashMap::new(), } } - fn add_var(&mut self, v: String, ty: Ty, name: Name) { + fn add_var(&mut self, v: Symbol, ty: Ty, name: Name) { self.values.last_mut().unwrap().insert(v, (ty, name)); } - fn lookup_var(&self, v: &str) -> Option<(Ty, Name)> { - if let Some((ty, name)) = self.values.iter().rev().find_map(|scope| scope.get(v)) { + fn lookup_var(&self, v: Symbol) -> Option<(Ty, Name)> { + if let Some((ty, name)) = self.values.iter().rev().find_map(|scope| scope.get(&v)) { Some((ty.clone(), *name)) } else { None } } - fn lookup_var_or_func(&self, v: &str) -> Option<(Ty, Name)> { + fn lookup_var_or_func(&self, v: Symbol) -> Option<(Ty, Name)> { self.lookup_var(v).or_else(|| { let def = self.lookup_func(v)?; if !def.ty_params.is_empty() { @@ -142,19 +83,11 @@ impl Ctx { }) } - fn add_type_var(&mut self, v: String, name: Name) { - self.type_vars.insert(v, name); - } - - fn lookup_type_var(&self, v: &str) -> Option { - self.type_vars.get(v).copied() + fn lookup_func(&self, name: Symbol) -> Option> { + self.functions.get(&name).cloned() } - fn clear_type_vars(&mut self) { - self.type_vars.clear() - } - - fn add_func(&mut self, v: String, name: Name, ty_params: Vec<(String, Name)>, ty: FuncTy) { + fn add_func(&mut self, v: Symbol, name: Name, ty_params: Vec, ty: FuncTy) { self.functions.insert( v, Rc::new(FuncDef { @@ -165,8 +98,16 @@ impl Ctx { ); } - fn lookup_func(&self, name: &str) -> Option> { - self.functions.get(name).cloned() + fn add_type_var(&mut self, v: Symbol, name: Name) { + self.type_vars.insert(v, name); + } + + fn lookup_type_var(&self, v: Symbol) -> Option { + self.type_vars.get(&v).copied() + } + + fn clear_type_vars(&mut self) { + self.type_vars.clear() } fn return_type(&self) -> Option> { @@ -181,7 +122,7 @@ impl Ctx { self.return_type = ty } - fn declare_type_def(&mut self, v: &str, name: Name, def: TypeDef) { + fn declare_type_def(&mut self, v: Symbol, name: Name, def: TypeDef) { let mut is_sub_struct = false; if let TypeDef::Struct(struct_def) = &def { is_sub_struct = struct_def.variant.is_some() @@ -189,20 +130,25 @@ impl Ctx { // We don't record String -> Name mapping for variant structs // as those are looked up via their Variant name if !is_sub_struct { - self.types_names.insert(v.to_string(), name); + self.types_names.insert(v, name); } self.type_defs.insert(name, def); } - fn lookup_type_name(&self, v: &str) -> Option { - self.types_names.get(v).copied() + fn lookup_type_name(&self, v: Symbol) -> Option { + self.types_names.get(&v).copied() } fn lookup_type_def(&self, name: Name) -> Option { - self.type_defs.get(&name).cloned() + // TODO: Get rid of clone + self.type_defs.get(&name).cloned().or_else(|| { + self.uses + .values() + .find_map(|iface| iface.lookup_type_name(name)) + }) } - fn lookup_type(&self, v: &str) -> Option { + fn lookup_type(&self, v: Symbol) -> Option { let n = self.lookup_type_name(v)?; let def = self .lookup_type_def(n) @@ -210,30 +156,16 @@ impl Ctx { Some(def) } - fn lookup_struct(&self, ty: &str) -> Option> { - let def = self.lookup_type(ty)?; - match def { - TypeDef::Struct(s) => Some(s), - _ => None, - } - } - - fn lookup_struct_name(&self, name: Name) -> Rc { + fn lookup_struct_name(&self, name: Name) -> StructDef { let Some(TypeDef::Struct(d)) = self.lookup_type_def(name) else { panic!("inferred unknown struct name") }; d.clone() } - fn get_fields(&self, name: Name) -> &HashMap { - &self.field_defs.get(&name).unwrap().fields - } - - fn lookup_variant(&self, ty: &str) -> Option> { - let def = self.lookup_type(ty)?; - match def { - TypeDef::Variant(s) => Some(s), - _ => None, + fn set_fields(&mut self, name: Name, fields: HashMap) { + if let Some(TypeDef::Struct(def)) = self.type_defs.get_mut(&name) { + def.fields = fields; } } @@ -244,6 +176,28 @@ impl Ctx { fn leave_block(&mut self) { self.values.pop().expect("Tried to pop from an empty Ctx"); } + + fn add_use(&mut self, name: Symbol, interface: Interface) { + self.uses.insert(name, interface); + } + + fn lookup_qual_type_name(&self, q: Symbol, n: Name) -> Option { + self.uses + .get(&q) + .and_then(|interface| interface.lookup_type_name(n)) + } + + fn lookup_qual_type(&self, q: Symbol, v: &str) -> Option { + self.uses + .get(&q) + .and_then(|interface| interface.lookup_type(v)) + } + + fn lookup_qual_func(&self, q: Symbol, v: &str) -> Option { + self.uses + .get(&q) + .and_then(|interface| interface.lookup_func(v)) + } } #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] @@ -264,23 +218,25 @@ impl Occurrence { pub type OccurrenceMap = HashMap>; pub struct Typechecker { - pub occurrences: OccurrenceMap, + pub occurrences: OccurrenceMap, // Write only pub name_supply: NameSupply, - context: Ctx, -} - -impl Default for Typechecker { - fn default() -> Self { - Self::new() - } + context: TyCtx, // Can be split into mutable and immutable parts } impl Typechecker { - pub fn new() -> Typechecker { + pub fn new(module: ModuleId, deps: Vec<(String, Interface)>, ctx: &ir::Ctx) -> Typechecker { + let mut context = TyCtx::new(); + let name_supply = NameSupply::new(module); + for dep in &deps { + println!("[use {}]:\n{}", dep.0, dep.1.display(ctx)) + } + for (name, interface) in deps { + context.add_use(name_supply.get_or_intern(&name), interface); + } Typechecker { occurrences: HashMap::new(), - name_supply: NameSupply::new(), - context: Ctx::new(), + name_supply, + context, } } @@ -298,25 +254,84 @@ impl Typechecker { assert!(previous_ref.is_none()) } - pub fn infer_program(&mut self, root: &Root) -> (Option, Vec) { + pub fn infer_module( + &mut self, + module: &Module, + ) -> (Option, Interface, Vec) { let mut errors: TyErrors = TyErrors::new(); - let ir = self.infer_program_inner(&mut errors, root); - (ir, errors.errors) + let ir = self.infer_module_inner(&mut errors, module); + let interface = self.mk_interface(&mut errors, module); + (ir, interface, errors.errors) } - pub fn infer_program_inner( + fn mk_interface(&mut self, errors: &mut TyErrors, module: &Module) -> Interface { + let mut interface = Interface::default(); + let Some(header) = module.mod_header() else { + return interface; + }; + for export in header.mod_exports() { + match export { + ModExport::ModExportVal(n) => { + let tkn = n.ident_token().unwrap(); + let str_name = tkn.text().to_string(); + let name = self.sym(&str_name); + match self.context.lookup_func(name) { + Some(f) => { + self.record_ref(&tkn, f.name); + interface.functions.insert(str_name, (*f).clone()); + } + None => errors.report( + &n, + UnknownFunction(n.ident_token().unwrap().text().to_string()), + ), + } + } + ModExport::ModExportTy(n) => { + let tkn = n.upper_ident_token().unwrap(); + let str_name = tkn.text().to_string(); + let name = self.sym(&str_name); + match self.context.lookup_type(name) { + Some(TypeDef::Struct(def)) => { + self.record_ref(&tkn, def.name); + interface.struct_names.insert(str_name, def.name); + interface.structs.insert(def.name, def.clone()); + } + Some(TypeDef::Variant(def)) => { + self.record_ref(&tkn, def.name); + interface.variant_names.insert(str_name, def.name); + interface.variants.insert(def.name, def.clone()); + for (alt_str, alt_name) in &def.alternatives { + interface.struct_names.insert(alt_str.clone(), *alt_name); + interface + .structs + .insert(*alt_name, self.context.lookup_struct_name(*alt_name)); + } + } + None => errors.report( + &n, + UnknownType(n.upper_ident_token().unwrap().text().to_string()), + ), + } + } + ModExport::ModExportAll(_) => todo!("Can't export all yet"), + } + } + interface + } + + fn infer_module_inner( &mut self, errors: &mut TyErrors, - root: &Root, + module: &Module, ) -> Option { self.context.enter_block(); - let types = self.check_type_definitions(errors, root); - let imports = self.check_imports(errors, root); - self.check_function_headers(errors, root); + let types = self.check_type_definitions(errors, module); + let imports = self.check_imports(errors, module); + self.check_function_headers(errors, module); - let globals = self.check_globals(errors, root); - let functions = self.check_function_bodies(errors, root); + let globals = self.check_globals(errors, module); + let functions = self.check_function_bodies(errors, module); self.context.leave_block(); @@ -325,18 +340,21 @@ impl Typechecker { types: types?, globals, funcs: functions?, - start_fn: self.name_supply.start_idx(), }) } - fn check_imports(&mut self, errors: &mut TyErrors, root: &Root) -> Option> { + fn sym(&self, s: &str) -> Symbol { + self.name_supply.get_or_intern(s) + } + + fn check_imports(&mut self, errors: &mut TyErrors, module: &Module) -> Option> { let mut imports = vec![]; - for top_level in root.top_levels() { + for top_level in module.top_levels() { if let TopLevel::TopImport(i) = top_level { let Some(internal_name_tkn) = i.imp_internal().and_then(|x| x.ident_token()) else { continue; }; - let name = self.name_supply.func_idx(&internal_name_tkn); + let (name, sym) = self.name_supply.func_idx(&internal_name_tkn); self.record_def(&internal_name_tkn, name); let ty = if let Some(ty_node) = i.ty() { @@ -359,8 +377,7 @@ impl Typechecker { } }; imports.push(self.build_import_ir(&i, name, &ty)); - self.context - .add_func(internal_name_tkn.text().to_string(), name, vec![], ty); + self.context.add_func(sym, name, vec![], ty); } } imports.into_iter().collect() @@ -381,40 +398,41 @@ impl Typechecker { }) } - fn check_ty_param(&mut self, ty_param: &ParamTy) -> (String, Name) { + fn check_ty_param(&mut self, ty_param: &ParamTy) -> Name { let tkn = ty_param.ident_token().unwrap(); - let name = self.name_supply.type_var(&tkn); + let (name, _) = self.name_supply.type_var(&tkn); self.record_def(&tkn, name); - (tkn.text().to_string(), name) + name } fn check_type_definitions( &mut self, errors: &mut TyErrors, - root: &Root, + module: &Module, ) -> Option> { // Because types can be mutually recursive we need two passes: // - 1. Forward declare all types and their "shapes" let mut struct_defs = vec![]; - for top_level in root.top_levels() { + for top_level in module.top_levels() { match top_level { TopLevel::TopStruct(s) => { let Some(tkn) = s.upper_ident_token() else { continue; }; - let name = self.name_supply.type_idx(&tkn); + let (name, sym) = self.name_supply.type_idx(&tkn); self.record_def(&tkn, name); let ty_params = s.type_params().map(|p| self.check_ty_param(&p)).collect(); self.context.declare_type_def( - tkn.text(), + sym, name, - TypeDef::Struct(Rc::new(StructDef { + TypeDef::Struct(StructDef { name, span: s.syntax().text_range(), ty_params, variant: None, - })), + fields: HashMap::new(), + }), ); struct_defs.push((name, s)) } @@ -422,10 +440,10 @@ impl Typechecker { let Some(tkn) = v.upper_ident_token() else { continue; }; - let variant_name = self.name_supply.type_idx(&tkn); + let (variant_name, variant_sym) = self.name_supply.type_idx(&tkn); self.record_def(&tkn, variant_name); - let ty_params: Vec<(String, Name)> = + let ty_params: Vec = v.type_params().map(|p| self.check_ty_param(&p)).collect(); let mut alternatives = HashMap::new(); @@ -433,7 +451,7 @@ impl Typechecker { let Some(tkn) = s.upper_ident_token() else { continue; }; - let alt_name = self.name_supply.type_idx(&tkn); + let (alt_name, alt_sym) = self.name_supply.type_idx(&tkn); self.record_def(&tkn, alt_name); if s.type_params().next().is_some() { @@ -441,28 +459,29 @@ impl Typechecker { } self.context.declare_type_def( - tkn.text(), + alt_sym, alt_name, - TypeDef::Struct(Rc::new(StructDef { + TypeDef::Struct(StructDef { name: alt_name, span: s.syntax().text_range(), ty_params: ty_params.clone(), variant: Some(variant_name), - })), + fields: HashMap::new(), + }), ); alternatives.insert(tkn.text().to_string(), alt_name); struct_defs.push((alt_name, s)) } self.context.declare_type_def( - tkn.text(), + variant_sym, variant_name, - TypeDef::Variant(Rc::new(VariantDef { + TypeDef::Variant(VariantDef { name: variant_name, span: v.syntax().text_range(), ty_params, alternatives, - })), + }), ); } _ => {} @@ -475,13 +494,11 @@ impl Typechecker { panic!("Impossible! Failed to look up a struct def"); }; - let mut fields = StructFields { - fields: HashMap::new(), - }; - + let mut fields = HashMap::new(); self.context.clear_type_vars(); - for (s, n) in &def.ty_params { - self.context.add_type_var(s.clone(), *n) + for n in &def.ty_params { + let s = self.name_supply.resolve(*n); + self.context.add_type_var(s, *n) } for field in s.struct_fields() { let Some(field_name) = field.ident_token() else { @@ -491,15 +508,13 @@ impl Typechecker { Some(field_ty) => self.check_ty(errors, &field_ty), None => Ty::Error, }; - let name = self.name_supply.field_idx(&field_name); + let (name, _) = self.name_supply.field_idx(&field_name); self.record_def(&field_name, name); - fields - .fields - .insert(field_name.text().to_string(), (name, ty)); + fields.insert(field_name.text().to_string(), (name, ty)); } self.context.clear_type_vars(); - self.context.field_defs.insert(name, fields); + self.context.set_fields(name, fields); } let mut type_defs = vec![]; for (name, def) in self.context.type_defs.iter() { @@ -513,15 +528,15 @@ impl Typechecker { name: *name, span: s.span, variant: s.variant, - fields: self.context.field_defs.get(name).unwrap().to_ir(), + fields: s.fields.values().cloned().collect(), })), } } Some(type_defs) } - fn check_function_headers(&mut self, errors: &mut TyErrors, root: &Root) { - for top_level in root.top_levels() { + fn check_function_headers(&mut self, errors: &mut TyErrors, module: &Module) { + for top_level in module.top_levels() { if let TopLevel::TopFn(top_fn) = top_level { let Some(fn_name_tkn) = top_fn.ident_token() else { continue; @@ -532,10 +547,10 @@ impl Typechecker { let Some(tkn) = ty_arg.ident_token() else { continue; }; - let name = self.name_supply.type_var(&tkn); + let (name, sym) = self.name_supply.type_var(&tkn); self.record_def(&tkn, name); - self.context.add_type_var(tkn.to_string(), name); - ty_args.push((tkn.to_string(), name)) + self.context.add_type_var(sym, name); + ty_args.push(name) } let mut arguments = vec![]; @@ -546,23 +561,78 @@ impl Typechecker { .unwrap_or(Ty::Error); arguments.push(ty); } - let name = self.name_supply.func_idx(&fn_name_tkn); + let (name, sym) = self.name_supply.func_idx(&fn_name_tkn); self.record_def(&fn_name_tkn, name); let result = top_fn .ty() .map(|t| self.check_ty(errors, &t)) .unwrap_or(Ty::Unit); - self.context.add_func( - fn_name_tkn.text().to_string(), - name, - ty_args, - FuncTy { arguments, result }, - ); + self.context + .add_func(sym, name, ty_args, FuncTy { arguments, result }); self.context.clear_type_vars() } } } + fn lookup_type( + &mut self, + errors: &mut TyErrors, + mod_qualifier: Option, + qualifier: Option, + ty_tkn: &SyntaxToken, + ) -> Option { + let mod_qualifier_tkn = mod_qualifier.map(|q| q.ident_token().unwrap()); + if let Some(variant_tkn) = qualifier.map(|q| q.upper_ident_token().unwrap()) { + let opt_def = if let Some(ref mod_qual_tkn) = mod_qualifier_tkn { + self.context + .lookup_qual_type(self.sym(mod_qual_tkn.text()), variant_tkn.text()) + } else { + self.context.lookup_type(self.sym(variant_tkn.text())) + }; + let Some(TypeDef::Variant(def)) = opt_def else { + // TODO: Non-variant type error? + errors.report(&variant_tkn, UnknownType(variant_tkn.text().to_string())); + return None; + }; + self.record_ref(&variant_tkn, def.name); + + let Some(name) = def.alternatives.get(ty_tkn.text()) else { + errors.report( + ty_tkn, + UnknownType(format!("{}::{}", variant_tkn.text(), ty_tkn.text())), + ); + return None; + }; + self.record_ref(ty_tkn, *name); + let opt_struct_def = if let Some(mod_qual_tkn) = mod_qualifier_tkn { + self.context + .lookup_qual_type_name(self.sym(mod_qual_tkn.text()), *name) + } else { + self.context.lookup_type_def(*name) + }; + + assert!( + matches!(opt_struct_def, Some(TypeDef::Struct(_))), + "Non-struct typedef" + ); + opt_struct_def + } else { + let ty_name = ty_tkn.text(); + let opt_def = if let Some(mod_qual) = mod_qualifier_tkn { + self.context + .lookup_qual_type(self.sym(mod_qual.text()), ty_name) + } else { + self.context.lookup_type(self.sym(ty_name)) + }; + let Some(def) = opt_def else { + errors.report(ty_tkn, UnknownType(ty_name.to_string())); + return None; + }; + self.record_ref(ty_tkn, def.name()); + Some(def) + } + } + fn check_ty(&mut self, errors: &mut TyErrors, ty: &Type) -> Ty { match ty { Type::TyInt(_) => Ty::I32, @@ -575,51 +645,28 @@ impl Typechecker { None => Ty::Array(Box::new(Ty::Error)), }, Type::TyCons(t) => { - let (name, ty_def) = if let Some(ty) = - t.qualifier().map(|q| q.upper_ident_token().unwrap()) - { - let Some(TypeDef::Variant(def)) = self.context.lookup_type(ty.text()) else { - errors.report(&ty, UnknownType(ty.text().to_string())); - return Ty::Error; - }; - self.record_ref(&ty, def.name); - - let Some(alt) = t.upper_ident_token() else { - return Ty::Error; - }; - let Some(name) = def.alternatives.get(alt.text()) else { - errors.report(&alt, UnknownType(format!("{}::{}", ty.text(), alt.text()))); - return Ty::Error; - }; - self.record_ref(&alt, *name); - - (def.name, TypeDef::Variant(def)) - } else { - let ty_name = t.upper_ident_token().unwrap(); - let Some(def) = self.context.lookup_type(ty_name.text()) else { - errors.report(&ty_name, UnknownType(ty_name.text().to_string())); - return Ty::Error; - }; - self.record_ref(&ty_name, def.name()); - - (def.name(), def) + let Some(ty_tkn) = t.upper_ident_token() else { + return Ty::Error; + }; + let Some(ty_def) = + self.lookup_type(errors, t.mod_qualifier(), t.qualifier(), &ty_tkn) + else { + return Ty::Error; }; - let ty_args: Vec = t.type_args().map(|t| self.check_ty(errors, &t)).collect(); - let ty_param_names: Vec = - ty_def.ty_params().iter().map(|(_, n)| *n).collect(); + let ty_param_names = ty_def.ty_params(); if ty_param_names.len() != ty_args.len() { errors.report(t, TyArgCountMismatch(ty_param_names.len(), ty_args.len())); return Ty::Error; } Ty::Cons { - name, - ty_args: Substitution::new(&ty_param_names, &ty_args), + name: ty_def.name(), + ty_args: Substitution::new(ty_param_names, &ty_args), } } Type::TyVar(v) => { let tkn = v.ident_token().unwrap(); - if let Some(name) = self.context.lookup_type_var(tkn.text()) { + if let Some(name) = self.context.lookup_type_var(self.sym(tkn.text())) { self.record_ref(&tkn, name); Ty::Var(name) } else { @@ -643,9 +690,9 @@ impl Typechecker { } } - fn check_globals(&mut self, errors: &mut TyErrors, root: &Root) -> Vec { + fn check_globals(&mut self, errors: &mut TyErrors, module: &Module) -> Vec { let mut globals = vec![]; - for top_level in root.top_levels() { + for top_level in module.top_levels() { if let TopLevel::TopGlobal(top_global) = top_level { let (ty, ir) = match ( top_global.ty().map(|t| self.check_ty(errors, &t)), @@ -662,7 +709,7 @@ impl Typechecker { } }; if let Some(binder_tkn) = top_global.ident_token() { - let name = self.name_supply.global_idx(&binder_tkn); + let (name, sym) = self.name_supply.global_idx(&binder_tkn); self.record_def(&binder_tkn, name); if let Some(ir) = ir { globals.push(ir::Global { @@ -671,8 +718,7 @@ impl Typechecker { init: ir, }) } - self.context - .add_var(binder_tkn.text().to_string(), ty, name) + self.context.add_var(sym, ty, name) }; } } @@ -682,17 +728,17 @@ impl Typechecker { fn check_function_bodies( &mut self, errors: &mut TyErrors, - root: &Root, + module: &Module, ) -> Option> { let mut funcs = Some(vec![]); - for top_level in root.top_levels() { + for top_level in module.top_levels() { if let TopLevel::TopFn(top_fn) = top_level { let mut builder = ir::FuncBuilder::default(); let Some(func_name) = top_fn.ident_token() else { funcs = None; continue; }; - let Some(def) = self.context.lookup_func(func_name.text()) else { + let Some(def) = self.context.lookup_func(self.sym(func_name.text())) else { panic!("didn't pre-declare function, {}", func_name.text()) }; @@ -700,10 +746,10 @@ impl Typechecker { let func_ty = def.ty.clone(); self.context.enter_block(); - for (v, name) in def.ty_params.iter() { + for name in &def.ty_params { builder.ty_params(Some(*name)); - // TODO ideally we shouldn't need to clone here - self.context.add_type_var(v.clone(), *name); + let v = self.name_supply.resolve(*name); + self.context.add_type_var(v, *name); } for (param, ty) in top_fn.params().zip(func_ty.arguments.into_iter()) { @@ -711,10 +757,10 @@ impl Typechecker { funcs = None; continue; }; - let name = self.name_supply.local_idx(&ident_tkn); + let (name, sym) = self.name_supply.local_idx(&ident_tkn); builder.params(Some((name, ty.clone()))); self.record_def(&ident_tkn, name); - self.context.add_var(ident_tkn.text().to_string(), ty, name); + self.context.add_var(sym, ty, name); } builder.return_ty(Some(func_ty.result.clone())); @@ -826,18 +872,38 @@ impl Typechecker { (ty, builder.build()) } Expr::EVar(v) => { + let mod_qual_tkn = v.mod_qualifier().map(|q| q.ident_token().unwrap()); let var_tkn = v.ident_token().unwrap(); - match self.context.lookup_var_or_func(var_tkn.text()) { - None => { - errors.report(&var_tkn, UnknownVar(var_tkn.text().to_string())); - return None; + if let Some(mod_qual_tkn) = mod_qual_tkn { + match self + .context + .lookup_qual_func(self.sym(mod_qual_tkn.text()), var_tkn.text()) + { + None => { + errors.report(&var_tkn, UnknownVar(var_tkn.text().to_string())); + return None; + } + Some(func_def) => { + let mut builder = VarBuilder::default(); + builder.name(Some(func_def.name)); + let ir = builder.build(); + self.record_ref(&var_tkn, func_def.name); + (Ty::Func(Box::new(func_def.ty)), ir) + } } - Some((ty, name)) => { - let mut builder = VarBuilder::default(); - builder.name(Some(name)); - let ir = builder.build(); - self.record_ref(&var_tkn, name); - (ty, ir) + } else { + match self.context.lookup_var_or_func(self.sym(var_tkn.text())) { + None => { + errors.report(&var_tkn, UnknownVar(var_tkn.text().to_string())); + return None; + } + Some((ty, name)) => { + let mut builder = VarBuilder::default(); + builder.name(Some(name)); + let ir = builder.build(); + self.record_ref(&var_tkn, name); + (ty, ir) + } } } } @@ -918,12 +984,7 @@ impl Typechecker { None => { errors.report( &op_tkn, - Message(format!( - "Invalid operator {} for lhs of type {} and rhs of type {}", - op_tkn.text(), - lhs_ty.display(self.name_supply.name_map()), - rhs_ty.display(self.name_supply.name_map()) - )), + InvalidOperator(op_tkn.text().to_string(), lhs_ty, rhs_ty), ); return None; } @@ -953,7 +1014,7 @@ impl Typechecker { let Some(name_tkn) = param.ident_token() else { continue; }; - let name = self.name_supply.local_idx(&name_tkn); + let (name, sym) = self.name_supply.local_idx(&name_tkn); let ty = match param.ty() { None => Ty::Error, Some(t) => self.check_ty(errors, &t), @@ -961,7 +1022,7 @@ impl Typechecker { builder.params(Some((name, ty.clone()))); ty_func.arguments.push(ty.clone()); params.insert(name); - self.context.add_var(name_tkn.text().to_string(), ty, name); + self.context.add_var(sym, ty, name); } if let Some(body) = lambda.body() { @@ -1021,6 +1082,16 @@ impl Typechecker { Some((ty, ir_expr)) } + fn lookup_func(&self, qual: Option, name: &str) -> Option> { + if let Some(qual) = qual { + self.context + .lookup_qual_func(self.sym(qual.text()), name) + .map(Rc::new) + } else { + self.context.lookup_func(self.sym(name)) + } + } + fn check_call( &mut self, errors: &mut TyErrors, @@ -1033,17 +1104,19 @@ impl Typechecker { .map(|tas| tas.types().map(|t| self.check_ty(errors, &t)).collect()) .unwrap_or_default(); let callee = if let Expr::EVar(v) = &func_expr { + let mod_qual_tkn = v.mod_qualifier().map(|q| q.ident_token().unwrap()); let var_tkn = v.ident_token().unwrap(); - if self.context.lookup_var(var_tkn.text()).is_some() { + if mod_qual_tkn.is_none() && self.context.lookup_var(self.sym(var_tkn.text())).is_some() + { if !ty_args.is_empty() { errors.report(&var_tkn, CantInstantiateFunctionRef); return None; } let (ty, ir) = self.infer_expr(errors, &func_expr); (ty, ir.map(ir::Callee::FuncRef)) - } else if let Some(def) = self.context.lookup_func(var_tkn.text()) { + } else if let Some(def) = self.lookup_func(mod_qual_tkn, var_tkn.text()) { self.record_ref(&var_tkn, def.name); - let ty_params: Vec = def.ty_params.iter().map(|(_, name)| *name).collect(); + let ty_params: &[Name] = &def.ty_params; // NOTE(early-return-control-flow) if !ty_params.is_empty() && ty_args.is_empty() { return self.infer_poly_call(errors, def, &var_tkn, call_expr, expected); @@ -1055,7 +1128,7 @@ impl Typechecker { ); return None; } - let subst = Substitution::new(&ty_params, &ty_args); + let subst = Substitution::new(ty_params, &ty_args); let ty = subst.apply_func(def.ty.clone()); ( Ty::Func(Box::new(ty)), @@ -1113,14 +1186,14 @@ impl Typechecker { fn infer_poly_struct( &mut self, errors: &mut TyErrors, - def: Rc, + def: &StructDef, struct_tkn: &SyntaxToken, struct_expr: &EStruct, ) -> Option<(Ty, Option)> { let fresh_subst = { let mut fresh_subst = Substitution::empty(); - for (_, n) in def.ty_params.iter() { - fresh_subst.insert(*n, Ty::Var(self.name_supply.gen_idx())); + for n in &def.ty_params { + fresh_subst.insert(*n, Ty::Var(self.name_supply.gen_idx("poly"))); } fresh_subst }; @@ -1139,7 +1212,7 @@ impl Typechecker { continue; }; let applied_ty = subst.apply(fresh_subst.apply(expected_ty)); - let ir = if applied_ty.vars().iter().any(|v| matches!(v, Name::Gen(_))) { + let ir = if applied_ty.vars().iter().any(|v| v.tag == NameTag::Gen) { let (ty, ir) = self.infer_expr(errors, &expr); if ty != Ty::Error { if let Err(err) = match_ty(&mut subst, applied_ty, &ty) { @@ -1153,22 +1226,22 @@ impl Typechecker { builder.fields(ir.map(|ir| (name, ir))); } - for field_name in self.context.field_defs.get(&def.name).unwrap().names() { - if !seen.contains(&field_name) { + for (field_name, _) in self.context.lookup_struct_name(def.name).fields.values() { + if !seen.contains(field_name) { errors.report( struct_tkn, MissingField { struct_name: def.name, - field_name, + field_name: *field_name, }, ); } } let mut final_subst = Substitution::empty(); - for (_, n) in def.ty_params.iter() { + for n in &def.ty_params { let solved = subst.apply(fresh_subst.apply(Ty::Var(*n))); - if matches!(solved, Ty::Var(Name::Gen(_))) { + if matches!(solved, Ty::Var(name) if name.tag == NameTag::Gen) { errors.report(struct_tkn, CantInferTypeParam(*n)); return None; } @@ -1197,8 +1270,8 @@ impl Typechecker { // so recursive calls don't mess with us let fresh_subst = { let mut fresh_subst = Substitution::empty(); - for (_, n) in def.ty_params.iter() { - fresh_subst.insert(*n, Ty::Var(self.name_supply.gen_idx())); + for n in def.ty_params.iter() { + fresh_subst.insert(*n, Ty::Var(self.name_supply.gen_idx("poly_call"))); } fresh_subst }; @@ -1222,7 +1295,7 @@ impl Typechecker { let mut builder = ir::CallBuilder::default(); for (arg, expected_ty) in args.iter().zip(func_ty.arguments.iter()) { let applied_ty = subst.apply(expected_ty.clone()); - let ir = if applied_ty.vars().iter().any(|v| matches!(v, Name::Gen(_))) { + let ir = if applied_ty.vars().iter().any(|v| v.tag == NameTag::Gen) { let (ty, ir) = self.infer_expr(errors, arg); if ty != Ty::Error { if let Err(err) = match_ty(&mut subst, applied_ty, &ty) { @@ -1236,9 +1309,9 @@ impl Typechecker { builder.arguments(ir); } let mut final_subst = Substitution::empty(); - for (_, n) in def.ty_params.iter() { + for n in def.ty_params.iter() { let solved = subst.apply(fresh_subst.apply(Ty::Var(*n))); - if matches!(solved, Ty::Var(Name::Gen(_))) { + if matches!(solved, Ty::Var(name) if name.tag == NameTag::Gen) { errors.report(func_tkn, CantInferTypeParam(*n)); return None; } @@ -1256,40 +1329,6 @@ impl Typechecker { )) } - fn lookup_struct( - &mut self, - errors: &mut TyErrors, - struct_expr: &EStruct, - ) -> Option<(Rc, SyntaxToken)> { - let (struct_def, struct_name_tkn) = if let Some(ty) = struct_expr - .qualifier() - .map(|q| q.upper_ident_token().unwrap()) - { - let alt = struct_expr.upper_ident_token()?; - let struct_def = self.context.lookup_variant(ty.text()).and_then(|def| { - self.record_ref(&ty, def.name); - def.lookup_alternative(alt.text()) - .map(|alt_name| self.context.lookup_struct_name(alt_name)) - }); - (struct_def, alt) - } else { - let tkn = struct_expr.upper_ident_token()?; - (self.context.lookup_struct(tkn.text()), tkn) - }; - let def = match struct_def { - None => { - errors.report( - &struct_name_tkn, - UnknownType(struct_name_tkn.text().to_string()), - ); - return None; - } - Some(def) => def, - }; - self.record_ref(&struct_name_tkn, def.name); - Some((def, struct_name_tkn)) - } - fn lookup_struct_field( &mut self, errors: &mut TyErrors, @@ -1299,7 +1338,8 @@ impl Typechecker { let field_tkn = field.ident_token()?; let Some((field_name, ty)) = self .context - .get_fields(struct_name) + .lookup_struct_name(struct_name) + .fields .get(field_tkn.text()) .cloned() else { @@ -1322,7 +1362,21 @@ impl Typechecker { struct_expr: &EStruct, expected: Option<&Ty>, ) -> Option<(Ty, Option)> { - let (def, struct_name_tkn) = self.lookup_struct(errors, struct_expr)?; + let struct_name_tkn = struct_expr.upper_ident_token()?; + let TypeDef::Struct(def) = self.lookup_type( + errors, + struct_expr.mod_qualifier(), + struct_expr.qualifier(), + &struct_name_tkn, + )? + else { + // TODO: Report struct expr of variant type? + errors.report( + &struct_name_tkn, + UnknownType(struct_name_tkn.text().to_string()), + ); + return None; + }; let mut builder = ir::StructBuilder::default(); builder.name(Some(def.name)); @@ -1330,7 +1384,7 @@ impl Typechecker { struct_expr.e_ty_arg_list().map(|t| t.types().collect()); let subst = if !def.ty_params.is_empty() && ty_arg_list.is_none() { match expected { - None => return self.infer_poly_struct(errors, def, &struct_name_tkn, struct_expr), + None => return self.infer_poly_struct(errors, &def, &struct_name_tkn, struct_expr), Some(expected) => { let Some(subst) = infer_struct_instantiation(&def, expected) else { errors.report( @@ -1357,12 +1411,12 @@ impl Typechecker { ); return None; } - let ty_arg_names: Vec = def.ty_params.iter().map(|(_, name)| *name).collect(); + let ty_arg_names: &[Name] = &def.ty_params; let tys: Vec = ty_arg_list .into_iter() .map(|t| self.check_ty(errors, &t)) .collect(); - Some(Substitution::new(&ty_arg_names, &tys)) + Some(Substitution::new(ty_arg_names, &tys)) }; let subst = subst.unwrap_or_default(); @@ -1380,13 +1434,13 @@ impl Typechecker { } } // TODO report all missing fields at once - for field_name in self.context.field_defs.get(&def.name).unwrap().names() { - if !seen.contains(&field_name) { + for (field_name, _) in self.context.lookup_struct_name(def.name).fields.values() { + if !seen.contains(field_name) { errors.report( &struct_name_tkn, MissingField { struct_name: def.name, - field_name, + field_name: *field_name, }, ); } @@ -1502,7 +1556,7 @@ impl Typechecker { } (Expr::EStruct(expr), ty) => { let (ty, ir) = self.check_struct(errors, expr, Some(ty))?; - // Bit weird to duplicate this here + // A bit weird to duplicate this here if *expected != Ty::Error && !matches!(ty, Ty::Error | Ty::Diverge) && ty.ne(expected) @@ -1603,7 +1657,8 @@ impl Typechecker { s, ty_args, self.context - .get_fields(*name) + .lookup_struct_name(*name) + .fields .get(field_name_tkn.text()) .cloned(), ), @@ -1659,11 +1714,10 @@ impl Typechecker { builder.expr(ir); if let Some(binder_tkn) = let_decl.ident_token() { - let name = self.name_supply.local_idx(&binder_tkn); + let (name, sym) = self.name_supply.local_idx(&binder_tkn); builder.binder(Some(name)); self.record_def(&binder_tkn, name); - self.context - .add_var(binder_tkn.text().to_string(), ty, name) + self.context.add_var(sym, ty, name) } (Ty::Unit, builder.build()) } @@ -1721,7 +1775,9 @@ impl Typechecker { let (ty, ir_data) = match expr { SetTargetExpr::EVar(var) => { let ident_tkn = var.ident_token().unwrap(); - if let Some((ty, name)) = self.context.lookup_var_or_func(ident_tkn.text()) { + if let Some((ty, name)) = + self.context.lookup_var_or_func(self.sym(ident_tkn.text())) + { let ir = ir::SetTargetData::SetVar { name }; self.record_ref(&ident_tkn, name); (ty, Some(ir)) @@ -1789,44 +1845,32 @@ impl Typechecker { ) -> Option { let ir = match pattern { Pattern::PatVariant(pat) => { - let ty = pat.qualifier()?.upper_ident_token()?; - let ctor = pat.upper_ident_token()?; - let var = pat.ident_token()?; - let mut builder = ir::PatVariantBuilder::default(); - let Some(def) = self.context.lookup_variant(ty.text()) else { - errors.report(&ty, UnknownType(ty.text().to_string())); + let ty_tkn = pat.upper_ident_token()?; + let TypeDef::Struct(def) = + self.lookup_type(errors, pat.mod_qualifier(), pat.qualifier(), &ty_tkn)? + else { + errors.report(&ty_tkn, UnknownType(ty_tkn.text().to_string())); return None; }; - self.record_ref(&ty, def.name); - builder.variant(Some(def.name)); match expected { - Ty::Cons { name: s, ty_args } if def.name == *s => { - if let Some(struct_name) = def.alternatives.get(ctor.text()) { - self.record_ref(&ctor, *struct_name); - builder.alternative(Some(*struct_name)); - let name = self.name_supply.local_idx(&var); - self.context.add_var( - var.text().to_string(), - // TODO Think about this clone - Ty::Cons { - name: *struct_name, - ty_args: ty_args.clone(), - }, - name, - ); - builder.binder(Some(name)); - self.record_def(&var, name); - builder.build() - } else { - errors.report( - &ctor, - UnknownAlternative { - variant_name: def.name, - alternative: ctor.text().to_string(), - }, - ); - None - } + Ty::Cons { name: s, ty_args } if def.name == *s || def.variant == Some(*s) => { + let var = pat.ident_token()?; + let mut builder = ir::PatVariantBuilder::default(); + builder.variant(def.variant); + builder.alternative(Some(def.name)); + let (name, sym) = self.name_supply.local_idx(&var); + self.context.add_var( + sym, + // TODO Think about this clone + Ty::Cons { + name: def.name, + ty_args: ty_args.clone(), + }, + name, + ); + builder.binder(Some(name)); + self.record_def(&var, name); + builder.build() } Ty::Error => None, _ => { @@ -1841,10 +1885,9 @@ impl Typechecker { } } Pattern::PatVar(v) => { - let ident_tkn = v.ident_token().unwrap(); - let name = self.name_supply.local_idx(&ident_tkn); - self.context - .add_var(ident_tkn.text().to_string(), expected.clone(), name); + let ident_tkn = v.ident_token()?; + let (name, sym) = self.name_supply.local_idx(&ident_tkn); + self.context.add_var(sym, expected.clone(), name); self.record_def(&ident_tkn, name); let mut builder = PatVarBuilder::default(); builder.var(Some(name)); @@ -1923,7 +1966,14 @@ fn match_ty(subst: &mut Substitution, definition: Ty, inferred: &Ty) -> Result<( // Cow? let definition = subst.apply(definition); match (definition, inferred) { - (Ty::Var(n @ Name::Gen(_)), t) => { + ( + Ty::Var( + n @ Name { + tag: NameTag::Gen, .. + }, + ), + t, + ) => { // We don't solve for ERROR or DIVERGE, because we're still hoping to // solve for a real type. if !matches!(t, Ty::Error | Ty::Diverge) && subst.insert(n, t.clone()).is_some() { @@ -1966,7 +2016,7 @@ fn match_ty(subst: &mut Substitution, definition: Ty, inferred: &Ty) -> Result<( if t1 == *t2 { Ok(()) } else { - Err(TyErrorData::TypeMismatch { + Err(TypeMismatch { expected: t1.clone(), actual: t2.clone(), }) diff --git a/crates/frontend/src/types/error.rs b/crates/frontend/src/types/error.rs index a8df1f0b..646a9cb1 100644 --- a/crates/frontend/src/types/error.rs +++ b/crates/frontend/src/types/error.rs @@ -1,4 +1,4 @@ -use crate::ir::{Name, NameMap, Ty}; +use crate::ir::{Ctx, Name, Ty}; use crate::syntax::{AstNode, SyntaxNode, SyntaxToken}; use ariadne::{Config, Label, Report, ReportKind, Source}; use core::fmt; @@ -79,12 +79,12 @@ impl TyError { pub fn display<'err, 'src>( &'err self, source: &'src str, - name_map: &'src NameMap, + ctx: &'src Ctx, colors: bool, ) -> TyErrorDisplay<'src, 'err> { TyErrorDisplay { source, - name_map, + ctx, ty_error: self, colors, } @@ -96,21 +96,21 @@ impl TyError { (start, end) } - pub fn message(&self, name_map: &NameMap) -> String { - error_label(&self.it, name_map) + pub fn message(&self, ctx: &Ctx) -> String { + error_label(&self.it, ctx) } } pub struct TyErrorDisplay<'src, 'err> { ty_error: &'err TyError, source: &'src str, - name_map: &'src NameMap, + ctx: &'src Ctx, colors: bool, } impl fmt::Display for TyErrorDisplay<'_, '_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - render_ty_error(self.source, self.name_map, self.ty_error, self.colors, f); + render_ty_error(self.source, self.ctx, self.ty_error, self.colors, f); Ok(()) } } @@ -119,12 +119,11 @@ impl fmt::Display for TyErrorDisplay<'_, '_> { pub enum TyErrorData { MissingNode(String), InvalidLiteral, - InvalidOperator, CantInferEmptyArray, CantInstantiateFunctionRef, TypeParamInVariantStruct, CantReturnFromGlobal, - Message(String), + InvalidOperator(String, Ty, Ty), UnknownVar(String), UnknownFunction(String), UnknownType(String), @@ -171,8 +170,7 @@ fn code_for_error(err_data: &TyErrorData) -> i32 { match err_data { TyErrorData::MissingNode(_) => 1, TyErrorData::InvalidLiteral => 2, - TyErrorData::InvalidOperator => 3, - TyErrorData::Message(_) => 4, + TyErrorData::InvalidOperator(_, _, _) => 3, TyErrorData::UnknownVar(_) => 5, TyErrorData::UnknownFunction(_) => 6, TyErrorData::UnknownType(_) => 7, @@ -198,15 +196,17 @@ fn code_for_error(err_data: &TyErrorData) -> i32 { } } -fn error_label(err_data: &TyErrorData, name_map: &NameMap) -> String { +fn error_label(err_data: &TyErrorData, ctx: &Ctx) -> String { match err_data { TyErrorData::MissingNode(n) => format!("Internal/Parse error: Expected a node labeled {n}"), TyErrorData::InvalidLiteral => "Invalid literal couldn't be parsed".to_string(), - TyErrorData::InvalidOperator => "The impossible happened! An invalid operator".to_string(), + TyErrorData::InvalidOperator(op, lhs, rhs) => format!("Invalid operator {} for lhs of type {} and rhs of type {}", op, + lhs.display(ctx), + rhs.display(ctx) + ), TyErrorData::CantInferEmptyArray => "Can't infer type of an empty array".to_string(), TyErrorData::CantInstantiateFunctionRef => "Can't instantiate function reference. Only top-level functions may be polymorphic at this time.".to_string(), TyErrorData::CantReturnFromGlobal => "Can't 'return' from a global definition.".to_string(), - TyErrorData::Message(m) => m.clone(), TyErrorData::UnknownVar(v) => format!("Unknown variable {v}"), TyErrorData::UnknownFunction(f) => format!("Unknown function {f}"), TyErrorData::UnknownType(t) => format!("Unknown type {t}"), @@ -215,20 +215,20 @@ fn error_label(err_data: &TyErrorData, name_map: &NameMap) -> String { } TyErrorData::NonArrayIdx(ty) => format!( "Tried to index into a non-array type {}", - ty.display(name_map) + ty.display(ctx) ), TyErrorData::NonStructIdx(ty) => format!( "Tried to index into a non-struct type {}", - ty.display(name_map) + ty.display(ctx) ), TyErrorData::NotAFunction(ty) => format!( "Can't a call a value of type {} as a function", - ty.display(name_map) + ty.display(ctx) ), TyErrorData::NonFunctionImport { name, ty } => format!( "Can't import a non-function value. {} is of type {}", - name_map.get(name).unwrap().it, - ty.display(name_map) + ctx.display_name(*name), + ty.display(ctx) ), TyErrorData::ArgCountMismatch(expected, actual) => format!( "Mismatched arg count. Expected {expected} {}, but got {actual}", @@ -253,57 +253,57 @@ fn error_label(err_data: &TyErrorData, name_map: &NameMap) -> String { actual, } => format!( "Mismatched field type. {}.{} expects {}, but got {}", - name_map.get(struct_name).unwrap().it, - name_map.get(field_name).unwrap().it, - expected.display(name_map), - actual.display(name_map) + ctx.display_name(*struct_name), + ctx.display_name(*field_name), + expected.display(ctx), + actual.display(ctx) ), TyErrorData::UnknownAlternative { variant_name, alternative, } => format!( "Unknown alternative. {} does not have an alternative named {alternative}", - name_map.get(variant_name).unwrap().it + ctx.display_name(*variant_name), ), TyErrorData::UnknownField { struct_name, field_name, } => format!( "Unknown field. {} does not have a field named {field_name}", - name_map.get(struct_name).unwrap().it + ctx.display_name(*struct_name) ), TyErrorData::MissingField { struct_name, field_name, } => format!( "Missing field. {}.{} was not provided", - name_map.get(struct_name).unwrap().it, - name_map.get(field_name).unwrap().it + ctx.display_name(*struct_name), + ctx.display_name(*field_name) ), TyErrorData::TypeMismatch { expected, actual } => format!( "Type mismatch. Expected {}, but got {}", - expected.display(name_map), - actual.display(name_map) + expected.display(ctx), + actual.display(ctx) ), TyErrorData::PatternTypeMismatch { expected } => format!( "This pattern can't match a value of type {}", - expected.display(name_map), + expected.display(ctx), ), TyErrorData::TypeParamInVariantStruct => { "Can't declare type parameters for structs in a variant.".to_string() } TyErrorData::CantReassignCapturedVariable(n) => { - format!("Can't reassign the captured variable '{}'. Maybe you want to box this variable in a struct?", name_map.get(n).unwrap().it) + format!("Can't reassign the captured variable '{}'. Maybe you want to box this variable in a struct?", ctx.display_name(*n)) } TyErrorData::CantInferTypeParam(n) => { - format!("Can't infer type parameter '{}'. Explicitly supply the instantiation", name_map.get(n).unwrap().it) + format!("Can't infer type parameter '{}'. Explicitly supply the instantiation", ctx.display_name(*n)) }, } } pub fn render_ty_error( source: &str, - name_map: &NameMap, + ctx: &Ctx, ty_error: &TyError, colors: bool, output: &mut fmt::Formatter, @@ -314,13 +314,13 @@ pub fn render_ty_error( Report::build(ReportKind::Error, file_name, 12) .with_code(code_for_error(&ty_error.it)) - .with_message(error_label(&ty_error.it, name_map)) + .with_message(error_label(&ty_error.it, ctx)) .with_label( Label::new(( file_name, ty_error.at.start().into()..ty_error.at.end().into(), )) - .with_message(error_label(&ty_error.it, name_map)), + .with_message(error_label(&ty_error.it, ctx)), ) .with_config(Config::default().with_color(colors)) .finish() diff --git a/crates/frontend/src/types/module.rs b/crates/frontend/src/types/module.rs new file mode 100644 index 00000000..d5b8e75a --- /dev/null +++ b/crates/frontend/src/types/module.rs @@ -0,0 +1,256 @@ +use rowan::TextRange; + +use crate::ir::{Ctx, FuncTy, Name, Symbol, Ty}; +use core::fmt; +use std::collections::HashMap; + +#[derive(Debug, Clone)] +pub struct StructDef { + pub name: Name, + pub span: TextRange, + pub variant: Option, + pub ty_params: Vec, + pub fields: HashMap, +} + +impl StructDef { + pub fn display<'a>(&'a self, ctx: &'a Ctx) -> StructDefDisplay<'a> { + StructDefDisplay { def: self, ctx } + } +} + +pub struct StructDefDisplay<'a> { + def: &'a StructDef, + ctx: &'a Ctx, +} + +impl<'a> fmt::Display for StructDefDisplay<'a> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "struct {}", self.ctx.display_name(self.def.name))?; + if !self.def.ty_params.is_empty() { + write!(f, "[")?; + for (i, ty_param) in self.def.ty_params.iter().enumerate() { + if i != 0 { + write!(f, ", ")?; + } + write!(f, "{}", self.ctx.display_name(*ty_param))?; + } + write!(f, "]")?; + } + if let Some(variant) = self.def.variant { + write!(f, " <: {}", self.ctx.display_name(variant))?; + } + write!(f, " {{")?; + for (i, (name, ty)) in self.def.fields.values().enumerate() { + if i != 0 { + write!(f, ", ")?; + } + write!( + f, + "{}: {}", + self.ctx.display_name(*name), + ty.display(self.ctx) + )?; + } + write!(f, "}}")?; + Ok(()) + } +} + +#[derive(Debug, Clone)] +pub struct VariantDef { + pub name: Name, + pub span: TextRange, + pub ty_params: Vec, + // TODO: The ordering of these alternatives needs to be deterministic + pub alternatives: HashMap, +} + +impl VariantDef { + pub fn lookup_alternative(&self, name: &str) -> Option { + self.alternatives.get(name).copied() + } + + pub fn display<'a>(&'a self, ctx: &'a Ctx) -> VariantDefDisplay<'a> { + VariantDefDisplay { def: self, ctx } + } +} + +pub struct VariantDefDisplay<'a> { + def: &'a VariantDef, + ctx: &'a Ctx, +} + +impl<'a> fmt::Display for VariantDefDisplay<'a> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "variant {}", self.ctx.display_name(self.def.name))?; + if !self.def.ty_params.is_empty() { + write!(f, "[")?; + for (i, ty_param) in self.def.ty_params.iter().enumerate() { + if i != 0 { + write!(f, ", ")?; + } + write!(f, "{}", self.ctx.display_name(*ty_param))?; + } + write!(f, "]")?; + } + write!(f, " {{")?; + for (i, (_, name)) in self.def.alternatives.iter().enumerate() { + if i != 0 { + write!(f, ", ")?; + } + write!(f, "{}", self.ctx.display_name(*name))?; + } + write!(f, "}}")?; + Ok(()) + } +} + +#[derive(Debug, Clone)] +pub enum TypeDef { + Struct(StructDef), + Variant(VariantDef), +} +impl TypeDef { + pub fn name(&self) -> Name { + match self { + TypeDef::Struct(x) => x.name, + TypeDef::Variant(x) => x.name, + } + } + + pub fn ty_params(&self) -> &[Name] { + match self { + TypeDef::Struct(x) => &x.ty_params, + TypeDef::Variant(x) => &x.ty_params, + } + } +} + +#[derive(Debug, Clone)] +pub struct StructFields { + // TODO: The ordering of these fields needs to be deterministic + pub fields: HashMap, +} + +impl StructFields { + pub fn to_ir(&self) -> Vec<(Name, Ty)> { + self.fields.values().cloned().collect() + } + + pub fn names(&self) -> Vec { + self.fields.values().map(|(n, _)| *n).collect() + } +} + +#[derive(Debug, Clone)] +pub struct FuncDef { + pub name: Name, + pub ty_params: Vec, + pub ty: FuncTy, +} + +impl FuncDef { + pub fn display<'a>(&'a self, ctx: &'a Ctx) -> FuncDefDisplay<'a> { + FuncDefDisplay { def: self, ctx } + } +} + +pub struct FuncDefDisplay<'a> { + def: &'a FuncDef, + ctx: &'a Ctx, +} + +impl<'a> fmt::Display for FuncDefDisplay<'a> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "fn {}", self.ctx.display_name(self.def.name))?; + if !self.def.ty_params.is_empty() { + write!(f, "[")?; + for (i, ty_param) in self.def.ty_params.iter().enumerate() { + if i != 0 { + write!(f, ", ")?; + } + write!(f, "{}", self.ctx.display_name(*ty_param))?; + } + write!(f, "]")?; + } + write!(f, "(")?; + for (i, ty) in self.def.ty.arguments.iter().enumerate() { + if i != 0 { + write!(f, ", ")?; + } + write!(f, "{}", ty.display(self.ctx))?; + } + write!(f, ")")?; + write!(f, " -> {}", self.def.ty.result.display(self.ctx))?; + Ok(()) + } +} + +/// Contains all information needed to type check another module that uses +/// this module +#[derive(Debug, Default, Clone)] +pub struct Interface { + pub structs: HashMap, + pub struct_names: HashMap, + pub variants: HashMap, + pub variant_names: HashMap, + pub functions: HashMap, +} + +impl Interface { + pub fn display<'a>(&'a self, ctx: &'a Ctx) -> InterfaceDisplay<'a> { + InterfaceDisplay { + interface: self, + ctx, + } + } + + pub fn lookup_type(&self, name: &str) -> Option { + self.struct_names + .get(name) + .map(|n| TypeDef::Struct(self.structs.get(n).unwrap().clone())) + .or_else(|| { + self.variant_names + .get(name) + .map(|n| TypeDef::Variant(self.variants.get(n).unwrap().clone())) + }) + } + pub fn lookup_type_name(&self, name: Name) -> Option { + self.structs + .get(&name) + .map(|n| TypeDef::Struct(n.clone())) + .or_else(|| { + self.variants + .get(&name) + .map(|n| TypeDef::Variant(n.clone())) + }) + } + + pub fn lookup_func(&self, name: &str) -> Option { + self.functions.get(name).cloned() + } +} + +pub struct InterfaceDisplay<'a> { + interface: &'a Interface, + ctx: &'a Ctx, +} + +impl<'a> fmt::Display for InterfaceDisplay<'a> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + writeln!(f, "Structs:")?; + for def in self.interface.structs.values() { + writeln!(f, " {}", def.display(self.ctx))?; + } + writeln!(f, "Variants:")?; + for def in self.interface.variants.values() { + writeln!(f, " {}", def.display(self.ctx))?; + } + writeln!(f, "Functions:")?; + for def in self.interface.functions.values() { + writeln!(f, " {}", def.display(self.ctx))?; + } + Ok(()) + } +} diff --git a/crates/frontend/src/types/names.rs b/crates/frontend/src/types/names.rs index b80dab1b..fe04cfa8 100644 --- a/crates/frontend/src/types/names.rs +++ b/crates/frontend/src/types/names.rs @@ -1,62 +1,51 @@ -use crate::ir::{self, Id, Name, NameMap}; +use crate::ir::{self, ModuleId, Name, Symbol}; use crate::syntax::SyntaxToken; -use text_size::TextRange; -#[derive(Debug, Clone, Default)] -pub struct NameSupply(ir::NameSupply); - -fn token_into_id(tkn: &SyntaxToken) -> Id { - Id { - it: tkn.text().to_string(), - at: tkn.text_range(), - } -} +#[derive(Debug)] +pub struct NameSupply(ir::NameSupply, ModuleId); impl NameSupply { - pub fn new() -> Self { - Self::default() + pub fn new(module: ModuleId) -> Self { + Self(ir::NameSupply::new(), module) } - pub fn take(self) -> ir::NameSupply { - self.0 + pub fn take(self) -> (ir::NameSupply, ModuleId) { + (self.0, self.1) } - pub fn local_idx(&mut self, local: &SyntaxToken) -> Name { - self.0.local_idx(token_into_id(local)) + pub fn local_idx(&self, tkn: &SyntaxToken) -> (Name, Symbol) { + self.0.local_idx(self.1, tkn.text(), tkn.text_range()) } - pub fn global_idx(&mut self, global: &SyntaxToken) -> Name { - self.0.global_idx(token_into_id(global)) + pub fn global_idx(&self, tkn: &SyntaxToken) -> (Name, Symbol) { + self.0.global_idx(self.1, tkn.text(), tkn.text_range()) } - pub fn func_idx(&mut self, func: &SyntaxToken) -> Name { - self.0.func_idx(token_into_id(func)) + pub fn func_idx(&self, tkn: &SyntaxToken) -> (Name, Symbol) { + self.0.func_idx(self.1, tkn.text(), tkn.text_range()) } - pub fn type_idx(&mut self, typ: &SyntaxToken) -> Name { - self.0.type_idx(token_into_id(typ)) + pub fn type_idx(&mut self, tkn: &SyntaxToken) -> (Name, Symbol) { + self.0.type_idx(self.1, tkn.text(), tkn.text_range()) } - pub fn type_var(&mut self, typ_var: &SyntaxToken) -> Name { - self.0.type_var(token_into_id(typ_var)) + pub fn type_var(&mut self, tkn: &SyntaxToken) -> (Name, Symbol) { + self.0.type_var_idx(self.1, tkn.text(), tkn.text_range()) } - pub fn field_idx(&mut self, field: &SyntaxToken) -> Name { - self.0.field_idx(token_into_id(field)) + pub fn field_idx(&self, tkn: &SyntaxToken) -> (Name, Symbol) { + self.0.field_idx(self.1, tkn.text(), tkn.text_range()) } - pub fn gen_idx(&mut self) -> Name { - self.0.gen_idx() + pub fn gen_idx(&self, it: &str) -> Name { + self.0.gen_idx(self.1, it).0 } - pub fn start_idx(&mut self) -> Name { - self.0.func_idx(Id { - it: "$start".to_string(), - at: TextRange::default(), - }) + pub fn resolve(&self, name: Name) -> ir::Symbol { + self.0.lookup(name).it } - pub fn name_map(&self) -> &NameMap { - &self.0.name_map + pub fn get_or_intern(&self, s: &str) -> ir::Symbol { + self.0.get_or_intern(s) } } diff --git a/crates/frontend/tests/lib.rs b/crates/frontend/tests/lib.rs index 356f3f11..f3840eaf 100644 --- a/crates/frontend/tests/lib.rs +++ b/crates/frontend/tests/lib.rs @@ -1,5 +1,4 @@ use frontend::run_frontend; -use frontend::types::CheckResult; use frontend::{parser::parse_prog, CheckError}; use insta::{assert_snapshot, glob}; use std::fmt::Write; @@ -63,9 +62,9 @@ fn normalize_newlines(src: &mut String) { } fn snapshot_type_errors(path: &Path, source: &str) -> String { - let CheckResult { names, errors, .. } = run_frontend(source); - if errors - .iter() + let result = run_frontend(source); + if result + .errors() .any(|e| matches!(e, CheckError::ParseError(_))) { panic!( @@ -73,16 +72,16 @@ fn snapshot_type_errors(path: &Path, source: &str) -> String { path.display() ) } - if errors.is_empty() { + if !result.has_errors() { panic!("{} was expected to fail, but didn't", path.display()) } let mut err_buf = String::new(); - for error in errors { + for error in result.errors() { write!( &mut err_buf, "{}", - error.display(source, &names.name_map, false) + error.display(source, &result.ctx, false) ) .unwrap(); } diff --git a/crates/frontend/tests/parsing/modules.nemo b/crates/frontend/tests/parsing/modules.nemo new file mode 100644 index 00000000..5074e16c --- /dev/null +++ b/crates/frontend/tests/parsing/modules.nemo @@ -0,0 +1,15 @@ +module str +exports (Str, len, print_char) + +use option +use prim_bytes + +import print_char : fn (i32) -> unit from print_char + +global s : option::Option[i32] = option::some(10) +global s2 = option::Option::Some { value = 10 } + +struct Str {} + +fn len(s: Str) { } +fn concat(s1 : Str, s2 : Str) { } diff --git a/crates/frontend/tests/snapshots/lib__parsing@arrays.nemo.snap b/crates/frontend/tests/snapshots/lib__parsing@arrays.nemo.snap index 53cca20a..92000df9 100644 --- a/crates/frontend/tests/snapshots/lib__parsing@arrays.nemo.snap +++ b/crates/frontend/tests/snapshots/lib__parsing@arrays.nemo.snap @@ -1,182 +1,183 @@ --- source: crates/frontend/tests/lib.rs -assertion_line: 132 +assertion_line: 129 expression: output input_file: crates/frontend/tests/parsing/arrays.nemo --- Root@0..165 - TopGlobal@0..13 - GLOBAL_KW@0..6 "global" - SPACE@6..7 " " - IDENT@7..8 "_" - SPACE@8..9 " " - EQUALS@9..10 "=" - SPACE@10..11 " " - EArray@11..13 - L_BRACKET@11..12 "[" - R_BRACKET@12..13 "]" - TopGlobal@13..28 - LINEFEED@13..14 "\n" - GLOBAL_KW@14..20 "global" - SPACE@20..21 " " - IDENT@21..22 "_" - SPACE@22..23 " " - EQUALS@23..24 "=" - SPACE@24..25 " " - EArray@25..28 - L_BRACKET@25..26 "[" - ELit@26..27 - LitInt@26..27 - INT_LIT@26..27 "1" - R_BRACKET@27..28 "]" - TopGlobal@28..46 - LINEFEED@28..29 "\n" - GLOBAL_KW@29..35 "global" - SPACE@35..36 " " - IDENT@36..37 "_" - SPACE@37..38 " " - EQUALS@38..39 "=" - SPACE@39..40 " " - EArray@40..46 - L_BRACKET@40..41 "[" - ELit@41..42 - LitInt@41..42 - INT_LIT@41..42 "1" - COMMA@42..43 "," - SPACE@43..44 " " - ELit@44..45 - LitInt@44..45 - INT_LIT@44..45 "2" - R_BRACKET@45..46 "]" - TopGlobal@46..65 - LINEFEED@46..47 "\n" - GLOBAL_KW@47..53 "global" - SPACE@53..54 " " - IDENT@54..55 "_" - SPACE@55..56 " " - EQUALS@56..57 "=" - SPACE@57..58 " " - EArray@58..65 - L_BRACKET@58..59 "[" - ELit@59..60 - LitInt@59..60 - INT_LIT@59..60 "1" - COMMA@60..61 "," - SPACE@61..62 " " - ELit@62..63 - LitInt@62..63 - INT_LIT@62..63 "2" - COMMA@63..64 "," - R_BRACKET@64..65 "]" - TopGlobal@65..86 - LINEFEED@65..66 "\n" - GLOBAL_KW@66..72 "global" - SPACE@72..73 " " - IDENT@73..74 "_" - SPACE@74..75 " " - EQUALS@75..76 "=" - SPACE@76..77 " " - EArray@77..86 - L_BRACKET@77..78 "[" - EArray@78..81 - L_BRACKET@78..79 "[" - ELit@79..80 - LitInt@79..80 - INT_LIT@79..80 "1" - R_BRACKET@80..81 "]" - COMMA@81..82 "," - SPACE@82..83 " " - EArray@83..85 - L_BRACKET@83..84 "[" - R_BRACKET@84..85 "]" - R_BRACKET@85..86 "]" - TopGlobal@86..102 - LINEFEED@86..87 "\n" - GLOBAL_KW@87..93 "global" - SPACE@93..94 " " - IDENT@94..95 "_" - SPACE@95..96 " " - EQUALS@96..97 "=" - SPACE@97..98 " " - EArrayIdx@98..102 - EVar@98..99 - IDENT@98..99 "x" - L_BRACKET@99..100 "[" - ELit@100..101 - LitInt@100..101 - INT_LIT@100..101 "1" - R_BRACKET@101..102 "]" - TopGlobal@102..121 - LINEFEED@102..103 "\n" - GLOBAL_KW@103..109 "global" - SPACE@109..110 " " - IDENT@110..111 "_" - SPACE@111..112 " " - EQUALS@112..113 "=" - SPACE@113..114 " " - EArrayIdx@114..121 - EVar@114..115 - IDENT@114..115 "x" - L_BRACKET@115..116 "[" - EArrayIdx@116..120 - EVar@116..117 - IDENT@116..117 "x" - L_BRACKET@117..118 "[" - EVar@118..119 - IDENT@118..119 "x" - R_BRACKET@119..120 "]" - R_BRACKET@120..121 "]" - TopGlobal@121..142 - LINEFEED@121..122 "\n" - GLOBAL_KW@122..128 "global" - SPACE@128..129 " " - IDENT@129..130 "_" - SPACE@130..131 " " - EQUALS@131..132 "=" - SPACE@132..133 " " - EArrayIdx@133..142 - EArray@133..139 - L_BRACKET@133..134 "[" - ELit@134..135 - LitInt@134..135 - INT_LIT@134..135 "1" - COMMA@135..136 "," - SPACE@136..137 " " - ELit@137..138 - LitInt@137..138 - INT_LIT@137..138 "2" - R_BRACKET@138..139 "]" - L_BRACKET@139..140 "[" - ELit@140..141 - LitInt@140..141 - INT_LIT@140..141 "0" - R_BRACKET@141..142 "]" - TopGlobal@142..165 - LINEFEED@142..143 "\n" - GLOBAL_KW@143..149 "global" - SPACE@149..150 " " - IDENT@150..151 "_" - SPACE@151..152 " " - EQUALS@152..153 "=" - SPACE@153..154 " " - EArrayIdx@154..165 - EArrayIdx@154..162 - EArray@154..159 - L_BRACKET@154..155 "[" - EArray@155..158 - L_BRACKET@155..156 "[" - ELit@156..157 - LitInt@156..157 - INT_LIT@156..157 "1" - R_BRACKET@157..158 "]" - R_BRACKET@158..159 "]" - L_BRACKET@159..160 "[" - ELit@160..161 - LitInt@160..161 - INT_LIT@160..161 "0" - R_BRACKET@161..162 "]" - L_BRACKET@162..163 "[" - ELit@163..164 - LitInt@163..164 - INT_LIT@163..164 "0" - R_BRACKET@164..165 "]" + Module@0..165 + TopGlobal@0..13 + GLOBAL_KW@0..6 "global" + SPACE@6..7 " " + IDENT@7..8 "_" + SPACE@8..9 " " + EQUALS@9..10 "=" + SPACE@10..11 " " + EArray@11..13 + L_BRACKET@11..12 "[" + R_BRACKET@12..13 "]" + TopGlobal@13..28 + LINEFEED@13..14 "\n" + GLOBAL_KW@14..20 "global" + SPACE@20..21 " " + IDENT@21..22 "_" + SPACE@22..23 " " + EQUALS@23..24 "=" + SPACE@24..25 " " + EArray@25..28 + L_BRACKET@25..26 "[" + ELit@26..27 + LitInt@26..27 + INT_LIT@26..27 "1" + R_BRACKET@27..28 "]" + TopGlobal@28..46 + LINEFEED@28..29 "\n" + GLOBAL_KW@29..35 "global" + SPACE@35..36 " " + IDENT@36..37 "_" + SPACE@37..38 " " + EQUALS@38..39 "=" + SPACE@39..40 " " + EArray@40..46 + L_BRACKET@40..41 "[" + ELit@41..42 + LitInt@41..42 + INT_LIT@41..42 "1" + COMMA@42..43 "," + SPACE@43..44 " " + ELit@44..45 + LitInt@44..45 + INT_LIT@44..45 "2" + R_BRACKET@45..46 "]" + TopGlobal@46..65 + LINEFEED@46..47 "\n" + GLOBAL_KW@47..53 "global" + SPACE@53..54 " " + IDENT@54..55 "_" + SPACE@55..56 " " + EQUALS@56..57 "=" + SPACE@57..58 " " + EArray@58..65 + L_BRACKET@58..59 "[" + ELit@59..60 + LitInt@59..60 + INT_LIT@59..60 "1" + COMMA@60..61 "," + SPACE@61..62 " " + ELit@62..63 + LitInt@62..63 + INT_LIT@62..63 "2" + COMMA@63..64 "," + R_BRACKET@64..65 "]" + TopGlobal@65..86 + LINEFEED@65..66 "\n" + GLOBAL_KW@66..72 "global" + SPACE@72..73 " " + IDENT@73..74 "_" + SPACE@74..75 " " + EQUALS@75..76 "=" + SPACE@76..77 " " + EArray@77..86 + L_BRACKET@77..78 "[" + EArray@78..81 + L_BRACKET@78..79 "[" + ELit@79..80 + LitInt@79..80 + INT_LIT@79..80 "1" + R_BRACKET@80..81 "]" + COMMA@81..82 "," + SPACE@82..83 " " + EArray@83..85 + L_BRACKET@83..84 "[" + R_BRACKET@84..85 "]" + R_BRACKET@85..86 "]" + TopGlobal@86..102 + LINEFEED@86..87 "\n" + GLOBAL_KW@87..93 "global" + SPACE@93..94 " " + IDENT@94..95 "_" + SPACE@95..96 " " + EQUALS@96..97 "=" + SPACE@97..98 " " + EArrayIdx@98..102 + EVar@98..99 + IDENT@98..99 "x" + L_BRACKET@99..100 "[" + ELit@100..101 + LitInt@100..101 + INT_LIT@100..101 "1" + R_BRACKET@101..102 "]" + TopGlobal@102..121 + LINEFEED@102..103 "\n" + GLOBAL_KW@103..109 "global" + SPACE@109..110 " " + IDENT@110..111 "_" + SPACE@111..112 " " + EQUALS@112..113 "=" + SPACE@113..114 " " + EArrayIdx@114..121 + EVar@114..115 + IDENT@114..115 "x" + L_BRACKET@115..116 "[" + EArrayIdx@116..120 + EVar@116..117 + IDENT@116..117 "x" + L_BRACKET@117..118 "[" + EVar@118..119 + IDENT@118..119 "x" + R_BRACKET@119..120 "]" + R_BRACKET@120..121 "]" + TopGlobal@121..142 + LINEFEED@121..122 "\n" + GLOBAL_KW@122..128 "global" + SPACE@128..129 " " + IDENT@129..130 "_" + SPACE@130..131 " " + EQUALS@131..132 "=" + SPACE@132..133 " " + EArrayIdx@133..142 + EArray@133..139 + L_BRACKET@133..134 "[" + ELit@134..135 + LitInt@134..135 + INT_LIT@134..135 "1" + COMMA@135..136 "," + SPACE@136..137 " " + ELit@137..138 + LitInt@137..138 + INT_LIT@137..138 "2" + R_BRACKET@138..139 "]" + L_BRACKET@139..140 "[" + ELit@140..141 + LitInt@140..141 + INT_LIT@140..141 "0" + R_BRACKET@141..142 "]" + TopGlobal@142..165 + LINEFEED@142..143 "\n" + GLOBAL_KW@143..149 "global" + SPACE@149..150 " " + IDENT@150..151 "_" + SPACE@151..152 " " + EQUALS@152..153 "=" + SPACE@153..154 " " + EArrayIdx@154..165 + EArrayIdx@154..162 + EArray@154..159 + L_BRACKET@154..155 "[" + EArray@155..158 + L_BRACKET@155..156 "[" + ELit@156..157 + LitInt@156..157 + INT_LIT@156..157 "1" + R_BRACKET@157..158 "]" + R_BRACKET@158..159 "]" + L_BRACKET@159..160 "[" + ELit@160..161 + LitInt@160..161 + INT_LIT@160..161 "0" + R_BRACKET@161..162 "]" + L_BRACKET@162..163 "[" + ELit@163..164 + LitInt@163..164 + INT_LIT@163..164 "0" + R_BRACKET@164..165 "]" diff --git a/crates/frontend/tests/snapshots/lib__parsing@block.nemo.snap b/crates/frontend/tests/snapshots/lib__parsing@block.nemo.snap index 2046661c..992155f9 100644 --- a/crates/frontend/tests/snapshots/lib__parsing@block.nemo.snap +++ b/crates/frontend/tests/snapshots/lib__parsing@block.nemo.snap @@ -1,63 +1,64 @@ --- source: crates/frontend/tests/lib.rs -assertion_line: 132 +assertion_line: 129 expression: output input_file: crates/frontend/tests/parsing/block.nemo --- Root@0..63 - TopGlobal@0..13 - GLOBAL_KW@0..6 "global" - SPACE@6..7 " " - IDENT@7..8 "_" - SPACE@8..9 " " - EQUALS@9..10 "=" - SPACE@10..11 " " - EBlock@11..13 - L_BRACE@11..12 "{" - R_BRACE@12..13 "}" - TopGlobal@13..28 - LINEFEED@13..14 "\n" - GLOBAL_KW@14..20 "global" - SPACE@20..21 " " - IDENT@21..22 "_" - SPACE@22..23 " " - EQUALS@23..24 "=" - SPACE@24..25 " " - EBlock@25..28 - L_BRACE@25..26 "{" - DExpr@26..27 - ELit@26..27 - LitInt@26..27 - INT_LIT@26..27 "1" - R_BRACE@27..28 "}" - TopGlobal@28..63 - LINEFEED@28..29 "\n" - GLOBAL_KW@29..35 "global" - SPACE@35..36 " " - IDENT@36..37 "_" - SPACE@37..38 " " - EQUALS@38..39 "=" - SPACE@39..40 " " - EBlock@40..63 - L_BRACE@40..41 "{" - DExpr@41..47 - ELit@41..47 - LitInt@41..47 - LINEFEED@41..42 "\n" - SPACE@42..46 " " - INT_LIT@46..47 "1" - SEMICOLON@47..48 ";" - DExpr@48..54 - EVar@48..54 - LINEFEED@48..49 "\n" - SPACE@49..53 " " - IDENT@53..54 "x" - SEMICOLON@54..55 ";" - DExpr@55..61 - ELit@55..61 - LitInt@55..61 - LINEFEED@55..56 "\n" - SPACE@56..60 " " - INT_LIT@60..61 "2" - LINEFEED@61..62 "\n" - R_BRACE@62..63 "}" + Module@0..63 + TopGlobal@0..13 + GLOBAL_KW@0..6 "global" + SPACE@6..7 " " + IDENT@7..8 "_" + SPACE@8..9 " " + EQUALS@9..10 "=" + SPACE@10..11 " " + EBlock@11..13 + L_BRACE@11..12 "{" + R_BRACE@12..13 "}" + TopGlobal@13..28 + LINEFEED@13..14 "\n" + GLOBAL_KW@14..20 "global" + SPACE@20..21 " " + IDENT@21..22 "_" + SPACE@22..23 " " + EQUALS@23..24 "=" + SPACE@24..25 " " + EBlock@25..28 + L_BRACE@25..26 "{" + DExpr@26..27 + ELit@26..27 + LitInt@26..27 + INT_LIT@26..27 "1" + R_BRACE@27..28 "}" + TopGlobal@28..63 + LINEFEED@28..29 "\n" + GLOBAL_KW@29..35 "global" + SPACE@35..36 " " + IDENT@36..37 "_" + SPACE@37..38 " " + EQUALS@38..39 "=" + SPACE@39..40 " " + EBlock@40..63 + L_BRACE@40..41 "{" + DExpr@41..47 + ELit@41..47 + LitInt@41..47 + LINEFEED@41..42 "\n" + SPACE@42..46 " " + INT_LIT@46..47 "1" + SEMICOLON@47..48 ";" + DExpr@48..54 + EVar@48..54 + LINEFEED@48..49 "\n" + SPACE@49..53 " " + IDENT@53..54 "x" + SEMICOLON@54..55 ";" + DExpr@55..61 + ELit@55..61 + LitInt@55..61 + LINEFEED@55..56 "\n" + SPACE@56..60 " " + INT_LIT@60..61 "2" + LINEFEED@61..62 "\n" + R_BRACE@62..63 "}" diff --git a/crates/frontend/tests/snapshots/lib__parsing@closures.nemo.snap b/crates/frontend/tests/snapshots/lib__parsing@closures.nemo.snap index 05752908..5afdfb29 100644 --- a/crates/frontend/tests/snapshots/lib__parsing@closures.nemo.snap +++ b/crates/frontend/tests/snapshots/lib__parsing@closures.nemo.snap @@ -1,134 +1,136 @@ --- source: crates/frontend/tests/lib.rs +assertion_line: 129 expression: output input_file: crates/frontend/tests/parsing/closures.nemo --- Root@0..121 - TopFn@0..121 - FN_KW@0..2 "fn" - SPACE@2..3 " " - IDENT@3..7 "main" - L_PAREN@7..8 "(" - R_PAREN@8..9 ")" - SPACE@9..10 " " - EBlock@10..121 - L_BRACE@10..11 "{" - DExpr@11..49 - ECall@11..49 - EParen@11..45 - LINEFEED@11..12 "\n" - SPACE@12..14 " " - L_PAREN@14..15 "(" - ELambda@15..44 - FN_KW@15..17 "fn" - SPACE@17..18 " " - L_PAREN@18..19 "(" - Param@19..26 - IDENT@19..20 "x" - SPACE@20..21 " " - COLON@21..22 ":" - SPACE@22..23 " " - TyInt@23..26 - I32_BUILTIN@23..26 "i32" - R_PAREN@26..27 ")" - SPACE@27..28 " " - ARROW@28..30 "->" - SPACE@30..31 " " - TyInt@31..35 - I32_BUILTIN@31..34 "i32" - SPACE@34..35 " " - EBlock@35..44 - L_BRACE@35..36 "{" - SPACE@36..37 " " - DExpr@37..43 - EBinary@37..43 - EVar@37..39 - IDENT@37..38 "x" - SPACE@38..39 " " - BinOp@39..41 - PLUS@39..40 "+" - SPACE@40..41 " " - ELit@41..43 - LitInt@41..43 - INT_LIT@41..42 "1" - SPACE@42..43 " " - R_BRACE@43..44 "}" - R_PAREN@44..45 ")" - EArgList@45..49 - L_PAREN@45..46 "(" - ELit@46..48 - LitInt@46..48 - INT_LIT@46..48 "10" - R_PAREN@48..49 ")" - SEMICOLON@49..50 ";" - DExpr@50..112 - ECall@50..112 - EVar@50..57 - LINEFEED@50..51 "\n" - LINEFEED@51..52 "\n" - SPACE@52..54 " " - IDENT@54..57 "map" - EArgList@57..112 - L_PAREN@57..58 "(" - EVar@58..59 - IDENT@58..59 "o" - COMMA@59..60 "," - SPACE@60..61 " " - ELambda@61..111 - FN_KW@61..63 "fn" - SPACE@63..64 " " - L_PAREN@64..65 "(" - Param@65..72 - IDENT@65..66 "x" - SPACE@66..67 " " - COLON@67..68 ":" - SPACE@68..69 " " - TyInt@69..72 - I32_BUILTIN@69..72 "i32" - R_PAREN@72..73 ")" - SPACE@73..74 " " - ARROW@74..76 "->" - SPACE@76..77 " " - TyInt@77..81 - I32_BUILTIN@77..80 "i32" - SPACE@80..81 " " - EBlock@81..111 - L_BRACE@81..82 "{" - DLet@82..100 - LINEFEED@82..83 "\n" - SPACE@83..87 " " - LET_KW@87..90 "let" - SPACE@90..91 " " - IDENT@91..92 "y" - SPACE@92..93 " " - EQUALS@93..94 "=" - SPACE@94..95 " " - EBinary@95..100 - EVar@95..97 - IDENT@95..96 "x" - SPACE@96..97 " " - BinOp@97..99 - STAR@97..98 "*" - SPACE@98..99 " " - EVar@99..100 - IDENT@99..100 "x" - SEMICOLON@100..101 ";" - DExpr@101..107 - EVar@101..107 - LINEFEED@101..102 "\n" - SPACE@102..106 " " - IDENT@106..107 "y" - LINEFEED@107..108 "\n" - SPACE@108..110 " " - R_BRACE@110..111 "}" - R_PAREN@111..112 ")" - SEMICOLON@112..113 ";" - DExpr@113..118 - EBlock@113..118 - LINEFEED@113..114 "\n" - SPACE@114..116 " " - L_BRACE@116..117 "{" - R_BRACE@117..118 "}" - SEMICOLON@118..119 ";" - LINEFEED@119..120 "\n" - R_BRACE@120..121 "}" + Module@0..121 + TopFn@0..121 + FN_KW@0..2 "fn" + SPACE@2..3 " " + IDENT@3..7 "main" + L_PAREN@7..8 "(" + R_PAREN@8..9 ")" + SPACE@9..10 " " + EBlock@10..121 + L_BRACE@10..11 "{" + DExpr@11..49 + ECall@11..49 + EParen@11..45 + LINEFEED@11..12 "\n" + SPACE@12..14 " " + L_PAREN@14..15 "(" + ELambda@15..44 + FN_KW@15..17 "fn" + SPACE@17..18 " " + L_PAREN@18..19 "(" + Param@19..26 + IDENT@19..20 "x" + SPACE@20..21 " " + COLON@21..22 ":" + SPACE@22..23 " " + TyInt@23..26 + I32_BUILTIN@23..26 "i32" + R_PAREN@26..27 ")" + SPACE@27..28 " " + ARROW@28..30 "->" + SPACE@30..31 " " + TyInt@31..35 + I32_BUILTIN@31..34 "i32" + SPACE@34..35 " " + EBlock@35..44 + L_BRACE@35..36 "{" + SPACE@36..37 " " + DExpr@37..43 + EBinary@37..43 + EVar@37..39 + IDENT@37..38 "x" + SPACE@38..39 " " + BinOp@39..41 + PLUS@39..40 "+" + SPACE@40..41 " " + ELit@41..43 + LitInt@41..43 + INT_LIT@41..42 "1" + SPACE@42..43 " " + R_BRACE@43..44 "}" + R_PAREN@44..45 ")" + EArgList@45..49 + L_PAREN@45..46 "(" + ELit@46..48 + LitInt@46..48 + INT_LIT@46..48 "10" + R_PAREN@48..49 ")" + SEMICOLON@49..50 ";" + DExpr@50..112 + ECall@50..112 + EVar@50..57 + LINEFEED@50..51 "\n" + LINEFEED@51..52 "\n" + SPACE@52..54 " " + IDENT@54..57 "map" + EArgList@57..112 + L_PAREN@57..58 "(" + EVar@58..59 + IDENT@58..59 "o" + COMMA@59..60 "," + SPACE@60..61 " " + ELambda@61..111 + FN_KW@61..63 "fn" + SPACE@63..64 " " + L_PAREN@64..65 "(" + Param@65..72 + IDENT@65..66 "x" + SPACE@66..67 " " + COLON@67..68 ":" + SPACE@68..69 " " + TyInt@69..72 + I32_BUILTIN@69..72 "i32" + R_PAREN@72..73 ")" + SPACE@73..74 " " + ARROW@74..76 "->" + SPACE@76..77 " " + TyInt@77..81 + I32_BUILTIN@77..80 "i32" + SPACE@80..81 " " + EBlock@81..111 + L_BRACE@81..82 "{" + DLet@82..100 + LINEFEED@82..83 "\n" + SPACE@83..87 " " + LET_KW@87..90 "let" + SPACE@90..91 " " + IDENT@91..92 "y" + SPACE@92..93 " " + EQUALS@93..94 "=" + SPACE@94..95 " " + EBinary@95..100 + EVar@95..97 + IDENT@95..96 "x" + SPACE@96..97 " " + BinOp@97..99 + STAR@97..98 "*" + SPACE@98..99 " " + EVar@99..100 + IDENT@99..100 "x" + SEMICOLON@100..101 ";" + DExpr@101..107 + EVar@101..107 + LINEFEED@101..102 "\n" + SPACE@102..106 " " + IDENT@106..107 "y" + LINEFEED@107..108 "\n" + SPACE@108..110 " " + R_BRACE@110..111 "}" + R_PAREN@111..112 ")" + SEMICOLON@112..113 ";" + DExpr@113..118 + EBlock@113..118 + LINEFEED@113..114 "\n" + SPACE@114..116 " " + L_BRACE@116..117 "{" + R_BRACE@117..118 "}" + SEMICOLON@118..119 ";" + LINEFEED@119..120 "\n" + R_BRACE@120..121 "}" diff --git a/crates/frontend/tests/snapshots/lib__parsing@decl.nemo.snap b/crates/frontend/tests/snapshots/lib__parsing@decl.nemo.snap index 010da057..e6f7f8e7 100644 --- a/crates/frontend/tests/snapshots/lib__parsing@decl.nemo.snap +++ b/crates/frontend/tests/snapshots/lib__parsing@decl.nemo.snap @@ -1,178 +1,179 @@ --- source: crates/frontend/tests/lib.rs -assertion_line: 132 +assertion_line: 129 expression: output input_file: crates/frontend/tests/parsing/decl.nemo --- Root@0..179 - TopGlobal@0..179 - GLOBAL_KW@0..6 "global" - SPACE@6..7 " " - IDENT@7..8 "_" - SPACE@8..9 " " - EQUALS@9..10 "=" - SPACE@10..11 " " - EBlock@11..179 - L_BRACE@11..12 "{" - DLet@12..26 - LINEFEED@12..13 "\n" - SPACE@13..17 " " - LET_KW@17..20 "let" - SPACE@20..21 " " - IDENT@21..22 "x" - SPACE@22..23 " " - EQUALS@23..24 "=" - SPACE@24..25 " " - ELit@25..26 - LitInt@25..26 - INT_LIT@25..26 "1" - SEMICOLON@26..27 ";" - DLet@27..48 - LINEFEED@27..28 "\n" - SPACE@28..32 " " - LET_KW@32..35 "let" - SPACE@35..36 " " - IDENT@36..37 "y" - SPACE@37..38 " " - COLON@38..39 ":" - SPACE@39..40 " " - TyInt@40..44 - I32_BUILTIN@40..43 "i32" - SPACE@43..44 " " - EQUALS@44..45 "=" - SPACE@45..46 " " - ELit@46..48 - LitInt@46..48 - INT_LIT@46..48 "10" - SEMICOLON@48..49 ";" - DSet@49..63 - LINEFEED@49..50 "\n" - SPACE@50..54 " " - SET_KW@54..57 "set" - SPACE@57..58 " " - SetTarget@58..60 - EVar@58..60 - IDENT@58..59 "x" - SPACE@59..60 " " - EQUALS@60..61 "=" - SPACE@61..62 " " - ELit@62..63 - LitInt@62..63 - INT_LIT@62..63 "1" - SEMICOLON@63..64 ";" - DSet@64..81 - LINEFEED@64..65 "\n" - SPACE@65..69 " " - SET_KW@69..72 "set" - SPACE@72..73 " " - SetTarget@73..78 - EArrayIdx@73..78 - EVar@73..74 - IDENT@73..74 "x" - L_BRACKET@74..75 "[" - ELit@75..76 - LitInt@75..76 - INT_LIT@75..76 "0" - R_BRACKET@76..77 "]" - SPACE@77..78 " " - EQUALS@78..79 "=" - SPACE@79..80 " " - ELit@80..81 - LitInt@80..81 - INT_LIT@80..81 "1" - SEMICOLON@81..82 ";" - DSet@82..98 - LINEFEED@82..83 "\n" - SPACE@83..87 " " - SET_KW@87..90 "set" - SPACE@90..91 " " - SetTarget@91..95 - EStructIdx@91..95 - EVar@91..92 - IDENT@91..92 "x" - DOT@92..93 "." - IDENT@93..94 "y" - SPACE@94..95 " " - EQUALS@95..96 "=" - SPACE@96..97 " " - ELit@97..98 - LitInt@97..98 - INT_LIT@97..98 "1" - SEMICOLON@98..99 ";" - DSet@99..118 - LINEFEED@99..100 "\n" - SPACE@100..104 " " - SET_KW@104..107 "set" - SPACE@107..108 " " - SetTarget@108..115 - EStructIdx@108..115 - EArrayIdx@108..112 - EVar@108..109 - IDENT@108..109 "x" - L_BRACKET@109..110 "[" - ELit@110..111 - LitInt@110..111 - INT_LIT@110..111 "0" - R_BRACKET@111..112 "]" - DOT@112..113 "." - IDENT@113..114 "y" - SPACE@114..115 " " - EQUALS@115..116 "=" - SPACE@116..117 " " - ELit@117..118 - LitInt@117..118 - INT_LIT@117..118 "1" - SEMICOLON@118..119 ";" - DSet@119..138 - LINEFEED@119..120 "\n" - SPACE@120..124 " " - SET_KW@124..127 "set" - SPACE@127..128 " " - SetTarget@128..135 - EArrayIdx@128..135 - EStructIdx@128..131 - EVar@128..129 - IDENT@128..129 "x" - DOT@129..130 "." - IDENT@130..131 "y" - L_BRACKET@131..132 "[" - ELit@132..133 - LitInt@132..133 - INT_LIT@132..133 "0" - R_BRACKET@133..134 "]" - SPACE@134..135 " " - EQUALS@135..136 "=" - SPACE@136..137 " " - ELit@137..138 - LitInt@137..138 - INT_LIT@137..138 "1" - SEMICOLON@138..139 ";" - DWhile@139..176 - LINEFEED@139..140 "\n" - SPACE@140..144 " " - WHILE_KW@144..149 "while" - SPACE@149..150 " " - EVar@150..152 - IDENT@150..151 "x" - SPACE@151..152 " " - EBlock@152..176 - L_BRACE@152..153 "{" - DExpr@153..161 - ELit@153..161 - LitInt@153..161 - LINEFEED@153..154 "\n" - SPACE@154..160 " " - INT_LIT@160..161 "1" - SEMICOLON@161..162 ";" - DExpr@162..170 - ELit@162..170 - LitInt@162..170 - LINEFEED@162..163 "\n" - SPACE@163..169 " " - INT_LIT@169..170 "2" - LINEFEED@170..171 "\n" - SPACE@171..175 " " - R_BRACE@175..176 "}" - SEMICOLON@176..177 ";" - LINEFEED@177..178 "\n" - R_BRACE@178..179 "}" + Module@0..179 + TopGlobal@0..179 + GLOBAL_KW@0..6 "global" + SPACE@6..7 " " + IDENT@7..8 "_" + SPACE@8..9 " " + EQUALS@9..10 "=" + SPACE@10..11 " " + EBlock@11..179 + L_BRACE@11..12 "{" + DLet@12..26 + LINEFEED@12..13 "\n" + SPACE@13..17 " " + LET_KW@17..20 "let" + SPACE@20..21 " " + IDENT@21..22 "x" + SPACE@22..23 " " + EQUALS@23..24 "=" + SPACE@24..25 " " + ELit@25..26 + LitInt@25..26 + INT_LIT@25..26 "1" + SEMICOLON@26..27 ";" + DLet@27..48 + LINEFEED@27..28 "\n" + SPACE@28..32 " " + LET_KW@32..35 "let" + SPACE@35..36 " " + IDENT@36..37 "y" + SPACE@37..38 " " + COLON@38..39 ":" + SPACE@39..40 " " + TyInt@40..44 + I32_BUILTIN@40..43 "i32" + SPACE@43..44 " " + EQUALS@44..45 "=" + SPACE@45..46 " " + ELit@46..48 + LitInt@46..48 + INT_LIT@46..48 "10" + SEMICOLON@48..49 ";" + DSet@49..63 + LINEFEED@49..50 "\n" + SPACE@50..54 " " + SET_KW@54..57 "set" + SPACE@57..58 " " + SetTarget@58..60 + EVar@58..60 + IDENT@58..59 "x" + SPACE@59..60 " " + EQUALS@60..61 "=" + SPACE@61..62 " " + ELit@62..63 + LitInt@62..63 + INT_LIT@62..63 "1" + SEMICOLON@63..64 ";" + DSet@64..81 + LINEFEED@64..65 "\n" + SPACE@65..69 " " + SET_KW@69..72 "set" + SPACE@72..73 " " + SetTarget@73..78 + EArrayIdx@73..78 + EVar@73..74 + IDENT@73..74 "x" + L_BRACKET@74..75 "[" + ELit@75..76 + LitInt@75..76 + INT_LIT@75..76 "0" + R_BRACKET@76..77 "]" + SPACE@77..78 " " + EQUALS@78..79 "=" + SPACE@79..80 " " + ELit@80..81 + LitInt@80..81 + INT_LIT@80..81 "1" + SEMICOLON@81..82 ";" + DSet@82..98 + LINEFEED@82..83 "\n" + SPACE@83..87 " " + SET_KW@87..90 "set" + SPACE@90..91 " " + SetTarget@91..95 + EStructIdx@91..95 + EVar@91..92 + IDENT@91..92 "x" + DOT@92..93 "." + IDENT@93..94 "y" + SPACE@94..95 " " + EQUALS@95..96 "=" + SPACE@96..97 " " + ELit@97..98 + LitInt@97..98 + INT_LIT@97..98 "1" + SEMICOLON@98..99 ";" + DSet@99..118 + LINEFEED@99..100 "\n" + SPACE@100..104 " " + SET_KW@104..107 "set" + SPACE@107..108 " " + SetTarget@108..115 + EStructIdx@108..115 + EArrayIdx@108..112 + EVar@108..109 + IDENT@108..109 "x" + L_BRACKET@109..110 "[" + ELit@110..111 + LitInt@110..111 + INT_LIT@110..111 "0" + R_BRACKET@111..112 "]" + DOT@112..113 "." + IDENT@113..114 "y" + SPACE@114..115 " " + EQUALS@115..116 "=" + SPACE@116..117 " " + ELit@117..118 + LitInt@117..118 + INT_LIT@117..118 "1" + SEMICOLON@118..119 ";" + DSet@119..138 + LINEFEED@119..120 "\n" + SPACE@120..124 " " + SET_KW@124..127 "set" + SPACE@127..128 " " + SetTarget@128..135 + EArrayIdx@128..135 + EStructIdx@128..131 + EVar@128..129 + IDENT@128..129 "x" + DOT@129..130 "." + IDENT@130..131 "y" + L_BRACKET@131..132 "[" + ELit@132..133 + LitInt@132..133 + INT_LIT@132..133 "0" + R_BRACKET@133..134 "]" + SPACE@134..135 " " + EQUALS@135..136 "=" + SPACE@136..137 " " + ELit@137..138 + LitInt@137..138 + INT_LIT@137..138 "1" + SEMICOLON@138..139 ";" + DWhile@139..176 + LINEFEED@139..140 "\n" + SPACE@140..144 " " + WHILE_KW@144..149 "while" + SPACE@149..150 " " + EVar@150..152 + IDENT@150..151 "x" + SPACE@151..152 " " + EBlock@152..176 + L_BRACE@152..153 "{" + DExpr@153..161 + ELit@153..161 + LitInt@153..161 + LINEFEED@153..154 "\n" + SPACE@154..160 " " + INT_LIT@160..161 "1" + SEMICOLON@161..162 ";" + DExpr@162..170 + ELit@162..170 + LitInt@162..170 + LINEFEED@162..163 "\n" + SPACE@163..169 " " + INT_LIT@169..170 "2" + LINEFEED@170..171 "\n" + SPACE@171..175 " " + R_BRACE@175..176 "}" + SEMICOLON@176..177 ";" + LINEFEED@177..178 "\n" + R_BRACE@178..179 "}" diff --git a/crates/frontend/tests/snapshots/lib__parsing@expr_postfix.nemo.snap b/crates/frontend/tests/snapshots/lib__parsing@expr_postfix.nemo.snap index 4e739995..d85cf6c5 100644 --- a/crates/frontend/tests/snapshots/lib__parsing@expr_postfix.nemo.snap +++ b/crates/frontend/tests/snapshots/lib__parsing@expr_postfix.nemo.snap @@ -1,151 +1,152 @@ --- source: crates/frontend/tests/lib.rs -assertion_line: 132 +assertion_line: 129 expression: output input_file: crates/frontend/tests/parsing/expr_postfix.nemo --- Root@0..128 - TopGlobal@0..14 - GLOBAL_KW@0..6 "global" - SPACE@6..7 " " - IDENT@7..8 "_" - SPACE@8..9 " " - EQUALS@9..10 "=" - SPACE@10..11 " " - ECall@11..14 - EVar@11..12 - IDENT@11..12 "f" - EArgList@12..14 - L_PAREN@12..13 "(" - R_PAREN@13..14 ")" - TopGlobal@14..30 - LINEFEED@14..15 "\n" - GLOBAL_KW@15..21 "global" - SPACE@21..22 " " - IDENT@22..23 "_" - SPACE@23..24 " " - EQUALS@24..25 "=" - SPACE@25..26 " " - ECall@26..30 - EVar@26..27 - IDENT@26..27 "f" - EArgList@27..30 - L_PAREN@27..28 "(" - ELit@28..29 - LitInt@28..29 - INT_LIT@28..29 "1" - R_PAREN@29..30 ")" - TopGlobal@30..50 - LINEFEED@30..31 "\n" - GLOBAL_KW@31..37 "global" - SPACE@37..38 " " - IDENT@38..39 "_" - SPACE@39..40 " " - EQUALS@40..41 "=" - SPACE@41..42 " " - ECall@42..50 - EVar@42..43 - IDENT@42..43 "f" - EArgList@43..50 - L_PAREN@43..44 "(" - ELit@44..45 - LitInt@44..45 - INT_LIT@44..45 "1" - COMMA@45..46 "," - SPACE@46..47 " " - ELit@47..48 - LitInt@47..48 - INT_LIT@47..48 "2" - COMMA@48..49 "," - R_PAREN@49..50 ")" - TopGlobal@50..72 - LINEFEED@50..51 "\n" - GLOBAL_KW@51..57 "global" - SPACE@57..58 " " - IDENT@58..59 "_" - SPACE@59..60 " " - EQUALS@60..61 "=" - SPACE@61..62 " " - ECall@62..72 - EVar@62..63 - IDENT@62..63 "f" - EArgList@63..72 - L_PAREN@63..64 "(" - ELit@64..65 - LitInt@64..65 - INT_LIT@64..65 "1" - COMMA@65..66 "," - SPACE@66..67 " " - ECall@67..71 - EVar@67..68 - IDENT@67..68 "f" - EArgList@68..71 - L_PAREN@68..69 "(" - ELit@69..70 - LitInt@69..70 - INT_LIT@69..70 "2" - R_PAREN@70..71 ")" - R_PAREN@71..72 ")" - TopGlobal@72..89 - LINEFEED@72..73 "\n" - GLOBAL_KW@73..79 "global" - SPACE@79..80 " " - IDENT@80..81 "_" - SPACE@81..82 " " - EQUALS@82..83 "=" - SPACE@83..84 " " - ECall@84..89 - EStructIdx@84..87 - EVar@84..85 - IDENT@84..85 "x" - DOT@85..86 "." - IDENT@86..87 "f" - EArgList@87..89 - L_PAREN@87..88 "(" - R_PAREN@88..89 ")" - TopGlobal@89..109 - LINEFEED@89..90 "\n" - GLOBAL_KW@90..96 "global" - SPACE@96..97 " " - IDENT@97..98 "_" - SPACE@98..99 " " - EQUALS@99..100 "=" - SPACE@100..101 " " - ECall@101..109 - EStructIdx@101..107 - EArrayIdx@101..105 - EVar@101..102 - IDENT@101..102 "x" - L_BRACKET@102..103 "[" - ELit@103..104 - LitInt@103..104 - INT_LIT@103..104 "1" - R_BRACKET@104..105 "]" - DOT@105..106 "." - IDENT@106..107 "f" - EArgList@107..109 - L_PAREN@107..108 "(" - R_PAREN@108..109 ")" - TopGlobal@109..128 - LINEFEED@109..110 "\n" - GLOBAL_KW@110..116 "global" - SPACE@116..117 " " - IDENT@117..118 "_" - SPACE@118..119 " " - EQUALS@119..120 "=" - SPACE@120..121 " " - ECall@121..128 - ECall@121..125 - EVar@121..122 - IDENT@121..122 "f" - EArgList@122..125 - L_PAREN@122..123 "(" - ELit@123..124 - LitInt@123..124 - INT_LIT@123..124 "1" - R_PAREN@124..125 ")" - EArgList@125..128 - L_PAREN@125..126 "(" - EVar@126..127 - IDENT@126..127 "x" - R_PAREN@127..128 ")" + Module@0..128 + TopGlobal@0..14 + GLOBAL_KW@0..6 "global" + SPACE@6..7 " " + IDENT@7..8 "_" + SPACE@8..9 " " + EQUALS@9..10 "=" + SPACE@10..11 " " + ECall@11..14 + EVar@11..12 + IDENT@11..12 "f" + EArgList@12..14 + L_PAREN@12..13 "(" + R_PAREN@13..14 ")" + TopGlobal@14..30 + LINEFEED@14..15 "\n" + GLOBAL_KW@15..21 "global" + SPACE@21..22 " " + IDENT@22..23 "_" + SPACE@23..24 " " + EQUALS@24..25 "=" + SPACE@25..26 " " + ECall@26..30 + EVar@26..27 + IDENT@26..27 "f" + EArgList@27..30 + L_PAREN@27..28 "(" + ELit@28..29 + LitInt@28..29 + INT_LIT@28..29 "1" + R_PAREN@29..30 ")" + TopGlobal@30..50 + LINEFEED@30..31 "\n" + GLOBAL_KW@31..37 "global" + SPACE@37..38 " " + IDENT@38..39 "_" + SPACE@39..40 " " + EQUALS@40..41 "=" + SPACE@41..42 " " + ECall@42..50 + EVar@42..43 + IDENT@42..43 "f" + EArgList@43..50 + L_PAREN@43..44 "(" + ELit@44..45 + LitInt@44..45 + INT_LIT@44..45 "1" + COMMA@45..46 "," + SPACE@46..47 " " + ELit@47..48 + LitInt@47..48 + INT_LIT@47..48 "2" + COMMA@48..49 "," + R_PAREN@49..50 ")" + TopGlobal@50..72 + LINEFEED@50..51 "\n" + GLOBAL_KW@51..57 "global" + SPACE@57..58 " " + IDENT@58..59 "_" + SPACE@59..60 " " + EQUALS@60..61 "=" + SPACE@61..62 " " + ECall@62..72 + EVar@62..63 + IDENT@62..63 "f" + EArgList@63..72 + L_PAREN@63..64 "(" + ELit@64..65 + LitInt@64..65 + INT_LIT@64..65 "1" + COMMA@65..66 "," + SPACE@66..67 " " + ECall@67..71 + EVar@67..68 + IDENT@67..68 "f" + EArgList@68..71 + L_PAREN@68..69 "(" + ELit@69..70 + LitInt@69..70 + INT_LIT@69..70 "2" + R_PAREN@70..71 ")" + R_PAREN@71..72 ")" + TopGlobal@72..89 + LINEFEED@72..73 "\n" + GLOBAL_KW@73..79 "global" + SPACE@79..80 " " + IDENT@80..81 "_" + SPACE@81..82 " " + EQUALS@82..83 "=" + SPACE@83..84 " " + ECall@84..89 + EStructIdx@84..87 + EVar@84..85 + IDENT@84..85 "x" + DOT@85..86 "." + IDENT@86..87 "f" + EArgList@87..89 + L_PAREN@87..88 "(" + R_PAREN@88..89 ")" + TopGlobal@89..109 + LINEFEED@89..90 "\n" + GLOBAL_KW@90..96 "global" + SPACE@96..97 " " + IDENT@97..98 "_" + SPACE@98..99 " " + EQUALS@99..100 "=" + SPACE@100..101 " " + ECall@101..109 + EStructIdx@101..107 + EArrayIdx@101..105 + EVar@101..102 + IDENT@101..102 "x" + L_BRACKET@102..103 "[" + ELit@103..104 + LitInt@103..104 + INT_LIT@103..104 "1" + R_BRACKET@104..105 "]" + DOT@105..106 "." + IDENT@106..107 "f" + EArgList@107..109 + L_PAREN@107..108 "(" + R_PAREN@108..109 ")" + TopGlobal@109..128 + LINEFEED@109..110 "\n" + GLOBAL_KW@110..116 "global" + SPACE@116..117 " " + IDENT@117..118 "_" + SPACE@118..119 " " + EQUALS@119..120 "=" + SPACE@120..121 " " + ECall@121..128 + ECall@121..125 + EVar@121..122 + IDENT@121..122 "f" + EArgList@122..125 + L_PAREN@122..123 "(" + ELit@123..124 + LitInt@123..124 + INT_LIT@123..124 "1" + R_PAREN@124..125 ")" + EArgList@125..128 + L_PAREN@125..126 "(" + EVar@126..127 + IDENT@126..127 "x" + R_PAREN@127..128 ")" diff --git a/crates/frontend/tests/snapshots/lib__parsing@global_annotation.nemo.snap b/crates/frontend/tests/snapshots/lib__parsing@global_annotation.nemo.snap index 420d85a4..c1d634cd 100644 --- a/crates/frontend/tests/snapshots/lib__parsing@global_annotation.nemo.snap +++ b/crates/frontend/tests/snapshots/lib__parsing@global_annotation.nemo.snap @@ -1,221 +1,222 @@ --- source: crates/frontend/tests/lib.rs -assertion_line: 132 +assertion_line: 129 expression: output input_file: crates/frontend/tests/parsing/global_annotation.nemo --- Root@0..255 - TopGlobal@0..18 - GLOBAL_KW@0..6 "global" - SPACE@6..7 " " - IDENT@7..8 "_" - SPACE@8..9 " " - COLON@9..10 ":" - SPACE@10..11 " " - TyInt@11..15 - I32_BUILTIN@11..14 "i32" - SPACE@14..15 " " - EQUALS@15..16 "=" - SPACE@16..17 " " - ELit@17..18 - LitInt@17..18 - INT_LIT@17..18 "0" - TopGlobal@18..37 - LINEFEED@18..19 "\n" - GLOBAL_KW@19..25 "global" - SPACE@25..26 " " - IDENT@26..27 "_" - SPACE@27..28 " " - COLON@28..29 ":" - SPACE@29..30 " " - TyFloat@30..34 - F32_BUILTIN@30..33 "f32" - SPACE@33..34 " " - EQUALS@34..35 "=" - SPACE@35..36 " " - ELit@36..37 - LitInt@36..37 - INT_LIT@36..37 "0" - TopGlobal@37..57 - LINEFEED@37..38 "\n" - GLOBAL_KW@38..44 "global" - SPACE@44..45 " " - IDENT@45..46 "_" - SPACE@46..47 " " - COLON@47..48 ":" - SPACE@48..49 " " - TyBool@49..54 - BOOL_BUILTIN@49..53 "bool" - SPACE@53..54 " " - EQUALS@54..55 "=" - SPACE@55..56 " " - ELit@56..57 - LitInt@56..57 - INT_LIT@56..57 "0" - TopGlobal@57..77 - LINEFEED@57..58 "\n" - GLOBAL_KW@58..64 "global" - SPACE@64..65 " " - IDENT@65..66 "_" - SPACE@66..67 " " - COLON@67..68 ":" - SPACE@68..69 " " - TyUnit@69..74 - UNIT_BUILTIN@69..73 "unit" - SPACE@73..74 " " - EQUALS@74..75 "=" - SPACE@75..76 " " - ELit@76..77 - LitInt@76..77 - INT_LIT@76..77 "0" - TopGlobal@77..99 - LINEFEED@77..78 "\n" - GLOBAL_KW@78..84 "global" - SPACE@84..85 " " - IDENT@85..86 "_" - SPACE@86..87 " " - COLON@87..88 ":" - SPACE@88..89 " " - TyCons@89..96 - UPPER_IDENT@89..95 "Struct" - SPACE@95..96 " " - EQUALS@96..97 "=" - SPACE@97..98 " " - ELit@98..99 - LitInt@98..99 - INT_LIT@98..99 "0" - TopGlobal@99..120 - LINEFEED@99..100 "\n" - GLOBAL_KW@100..106 "global" - SPACE@106..107 " " - IDENT@107..108 "_" - SPACE@108..109 " " - COLON@109..110 ":" - SPACE@110..111 " " - TyArray@111..117 - L_BRACKET@111..112 "[" - TyInt@112..115 - I32_BUILTIN@112..115 "i32" - R_BRACKET@115..116 "]" - SPACE@116..117 " " - EQUALS@117..118 "=" - SPACE@118..119 " " - ELit@119..120 - LitInt@119..120 - INT_LIT@119..120 "0" - TopGlobal@120..146 - LINEFEED@120..121 "\n" - GLOBAL_KW@121..127 "global" - SPACE@127..128 " " - IDENT@128..129 "_" - SPACE@129..130 " " - COLON@130..131 ":" - SPACE@131..132 " " - TyArray@132..143 - L_BRACKET@132..133 "[" - TyArray@133..141 - L_BRACKET@133..134 "[" - TyCons@134..140 - UPPER_IDENT@134..140 "Struct" - R_BRACKET@140..141 "]" - R_BRACKET@141..142 "]" - SPACE@142..143 " " - EQUALS@143..144 "=" - SPACE@144..145 " " - ELit@145..146 - LitInt@145..146 - INT_LIT@145..146 "0" - TopGlobal@146..174 - LINEFEED@146..147 "\n" - GLOBAL_KW@147..153 "global" - SPACE@153..154 " " - IDENT@154..155 "_" - SPACE@155..156 " " - COLON@156..157 ":" - SPACE@157..158 " " - TyFn@158..171 - FN_KW@158..160 "fn" - TyArgList@160..163 - L_PAREN@160..161 "(" - R_PAREN@161..162 ")" - SPACE@162..163 " " - ARROW@163..165 "->" - SPACE@165..166 " " - TyUnit@166..171 - UNIT_BUILTIN@166..170 "unit" - SPACE@170..171 " " - EQUALS@171..172 "=" - SPACE@172..173 " " - ELit@173..174 - LitInt@173..174 - INT_LIT@173..174 "0" - TopGlobal@174..204 - LINEFEED@174..175 "\n" - GLOBAL_KW@175..181 "global" - SPACE@181..182 " " - IDENT@182..183 "_" - SPACE@183..184 " " - COLON@184..185 ":" - SPACE@185..186 " " - TyFn@186..201 - FN_KW@186..188 "fn" - TyArgList@188..194 - L_PAREN@188..189 "(" - TyInt@189..192 - I32_BUILTIN@189..192 "i32" - R_PAREN@192..193 ")" - SPACE@193..194 " " - ARROW@194..196 "->" - SPACE@196..197 " " - TyFloat@197..201 - F32_BUILTIN@197..200 "f32" - SPACE@200..201 " " - EQUALS@201..202 "=" - SPACE@202..203 " " - ELit@203..204 - LitInt@203..204 - INT_LIT@203..204 "0" - TopGlobal@204..255 - LINEFEED@204..205 "\n" - GLOBAL_KW@205..211 "global" - SPACE@211..212 " " - IDENT@212..213 "_" - SPACE@213..214 " " - COLON@214..215 ":" - SPACE@215..216 " " - TyFn@216..252 - FN_KW@216..218 "fn" - TyArgList@218..245 - L_PAREN@218..219 "(" - TyInt@219..222 - I32_BUILTIN@219..222 "i32" - COMMA@222..223 "," - SPACE@223..224 " " - TyFloat@224..227 - F32_BUILTIN@224..227 "f32" - COMMA@227..228 "," - SPACE@228..229 " " - TyFn@229..243 - FN_KW@229..231 "fn" - TyArgList@231..237 - L_PAREN@231..232 "(" - TyInt@232..235 - I32_BUILTIN@232..235 "i32" - R_PAREN@235..236 ")" - SPACE@236..237 " " - ARROW@237..239 "->" - SPACE@239..240 " " - TyInt@240..243 - I32_BUILTIN@240..243 "i32" - R_PAREN@243..244 ")" - SPACE@244..245 " " - ARROW@245..247 "->" - SPACE@247..248 " " - TyFloat@248..252 - F32_BUILTIN@248..251 "f32" - SPACE@251..252 " " - EQUALS@252..253 "=" - SPACE@253..254 " " - ELit@254..255 - LitInt@254..255 - INT_LIT@254..255 "0" + Module@0..255 + TopGlobal@0..18 + GLOBAL_KW@0..6 "global" + SPACE@6..7 " " + IDENT@7..8 "_" + SPACE@8..9 " " + COLON@9..10 ":" + SPACE@10..11 " " + TyInt@11..15 + I32_BUILTIN@11..14 "i32" + SPACE@14..15 " " + EQUALS@15..16 "=" + SPACE@16..17 " " + ELit@17..18 + LitInt@17..18 + INT_LIT@17..18 "0" + TopGlobal@18..37 + LINEFEED@18..19 "\n" + GLOBAL_KW@19..25 "global" + SPACE@25..26 " " + IDENT@26..27 "_" + SPACE@27..28 " " + COLON@28..29 ":" + SPACE@29..30 " " + TyFloat@30..34 + F32_BUILTIN@30..33 "f32" + SPACE@33..34 " " + EQUALS@34..35 "=" + SPACE@35..36 " " + ELit@36..37 + LitInt@36..37 + INT_LIT@36..37 "0" + TopGlobal@37..57 + LINEFEED@37..38 "\n" + GLOBAL_KW@38..44 "global" + SPACE@44..45 " " + IDENT@45..46 "_" + SPACE@46..47 " " + COLON@47..48 ":" + SPACE@48..49 " " + TyBool@49..54 + BOOL_BUILTIN@49..53 "bool" + SPACE@53..54 " " + EQUALS@54..55 "=" + SPACE@55..56 " " + ELit@56..57 + LitInt@56..57 + INT_LIT@56..57 "0" + TopGlobal@57..77 + LINEFEED@57..58 "\n" + GLOBAL_KW@58..64 "global" + SPACE@64..65 " " + IDENT@65..66 "_" + SPACE@66..67 " " + COLON@67..68 ":" + SPACE@68..69 " " + TyUnit@69..74 + UNIT_BUILTIN@69..73 "unit" + SPACE@73..74 " " + EQUALS@74..75 "=" + SPACE@75..76 " " + ELit@76..77 + LitInt@76..77 + INT_LIT@76..77 "0" + TopGlobal@77..99 + LINEFEED@77..78 "\n" + GLOBAL_KW@78..84 "global" + SPACE@84..85 " " + IDENT@85..86 "_" + SPACE@86..87 " " + COLON@87..88 ":" + SPACE@88..89 " " + TyCons@89..96 + UPPER_IDENT@89..95 "Struct" + SPACE@95..96 " " + EQUALS@96..97 "=" + SPACE@97..98 " " + ELit@98..99 + LitInt@98..99 + INT_LIT@98..99 "0" + TopGlobal@99..120 + LINEFEED@99..100 "\n" + GLOBAL_KW@100..106 "global" + SPACE@106..107 " " + IDENT@107..108 "_" + SPACE@108..109 " " + COLON@109..110 ":" + SPACE@110..111 " " + TyArray@111..117 + L_BRACKET@111..112 "[" + TyInt@112..115 + I32_BUILTIN@112..115 "i32" + R_BRACKET@115..116 "]" + SPACE@116..117 " " + EQUALS@117..118 "=" + SPACE@118..119 " " + ELit@119..120 + LitInt@119..120 + INT_LIT@119..120 "0" + TopGlobal@120..146 + LINEFEED@120..121 "\n" + GLOBAL_KW@121..127 "global" + SPACE@127..128 " " + IDENT@128..129 "_" + SPACE@129..130 " " + COLON@130..131 ":" + SPACE@131..132 " " + TyArray@132..143 + L_BRACKET@132..133 "[" + TyArray@133..141 + L_BRACKET@133..134 "[" + TyCons@134..140 + UPPER_IDENT@134..140 "Struct" + R_BRACKET@140..141 "]" + R_BRACKET@141..142 "]" + SPACE@142..143 " " + EQUALS@143..144 "=" + SPACE@144..145 " " + ELit@145..146 + LitInt@145..146 + INT_LIT@145..146 "0" + TopGlobal@146..174 + LINEFEED@146..147 "\n" + GLOBAL_KW@147..153 "global" + SPACE@153..154 " " + IDENT@154..155 "_" + SPACE@155..156 " " + COLON@156..157 ":" + SPACE@157..158 " " + TyFn@158..171 + FN_KW@158..160 "fn" + TyArgList@160..163 + L_PAREN@160..161 "(" + R_PAREN@161..162 ")" + SPACE@162..163 " " + ARROW@163..165 "->" + SPACE@165..166 " " + TyUnit@166..171 + UNIT_BUILTIN@166..170 "unit" + SPACE@170..171 " " + EQUALS@171..172 "=" + SPACE@172..173 " " + ELit@173..174 + LitInt@173..174 + INT_LIT@173..174 "0" + TopGlobal@174..204 + LINEFEED@174..175 "\n" + GLOBAL_KW@175..181 "global" + SPACE@181..182 " " + IDENT@182..183 "_" + SPACE@183..184 " " + COLON@184..185 ":" + SPACE@185..186 " " + TyFn@186..201 + FN_KW@186..188 "fn" + TyArgList@188..194 + L_PAREN@188..189 "(" + TyInt@189..192 + I32_BUILTIN@189..192 "i32" + R_PAREN@192..193 ")" + SPACE@193..194 " " + ARROW@194..196 "->" + SPACE@196..197 " " + TyFloat@197..201 + F32_BUILTIN@197..200 "f32" + SPACE@200..201 " " + EQUALS@201..202 "=" + SPACE@202..203 " " + ELit@203..204 + LitInt@203..204 + INT_LIT@203..204 "0" + TopGlobal@204..255 + LINEFEED@204..205 "\n" + GLOBAL_KW@205..211 "global" + SPACE@211..212 " " + IDENT@212..213 "_" + SPACE@213..214 " " + COLON@214..215 ":" + SPACE@215..216 " " + TyFn@216..252 + FN_KW@216..218 "fn" + TyArgList@218..245 + L_PAREN@218..219 "(" + TyInt@219..222 + I32_BUILTIN@219..222 "i32" + COMMA@222..223 "," + SPACE@223..224 " " + TyFloat@224..227 + F32_BUILTIN@224..227 "f32" + COMMA@227..228 "," + SPACE@228..229 " " + TyFn@229..243 + FN_KW@229..231 "fn" + TyArgList@231..237 + L_PAREN@231..232 "(" + TyInt@232..235 + I32_BUILTIN@232..235 "i32" + R_PAREN@235..236 ")" + SPACE@236..237 " " + ARROW@237..239 "->" + SPACE@239..240 " " + TyInt@240..243 + I32_BUILTIN@240..243 "i32" + R_PAREN@243..244 ")" + SPACE@244..245 " " + ARROW@245..247 "->" + SPACE@247..248 " " + TyFloat@248..252 + F32_BUILTIN@248..251 "f32" + SPACE@251..252 " " + EQUALS@252..253 "=" + SPACE@253..254 " " + ELit@254..255 + LitInt@254..255 + INT_LIT@254..255 "0" diff --git a/crates/frontend/tests/snapshots/lib__parsing@if.nemo.snap b/crates/frontend/tests/snapshots/lib__parsing@if.nemo.snap index 395c8e80..8d0fb0cc 100644 --- a/crates/frontend/tests/snapshots/lib__parsing@if.nemo.snap +++ b/crates/frontend/tests/snapshots/lib__parsing@if.nemo.snap @@ -1,42 +1,43 @@ --- source: crates/frontend/tests/lib.rs -assertion_line: 132 +assertion_line: 129 expression: output input_file: crates/frontend/tests/parsing/if.nemo --- Root@0..35 - TopGlobal@0..35 - GLOBAL_KW@0..6 "global" - SPACE@6..7 " " - IDENT@7..8 "_" - SPACE@8..9 " " - EQUALS@9..10 "=" - SPACE@10..11 " " - EIf@11..35 - IF_KW@11..13 "if" - SPACE@13..14 " " - ELit@14..19 - LitBool@14..19 - TRUE_KW@14..18 "true" - SPACE@18..19 " " - EBlock@19..25 - L_BRACE@19..20 "{" - SPACE@20..21 " " - DExpr@21..23 - ELit@21..23 - LitInt@21..23 - INT_LIT@21..22 "1" - SPACE@22..23 " " - R_BRACE@23..24 "}" - SPACE@24..25 " " - ELSE_KW@25..29 "else" - SPACE@29..30 " " - EBlock@30..35 - L_BRACE@30..31 "{" - SPACE@31..32 " " - DExpr@32..34 - ELit@32..34 - LitInt@32..34 - INT_LIT@32..33 "3" - SPACE@33..34 " " - R_BRACE@34..35 "}" + Module@0..35 + TopGlobal@0..35 + GLOBAL_KW@0..6 "global" + SPACE@6..7 " " + IDENT@7..8 "_" + SPACE@8..9 " " + EQUALS@9..10 "=" + SPACE@10..11 " " + EIf@11..35 + IF_KW@11..13 "if" + SPACE@13..14 " " + ELit@14..19 + LitBool@14..19 + TRUE_KW@14..18 "true" + SPACE@18..19 " " + EBlock@19..25 + L_BRACE@19..20 "{" + SPACE@20..21 " " + DExpr@21..23 + ELit@21..23 + LitInt@21..23 + INT_LIT@21..22 "1" + SPACE@22..23 " " + R_BRACE@23..24 "}" + SPACE@24..25 " " + ELSE_KW@25..29 "else" + SPACE@29..30 " " + EBlock@30..35 + L_BRACE@30..31 "{" + SPACE@31..32 " " + DExpr@32..34 + ELit@32..34 + LitInt@32..34 + INT_LIT@32..33 "3" + SPACE@33..34 " " + R_BRACE@34..35 "}" diff --git a/crates/frontend/tests/snapshots/lib__parsing@infix_op.nemo.snap b/crates/frontend/tests/snapshots/lib__parsing@infix_op.nemo.snap index de84f93f..6062ba91 100644 --- a/crates/frontend/tests/snapshots/lib__parsing@infix_op.nemo.snap +++ b/crates/frontend/tests/snapshots/lib__parsing@infix_op.nemo.snap @@ -1,255 +1,256 @@ --- source: crates/frontend/tests/lib.rs -assertion_line: 134 +assertion_line: 129 expression: output input_file: crates/frontend/tests/parsing/infix_op.nemo --- Root@0..211 - TopGlobal@0..16 - GLOBAL_KW@0..6 "global" - SPACE@6..7 " " - IDENT@7..8 "_" - SPACE@8..9 " " - EQUALS@9..10 "=" - SPACE@10..11 " " - EBinary@11..16 - ELit@11..13 - LitInt@11..13 - INT_LIT@11..12 "1" - SPACE@12..13 " " - BinOp@13..15 - PLUS@13..14 "+" - SPACE@14..15 " " - ELit@15..16 - LitInt@15..16 - INT_LIT@15..16 "1" - TopGlobal@16..37 - LINEFEED@16..17 "\n" - GLOBAL_KW@17..23 "global" - SPACE@23..24 " " - IDENT@24..25 "_" - SPACE@25..26 " " - EQUALS@26..27 "=" - SPACE@27..28 " " - EBinary@28..37 - ELit@28..30 - LitInt@28..30 - INT_LIT@28..29 "1" - SPACE@29..30 " " - BinOp@30..32 - PLUS@30..31 "+" - SPACE@31..32 " " - EBinary@32..37 - ELit@32..34 - LitInt@32..34 - INT_LIT@32..33 "1" - SPACE@33..34 " " - BinOp@34..36 - PLUS@34..35 "+" - SPACE@35..36 " " - ELit@36..37 - LitInt@36..37 - INT_LIT@36..37 "1" - TopGlobal@37..58 - LINEFEED@37..38 "\n" - GLOBAL_KW@38..44 "global" - SPACE@44..45 " " - IDENT@45..46 "_" - SPACE@46..47 " " - EQUALS@47..48 "=" - SPACE@48..49 " " - EBinary@49..58 - EBinary@49..55 - ELit@49..51 - LitInt@49..51 - INT_LIT@49..50 "1" - SPACE@50..51 " " - BinOp@51..53 - STAR@51..52 "*" - SPACE@52..53 " " - ELit@53..55 - LitInt@53..55 - INT_LIT@53..54 "1" - SPACE@54..55 " " - BinOp@55..57 - PLUS@55..56 "+" - SPACE@56..57 " " - ELit@57..58 - LitInt@57..58 - INT_LIT@57..58 "1" - TopGlobal@58..79 - LINEFEED@58..59 "\n" - GLOBAL_KW@59..65 "global" - SPACE@65..66 " " - IDENT@66..67 "_" - SPACE@67..68 " " - EQUALS@68..69 "=" - SPACE@69..70 " " - EBinary@70..79 - ELit@70..72 - LitInt@70..72 - INT_LIT@70..71 "1" - SPACE@71..72 " " - BinOp@72..74 - PLUS@72..73 "+" - SPACE@73..74 " " - EBinary@74..79 - ELit@74..76 - LitInt@74..76 - INT_LIT@74..75 "1" - SPACE@75..76 " " - BinOp@76..78 - STAR@76..77 "*" - SPACE@77..78 " " - ELit@78..79 - LitInt@78..79 - INT_LIT@78..79 "1" - TopGlobal@79..145 - LINEFEED@79..80 "\n" - GLOBAL_KW@80..86 "global" - SPACE@86..87 " " - IDENT@87..88 "_" - SPACE@88..89 " " - EQUALS@89..90 "=" - SPACE@90..91 " " - EBinary@91..145 - EBinary@91..98 - ELit@91..93 - LitInt@91..93 - INT_LIT@91..92 "1" - SPACE@92..93 " " - BinOp@93..96 - L_ANGLE_EQ@93..95 "<=" - SPACE@95..96 " " - ELit@96..98 - LitInt@96..98 - INT_LIT@96..97 "2" - SPACE@97..98 " " - BinOp@98..101 - ANDAND@98..100 "&&" - SPACE@100..101 " " - EBinary@101..145 - EBinary@101..117 - EBinary@101..107 - ELit@101..103 - LitInt@101..103 - INT_LIT@101..102 "1" - SPACE@102..103 " " - BinOp@103..105 - L_ANGLE@103..104 "<" - SPACE@104..105 " " - ELit@105..107 - LitInt@105..107 - INT_LIT@105..106 "1" - SPACE@106..107 " " - BinOp@107..110 - OROR@107..109 "||" - SPACE@109..110 " " - EBinary@110..117 - ELit@110..112 - LitInt@110..112 - INT_LIT@110..111 "1" - SPACE@111..112 " " - BinOp@112..115 - R_ANGLE_EQ@112..114 ">=" - SPACE@114..115 " " - ELit@115..117 - LitInt@115..117 - INT_LIT@115..116 "3" - SPACE@116..117 " " - BinOp@117..120 - ANDAND@117..119 "&&" - SPACE@119..120 " " - EBinary@120..145 - EBinary@120..126 - ELit@120..122 - LitInt@120..122 - INT_LIT@120..121 "3" - SPACE@121..122 " " - BinOp@122..124 - R_ANGLE@122..123 ">" - SPACE@123..124 " " - ELit@124..126 - LitInt@124..126 - INT_LIT@124..125 "4" - SPACE@125..126 " " - BinOp@126..129 - OROR@126..128 "||" - SPACE@128..129 " " - EBinary@129..145 - EBinary@129..136 - ELit@129..131 - LitInt@129..131 - INT_LIT@129..130 "1" - SPACE@130..131 " " - BinOp@131..134 - DOUBLE_EQUALS@131..133 "==" - SPACE@133..134 " " - ELit@134..136 - LitInt@134..136 - INT_LIT@134..135 "1" - SPACE@135..136 " " - BinOp@136..139 - OROR@136..138 "||" - SPACE@138..139 " " - EBinary@139..145 - ELit@139..141 - LitInt@139..141 - INT_LIT@139..140 "1" - SPACE@140..141 " " - BinOp@141..144 - NOT_EQUALS@141..143 "!=" - SPACE@143..144 " " - ELit@144..145 - LitInt@144..145 - INT_LIT@144..145 "2" - TopGlobal@145..164 - LINEFEED@145..146 "\n" - GLOBAL_KW@146..152 "global" - SPACE@152..153 " " - IDENT@153..154 "_" - SPACE@154..155 " " - EQUALS@155..156 "=" - SPACE@156..157 " " - EBinary@157..164 - ELit@157..159 - LitInt@157..159 - INT_LIT@157..158 "1" - SPACE@158..159 " " - BinOp@159..161 - PLUS@159..160 "+" - SPACE@160..161 " " - EStructIdx@161..164 - EVar@161..162 - IDENT@161..162 "x" - DOT@162..163 "." - IDENT@163..164 "y" - TopGlobal@164..211 - LINEFEED@164..165 "\n" - GLOBAL_KW@165..171 "global" - SPACE@171..172 " " - IDENT@172..173 "_" - SPACE@173..174 " " - EQUALS@174..175 "=" - SPACE@175..176 " " - EBinary@176..211 - ECall@176..193 - EVar@176..183 - IDENT@176..183 "f32_abs" - EArgList@183..193 - L_PAREN@183..184 "(" - EVar@184..191 - IDENT@184..191 "delta_x" - R_PAREN@191..192 ")" - SPACE@192..193 " " - BinOp@193..195 - R_ANGLE@193..194 ">" - SPACE@194..195 " " - ECall@195..211 - EVar@195..202 - IDENT@195..202 "f32_abs" - EArgList@202..211 - L_PAREN@202..203 "(" - EVar@203..210 - IDENT@203..210 "delta_y" - R_PAREN@210..211 ")" + Module@0..211 + TopGlobal@0..16 + GLOBAL_KW@0..6 "global" + SPACE@6..7 " " + IDENT@7..8 "_" + SPACE@8..9 " " + EQUALS@9..10 "=" + SPACE@10..11 " " + EBinary@11..16 + ELit@11..13 + LitInt@11..13 + INT_LIT@11..12 "1" + SPACE@12..13 " " + BinOp@13..15 + PLUS@13..14 "+" + SPACE@14..15 " " + ELit@15..16 + LitInt@15..16 + INT_LIT@15..16 "1" + TopGlobal@16..37 + LINEFEED@16..17 "\n" + GLOBAL_KW@17..23 "global" + SPACE@23..24 " " + IDENT@24..25 "_" + SPACE@25..26 " " + EQUALS@26..27 "=" + SPACE@27..28 " " + EBinary@28..37 + ELit@28..30 + LitInt@28..30 + INT_LIT@28..29 "1" + SPACE@29..30 " " + BinOp@30..32 + PLUS@30..31 "+" + SPACE@31..32 " " + EBinary@32..37 + ELit@32..34 + LitInt@32..34 + INT_LIT@32..33 "1" + SPACE@33..34 " " + BinOp@34..36 + PLUS@34..35 "+" + SPACE@35..36 " " + ELit@36..37 + LitInt@36..37 + INT_LIT@36..37 "1" + TopGlobal@37..58 + LINEFEED@37..38 "\n" + GLOBAL_KW@38..44 "global" + SPACE@44..45 " " + IDENT@45..46 "_" + SPACE@46..47 " " + EQUALS@47..48 "=" + SPACE@48..49 " " + EBinary@49..58 + EBinary@49..55 + ELit@49..51 + LitInt@49..51 + INT_LIT@49..50 "1" + SPACE@50..51 " " + BinOp@51..53 + STAR@51..52 "*" + SPACE@52..53 " " + ELit@53..55 + LitInt@53..55 + INT_LIT@53..54 "1" + SPACE@54..55 " " + BinOp@55..57 + PLUS@55..56 "+" + SPACE@56..57 " " + ELit@57..58 + LitInt@57..58 + INT_LIT@57..58 "1" + TopGlobal@58..79 + LINEFEED@58..59 "\n" + GLOBAL_KW@59..65 "global" + SPACE@65..66 " " + IDENT@66..67 "_" + SPACE@67..68 " " + EQUALS@68..69 "=" + SPACE@69..70 " " + EBinary@70..79 + ELit@70..72 + LitInt@70..72 + INT_LIT@70..71 "1" + SPACE@71..72 " " + BinOp@72..74 + PLUS@72..73 "+" + SPACE@73..74 " " + EBinary@74..79 + ELit@74..76 + LitInt@74..76 + INT_LIT@74..75 "1" + SPACE@75..76 " " + BinOp@76..78 + STAR@76..77 "*" + SPACE@77..78 " " + ELit@78..79 + LitInt@78..79 + INT_LIT@78..79 "1" + TopGlobal@79..145 + LINEFEED@79..80 "\n" + GLOBAL_KW@80..86 "global" + SPACE@86..87 " " + IDENT@87..88 "_" + SPACE@88..89 " " + EQUALS@89..90 "=" + SPACE@90..91 " " + EBinary@91..145 + EBinary@91..98 + ELit@91..93 + LitInt@91..93 + INT_LIT@91..92 "1" + SPACE@92..93 " " + BinOp@93..96 + L_ANGLE_EQ@93..95 "<=" + SPACE@95..96 " " + ELit@96..98 + LitInt@96..98 + INT_LIT@96..97 "2" + SPACE@97..98 " " + BinOp@98..101 + ANDAND@98..100 "&&" + SPACE@100..101 " " + EBinary@101..145 + EBinary@101..117 + EBinary@101..107 + ELit@101..103 + LitInt@101..103 + INT_LIT@101..102 "1" + SPACE@102..103 " " + BinOp@103..105 + L_ANGLE@103..104 "<" + SPACE@104..105 " " + ELit@105..107 + LitInt@105..107 + INT_LIT@105..106 "1" + SPACE@106..107 " " + BinOp@107..110 + OROR@107..109 "||" + SPACE@109..110 " " + EBinary@110..117 + ELit@110..112 + LitInt@110..112 + INT_LIT@110..111 "1" + SPACE@111..112 " " + BinOp@112..115 + R_ANGLE_EQ@112..114 ">=" + SPACE@114..115 " " + ELit@115..117 + LitInt@115..117 + INT_LIT@115..116 "3" + SPACE@116..117 " " + BinOp@117..120 + ANDAND@117..119 "&&" + SPACE@119..120 " " + EBinary@120..145 + EBinary@120..126 + ELit@120..122 + LitInt@120..122 + INT_LIT@120..121 "3" + SPACE@121..122 " " + BinOp@122..124 + R_ANGLE@122..123 ">" + SPACE@123..124 " " + ELit@124..126 + LitInt@124..126 + INT_LIT@124..125 "4" + SPACE@125..126 " " + BinOp@126..129 + OROR@126..128 "||" + SPACE@128..129 " " + EBinary@129..145 + EBinary@129..136 + ELit@129..131 + LitInt@129..131 + INT_LIT@129..130 "1" + SPACE@130..131 " " + BinOp@131..134 + DOUBLE_EQUALS@131..133 "==" + SPACE@133..134 " " + ELit@134..136 + LitInt@134..136 + INT_LIT@134..135 "1" + SPACE@135..136 " " + BinOp@136..139 + OROR@136..138 "||" + SPACE@138..139 " " + EBinary@139..145 + ELit@139..141 + LitInt@139..141 + INT_LIT@139..140 "1" + SPACE@140..141 " " + BinOp@141..144 + NOT_EQUALS@141..143 "!=" + SPACE@143..144 " " + ELit@144..145 + LitInt@144..145 + INT_LIT@144..145 "2" + TopGlobal@145..164 + LINEFEED@145..146 "\n" + GLOBAL_KW@146..152 "global" + SPACE@152..153 " " + IDENT@153..154 "_" + SPACE@154..155 " " + EQUALS@155..156 "=" + SPACE@156..157 " " + EBinary@157..164 + ELit@157..159 + LitInt@157..159 + INT_LIT@157..158 "1" + SPACE@158..159 " " + BinOp@159..161 + PLUS@159..160 "+" + SPACE@160..161 " " + EStructIdx@161..164 + EVar@161..162 + IDENT@161..162 "x" + DOT@162..163 "." + IDENT@163..164 "y" + TopGlobal@164..211 + LINEFEED@164..165 "\n" + GLOBAL_KW@165..171 "global" + SPACE@171..172 " " + IDENT@172..173 "_" + SPACE@173..174 " " + EQUALS@174..175 "=" + SPACE@175..176 " " + EBinary@176..211 + ECall@176..193 + EVar@176..183 + IDENT@176..183 "f32_abs" + EArgList@183..193 + L_PAREN@183..184 "(" + EVar@184..191 + IDENT@184..191 "delta_x" + R_PAREN@191..192 ")" + SPACE@192..193 " " + BinOp@193..195 + R_ANGLE@193..194 ">" + SPACE@194..195 " " + ECall@195..211 + EVar@195..202 + IDENT@195..202 "f32_abs" + EArgList@202..211 + L_PAREN@202..203 "(" + EVar@203..210 + IDENT@203..210 "delta_y" + R_PAREN@210..211 ")" diff --git a/crates/frontend/tests/snapshots/lib__parsing@literals.nemo.snap b/crates/frontend/tests/snapshots/lib__parsing@literals.nemo.snap index 93969500..f9daa264 100644 --- a/crates/frontend/tests/snapshots/lib__parsing@literals.nemo.snap +++ b/crates/frontend/tests/snapshots/lib__parsing@literals.nemo.snap @@ -1,116 +1,117 @@ --- source: crates/frontend/tests/lib.rs -assertion_line: 132 +assertion_line: 129 expression: output input_file: crates/frontend/tests/parsing/literals.nemo --- Root@0..180 - TopGlobal@0..12 - GLOBAL_KW@0..6 "global" - SPACE@6..7 " " - IDENT@7..8 "_" - SPACE@8..9 " " - EQUALS@9..10 "=" - SPACE@10..11 " " - ELit@11..12 - LitInt@11..12 - INT_LIT@11..12 "0" - TopGlobal@12..28 - LINEFEED@12..13 "\n" - GLOBAL_KW@13..19 "global" - SPACE@19..20 " " - IDENT@20..21 "_" - SPACE@21..22 " " - EQUALS@22..23 "=" - SPACE@23..24 " " - ELit@24..28 - LitInt@24..28 - INT_LIT@24..28 "4242" - TopGlobal@28..50 - LINEFEED@28..29 "\n" - GLOBAL_KW@29..35 "global" - SPACE@35..36 " " - IDENT@36..37 "_" - SPACE@37..38 " " - EQUALS@38..39 "=" - SPACE@39..40 " " - ELit@40..50 - LitInt@40..50 - BINARY_LIT@40..50 "0b01010101" - TopGlobal@50..71 - LINEFEED@50..51 "\n" - GLOBAL_KW@51..57 "global" - SPACE@57..58 " " - IDENT@58..59 "_" - SPACE@59..60 " " - EQUALS@60..61 "=" - SPACE@61..62 " " - ELit@62..71 - LitInt@62..71 - HEX_LIT@62..71 "0xDeAdBeE" - TopGlobal@71..93 - LINEFEED@71..72 "\n" - GLOBAL_KW@72..78 "global" - SPACE@78..79 " " - IDENT@79..80 "_" - SPACE@80..81 " " - EQUALS@81..82 "=" - SPACE@82..83 " " - ELit@83..93 - LitInt@83..93 - HEX_LIT@83..93 "0x1aAbB2cC" - TopGlobal@93..109 - LINEFEED@93..94 "\n" - GLOBAL_KW@94..100 "global" - SPACE@100..101 " " - IDENT@101..102 "_" - SPACE@102..103 " " - EQUALS@103..104 "=" - SPACE@104..105 " " - ELit@105..109 - LitBool@105..109 - TRUE_KW@105..109 "true" - TopGlobal@109..126 - LINEFEED@109..110 "\n" - GLOBAL_KW@110..116 "global" - SPACE@116..117 " " - IDENT@117..118 "_" - SPACE@118..119 " " - EQUALS@119..120 "=" - SPACE@120..121 " " - ELit@121..126 - LitBool@121..126 - FALSE_KW@121..126 "false" - TopGlobal@126..141 - LINEFEED@126..127 "\n" - GLOBAL_KW@127..133 "global" - SPACE@133..134 " " - IDENT@134..135 "_" - SPACE@135..136 " " - EQUALS@136..137 "=" - SPACE@137..138 " " - ELit@138..141 - LitFloat@138..141 - FLOAT_LIT@138..141 "0.0" - TopGlobal@141..159 - LINEFEED@141..142 "\n" - GLOBAL_KW@142..148 "global" - SPACE@148..149 " " - IDENT@149..150 "_" - SPACE@150..151 " " - EQUALS@151..152 "=" - SPACE@152..153 " " - ELit@153..159 - LitFloat@153..159 - FLOAT_LIT@153..159 "0.1234" - TopGlobal@159..180 - LINEFEED@159..160 "\n" - GLOBAL_KW@160..166 "global" - SPACE@166..167 " " - IDENT@167..168 "_" - SPACE@168..169 " " - EQUALS@169..170 "=" - SPACE@170..171 " " - ELit@171..180 - LitFloat@171..180 - FLOAT_LIT@171..180 "1234.1234" + Module@0..180 + TopGlobal@0..12 + GLOBAL_KW@0..6 "global" + SPACE@6..7 " " + IDENT@7..8 "_" + SPACE@8..9 " " + EQUALS@9..10 "=" + SPACE@10..11 " " + ELit@11..12 + LitInt@11..12 + INT_LIT@11..12 "0" + TopGlobal@12..28 + LINEFEED@12..13 "\n" + GLOBAL_KW@13..19 "global" + SPACE@19..20 " " + IDENT@20..21 "_" + SPACE@21..22 " " + EQUALS@22..23 "=" + SPACE@23..24 " " + ELit@24..28 + LitInt@24..28 + INT_LIT@24..28 "4242" + TopGlobal@28..50 + LINEFEED@28..29 "\n" + GLOBAL_KW@29..35 "global" + SPACE@35..36 " " + IDENT@36..37 "_" + SPACE@37..38 " " + EQUALS@38..39 "=" + SPACE@39..40 " " + ELit@40..50 + LitInt@40..50 + BINARY_LIT@40..50 "0b01010101" + TopGlobal@50..71 + LINEFEED@50..51 "\n" + GLOBAL_KW@51..57 "global" + SPACE@57..58 " " + IDENT@58..59 "_" + SPACE@59..60 " " + EQUALS@60..61 "=" + SPACE@61..62 " " + ELit@62..71 + LitInt@62..71 + HEX_LIT@62..71 "0xDeAdBeE" + TopGlobal@71..93 + LINEFEED@71..72 "\n" + GLOBAL_KW@72..78 "global" + SPACE@78..79 " " + IDENT@79..80 "_" + SPACE@80..81 " " + EQUALS@81..82 "=" + SPACE@82..83 " " + ELit@83..93 + LitInt@83..93 + HEX_LIT@83..93 "0x1aAbB2cC" + TopGlobal@93..109 + LINEFEED@93..94 "\n" + GLOBAL_KW@94..100 "global" + SPACE@100..101 " " + IDENT@101..102 "_" + SPACE@102..103 " " + EQUALS@103..104 "=" + SPACE@104..105 " " + ELit@105..109 + LitBool@105..109 + TRUE_KW@105..109 "true" + TopGlobal@109..126 + LINEFEED@109..110 "\n" + GLOBAL_KW@110..116 "global" + SPACE@116..117 " " + IDENT@117..118 "_" + SPACE@118..119 " " + EQUALS@119..120 "=" + SPACE@120..121 " " + ELit@121..126 + LitBool@121..126 + FALSE_KW@121..126 "false" + TopGlobal@126..141 + LINEFEED@126..127 "\n" + GLOBAL_KW@127..133 "global" + SPACE@133..134 " " + IDENT@134..135 "_" + SPACE@135..136 " " + EQUALS@136..137 "=" + SPACE@137..138 " " + ELit@138..141 + LitFloat@138..141 + FLOAT_LIT@138..141 "0.0" + TopGlobal@141..159 + LINEFEED@141..142 "\n" + GLOBAL_KW@142..148 "global" + SPACE@148..149 " " + IDENT@149..150 "_" + SPACE@150..151 " " + EQUALS@151..152 "=" + SPACE@152..153 " " + ELit@153..159 + LitFloat@153..159 + FLOAT_LIT@153..159 "0.1234" + TopGlobal@159..180 + LINEFEED@159..160 "\n" + GLOBAL_KW@160..166 "global" + SPACE@166..167 " " + IDENT@167..168 "_" + SPACE@168..169 " " + EQUALS@169..170 "=" + SPACE@170..171 " " + ELit@171..180 + LitFloat@171..180 + FLOAT_LIT@171..180 "1234.1234" diff --git a/crates/frontend/tests/snapshots/lib__parsing@modules.nemo.snap b/crates/frontend/tests/snapshots/lib__parsing@modules.nemo.snap new file mode 100644 index 00000000..30c26e98 --- /dev/null +++ b/crates/frontend/tests/snapshots/lib__parsing@modules.nemo.snap @@ -0,0 +1,183 @@ +--- +source: crates/frontend/tests/lib.rs +expression: output +input_file: crates/frontend/tests/parsing/modules.nemo +--- +Root@0..290 + Module@0..290 + ModHeader@0..68 + MODULE_KW@0..6 "module" + SPACE@6..7 " " + IDENT@7..10 "str" + LINEFEED@10..11 "\n" + EXPORTS_KW@11..18 "exports" + SPACE@18..19 " " + L_PAREN@19..20 "(" + ModExportTy@20..23 + UPPER_IDENT@20..23 "Str" + COMMA@23..24 "," + SPACE@24..25 " " + ModExportVal@25..28 + IDENT@25..28 "len" + COMMA@28..29 "," + SPACE@29..30 " " + ModExportVal@30..40 + IDENT@30..40 "print_char" + R_PAREN@40..41 ")" + ModUse@41..53 + LINEFEED@41..42 "\n" + LINEFEED@42..43 "\n" + USE_KW@43..46 "use" + SPACE@46..47 " " + IDENT@47..53 "option" + ModUse@53..68 + LINEFEED@53..54 "\n" + USE_KW@54..57 "use" + SPACE@57..58 " " + IDENT@58..68 "prim_bytes" + TopImport@68..122 + LINEFEED@68..69 "\n" + LINEFEED@69..70 "\n" + IMPORT_KW@70..76 "import" + SPACE@76..77 " " + ImpInternal@77..88 + IDENT@77..87 "print_char" + SPACE@87..88 " " + COLON@88..89 ":" + SPACE@89..90 " " + TyFn@90..107 + FN_KW@90..92 "fn" + SPACE@92..93 " " + TyArgList@93..99 + L_PAREN@93..94 "(" + TyInt@94..97 + I32_BUILTIN@94..97 "i32" + R_PAREN@97..98 ")" + SPACE@98..99 " " + ARROW@99..101 "->" + SPACE@101..102 " " + TyUnit@102..107 + UNIT_BUILTIN@102..106 "unit" + SPACE@106..107 " " + FROM_KW@107..111 "from" + SPACE@111..112 " " + ImpExternal@112..122 + IDENT@112..122 "print_char" + TopGlobal@122..173 + LINEFEED@122..123 "\n" + LINEFEED@123..124 "\n" + GLOBAL_KW@124..130 "global" + SPACE@130..131 " " + IDENT@131..132 "s" + SPACE@132..133 " " + COLON@133..134 ":" + SPACE@134..135 " " + TyCons@135..155 + ModQualifier@135..143 + IDENT@135..141 "option" + DOUBLE_COLON@141..143 "::" + UPPER_IDENT@143..149 "Option" + L_BRACKET@149..150 "[" + TyInt@150..153 + I32_BUILTIN@150..153 "i32" + R_BRACKET@153..154 "]" + SPACE@154..155 " " + EQUALS@155..156 "=" + SPACE@156..157 " " + ECall@157..173 + EVar@157..169 + ModQualifier@157..165 + IDENT@157..163 "option" + DOUBLE_COLON@163..165 "::" + IDENT@165..169 "some" + EArgList@169..173 + L_PAREN@169..170 "(" + ELit@170..172 + LitInt@170..172 + INT_LIT@170..172 "10" + R_PAREN@172..173 ")" + TopGlobal@173..221 + LINEFEED@173..174 "\n" + GLOBAL_KW@174..180 "global" + SPACE@180..181 " " + IDENT@181..183 "s2" + SPACE@183..184 " " + EQUALS@184..185 "=" + SPACE@185..186 " " + EStruct@186..221 + ModQualifier@186..194 + IDENT@186..192 "option" + DOUBLE_COLON@192..194 "::" + Qualifier@194..202 + UPPER_IDENT@194..200 "Option" + DOUBLE_COLON@200..202 "::" + UPPER_IDENT@202..206 "Some" + SPACE@206..207 " " + L_BRACE@207..208 "{" + SPACE@208..209 " " + EStructField@209..220 + IDENT@209..214 "value" + SPACE@214..215 " " + EQUALS@215..216 "=" + SPACE@216..217 " " + ELit@217..220 + LitInt@217..220 + INT_LIT@217..219 "10" + SPACE@219..220 " " + R_BRACE@220..221 "}" + TopStruct@221..236 + LINEFEED@221..222 "\n" + LINEFEED@222..223 "\n" + STRUCT_KW@223..229 "struct" + SPACE@229..230 " " + UPPER_IDENT@230..233 "Str" + SPACE@233..234 " " + L_BRACE@234..235 "{" + R_BRACE@235..236 "}" + TopFn@236..256 + LINEFEED@236..237 "\n" + LINEFEED@237..238 "\n" + FN_KW@238..240 "fn" + SPACE@240..241 " " + IDENT@241..244 "len" + L_PAREN@244..245 "(" + Param@245..251 + IDENT@245..246 "s" + COLON@246..247 ":" + SPACE@247..248 " " + TyCons@248..251 + UPPER_IDENT@248..251 "Str" + R_PAREN@251..252 ")" + SPACE@252..253 " " + EBlock@253..256 + L_BRACE@253..254 "{" + SPACE@254..255 " " + R_BRACE@255..256 "}" + TopFn@256..290 + LINEFEED@256..257 "\n" + FN_KW@257..259 "fn" + SPACE@259..260 " " + IDENT@260..266 "concat" + L_PAREN@266..267 "(" + Param@267..277 + IDENT@267..269 "s1" + SPACE@269..270 " " + COLON@270..271 ":" + SPACE@271..272 " " + TyCons@272..275 + UPPER_IDENT@272..275 "Str" + COMMA@275..276 "," + SPACE@276..277 " " + Param@277..285 + IDENT@277..279 "s2" + SPACE@279..280 " " + COLON@280..281 ":" + SPACE@281..282 " " + TyCons@282..285 + UPPER_IDENT@282..285 "Str" + R_PAREN@285..286 ")" + SPACE@286..287 " " + EBlock@287..290 + L_BRACE@287..288 "{" + SPACE@288..289 " " + R_BRACE@289..290 "}" diff --git a/crates/frontend/tests/snapshots/lib__parsing@poly.nemo.snap b/crates/frontend/tests/snapshots/lib__parsing@poly.nemo.snap index d2b03767..0d85299b 100644 --- a/crates/frontend/tests/snapshots/lib__parsing@poly.nemo.snap +++ b/crates/frontend/tests/snapshots/lib__parsing@poly.nemo.snap @@ -1,139 +1,140 @@ --- source: crates/frontend/tests/lib.rs -assertion_line: 132 +assertion_line: 129 expression: output input_file: crates/frontend/tests/parsing/poly.nemo --- Root@0..153 - TopFn@0..63 - FN_KW@0..2 "fn" - SPACE@2..3 " " - IDENT@3..7 "poly" - L_BRACKET@7..8 "[" - ParamTy@8..11 - IDENT@8..9 "a" - COMMA@9..10 "," - SPACE@10..11 " " - ParamTy@11..12 - IDENT@11..12 "b" - R_BRACKET@12..13 "]" - L_PAREN@13..14 "(" - Param@14..21 - IDENT@14..15 "a" - SPACE@15..16 " " - COLON@16..17 ":" - SPACE@17..18 " " - TyVar@18..19 - IDENT@18..19 "a" - COMMA@19..20 "," - SPACE@20..21 " " - Param@21..30 - IDENT@21..26 "other" - SPACE@26..27 " " - COLON@27..28 ":" - SPACE@28..29 " " - TyVar@29..30 - IDENT@29..30 "b" - R_PAREN@30..31 ")" - SPACE@31..32 " " - EBlock@32..63 - L_BRACE@32..33 "{" - DExpr@33..61 - ECall@33..61 - EVar@33..40 - LINEFEED@33..34 "\n" - SPACE@34..36 " " - IDENT@36..40 "poly" - ETyArgList@40..52 - HASH@40..41 "#" - L_BRACKET@41..42 "[" - TyInt@42..45 - I32_BUILTIN@42..45 "i32" - COMMA@45..46 "," - SPACE@46..47 " " - TyBool@47..51 - BOOL_BUILTIN@47..51 "bool" - R_BRACKET@51..52 "]" - EArgList@52..61 - L_PAREN@52..53 "(" - ELit@53..54 - LitInt@53..54 - INT_LIT@53..54 "1" - COMMA@54..55 "," - SPACE@55..56 " " - ELit@56..60 - LitBool@56..60 - TRUE_KW@56..60 "true" - R_PAREN@60..61 ")" - LINEFEED@61..62 "\n" - R_BRACE@62..63 "}" - TopStruct@63..96 - LINEFEED@63..64 "\n" - LINEFEED@64..65 "\n" - STRUCT_KW@65..71 "struct" - SPACE@71..72 " " - UPPER_IDENT@72..75 "Box" - L_BRACKET@75..76 "[" - ParamTy@76..77 - IDENT@76..77 "a" - R_BRACKET@77..78 "]" - SPACE@78..79 " " - L_BRACE@79..80 "{" - StructField@80..94 - LINEFEED@80..81 "\n" - SPACE@81..83 " " - IDENT@83..90 "content" - SPACE@90..91 " " - COLON@91..92 ":" - SPACE@92..93 " " - TyVar@93..94 - IDENT@93..94 "a" - LINEFEED@94..95 "\n" - R_BRACE@95..96 "}" - TopFn@96..153 - LINEFEED@96..97 "\n" - LINEFEED@97..98 "\n" - FN_KW@98..100 "fn" - SPACE@100..101 " " - IDENT@101..105 "main" - L_PAREN@105..106 "(" - R_PAREN@106..107 ")" - SPACE@107..108 " " - ARROW@108..110 "->" - SPACE@110..111 " " - TyCons@111..120 - UPPER_IDENT@111..114 "Box" - L_BRACKET@114..115 "[" - TyInt@115..118 - I32_BUILTIN@115..118 "i32" - R_BRACKET@118..119 "]" - SPACE@119..120 " " - EBlock@120..153 - L_BRACE@120..121 "{" - DExpr@121..151 - EStruct@121..151 - LINEFEED@121..122 "\n" - SPACE@122..124 " " - UPPER_IDENT@124..127 "Box" - SPACE@127..128 " " - ETyArgList@128..135 - HASH@128..129 "#" - L_BRACKET@129..130 "[" - TyInt@130..133 - I32_BUILTIN@130..133 "i32" - R_BRACKET@133..134 "]" - SPACE@134..135 " " - L_BRACE@135..136 "{" - SPACE@136..137 " " - EStructField@137..150 - IDENT@137..144 "content" - SPACE@144..145 " " - EQUALS@145..146 "=" - SPACE@146..147 " " - ELit@147..150 - LitInt@147..150 - INT_LIT@147..149 "42" - SPACE@149..150 " " - R_BRACE@150..151 "}" - LINEFEED@151..152 "\n" - R_BRACE@152..153 "}" + Module@0..153 + TopFn@0..63 + FN_KW@0..2 "fn" + SPACE@2..3 " " + IDENT@3..7 "poly" + L_BRACKET@7..8 "[" + ParamTy@8..11 + IDENT@8..9 "a" + COMMA@9..10 "," + SPACE@10..11 " " + ParamTy@11..12 + IDENT@11..12 "b" + R_BRACKET@12..13 "]" + L_PAREN@13..14 "(" + Param@14..21 + IDENT@14..15 "a" + SPACE@15..16 " " + COLON@16..17 ":" + SPACE@17..18 " " + TyVar@18..19 + IDENT@18..19 "a" + COMMA@19..20 "," + SPACE@20..21 " " + Param@21..30 + IDENT@21..26 "other" + SPACE@26..27 " " + COLON@27..28 ":" + SPACE@28..29 " " + TyVar@29..30 + IDENT@29..30 "b" + R_PAREN@30..31 ")" + SPACE@31..32 " " + EBlock@32..63 + L_BRACE@32..33 "{" + DExpr@33..61 + ECall@33..61 + EVar@33..40 + LINEFEED@33..34 "\n" + SPACE@34..36 " " + IDENT@36..40 "poly" + ETyArgList@40..52 + HASH@40..41 "#" + L_BRACKET@41..42 "[" + TyInt@42..45 + I32_BUILTIN@42..45 "i32" + COMMA@45..46 "," + SPACE@46..47 " " + TyBool@47..51 + BOOL_BUILTIN@47..51 "bool" + R_BRACKET@51..52 "]" + EArgList@52..61 + L_PAREN@52..53 "(" + ELit@53..54 + LitInt@53..54 + INT_LIT@53..54 "1" + COMMA@54..55 "," + SPACE@55..56 " " + ELit@56..60 + LitBool@56..60 + TRUE_KW@56..60 "true" + R_PAREN@60..61 ")" + LINEFEED@61..62 "\n" + R_BRACE@62..63 "}" + TopStruct@63..96 + LINEFEED@63..64 "\n" + LINEFEED@64..65 "\n" + STRUCT_KW@65..71 "struct" + SPACE@71..72 " " + UPPER_IDENT@72..75 "Box" + L_BRACKET@75..76 "[" + ParamTy@76..77 + IDENT@76..77 "a" + R_BRACKET@77..78 "]" + SPACE@78..79 " " + L_BRACE@79..80 "{" + StructField@80..94 + LINEFEED@80..81 "\n" + SPACE@81..83 " " + IDENT@83..90 "content" + SPACE@90..91 " " + COLON@91..92 ":" + SPACE@92..93 " " + TyVar@93..94 + IDENT@93..94 "a" + LINEFEED@94..95 "\n" + R_BRACE@95..96 "}" + TopFn@96..153 + LINEFEED@96..97 "\n" + LINEFEED@97..98 "\n" + FN_KW@98..100 "fn" + SPACE@100..101 " " + IDENT@101..105 "main" + L_PAREN@105..106 "(" + R_PAREN@106..107 ")" + SPACE@107..108 " " + ARROW@108..110 "->" + SPACE@110..111 " " + TyCons@111..120 + UPPER_IDENT@111..114 "Box" + L_BRACKET@114..115 "[" + TyInt@115..118 + I32_BUILTIN@115..118 "i32" + R_BRACKET@118..119 "]" + SPACE@119..120 " " + EBlock@120..153 + L_BRACE@120..121 "{" + DExpr@121..151 + EStruct@121..151 + LINEFEED@121..122 "\n" + SPACE@122..124 " " + UPPER_IDENT@124..127 "Box" + SPACE@127..128 " " + ETyArgList@128..135 + HASH@128..129 "#" + L_BRACKET@129..130 "[" + TyInt@130..133 + I32_BUILTIN@130..133 "i32" + R_BRACKET@133..134 "]" + SPACE@134..135 " " + L_BRACE@135..136 "{" + SPACE@136..137 " " + EStructField@137..150 + IDENT@137..144 "content" + SPACE@144..145 " " + EQUALS@145..146 "=" + SPACE@146..147 " " + ELit@147..150 + LitInt@147..150 + INT_LIT@147..149 "42" + SPACE@149..150 " " + R_BRACE@150..151 "}" + LINEFEED@151..152 "\n" + R_BRACE@152..153 "}" diff --git a/crates/frontend/tests/snapshots/lib__parsing@return.nemo.snap b/crates/frontend/tests/snapshots/lib__parsing@return.nemo.snap index cb2d9cb0..643cf5fa 100644 --- a/crates/frontend/tests/snapshots/lib__parsing@return.nemo.snap +++ b/crates/frontend/tests/snapshots/lib__parsing@return.nemo.snap @@ -1,28 +1,29 @@ --- source: crates/frontend/tests/lib.rs -assertion_line: 134 +assertion_line: 129 expression: output input_file: crates/frontend/tests/parsing/return.nemo --- Root@0..26 - TopFn@0..26 - FN_KW@0..2 "fn" - SPACE@2..3 " " - IDENT@3..7 "main" - L_PAREN@7..8 "(" - R_PAREN@8..9 ")" - SPACE@9..10 " " - EBlock@10..26 - L_BRACE@10..11 "{" - DExpr@11..23 - EReturn@11..23 - LINEFEED@11..12 "\n" - SPACE@12..14 " " - RETURN_KW@14..20 "return" - SPACE@20..21 " " - EBlock@21..23 - L_BRACE@21..22 "{" - R_BRACE@22..23 "}" - SEMICOLON@23..24 ";" - LINEFEED@24..25 "\n" - R_BRACE@25..26 "}" + Module@0..26 + TopFn@0..26 + FN_KW@0..2 "fn" + SPACE@2..3 " " + IDENT@3..7 "main" + L_PAREN@7..8 "(" + R_PAREN@8..9 ")" + SPACE@9..10 " " + EBlock@10..26 + L_BRACE@10..11 "{" + DExpr@11..23 + EReturn@11..23 + LINEFEED@11..12 "\n" + SPACE@12..14 " " + RETURN_KW@14..20 "return" + SPACE@20..21 " " + EBlock@21..23 + L_BRACE@21..22 "{" + R_BRACE@22..23 "}" + SEMICOLON@23..24 ";" + LINEFEED@24..25 "\n" + R_BRACE@25..26 "}" diff --git a/crates/frontend/tests/snapshots/lib__parsing@structs.nemo.snap b/crates/frontend/tests/snapshots/lib__parsing@structs.nemo.snap index 3193f55d..6b438e50 100644 --- a/crates/frontend/tests/snapshots/lib__parsing@structs.nemo.snap +++ b/crates/frontend/tests/snapshots/lib__parsing@structs.nemo.snap @@ -1,158 +1,159 @@ --- source: crates/frontend/tests/lib.rs -assertion_line: 132 +assertion_line: 129 expression: output input_file: crates/frontend/tests/parsing/structs.nemo --- Root@0..165 - TopGlobal@0..18 - GLOBAL_KW@0..6 "global" - SPACE@6..7 " " - IDENT@7..8 "_" - SPACE@8..9 " " - EQUALS@9..10 "=" - SPACE@10..11 " " - EStruct@11..18 - UPPER_IDENT@11..14 "Vec" - SPACE@14..15 " " - L_BRACE@15..16 "{" - SPACE@16..17 " " - R_BRACE@17..18 "}" - TopGlobal@18..44 - LINEFEED@18..19 "\n" - GLOBAL_KW@19..25 "global" - SPACE@25..26 " " - IDENT@26..27 "_" - SPACE@27..28 " " - EQUALS@28..29 "=" - SPACE@29..30 " " - EStruct@30..44 - UPPER_IDENT@30..33 "Vec" - SPACE@33..34 " " - L_BRACE@34..35 "{" - SPACE@35..36 " " - EStructField@36..43 - IDENT@36..37 "x" - SPACE@37..38 " " - EQUALS@38..39 "=" - SPACE@39..40 " " - ELit@40..43 - LitInt@40..43 - INT_LIT@40..42 "10" - SPACE@42..43 " " - R_BRACE@43..44 "}" - TopGlobal@44..79 - LINEFEED@44..45 "\n" - GLOBAL_KW@45..51 "global" - SPACE@51..52 " " - IDENT@52..53 "_" - SPACE@53..54 " " - EQUALS@54..55 "=" - SPACE@55..56 " " - EStruct@56..79 - UPPER_IDENT@56..59 "Vec" - SPACE@59..60 " " - L_BRACE@60..61 "{" - SPACE@61..62 " " - EStructField@62..68 - IDENT@62..63 "x" - SPACE@63..64 " " - EQUALS@64..65 "=" - SPACE@65..66 " " - ELit@66..68 - LitInt@66..68 - INT_LIT@66..68 "10" - COMMA@68..69 "," - SPACE@69..70 " " - EStructField@70..78 - IDENT@70..71 "y" - SPACE@71..72 " " - EQUALS@72..73 "=" - SPACE@73..74 " " - ELit@74..78 - LitFloat@74..78 - FLOAT_LIT@74..77 "1.0" - SPACE@77..78 " " - R_BRACE@78..79 "}" - TopGlobal@79..115 - LINEFEED@79..80 "\n" - GLOBAL_KW@80..86 "global" - SPACE@86..87 " " - IDENT@87..88 "_" - SPACE@88..89 " " - EQUALS@89..90 "=" - SPACE@90..91 " " - EStruct@91..115 - UPPER_IDENT@91..94 "Vec" - SPACE@94..95 " " - L_BRACE@95..96 "{" - SPACE@96..97 " " - EStructField@97..103 - IDENT@97..98 "x" - SPACE@98..99 " " - EQUALS@99..100 "=" - SPACE@100..101 " " - ELit@101..103 - LitInt@101..103 - INT_LIT@101..103 "10" - COMMA@103..104 "," - SPACE@104..105 " " - EStructField@105..112 - IDENT@105..106 "y" - SPACE@106..107 " " - EQUALS@107..108 "=" - SPACE@108..109 " " - ELit@109..112 - LitFloat@109..112 - FLOAT_LIT@109..112 "1.0" - COMMA@112..113 "," - SPACE@113..114 " " - R_BRACE@114..115 "}" - TopGlobal@115..130 - LINEFEED@115..116 "\n" - GLOBAL_KW@116..122 "global" - SPACE@122..123 " " - IDENT@123..124 "_" - SPACE@124..125 " " - EQUALS@125..126 "=" - SPACE@126..127 " " - EStructIdx@127..130 - EVar@127..128 - IDENT@127..128 "v" - DOT@128..129 "." - IDENT@129..130 "x" - TopGlobal@130..147 - LINEFEED@130..131 "\n" - GLOBAL_KW@131..137 "global" - SPACE@137..138 " " - IDENT@138..139 "_" - SPACE@139..140 " " - EQUALS@140..141 "=" - SPACE@141..142 " " - EStructIdx@142..147 - EStructIdx@142..145 - EVar@142..143 - IDENT@142..143 "v" - DOT@143..144 "." - IDENT@144..145 "x" - DOT@145..146 "." - IDENT@146..147 "y" - TopGlobal@147..165 - LINEFEED@147..148 "\n" - GLOBAL_KW@148..154 "global" - SPACE@154..155 " " - IDENT@155..156 "_" - SPACE@156..157 " " - EQUALS@157..158 "=" - SPACE@158..159 " " - EStructIdx@159..165 - EArrayIdx@159..163 - EVar@159..160 - IDENT@159..160 "v" - L_BRACKET@160..161 "[" - ELit@161..162 - LitInt@161..162 - INT_LIT@161..162 "0" - R_BRACKET@162..163 "]" - DOT@163..164 "." - IDENT@164..165 "y" + Module@0..165 + TopGlobal@0..18 + GLOBAL_KW@0..6 "global" + SPACE@6..7 " " + IDENT@7..8 "_" + SPACE@8..9 " " + EQUALS@9..10 "=" + SPACE@10..11 " " + EStruct@11..18 + UPPER_IDENT@11..14 "Vec" + SPACE@14..15 " " + L_BRACE@15..16 "{" + SPACE@16..17 " " + R_BRACE@17..18 "}" + TopGlobal@18..44 + LINEFEED@18..19 "\n" + GLOBAL_KW@19..25 "global" + SPACE@25..26 " " + IDENT@26..27 "_" + SPACE@27..28 " " + EQUALS@28..29 "=" + SPACE@29..30 " " + EStruct@30..44 + UPPER_IDENT@30..33 "Vec" + SPACE@33..34 " " + L_BRACE@34..35 "{" + SPACE@35..36 " " + EStructField@36..43 + IDENT@36..37 "x" + SPACE@37..38 " " + EQUALS@38..39 "=" + SPACE@39..40 " " + ELit@40..43 + LitInt@40..43 + INT_LIT@40..42 "10" + SPACE@42..43 " " + R_BRACE@43..44 "}" + TopGlobal@44..79 + LINEFEED@44..45 "\n" + GLOBAL_KW@45..51 "global" + SPACE@51..52 " " + IDENT@52..53 "_" + SPACE@53..54 " " + EQUALS@54..55 "=" + SPACE@55..56 " " + EStruct@56..79 + UPPER_IDENT@56..59 "Vec" + SPACE@59..60 " " + L_BRACE@60..61 "{" + SPACE@61..62 " " + EStructField@62..68 + IDENT@62..63 "x" + SPACE@63..64 " " + EQUALS@64..65 "=" + SPACE@65..66 " " + ELit@66..68 + LitInt@66..68 + INT_LIT@66..68 "10" + COMMA@68..69 "," + SPACE@69..70 " " + EStructField@70..78 + IDENT@70..71 "y" + SPACE@71..72 " " + EQUALS@72..73 "=" + SPACE@73..74 " " + ELit@74..78 + LitFloat@74..78 + FLOAT_LIT@74..77 "1.0" + SPACE@77..78 " " + R_BRACE@78..79 "}" + TopGlobal@79..115 + LINEFEED@79..80 "\n" + GLOBAL_KW@80..86 "global" + SPACE@86..87 " " + IDENT@87..88 "_" + SPACE@88..89 " " + EQUALS@89..90 "=" + SPACE@90..91 " " + EStruct@91..115 + UPPER_IDENT@91..94 "Vec" + SPACE@94..95 " " + L_BRACE@95..96 "{" + SPACE@96..97 " " + EStructField@97..103 + IDENT@97..98 "x" + SPACE@98..99 " " + EQUALS@99..100 "=" + SPACE@100..101 " " + ELit@101..103 + LitInt@101..103 + INT_LIT@101..103 "10" + COMMA@103..104 "," + SPACE@104..105 " " + EStructField@105..112 + IDENT@105..106 "y" + SPACE@106..107 " " + EQUALS@107..108 "=" + SPACE@108..109 " " + ELit@109..112 + LitFloat@109..112 + FLOAT_LIT@109..112 "1.0" + COMMA@112..113 "," + SPACE@113..114 " " + R_BRACE@114..115 "}" + TopGlobal@115..130 + LINEFEED@115..116 "\n" + GLOBAL_KW@116..122 "global" + SPACE@122..123 " " + IDENT@123..124 "_" + SPACE@124..125 " " + EQUALS@125..126 "=" + SPACE@126..127 " " + EStructIdx@127..130 + EVar@127..128 + IDENT@127..128 "v" + DOT@128..129 "." + IDENT@129..130 "x" + TopGlobal@130..147 + LINEFEED@130..131 "\n" + GLOBAL_KW@131..137 "global" + SPACE@137..138 " " + IDENT@138..139 "_" + SPACE@139..140 " " + EQUALS@140..141 "=" + SPACE@141..142 " " + EStructIdx@142..147 + EStructIdx@142..145 + EVar@142..143 + IDENT@142..143 "v" + DOT@143..144 "." + IDENT@144..145 "x" + DOT@145..146 "." + IDENT@146..147 "y" + TopGlobal@147..165 + LINEFEED@147..148 "\n" + GLOBAL_KW@148..154 "global" + SPACE@154..155 " " + IDENT@155..156 "_" + SPACE@156..157 " " + EQUALS@157..158 "=" + SPACE@158..159 " " + EStructIdx@159..165 + EArrayIdx@159..163 + EVar@159..160 + IDENT@159..160 "v" + L_BRACKET@160..161 "[" + ELit@161..162 + LitInt@161..162 + INT_LIT@161..162 "0" + R_BRACKET@162..163 "]" + DOT@163..164 "." + IDENT@164..165 "y" diff --git a/crates/frontend/tests/snapshots/lib__parsing@toplevels.nemo.snap b/crates/frontend/tests/snapshots/lib__parsing@toplevels.nemo.snap index 7e500c71..d431f83a 100644 --- a/crates/frontend/tests/snapshots/lib__parsing@toplevels.nemo.snap +++ b/crates/frontend/tests/snapshots/lib__parsing@toplevels.nemo.snap @@ -1,247 +1,248 @@ --- source: crates/frontend/tests/lib.rs -assertion_line: 132 +assertion_line: 129 expression: output input_file: crates/frontend/tests/parsing/toplevels.nemo --- Root@0..370 - TopImport@0..52 - IMPORT_KW@0..6 "import" - SPACE@6..7 " " - ImpInternal@7..16 - IDENT@7..15 "internal" - SPACE@15..16 " " - COLON@16..17 ":" - SPACE@17..18 " " - TyFn@18..39 - FN_KW@18..20 "fn" - SPACE@20..21 " " - TyArgList@21..32 - L_PAREN@21..22 "(" - TyInt@22..25 - I32_BUILTIN@22..25 "i32" - COMMA@25..26 "," - SPACE@26..27 " " - TyFloat@27..30 - F32_BUILTIN@27..30 "f32" - R_PAREN@30..31 ")" - SPACE@31..32 " " - ARROW@32..34 "->" - SPACE@34..35 " " - TyInt@35..39 - I32_BUILTIN@35..38 "i32" - SPACE@38..39 " " - FROM_KW@39..43 "from" - SPACE@43..44 " " - ImpExternal@44..52 - IDENT@44..52 "external" - TopStruct@52..90 - LINEFEED@52..53 "\n" - LINEFEED@53..54 "\n" - STRUCT_KW@54..60 "struct" - SPACE@60..61 " " - UPPER_IDENT@61..64 "Vec" - SPACE@64..65 " " - L_BRACE@65..66 "{" - StructField@66..76 - LINEFEED@66..67 "\n" - SPACE@67..69 " " - IDENT@69..70 "x" - SPACE@70..71 " " - COLON@71..72 ":" - SPACE@72..73 " " - TyFloat@73..76 - F32_BUILTIN@73..76 "f32" - COMMA@76..77 "," - StructField@77..87 - LINEFEED@77..78 "\n" - SPACE@78..80 " " - IDENT@80..81 "y" - SPACE@81..82 " " - COLON@82..83 ":" - SPACE@83..84 " " - TyFloat@84..87 - F32_BUILTIN@84..87 "f32" - COMMA@87..88 "," - LINEFEED@88..89 "\n" - R_BRACE@89..90 "}" - TopGlobal@90..105 - LINEFEED@90..91 "\n" - LINEFEED@91..92 "\n" - GLOBAL_KW@92..98 "global" - SPACE@98..99 " " - IDENT@99..100 "x" - SPACE@100..101 " " - EQUALS@101..102 "=" - SPACE@102..103 " " - ELit@103..105 - LitInt@103..105 - INT_LIT@103..105 "10" - TopGlobal@105..127 - LINEFEED@105..106 "\n" - GLOBAL_KW@106..112 "global" - SPACE@112..113 " " - IDENT@113..114 "y" - SPACE@114..115 " " - COLON@115..116 ":" - SPACE@116..117 " " - TyFloat@117..121 - F32_BUILTIN@117..120 "f32" - SPACE@120..121 " " - EQUALS@121..122 "=" - SPACE@122..123 " " - ELit@123..127 - LitFloat@123..127 - FLOAT_LIT@123..127 "10.0" - TopFn@127..143 - LINEFEED@127..128 "\n" - LINEFEED@128..129 "\n" - FN_KW@129..131 "fn" - SPACE@131..132 " " - IDENT@132..136 "main" - L_PAREN@136..137 "(" - R_PAREN@137..138 ")" - SPACE@138..139 " " - EBlock@139..143 - L_BRACE@139..140 "{" - LINEFEED@140..141 "\n" - LINEFEED@141..142 "\n" - R_BRACE@142..143 "}" - TopFn@143..190 - LINEFEED@143..144 "\n" - LINEFEED@144..145 "\n" - FN_KW@145..147 "fn" - SPACE@147..148 " " - IDENT@148..151 "add" - L_PAREN@151..152 "(" - Param@152..161 - IDENT@152..153 "x" - SPACE@153..154 " " - COLON@154..155 ":" - SPACE@155..156 " " - TyInt@156..159 - I32_BUILTIN@156..159 "i32" - COMMA@159..160 "," - SPACE@160..161 " " - Param@161..168 - IDENT@161..162 "y" - SPACE@162..163 " " - COLON@163..164 ":" - SPACE@164..165 " " - TyInt@165..168 - I32_BUILTIN@165..168 "i32" - R_PAREN@168..169 ")" - SPACE@169..170 " " - ARROW@170..172 "->" - SPACE@172..173 " " - TyInt@173..177 - I32_BUILTIN@173..176 "i32" - SPACE@176..177 " " - EBlock@177..190 - L_BRACE@177..178 "{" - DExpr@178..188 - EBinary@178..188 - EVar@178..185 - LINEFEED@178..179 "\n" - SPACE@179..183 " " - IDENT@183..184 "x" - SPACE@184..185 " " - BinOp@185..187 - PLUS@185..186 "+" - SPACE@186..187 " " - EVar@187..188 - IDENT@187..188 "y" - LINEFEED@188..189 "\n" - R_BRACE@189..190 "}" - TopFn@190..370 - LINEFEED@190..191 "\n" - LINEFEED@191..192 "\n" - FN_KW@192..194 "fn" - SPACE@194..195 " " - IDENT@195..207 "add_particle" - L_PAREN@207..208 "(" - Param@208..220 - IDENT@208..209 "p" - SPACE@209..210 " " - COLON@210..211 ":" - SPACE@211..212 " " - TyCons@212..220 - UPPER_IDENT@212..220 "Particle" - R_PAREN@220..221 ")" - SPACE@221..222 " " - EBlock@222..370 - L_BRACE@222..223 "{" - DSet@223..271 - LINEFEED@223..224 "\n" - SPACE@224..226 " " - SET_KW@226..229 "set" - SPACE@229..230 " " - SetTarget@230..268 - EArrayIdx@230..268 - EStructIdx@230..246 - EVar@230..239 - IDENT@230..239 "particles" - DOT@239..240 "." - IDENT@240..246 "buffer" - L_BRACKET@246..247 "[" - EStructIdx@247..266 - EVar@247..256 - IDENT@247..256 "particles" - DOT@256..257 "." - IDENT@257..266 "watermark" - R_BRACKET@266..267 "]" - SPACE@267..268 " " - EQUALS@268..269 "=" - SPACE@269..270 " " - EVar@270..271 - IDENT@270..271 "p" - SEMICOLON@271..272 ";" - DSet@272..368 - LINEFEED@272..273 "\n" - SPACE@273..275 " " - SET_KW@275..278 "set" - SPACE@278..279 " " - SetTarget@279..299 - EStructIdx@279..299 - EVar@279..288 - IDENT@279..288 "particles" - DOT@288..289 "." - IDENT@289..298 "watermark" - SPACE@298..299 " " - EQUALS@299..300 "=" - ECall@300..368 - EVar@300..314 - LINEFEED@300..301 "\n" - SPACE@301..305 " " - IDENT@305..314 "i32_rem_s" - EArgList@314..368 - L_PAREN@314..315 "(" - EBinary@315..338 - EStructIdx@315..335 - EVar@315..324 - IDENT@315..324 "particles" - DOT@324..325 "." - IDENT@325..334 "watermark" - SPACE@334..335 " " - BinOp@335..337 - PLUS@335..336 "+" - SPACE@336..337 " " - ELit@337..338 - LitInt@337..338 - INT_LIT@337..338 "1" - COMMA@338..339 "," - SPACE@339..340 " " - ECall@340..367 - EVar@340..349 - IDENT@340..349 "array_len" - EArgList@349..367 - L_PAREN@349..350 "(" - EStructIdx@350..366 - EVar@350..359 - IDENT@350..359 "particles" - DOT@359..360 "." - IDENT@360..366 "buffer" - R_PAREN@366..367 ")" - R_PAREN@367..368 ")" - LINEFEED@368..369 "\n" - R_BRACE@369..370 "}" + Module@0..370 + TopImport@0..52 + IMPORT_KW@0..6 "import" + SPACE@6..7 " " + ImpInternal@7..16 + IDENT@7..15 "internal" + SPACE@15..16 " " + COLON@16..17 ":" + SPACE@17..18 " " + TyFn@18..39 + FN_KW@18..20 "fn" + SPACE@20..21 " " + TyArgList@21..32 + L_PAREN@21..22 "(" + TyInt@22..25 + I32_BUILTIN@22..25 "i32" + COMMA@25..26 "," + SPACE@26..27 " " + TyFloat@27..30 + F32_BUILTIN@27..30 "f32" + R_PAREN@30..31 ")" + SPACE@31..32 " " + ARROW@32..34 "->" + SPACE@34..35 " " + TyInt@35..39 + I32_BUILTIN@35..38 "i32" + SPACE@38..39 " " + FROM_KW@39..43 "from" + SPACE@43..44 " " + ImpExternal@44..52 + IDENT@44..52 "external" + TopStruct@52..90 + LINEFEED@52..53 "\n" + LINEFEED@53..54 "\n" + STRUCT_KW@54..60 "struct" + SPACE@60..61 " " + UPPER_IDENT@61..64 "Vec" + SPACE@64..65 " " + L_BRACE@65..66 "{" + StructField@66..76 + LINEFEED@66..67 "\n" + SPACE@67..69 " " + IDENT@69..70 "x" + SPACE@70..71 " " + COLON@71..72 ":" + SPACE@72..73 " " + TyFloat@73..76 + F32_BUILTIN@73..76 "f32" + COMMA@76..77 "," + StructField@77..87 + LINEFEED@77..78 "\n" + SPACE@78..80 " " + IDENT@80..81 "y" + SPACE@81..82 " " + COLON@82..83 ":" + SPACE@83..84 " " + TyFloat@84..87 + F32_BUILTIN@84..87 "f32" + COMMA@87..88 "," + LINEFEED@88..89 "\n" + R_BRACE@89..90 "}" + TopGlobal@90..105 + LINEFEED@90..91 "\n" + LINEFEED@91..92 "\n" + GLOBAL_KW@92..98 "global" + SPACE@98..99 " " + IDENT@99..100 "x" + SPACE@100..101 " " + EQUALS@101..102 "=" + SPACE@102..103 " " + ELit@103..105 + LitInt@103..105 + INT_LIT@103..105 "10" + TopGlobal@105..127 + LINEFEED@105..106 "\n" + GLOBAL_KW@106..112 "global" + SPACE@112..113 " " + IDENT@113..114 "y" + SPACE@114..115 " " + COLON@115..116 ":" + SPACE@116..117 " " + TyFloat@117..121 + F32_BUILTIN@117..120 "f32" + SPACE@120..121 " " + EQUALS@121..122 "=" + SPACE@122..123 " " + ELit@123..127 + LitFloat@123..127 + FLOAT_LIT@123..127 "10.0" + TopFn@127..143 + LINEFEED@127..128 "\n" + LINEFEED@128..129 "\n" + FN_KW@129..131 "fn" + SPACE@131..132 " " + IDENT@132..136 "main" + L_PAREN@136..137 "(" + R_PAREN@137..138 ")" + SPACE@138..139 " " + EBlock@139..143 + L_BRACE@139..140 "{" + LINEFEED@140..141 "\n" + LINEFEED@141..142 "\n" + R_BRACE@142..143 "}" + TopFn@143..190 + LINEFEED@143..144 "\n" + LINEFEED@144..145 "\n" + FN_KW@145..147 "fn" + SPACE@147..148 " " + IDENT@148..151 "add" + L_PAREN@151..152 "(" + Param@152..161 + IDENT@152..153 "x" + SPACE@153..154 " " + COLON@154..155 ":" + SPACE@155..156 " " + TyInt@156..159 + I32_BUILTIN@156..159 "i32" + COMMA@159..160 "," + SPACE@160..161 " " + Param@161..168 + IDENT@161..162 "y" + SPACE@162..163 " " + COLON@163..164 ":" + SPACE@164..165 " " + TyInt@165..168 + I32_BUILTIN@165..168 "i32" + R_PAREN@168..169 ")" + SPACE@169..170 " " + ARROW@170..172 "->" + SPACE@172..173 " " + TyInt@173..177 + I32_BUILTIN@173..176 "i32" + SPACE@176..177 " " + EBlock@177..190 + L_BRACE@177..178 "{" + DExpr@178..188 + EBinary@178..188 + EVar@178..185 + LINEFEED@178..179 "\n" + SPACE@179..183 " " + IDENT@183..184 "x" + SPACE@184..185 " " + BinOp@185..187 + PLUS@185..186 "+" + SPACE@186..187 " " + EVar@187..188 + IDENT@187..188 "y" + LINEFEED@188..189 "\n" + R_BRACE@189..190 "}" + TopFn@190..370 + LINEFEED@190..191 "\n" + LINEFEED@191..192 "\n" + FN_KW@192..194 "fn" + SPACE@194..195 " " + IDENT@195..207 "add_particle" + L_PAREN@207..208 "(" + Param@208..220 + IDENT@208..209 "p" + SPACE@209..210 " " + COLON@210..211 ":" + SPACE@211..212 " " + TyCons@212..220 + UPPER_IDENT@212..220 "Particle" + R_PAREN@220..221 ")" + SPACE@221..222 " " + EBlock@222..370 + L_BRACE@222..223 "{" + DSet@223..271 + LINEFEED@223..224 "\n" + SPACE@224..226 " " + SET_KW@226..229 "set" + SPACE@229..230 " " + SetTarget@230..268 + EArrayIdx@230..268 + EStructIdx@230..246 + EVar@230..239 + IDENT@230..239 "particles" + DOT@239..240 "." + IDENT@240..246 "buffer" + L_BRACKET@246..247 "[" + EStructIdx@247..266 + EVar@247..256 + IDENT@247..256 "particles" + DOT@256..257 "." + IDENT@257..266 "watermark" + R_BRACKET@266..267 "]" + SPACE@267..268 " " + EQUALS@268..269 "=" + SPACE@269..270 " " + EVar@270..271 + IDENT@270..271 "p" + SEMICOLON@271..272 ";" + DSet@272..368 + LINEFEED@272..273 "\n" + SPACE@273..275 " " + SET_KW@275..278 "set" + SPACE@278..279 " " + SetTarget@279..299 + EStructIdx@279..299 + EVar@279..288 + IDENT@279..288 "particles" + DOT@288..289 "." + IDENT@289..298 "watermark" + SPACE@298..299 " " + EQUALS@299..300 "=" + ECall@300..368 + EVar@300..314 + LINEFEED@300..301 "\n" + SPACE@301..305 " " + IDENT@305..314 "i32_rem_s" + EArgList@314..368 + L_PAREN@314..315 "(" + EBinary@315..338 + EStructIdx@315..335 + EVar@315..324 + IDENT@315..324 "particles" + DOT@324..325 "." + IDENT@325..334 "watermark" + SPACE@334..335 " " + BinOp@335..337 + PLUS@335..336 "+" + SPACE@336..337 " " + ELit@337..338 + LitInt@337..338 + INT_LIT@337..338 "1" + COMMA@338..339 "," + SPACE@339..340 " " + ECall@340..367 + EVar@340..349 + IDENT@340..349 "array_len" + EArgList@349..367 + L_PAREN@349..350 "(" + EStructIdx@350..366 + EVar@350..359 + IDENT@350..359 "particles" + DOT@359..360 "." + IDENT@360..366 "buffer" + R_PAREN@366..367 ")" + R_PAREN@367..368 ")" + LINEFEED@368..369 "\n" + R_BRACE@369..370 "}" diff --git a/crates/frontend/tests/snapshots/lib__parsing@variants.nemo.snap b/crates/frontend/tests/snapshots/lib__parsing@variants.nemo.snap index 4aab36e1..ecbe98be 100644 --- a/crates/frontend/tests/snapshots/lib__parsing@variants.nemo.snap +++ b/crates/frontend/tests/snapshots/lib__parsing@variants.nemo.snap @@ -1,286 +1,287 @@ --- source: crates/frontend/tests/lib.rs -assertion_line: 132 +assertion_line: 129 expression: output input_file: crates/frontend/tests/parsing/variants.nemo --- Root@0..406 - TopVariant@0..104 - VARIANT_KW@0..7 "variant" - SPACE@7..8 " " - UPPER_IDENT@8..12 "Rope" - SPACE@12..13 " " - L_BRACE@13..14 "{" - TopStruct@14..43 - LINEFEED@14..15 "\n" - SPACE@15..17 " " - STRUCT_KW@17..23 "struct" - SPACE@23..24 " " - UPPER_IDENT@24..28 "Leaf" - SPACE@28..29 " " - L_BRACE@29..30 "{" - SPACE@30..31 " " - StructField@31..42 - IDENT@31..35 "char" - SPACE@35..36 " " - COLON@36..37 ":" - SPACE@37..38 " " - TyInt@38..42 - I32_BUILTIN@38..41 "i32" - SPACE@41..42 " " - R_BRACE@42..43 "}" - COMMA@43..44 "," - TopStruct@44..101 - LINEFEED@44..45 "\n" - SPACE@45..47 " " - STRUCT_KW@47..53 "struct" - SPACE@53..54 " " - UPPER_IDENT@54..58 "Node" - SPACE@58..59 " " - L_BRACE@59..60 "{" - StructField@60..82 - LINEFEED@60..61 "\n" - SPACE@61..65 " " - IDENT@65..73 "children" - SPACE@73..74 " " - COLON@74..75 ":" - SPACE@75..76 " " - TyArray@76..82 - L_BRACKET@76..77 "[" - TyCons@77..81 - UPPER_IDENT@77..81 "Rope" - R_BRACKET@81..82 "]" - COMMA@82..83 "," - StructField@83..97 - LINEFEED@83..84 "\n" - SPACE@84..88 " " - IDENT@88..91 "len" - SPACE@91..92 " " - COLON@92..93 ":" - SPACE@93..94 " " - TyInt@94..97 - I32_BUILTIN@94..97 "i32" - LINEFEED@97..98 "\n" - SPACE@98..100 " " - R_BRACE@100..101 "}" - COMMA@101..102 "," - LINEFEED@102..103 "\n" - R_BRACE@103..104 "}" - TopGlobal@104..140 - LINEFEED@104..105 "\n" - LINEFEED@105..106 "\n" - GLOBAL_KW@106..112 "global" - SPACE@112..113 " " - IDENT@113..114 "_" - SPACE@114..115 " " - EQUALS@115..116 "=" - SPACE@116..117 " " - EStruct@117..140 - Qualifier@117..123 - UPPER_IDENT@117..121 "Rope" - DOUBLE_COLON@121..123 "::" - UPPER_IDENT@123..127 "Leaf" - SPACE@127..128 " " - L_BRACE@128..129 "{" - SPACE@129..130 " " - EStructField@130..139 - IDENT@130..134 "char" - SPACE@134..135 " " - EQUALS@135..136 "=" - SPACE@136..137 " " - ELit@137..139 - LitInt@137..139 - INT_LIT@137..138 "2" - SPACE@138..139 " " - R_BRACE@139..140 "}" - TopGlobal@140..193 - LINEFEED@140..141 "\n" - GLOBAL_KW@141..147 "global" - SPACE@147..148 " " - IDENT@148..152 "rope" - SPACE@152..153 " " - EQUALS@153..154 "=" - SPACE@154..155 " " - EStruct@155..193 - Qualifier@155..161 - UPPER_IDENT@155..159 "Rope" - DOUBLE_COLON@159..161 "::" - UPPER_IDENT@161..165 "Node" - SPACE@165..166 " " - L_BRACE@166..167 "{" - SPACE@167..168 " " - EStructField@168..181 - IDENT@168..176 "children" - SPACE@176..177 " " - EQUALS@177..178 "=" - SPACE@178..179 " " - EArray@179..181 - L_BRACKET@179..180 "[" - R_BRACKET@180..181 "]" - COMMA@181..182 "," - SPACE@182..183 " " - EStructField@183..192 - IDENT@183..186 "len" - SPACE@186..187 " " - EQUALS@187..188 "=" - SPACE@188..189 " " - ELit@189..192 - LitInt@189..192 - INT_LIT@189..191 "10" - SPACE@191..192 " " - R_BRACE@192..193 "}" - TopGlobal@193..243 - LINEFEED@193..194 "\n" - GLOBAL_KW@194..200 "global" - SPACE@200..201 " " - IDENT@201..202 "_" - SPACE@202..203 " " - EQUALS@203..204 "=" - SPACE@204..205 " " - EStruct@205..243 - Qualifier@205..211 - UPPER_IDENT@205..209 "Rope" - DOUBLE_COLON@209..211 "::" - UPPER_IDENT@211..215 "Node" - SPACE@215..216 " " - L_BRACE@216..217 "{" - SPACE@217..218 " " - EStructField@218..231 - IDENT@218..226 "children" - SPACE@226..227 " " - EQUALS@227..228 "=" - SPACE@228..229 " " - EArray@229..231 - L_BRACKET@229..230 "[" - R_BRACKET@230..231 "]" - COMMA@231..232 "," - SPACE@232..233 " " - EStructField@233..242 - IDENT@233..236 "len" - SPACE@236..237 " " - EQUALS@237..238 "=" - SPACE@238..239 " " - ELit@239..242 - LitInt@239..242 - INT_LIT@239..241 "10" - SPACE@241..242 " " - R_BRACE@242..243 "}" - TopGlobal@243..368 - LINEFEED@243..244 "\n" - LINEFEED@244..245 "\n" - GLOBAL_KW@245..251 "global" - SPACE@251..252 " " - IDENT@252..253 "_" - SPACE@253..254 " " - EQUALS@254..255 "=" - SPACE@255..256 " " - EMatch@256..368 - MATCH_KW@256..261 "match" - SPACE@261..262 " " - EVar@262..267 - IDENT@262..266 "rope" - SPACE@266..267 " " - L_BRACE@267..268 "{" - EMatchBranch@268..303 - PatVariant@268..287 - Qualifier@268..277 - LINEFEED@268..269 "\n" - SPACE@269..271 " " - UPPER_IDENT@271..275 "Rope" - DOUBLE_COLON@275..277 "::" - UPPER_IDENT@277..281 "Leaf" - SPACE@281..282 " " - IDENT@282..286 "leaf" - SPACE@286..287 " " - FAT_ARROW@287..289 "=>" - SPACE@289..290 " " - EBlock@290..303 - L_BRACE@290..291 "{" - SPACE@291..292 " " - DExpr@292..302 - EStructIdx@292..302 - EVar@292..296 - IDENT@292..296 "leaf" - DOT@296..297 "." - IDENT@297..301 "char" - SPACE@301..302 " " - R_BRACE@302..303 "}" - COMMA@303..304 "," - EMatchBranch@304..365 - PatVariant@304..323 - Qualifier@304..313 - LINEFEED@304..305 "\n" - SPACE@305..307 " " - UPPER_IDENT@307..311 "Rope" - DOUBLE_COLON@311..313 "::" - UPPER_IDENT@313..317 "Node" - SPACE@317..318 " " - IDENT@318..322 "node" - SPACE@322..323 " " - FAT_ARROW@323..325 "=>" - SPACE@325..326 " " - EBlock@326..365 - L_BRACE@326..327 "{" - SPACE@327..328 " " - DExpr@328..364 - EBinary@328..364 - ECall@328..353 - EVar@328..337 - IDENT@328..337 "array_len" - EArgList@337..353 - L_PAREN@337..338 "(" - EStructIdx@338..351 - EVar@338..342 - IDENT@338..342 "node" - DOT@342..343 "." - IDENT@343..351 "children" - R_PAREN@351..352 ")" - SPACE@352..353 " " - BinOp@353..355 - PLUS@353..354 "+" - SPACE@354..355 " " - EStructIdx@355..364 - EVar@355..359 - IDENT@355..359 "node" - DOT@359..360 "." - IDENT@360..363 "len" - SPACE@363..364 " " - R_BRACE@364..365 "}" - COMMA@365..366 "," - LINEFEED@366..367 "\n" - R_BRACE@367..368 "}" - TopGlobal@368..406 - LINEFEED@368..369 "\n" - LINEFEED@369..370 "\n" - GLOBAL_KW@370..376 "global" - SPACE@376..377 " " - IDENT@377..378 "_" - SPACE@378..379 " " - EQUALS@379..380 "=" - SPACE@380..381 " " - EMatch@381..406 - MATCH_KW@381..386 "match" - SPACE@386..387 " " - ELit@387..390 - LitInt@387..390 - INT_LIT@387..389 "10" - SPACE@389..390 " " - L_BRACE@390..391 "{" - EMatchBranch@391..404 - PatVar@391..396 - LINEFEED@391..392 "\n" - SPACE@392..394 " " - IDENT@394..395 "x" - SPACE@395..396 " " - FAT_ARROW@396..398 "=>" - SPACE@398..399 " " - EBlock@399..404 - L_BRACE@399..400 "{" - SPACE@400..401 " " - DExpr@401..403 - EVar@401..403 - IDENT@401..402 "x" - SPACE@402..403 " " - R_BRACE@403..404 "}" - LINEFEED@404..405 "\n" - R_BRACE@405..406 "}" + Module@0..406 + TopVariant@0..104 + VARIANT_KW@0..7 "variant" + SPACE@7..8 " " + UPPER_IDENT@8..12 "Rope" + SPACE@12..13 " " + L_BRACE@13..14 "{" + TopStruct@14..43 + LINEFEED@14..15 "\n" + SPACE@15..17 " " + STRUCT_KW@17..23 "struct" + SPACE@23..24 " " + UPPER_IDENT@24..28 "Leaf" + SPACE@28..29 " " + L_BRACE@29..30 "{" + SPACE@30..31 " " + StructField@31..42 + IDENT@31..35 "char" + SPACE@35..36 " " + COLON@36..37 ":" + SPACE@37..38 " " + TyInt@38..42 + I32_BUILTIN@38..41 "i32" + SPACE@41..42 " " + R_BRACE@42..43 "}" + COMMA@43..44 "," + TopStruct@44..101 + LINEFEED@44..45 "\n" + SPACE@45..47 " " + STRUCT_KW@47..53 "struct" + SPACE@53..54 " " + UPPER_IDENT@54..58 "Node" + SPACE@58..59 " " + L_BRACE@59..60 "{" + StructField@60..82 + LINEFEED@60..61 "\n" + SPACE@61..65 " " + IDENT@65..73 "children" + SPACE@73..74 " " + COLON@74..75 ":" + SPACE@75..76 " " + TyArray@76..82 + L_BRACKET@76..77 "[" + TyCons@77..81 + UPPER_IDENT@77..81 "Rope" + R_BRACKET@81..82 "]" + COMMA@82..83 "," + StructField@83..97 + LINEFEED@83..84 "\n" + SPACE@84..88 " " + IDENT@88..91 "len" + SPACE@91..92 " " + COLON@92..93 ":" + SPACE@93..94 " " + TyInt@94..97 + I32_BUILTIN@94..97 "i32" + LINEFEED@97..98 "\n" + SPACE@98..100 " " + R_BRACE@100..101 "}" + COMMA@101..102 "," + LINEFEED@102..103 "\n" + R_BRACE@103..104 "}" + TopGlobal@104..140 + LINEFEED@104..105 "\n" + LINEFEED@105..106 "\n" + GLOBAL_KW@106..112 "global" + SPACE@112..113 " " + IDENT@113..114 "_" + SPACE@114..115 " " + EQUALS@115..116 "=" + SPACE@116..117 " " + EStruct@117..140 + Qualifier@117..123 + UPPER_IDENT@117..121 "Rope" + DOUBLE_COLON@121..123 "::" + UPPER_IDENT@123..127 "Leaf" + SPACE@127..128 " " + L_BRACE@128..129 "{" + SPACE@129..130 " " + EStructField@130..139 + IDENT@130..134 "char" + SPACE@134..135 " " + EQUALS@135..136 "=" + SPACE@136..137 " " + ELit@137..139 + LitInt@137..139 + INT_LIT@137..138 "2" + SPACE@138..139 " " + R_BRACE@139..140 "}" + TopGlobal@140..193 + LINEFEED@140..141 "\n" + GLOBAL_KW@141..147 "global" + SPACE@147..148 " " + IDENT@148..152 "rope" + SPACE@152..153 " " + EQUALS@153..154 "=" + SPACE@154..155 " " + EStruct@155..193 + Qualifier@155..161 + UPPER_IDENT@155..159 "Rope" + DOUBLE_COLON@159..161 "::" + UPPER_IDENT@161..165 "Node" + SPACE@165..166 " " + L_BRACE@166..167 "{" + SPACE@167..168 " " + EStructField@168..181 + IDENT@168..176 "children" + SPACE@176..177 " " + EQUALS@177..178 "=" + SPACE@178..179 " " + EArray@179..181 + L_BRACKET@179..180 "[" + R_BRACKET@180..181 "]" + COMMA@181..182 "," + SPACE@182..183 " " + EStructField@183..192 + IDENT@183..186 "len" + SPACE@186..187 " " + EQUALS@187..188 "=" + SPACE@188..189 " " + ELit@189..192 + LitInt@189..192 + INT_LIT@189..191 "10" + SPACE@191..192 " " + R_BRACE@192..193 "}" + TopGlobal@193..243 + LINEFEED@193..194 "\n" + GLOBAL_KW@194..200 "global" + SPACE@200..201 " " + IDENT@201..202 "_" + SPACE@202..203 " " + EQUALS@203..204 "=" + SPACE@204..205 " " + EStruct@205..243 + Qualifier@205..211 + UPPER_IDENT@205..209 "Rope" + DOUBLE_COLON@209..211 "::" + UPPER_IDENT@211..215 "Node" + SPACE@215..216 " " + L_BRACE@216..217 "{" + SPACE@217..218 " " + EStructField@218..231 + IDENT@218..226 "children" + SPACE@226..227 " " + EQUALS@227..228 "=" + SPACE@228..229 " " + EArray@229..231 + L_BRACKET@229..230 "[" + R_BRACKET@230..231 "]" + COMMA@231..232 "," + SPACE@232..233 " " + EStructField@233..242 + IDENT@233..236 "len" + SPACE@236..237 " " + EQUALS@237..238 "=" + SPACE@238..239 " " + ELit@239..242 + LitInt@239..242 + INT_LIT@239..241 "10" + SPACE@241..242 " " + R_BRACE@242..243 "}" + TopGlobal@243..368 + LINEFEED@243..244 "\n" + LINEFEED@244..245 "\n" + GLOBAL_KW@245..251 "global" + SPACE@251..252 " " + IDENT@252..253 "_" + SPACE@253..254 " " + EQUALS@254..255 "=" + SPACE@255..256 " " + EMatch@256..368 + MATCH_KW@256..261 "match" + SPACE@261..262 " " + EVar@262..267 + IDENT@262..266 "rope" + SPACE@266..267 " " + L_BRACE@267..268 "{" + EMatchBranch@268..303 + PatVariant@268..287 + Qualifier@268..277 + LINEFEED@268..269 "\n" + SPACE@269..271 " " + UPPER_IDENT@271..275 "Rope" + DOUBLE_COLON@275..277 "::" + UPPER_IDENT@277..281 "Leaf" + SPACE@281..282 " " + IDENT@282..286 "leaf" + SPACE@286..287 " " + FAT_ARROW@287..289 "=>" + SPACE@289..290 " " + EBlock@290..303 + L_BRACE@290..291 "{" + SPACE@291..292 " " + DExpr@292..302 + EStructIdx@292..302 + EVar@292..296 + IDENT@292..296 "leaf" + DOT@296..297 "." + IDENT@297..301 "char" + SPACE@301..302 " " + R_BRACE@302..303 "}" + COMMA@303..304 "," + EMatchBranch@304..365 + PatVariant@304..323 + Qualifier@304..313 + LINEFEED@304..305 "\n" + SPACE@305..307 " " + UPPER_IDENT@307..311 "Rope" + DOUBLE_COLON@311..313 "::" + UPPER_IDENT@313..317 "Node" + SPACE@317..318 " " + IDENT@318..322 "node" + SPACE@322..323 " " + FAT_ARROW@323..325 "=>" + SPACE@325..326 " " + EBlock@326..365 + L_BRACE@326..327 "{" + SPACE@327..328 " " + DExpr@328..364 + EBinary@328..364 + ECall@328..353 + EVar@328..337 + IDENT@328..337 "array_len" + EArgList@337..353 + L_PAREN@337..338 "(" + EStructIdx@338..351 + EVar@338..342 + IDENT@338..342 "node" + DOT@342..343 "." + IDENT@343..351 "children" + R_PAREN@351..352 ")" + SPACE@352..353 " " + BinOp@353..355 + PLUS@353..354 "+" + SPACE@354..355 " " + EStructIdx@355..364 + EVar@355..359 + IDENT@355..359 "node" + DOT@359..360 "." + IDENT@360..363 "len" + SPACE@363..364 " " + R_BRACE@364..365 "}" + COMMA@365..366 "," + LINEFEED@366..367 "\n" + R_BRACE@367..368 "}" + TopGlobal@368..406 + LINEFEED@368..369 "\n" + LINEFEED@369..370 "\n" + GLOBAL_KW@370..376 "global" + SPACE@376..377 " " + IDENT@377..378 "_" + SPACE@378..379 " " + EQUALS@379..380 "=" + SPACE@380..381 " " + EMatch@381..406 + MATCH_KW@381..386 "match" + SPACE@386..387 " " + ELit@387..390 + LitInt@387..390 + INT_LIT@387..389 "10" + SPACE@389..390 " " + L_BRACE@390..391 "{" + EMatchBranch@391..404 + PatVar@391..396 + LINEFEED@391..392 "\n" + SPACE@392..394 " " + IDENT@394..395 "x" + SPACE@395..396 " " + FAT_ARROW@396..398 "=>" + SPACE@398..399 " " + EBlock@399..404 + L_BRACE@399..400 "{" + SPACE@400..401 " " + DExpr@401..403 + EVar@401..403 + IDENT@401..402 "x" + SPACE@402..403 " " + R_BRACE@403..404 "}" + LINEFEED@404..405 "\n" + R_BRACE@405..406 "}" diff --git a/crates/frontend/tests/snapshots/lib__type_errors@operator_type_mismatch.nemo.snap b/crates/frontend/tests/snapshots/lib__type_errors@operator_type_mismatch.nemo.snap index 7f3da0af..17ee033a 100644 --- a/crates/frontend/tests/snapshots/lib__type_errors@operator_type_mismatch.nemo.snap +++ b/crates/frontend/tests/snapshots/lib__type_errors@operator_type_mismatch.nemo.snap @@ -1,10 +1,9 @@ --- source: crates/frontend/tests/lib.rs -assertion_line: 104 expression: output input_file: crates/frontend/tests/type_errors/operator_type_mismatch.nemo --- -[04] Error: Invalid operator + for lhs of type i32 and rhs of type f32 +[03] Error: Invalid operator + for lhs of type i32 and rhs of type f32 ╭─[source:1:13] │ 2 │ 1 + 2.0 diff --git a/crates/frontend/tests/snapshots/lib__type_errors@unknown_alternative.nemo.snap b/crates/frontend/tests/snapshots/lib__type_errors@unknown_alternative.nemo.snap index 54fcebe9..99b5916b 100644 --- a/crates/frontend/tests/snapshots/lib__type_errors@unknown_alternative.nemo.snap +++ b/crates/frontend/tests/snapshots/lib__type_errors@unknown_alternative.nemo.snap @@ -3,17 +3,17 @@ source: crates/frontend/tests/lib.rs expression: output input_file: crates/frontend/tests/type_errors/unknown_alternative.nemo --- -[07] Error: Unknown type Unknown +[07] Error: Unknown type V::Unknown ╭─[source:2:1] │ 6 │ V::Unknown {}; │ ───┬─── - │ ╰───── Unknown type Unknown + │ ╰───── Unknown type V::Unknown ───╯ -[19] Error: Unknown alternative. V does not have an alternative named Unknown +[07] Error: Unknown type V::Unknown ╭─[source:2:1] │ 9 │ V::Unknown _ => {} │ ───┬─── - │ ╰───── Unknown alternative. V does not have an alternative named Unknown + │ ╰───── Unknown type V::Unknown ───╯ diff --git a/crates/language-server/src/lib.rs b/crates/language-server/src/lib.rs index 4191572a..ac2d2e31 100644 --- a/crates/language-server/src/lib.rs +++ b/crates/language-server/src/lib.rs @@ -1,7 +1,7 @@ pub mod vfs; use frontend::highlight::HighlightKind; -use frontend::ir::NameMap; +use frontend::ir::Ctx; use frontend::CheckError; use line_index::{LineCol, LineIndex, TextRange}; use lsp_server::{Connection, ExtractError, Message, Notification, Request, RequestId, Response}; @@ -135,12 +135,11 @@ fn main_loop( result_id: None, items: file_data .check_result - .errors - .iter() + .errors() .map(|e| { make_diagnostic( - e, - &file_data.check_result.names.name_map, + &e, + &file_data.check_result.ctx, &file_data.line_index, ) }) @@ -274,7 +273,7 @@ fn main_loop( Ok(()) } -fn make_diagnostic(error: &CheckError, name_map: &NameMap, line_index: &LineIndex) -> Diagnostic { +fn make_diagnostic(error: &CheckError, ctx: &Ctx, line_index: &LineIndex) -> Diagnostic { let (start, end) = error.line_col(line_index); Diagnostic { range: Range { @@ -291,7 +290,7 @@ fn make_diagnostic(error: &CheckError, name_map: &NameMap, line_index: &LineInde code: None, code_description: None, source: Some("nemo".to_string()), - message: error.message(name_map), + message: error.message(ctx), related_information: None, tags: None, data: None, @@ -303,10 +302,13 @@ pub const HIGHLIGHT_NAMES: [&str; 7] = [ ]; fn semantic_tokens_new(file_data: &FileData) -> Vec { - let hls = frontend::highlight::highlight( - &file_data.check_result.parse, - &file_data.check_result.occurrences, - ); + let mut hls = vec![]; + for module in &file_data.check_result.modules { + hls.extend(frontend::highlight::highlight( + &module.parse, + &module.occurrences, + )); + } let mut tokens = vec![]; let mut prev_token_line_col: LineCol = LineCol { line: 0, col: 0 }; @@ -362,18 +364,15 @@ fn find_definition(file_data: &FileData, position: &Position) -> Option { line: position.line, col: position.character, })?; - let (_, occurrence) = file_data - .check_result - .occurrences - .iter() - .find(|(node_ptr, _)| node_ptr.0.contains(offset))?; + let (_, occurrence) = file_data.check_result.modules.iter().find_map(|module| { + module + .occurrences + .iter() + .find(|(node_ptr, _)| node_ptr.0.contains(offset)) + })?; let name = occurrence.name(); - file_data - .check_result - .names - .name_map - .get(name) - .and_then(|def| resolve_text_range(&def.at, &file_data.line_index)) + let range = file_data.check_result.ctx.resolve(*name).1; + resolve_text_range(&range, &file_data.line_index) } // fn hover(file_data: &FileData, position: &Position) -> Option { diff --git a/crates/language-server/src/vfs.rs b/crates/language-server/src/vfs.rs index ad136e6d..bc63714f 100644 --- a/crates/language-server/src/vfs.rs +++ b/crates/language-server/src/vfs.rs @@ -1,6 +1,5 @@ use frontend::run_frontend; -use frontend::types::CheckResult; -use frontend::CheckError; +use frontend::FrontendResult; use line_index::LineIndex; use std::collections::HashMap; use std::fs; @@ -10,7 +9,7 @@ use std::path::{Path, PathBuf}; #[derive(Debug)] pub struct FileData { pub content: String, - pub check_result: CheckResult, + pub check_result: FrontendResult, pub line_index: LineIndex, } diff --git a/crates/wasm-lib/Cargo.toml b/crates/wasm-lib/Cargo.toml index 2071f4e1..f4a61784 100644 --- a/crates/wasm-lib/Cargo.toml +++ b/crates/wasm-lib/Cargo.toml @@ -9,6 +9,6 @@ crate-type = ["cdylib"] [dependencies] frontend = { path = "../frontend" } backend = { path = "../backend" } -wasm-bindgen = "0.2.92" +wasm-bindgen = "0.2.93" wasmprinter = "0.209" console_error_panic_hook = "0.1.7" diff --git a/crates/wasm-lib/src/lib.rs b/crates/wasm-lib/src/lib.rs index c39e5514..2dd500f8 100644 --- a/crates/wasm-lib/src/lib.rs +++ b/crates/wasm-lib/src/lib.rs @@ -41,19 +41,31 @@ pub struct CompileResult { pub fn compile(input: &str) -> CompileResult { console_error_panic_hook::set_once(); let check_result = frontend::run_frontend(input); - let highlights = highlight::translate_to_utf16( - input, - highlight::highlight(&check_result.parse, &check_result.occurrences), - ) - .into_iter() - .map(|(start, end, kind)| Highlight::new(start, end, kind)) - .collect(); - let (name_map, result) = match check_result.ir { - Some(ir) if check_result.errors.is_empty() => { - let (wasm, names) = codegen(ir, check_result.names); - (names.name_map, Ok(wasm)) - } - _ => (check_result.names.name_map, Err(check_result.errors)), + let mut highlights = vec![]; + for module in &check_result.modules { + highlights.extend( + highlight::translate_to_utf16( + input, + highlight::highlight(&module.parse, &module.occurrences), + ) + .into_iter() + .map(|(start, end, kind)| Highlight::new(start, end, kind)), + ); + } + let result = if check_result.has_errors() { + let errors = check_result + .errors() + .map(|e| Diagnostic { + message: e.message(&check_result.ctx), + start: e.at().start().into(), + end: e.at().end().into(), + }) + .collect(); + Err(errors) + } else { + let (ctx, ir) = check_result.consume(); + let (wasm, _) = codegen(ir.expect("No IR despite no errors"), ctx); + Ok(wasm) }; match result { @@ -71,14 +83,7 @@ pub fn compile(input: &str) -> CompileResult { wasm: vec![], wast: "".to_string(), highlights, - errors: errors - .into_iter() - .map(|e| Diagnostic { - message: e.message(&name_map), - start: e.at().start().into(), - end: e.at().end().into(), - }) - .collect(), + errors, }, } } diff --git a/design/modules.md b/design/modules.md index 2aa7142a..40a37a16 100644 --- a/design/modules.md +++ b/design/modules.md @@ -14,3 +14,29 @@ means of abstraction (first class modules etc.) import <- wasm imports use <- module imports + +## Syntax +``` +use str + +fn main() { + let s : str::Str = str::new("hello"); + str::print(s) +} + +module option +exports (Option, some, none) + +variant Option[a] {} +fn some[a](t: a) -> Option[a] {} + +module str +exports (Str, len, print_char) + +import print_char : fn (i32) -> unit from print_char + +struct Str {} + +fn len(s: Str) -> Int { } +fn concat(s1 : Str, s2 : Str) -> Str { } +``` diff --git a/playground/examples/strings.nemo b/playground/examples/strings.nemo index 94f21ab7..94b64ca9 100644 --- a/playground/examples/strings.nemo +++ b/playground/examples/strings.nemo @@ -5,14 +5,14 @@ fn main() { let s2 = "😀"; let s3 = concat(s, s2); - print("Byte count:"); + print_bytes("Byte count:"); log(bytes_len(s3)); - print("Codepoint count:"); + print_bytes("Codepoint count:"); log(codepoint_len(s3)); - print("Concatenated:"); - print(s3) + print_bytes("Concatenated:"); + print_bytes(s3) } import log : fn (i32) -> unit from log @@ -85,8 +85,7 @@ fn chars(bs : bytes) -> fn () -> Option[i32] { } } -fn print(s: bytes) { - let next = chars(s); +fn print_chars(next: fn () -> Option[i32]) { while true { match next() { Option::None _ => { @@ -101,6 +100,10 @@ fn print(s: bytes) { }; } +fn print_bytes(s: bytes) { + print_chars(chars(s)) +} + // The following functions aren't used in the example, but they're nice to have fn bytes_eq(a: bytes, b: bytes) -> bool { let len = bytes_len(a); @@ -130,3 +133,52 @@ fn codepoint_len(bs : bytes) -> i32 { }; result } + +struct Str { + buf : bytes, + offset : i32, + len : i32, +} + +fn str_concat(a : Str, b : Str) -> Str { + let len = a.len + b.len; + let buf = bytes_new(0, len); + bytes_copy(buf, 0, a.buf, a.offset, a.len); + bytes_copy(buf, a.len, b.buf, b.offset, b.len); + Str { buf = buf, offset = 0, len = len } +} + +fn str_eq(a : Str, b : Str) -> bool { + if a.len != b.len { + return false; + } else {}; + let i = 0; + while i < a.len { + if bytes_get(a.buf, a.offset + i) != bytes_get(b.buf, b.offset + i) { + return false; + } else {}; + set i = i + 1; + }; + true +} + +fn str_new(buf : bytes) -> Str { + Str { buf = buf, offset = 0, len = bytes_len(buf) } +} + +fn str_chars(s : Str) -> fn () -> Option[i32] { + let offset = MutBox { value = s.offset }; + fn () -> Option[i32] { + if offset.value >= s.offset + s.len { + Option::None {} + } else { + let result = codepoint_at_byte(offset.value, s.buf); + set offset.value = offset.value + result.byte_count; + Option::Some { value = result.codepoint } + } + } +} + +fn str_print(s : Str) { + print_chars(str_chars(s)) +}