Rotth is a stack based concatenative language highly inspired by Porth
0

Configure Feed

Select the types of activity you want to include in your feed.

Generic structs mainly

Ivan Chinenov (Jun 17, 2022, 3:58 PM +0300) fefdcd91 5b46493b

+638 -421
-6
bar.rh
··· 1 - include "foo.rh" 2 - 3 - struct Har do 4 - a: u64 5 - b: u8 6 - end
-3
baz.rh
··· 1 - proc a: u64 do 2 - 69 3 - end
-1
foo.rh
··· 1 - include "baz.rh"
new_tokenizer

This is a binary file and will not be displayed.

-27
new_tokenizer.rh
··· 1 - include foo::baz::a Har from "bar.rh" 2 - 3 - ; struct Har do 4 - ; a: u64 5 - ; b: u8 6 - ; end 7 - 8 - 9 - proc hartaker &>Har : u64 do 10 - drop 0 11 - end 12 - 13 - proc main: u64 do 14 - a cast &>Har hartaker print 0 15 - end 16 - 17 - proc c1: u64 do 18 - a cast &>Har hartaker print 0 19 - end 20 - 21 - proc c2: u64 do 22 - a cast &>Har hartaker print 0 23 - end 24 - 25 - proc c3: u64 do 26 - a cast &>Har hartaker print 0 27 - end
+2 -2
rotth-lexer/src/lib.rs
··· 105 105 Token::Ptr => write!(f, "&>"), 106 106 Token::CompStop => write!(f, "&?&"), 107 107 Token::FieldAccess => write!(f, "->"), 108 - Token::LBracket => write!(f, "{{"), 109 - Token::RBracket => write!(f, "}}"), 108 + Token::LBracket => write!(f, "["), 109 + Token::RBracket => write!(f, "]"), 110 110 Token::KwInclude => write!(f, "include"), 111 111 Token::KwFrom => write!(f, "from"), 112 112 Token::KwReturn => write!(f, "return"),
+18
rotth-parser/src/ast.rs
··· 164 164 #[derive(Debug, Clone)] 165 165 pub struct Struct { 166 166 pub struct_: Spanned<Keyword>, 167 + pub generics: Option<Spanned<Generics>>, 167 168 pub name: Spanned<Word>, 168 169 pub do_: Spanned<Keyword>, 169 170 pub body: Vec<Spanned<NameTypePair>>, ··· 574 575 #[derive(Debug, Clone)] 575 576 pub struct ResolvedStruct { 576 577 pub name: Spanned<Word>, 578 + pub generics: Vec<Spanned<SmolStr>>, 577 579 pub fields: FnvHashMap<SmolStr, Spanned<NameTypePair>>, 578 580 } 579 581 ··· 704 706 fields.insert(name.clone(), field); 705 707 } 706 708 } 709 + let mut generics = Vec::new(); 710 + if let Some(Spanned { 711 + span: _, 712 + inner: 713 + Generics { 714 + left_bracket: _, 715 + tys, 716 + right_bracket: _, 717 + }, 718 + }) = s.generics 719 + { 720 + for ty in tys { 721 + generics.push(ty.map(|Word(ty)| ty)) 722 + } 723 + } 707 724 if errors.is_empty() { 708 725 Ok(ResolvedStruct { 709 726 name: s.name, 727 + generics, 710 728 fields, 711 729 }) 712 730 } else {
+15 -12
rotth-parser/src/ast/parsers.rs
··· 562 562 }) 563 563 } 564 564 565 - pub(super) fn struct_() -> impl Parser<Token, Spanned<TopLevel>, Error = Simple<Token, Span>> + Clone 566 - { 565 + pub(super) fn struct_() -> impl Parser<Token, Spanned<TopLevel>, Error = Simple<Token, Span>> { 567 566 kw_struct() 567 + .then(generics().or_not()) 568 568 .then(word()) 569 569 .then(kw_do()) 570 570 .then(name_type_pair().repeated()) 571 571 .then(kw_end()) 572 - .map_with_span(|((((struct_, name), do_), body), end), span| Spanned { 573 - span, 574 - inner: TopLevel::Struct(Struct { 575 - struct_, 576 - name, 577 - do_, 578 - body, 579 - end, 580 - }), 581 - }) 572 + .map_with_span( 573 + |(((((struct_, generics), name), do_), body), end), span| Spanned { 574 + span, 575 + inner: TopLevel::Struct(Struct { 576 + struct_, 577 + generics, 578 + name, 579 + do_, 580 + body, 581 + end, 582 + }), 583 + }, 584 + ) 582 585 } 583 586 584 587 pub(super) fn include() -> impl Parser<Token, Spanned<TopLevel>, Error = Simple<Token, Span>> + Clone
+7 -2
rotth-parser/src/hir.rs
··· 322 322 } else { 323 323 unreachable!() 324 324 }; 325 - let ResolvedStruct { name, fields } = &*struct_; 325 + let ResolvedStruct { 326 + name, 327 + fields, 328 + generics, 329 + } = &*struct_; 326 330 let Word(name) = name.inner.clone(); 327 331 let name = self.current_path.child(name); 328 - let mut builder = self.types.new_struct(name); 332 + let generics = generics.iter().map(|t| t.map_ref(|t| t.clone())).collect(); 333 + let mut builder = self.types.new_struct(name, generics); 329 334 for (name, ty) in fields { 330 335 let span = ty.ty.span; 331 336 let ty = ty.inner.ty.inner.clone();
+27 -1
rotth-parser/src/types.rs
··· 28 28 I8, 29 29 } 30 30 31 + impl Primitive { 32 + pub fn size(&self) -> usize { 33 + match self { 34 + Primitive::Void => 0, 35 + Primitive::Bool => 1, 36 + Primitive::Char => 1, 37 + Primitive::U64 => 8, 38 + Primitive::U32 => 4, 39 + Primitive::U16 => 2, 40 + Primitive::U8 => 1, 41 + Primitive::I64 => 8, 42 + Primitive::I32 => 4, 43 + Primitive::I16 => 2, 44 + Primitive::I8 => 1, 45 + } 46 + } 47 + } 48 + 31 49 impl std::fmt::Debug for Type { 32 50 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 33 51 match self { ··· 43 61 44 62 pub struct StructBuilder<'i> { 45 63 index: &'i mut StructIndex, 64 + generics: Vec<Spanned<SmolStr>>, 46 65 fields: FnvHashMap<SmolStr, Spanned<Type>>, 47 66 name: ItemPathBuf, 48 67 } ··· 56 75 pub fn finish(self) { 57 76 let struct_ = Struct { 58 77 name: self.name, 78 + generics: self.generics, 59 79 fields: self.fields, 60 80 }; 61 81 self.index.structs.push(struct_); ··· 68 88 } 69 89 70 90 impl StructIndex { 71 - pub fn new_struct(&'_ mut self, name: ItemPathBuf) -> StructBuilder<'_> { 91 + pub fn new_struct( 92 + &'_ mut self, 93 + name: ItemPathBuf, 94 + generics: Vec<Spanned<SmolStr>>, 95 + ) -> StructBuilder<'_> { 72 96 StructBuilder { 73 97 index: self, 74 98 fields: Default::default(), 99 + generics, 75 100 name, 76 101 } 77 102 } ··· 104 129 #[derive(Debug, PartialEq, Eq, Clone)] 105 130 pub struct Struct { 106 131 pub name: ItemPathBuf, 132 + pub generics: Vec<Spanned<SmolStr>>, 107 133 pub fields: FnvHashMap<SmolStr, Spanned<Type>>, 108 134 }
+19
rotth-src/examples/generic_struct.rh
··· 1 + struct [T] Vec do 2 + len: u64 3 + cap: u64 4 + buf: &>T 5 + end 6 + 7 + mem FOO_BUF do 8 32 * end 8 + 9 + proc main: u64 do 10 + var FOO: Vec 11 + 32 FOO -> cap !u64 12 + FOO -> buf 13 + bind buf: &>&>u64 do 14 + FOO_BUF cast u64 15 + buf cast &>u64 @u64 cast &>u64 16 + !u64 17 + end 18 + 0 19 + end
+6 -4
rotth-src/examples/simplegeneric.rh
··· 1 - include puts putc putu from "../std.rh" 1 + ; include puts putc putu from "../std.rh" 2 2 3 3 proc [T] inc T : T do 4 4 cast u64 1 + cast T 5 5 end 6 6 7 7 proc main: u64 do 8 - 1 inc putu 9 - "\n" puts 10 - 'a' inc putc 8 + ; 1 inc putu 9 + ; "\n" puts 10 + ; 'a' inc putc 11 + 12 + 1 inc print 11 13 0 12 14 end
+157 -138
rotth/src/ctir.rs
··· 1 1 use fnv::FnvHashMap; 2 - use rotth_parser::{path, types::Primitive}; 2 + use rotth_parser::path; 3 3 use smol_str::SmolStr; 4 4 use somok::Somok; 5 5 use std::fmt::Write; 6 6 7 7 use crate::{ 8 - inference::TermId, 8 + inference::{ReifiedType, TermId}, 9 9 tir::{ 10 - Bind, ConcreteType, Cond, CondBranch, FieldAccess, GenId, If, KConst, KMem, KProc, Type, 11 - TypeId, TypecheckedProgram, TypedIr, TypedNode, Var, While, 10 + Bind, ConcreteType, Cond, CondBranch, FieldAccess, GenId, If, KConst, KMem, Type, 11 + TypecheckedProgram, TypedIr, TypedNode, Var, While, 12 12 }, 13 - typecheck, Error, 13 + typecheck::{self, error, ErrorKind}, 14 + Error, 14 15 }; 15 16 use rotth_parser::ast::ItemPathBuf; 16 17 ··· 25 26 26 27 #[derive(Debug)] 27 28 pub struct ConcreteProgram { 28 - pub procs: FnvHashMap<ItemPathBuf, KProc<TypedNode<Type>>>, 29 - pub consts: FnvHashMap<ItemPathBuf, KConst<Type>>, 30 - pub mems: FnvHashMap<ItemPathBuf, KMem<Type>>, 31 - pub vars: FnvHashMap<ItemPathBuf, Var<Type>>, 32 - pub structs: FnvHashMap<TypeId, CStruct>, 29 + pub procs: FnvHashMap<ItemPathBuf, CProc>, 30 + pub consts: FnvHashMap<ItemPathBuf, KConst<ReifiedType>>, 31 + pub mems: FnvHashMap<ItemPathBuf, KMem<ReifiedType>>, 32 + pub vars: FnvHashMap<ItemPathBuf, Var<ReifiedType>>, 33 + // pub structs: FnvHashMap<TypeId, CStruct>, 33 34 } 34 35 35 - fn substitutions(subs: &mut FnvHashMap<GenId, Type>, g: &Type, c: &Type) { 36 + fn substitutions(subs: &mut FnvHashMap<GenId, ReifiedType>, g: &Type, c: &ReifiedType) { 36 37 match (g, c) { 37 - (Type::Generic(g), c @ Type::Concrete(_)) => { 38 + (Type::Generic(g), c) => { 38 39 subs.insert(*g, c.clone()); 39 40 } 40 - (Type::Concrete(g), Type::Concrete(c)) => { 41 - if let (ConcreteType::Ptr(box g), ConcreteType::Ptr(box c)) = (g, c) { 41 + (Type::Concrete(g), c) => { 42 + if let (ConcreteType::Ptr(box g), ReifiedType::Ptr(box c)) = (g, c) { 42 43 substitutions(subs, g, c) 43 44 } 44 45 } 45 - (_, Type::Generic(_)) => unreachable!(), 46 46 } 47 47 } 48 48 49 - #[derive(Debug)] 49 + #[derive(Debug, Clone)] 50 50 pub struct CStruct { 51 51 pub fields: FnvHashMap<SmolStr, Field>, 52 52 } 53 53 54 - #[derive(Debug)] 54 + impl CStruct { 55 + pub fn size(&self) -> usize { 56 + self.fields.iter().map(|(_, f)| f.ty.size()).sum() 57 + } 58 + } 59 + 60 + #[derive(Debug, Clone)] 55 61 pub struct Field { 56 - pub size: usize, 62 + pub ty: ReifiedType, 57 63 pub offset: usize, 58 64 } 59 65 66 + #[derive(Debug, Clone)] 67 + pub struct CProc { 68 + pub generics: FnvHashMap<SmolStr, GenId>, 69 + pub vars: FnvHashMap<ItemPathBuf, ReifiedType>, 70 + pub ins: Vec<ReifiedType>, 71 + pub outs: Vec<ReifiedType>, 72 + pub body: Vec<TypedNode<ReifiedType>>, 73 + } 74 + 60 75 #[derive(Default)] 61 76 pub struct Walker { 62 - procs: FnvHashMap<ItemPathBuf, Option<KProc<TypedNode<Type>>>>, 63 - consts: FnvHashMap<ItemPathBuf, Option<KConst<Type>>>, 64 - mems: FnvHashMap<ItemPathBuf, Option<KMem<Type>>>, 65 - vars: FnvHashMap<ItemPathBuf, Option<Var<Type>>>, 77 + procs: FnvHashMap<ItemPathBuf, Option<CProc>>, 78 + // structs: FnvHashMap<TypeId, CStruct>, 79 + consts: FnvHashMap<ItemPathBuf, Option<KConst<ReifiedType>>>, 80 + mems: FnvHashMap<ItemPathBuf, Option<KMem<ReifiedType>>>, 81 + vars: FnvHashMap<ItemPathBuf, Option<Var<ReifiedType>>>, 66 82 } 67 83 68 84 impl Walker { ··· 76 92 } 77 93 let mut this = Self::default(); 78 94 79 - let body = this.walk_body(&program, &main.body, &main.vars, &Default::default())?; 80 - let main = KProc { 81 - generics: Default::default(), 82 - vars: main.vars.clone(), 83 - span: main.span, 84 - ins: Default::default(), 85 - outs: main.outs.clone(), 86 - body, 87 - }; 95 + let main = this.walk_proc(&program, &path!(main), &Default::default())?; 88 96 this.procs.insert(path!(main), Some(main)); 89 97 let procs = this 90 98 .procs ··· 132 140 }) 133 141 .collect::<Result<_, _>>()?; 134 142 135 - let structs = program 136 - .structs 137 - .into_iter() 138 - .map(|(_, i)| { 139 - (i.id, { 140 - let mut offset = 0; 141 - let mut fields = i 142 - .fields 143 - .into_iter() 144 - .map(|(n, t)| { 145 - let f = match t { 146 - Type::Generic(_) => todo!(), 147 - Type::Concrete(c) => match c { 148 - ConcreteType::Ptr(_) => 8, 149 - ConcreteType::Primitive(p) => match p { 150 - Primitive::Void => 0, 151 - Primitive::Bool => 1, 152 - Primitive::Char => 1, 153 - Primitive::U64 => 8, 154 - Primitive::U32 => 4, 155 - Primitive::U16 => 2, 156 - Primitive::U8 => 1, 157 - Primitive::I64 => 8, 158 - Primitive::I32 => 4, 159 - Primitive::I16 => 2, 160 - Primitive::I8 => 1, 161 - }, 162 - ConcreteType::Custom(_) => todo!(), 163 - }, 164 - }; 165 - (n, f) 166 - }) 167 - .collect::<Vec<_>>(); 168 - fields.sort_by_key(|(_, s)| *s); 169 - let fields = fields 170 - .into_iter() 171 - .map(|(n, s)| { 172 - let f = Field { size: s, offset }; 173 - offset += s; 174 - 175 - (n, f) 176 - }) 177 - .collect(); 178 - 179 - CStruct { fields } 180 - }) 181 - }) 182 - .collect(); 183 - 184 143 Ok(ConcreteProgram { 185 144 procs, 186 145 consts, 187 146 mems, 188 147 vars, 189 - structs, 148 + // structs: this.structs, 190 149 }) 191 150 } else { 192 151 Error::from(ConcreteError::NoEntry).error() 193 152 } 194 153 } 195 154 155 + fn walk_proc( 156 + &mut self, 157 + program: &TypecheckedProgram, 158 + path: &ItemPathBuf, 159 + gensubs: &FnvHashMap<GenId, ReifiedType>, 160 + ) -> Result<CProc, Error> { 161 + let proc = program.procs.get(dbg! {path}).unwrap(); 162 + let body = self.walk_body(program, &proc.body, &proc.vars, gensubs)?; 163 + 164 + let vars = proc 165 + .vars 166 + .iter() 167 + .map(|(p, t)| Ok((p.clone(), program.engine.reify(gensubs, t.ty)?))) 168 + .collect::<Result<_, String>>(); 169 + let vars = match vars { 170 + Ok(vars) => vars, 171 + Err(message) => { 172 + return error( 173 + proc.span, 174 + ErrorKind::UnificationError(message), 175 + "Couldn't reify var types for this proc", 176 + ) 177 + } 178 + }; 179 + 180 + let ins = proc 181 + .ins 182 + .iter() 183 + .map(|t| program.engine.reify(gensubs, *t)) 184 + .collect::<Result<_, String>>(); 185 + let ins = match ins { 186 + Ok(ins) => ins, 187 + Err(message) => { 188 + return error( 189 + proc.span, 190 + ErrorKind::UnificationError(message), 191 + "Couldn't reify ins types for this proc", 192 + ) 193 + } 194 + }; 195 + let outs = proc 196 + .outs 197 + .iter() 198 + .map(|t| program.engine.reify(gensubs, *t)) 199 + .collect::<Result<_, String>>(); 200 + let outs = match outs { 201 + Ok(outs) => outs, 202 + Err(message) => { 203 + return error( 204 + proc.span, 205 + ErrorKind::UnificationError(message), 206 + "Couldn't reify outs types for this proc", 207 + ) 208 + } 209 + }; 210 + 211 + Ok(CProc { 212 + generics: proc.generics.clone(), 213 + vars, 214 + ins, 215 + outs, 216 + body, 217 + }) 218 + } 219 + 196 220 fn walk_body( 197 221 &mut self, 198 222 program: &TypecheckedProgram, 199 223 body: &[TypedNode<TermId>], 200 - local_vars: &FnvHashMap<ItemPathBuf, Var<Type>>, 201 - gensubs: &FnvHashMap<GenId, Type>, 202 - ) -> Result<Vec<TypedNode<Type>>, Error> { 224 + local_vars: &FnvHashMap<ItemPathBuf, Var<TermId>>, 225 + gensubs: &FnvHashMap<GenId, ReifiedType>, 226 + ) -> Result<Vec<TypedNode<ReifiedType>>, Error> { 203 227 let mut concrete_body = Vec::new(); 204 228 for node in body { 205 229 let node = self.walk_node(program, node, local_vars, gensubs)?; ··· 212 236 &mut self, 213 237 program: &TypecheckedProgram, 214 238 node: &TypedNode<TermId>, 215 - local_vars: &FnvHashMap<ItemPathBuf, Var<Type>>, 216 - gensubs: &FnvHashMap<GenId, Type>, 217 - ) -> Result<TypedNode<Type>, Error> { 239 + local_vars: &FnvHashMap<ItemPathBuf, Var<TermId>>, 240 + gensubs: &FnvHashMap<GenId, ReifiedType>, 241 + ) -> Result<TypedNode<ReifiedType>, Error> { 218 242 match &node.node { 219 243 TypedIr::GVarUse(var_name) => { 220 244 if let Some(_var) = program.vars.get(var_name) { 221 245 let ins = node 222 246 .ins 223 247 .iter() 224 - .map(|t| program.engine.reconstruct_substituting(gensubs, *t)) 248 + .map(|t| program.engine.reify(gensubs, *t)) 225 249 .collect::<Result<Vec<_>, _>>() 226 250 .unwrap(); 227 251 let outs = node 228 252 .outs 229 253 .iter() 230 - .map(|t| program.engine.reconstruct_substituting(gensubs, *t)) 254 + .map(|t| program.engine.reify(gensubs, *t)) 231 255 .collect::<Result<Vec<_>, _>>() 232 256 .unwrap(); 233 257 ··· 246 270 let ins = node 247 271 .ins 248 272 .iter() 249 - .map(|t| program.engine.reconstruct_substituting(gensubs, *t)) 273 + .map(|t| program.engine.reify(gensubs, *t)) 250 274 .collect::<Result<Vec<_>, _>>() 251 275 .unwrap(); 252 276 let outs = node 253 277 .outs 254 278 .iter() 255 - .map(|t| program.engine.reconstruct_substituting(gensubs, *t)) 279 + .map(|t| program.engine.reify(gensubs, *t)) 256 280 .collect::<Result<Vec<_>, _>>() 257 281 .unwrap(); 258 282 ··· 271 295 let ins = node 272 296 .ins 273 297 .iter() 274 - .map(|t| program.engine.reconstruct_substituting(gensubs, *t)) 298 + .map(|t| program.engine.reify(gensubs, *t)) 275 299 .collect::<Result<Vec<_>, _>>() 276 300 .unwrap(); 277 301 let outs = node 278 302 .outs 279 303 .iter() 280 - .map(|t| program.engine.reconstruct_substituting(gensubs, *t)) 304 + .map(|t| program.engine.reify(gensubs, *t)) 281 305 .collect::<Result<Vec<_>, _>>() 282 306 .unwrap(); 283 307 284 308 if !self.mems.contains_key(mem_name) { 285 309 self.mems.insert(mem_name.clone(), None); 286 - let body: Vec<TypedNode<Type>> = 310 + let body: Vec<TypedNode<ReifiedType>> = 287 311 self.walk_body(program, &mem.body, local_vars, &Default::default())?; 288 312 let mem = KMem { 289 313 span: mem.span, ··· 303 327 let ins = node 304 328 .ins 305 329 .iter() 306 - .map(|t| program.engine.reconstruct_substituting(gensubs, *t)) 330 + .map(|t| program.engine.reify(gensubs, *t)) 307 331 .collect::<Result<Vec<_>, _>>() 308 332 .unwrap(); 309 333 let outs = node 310 334 .outs 311 335 .iter() 312 - .map(|t| program.engine.reconstruct_substituting(gensubs, *t)) 336 + .map(|t| program.engine.reify(gensubs, *t)) 313 337 .collect::<Result<Vec<_>, _>>() 314 338 .unwrap(); 315 339 ··· 326 350 let ins = node 327 351 .ins 328 352 .iter() 329 - .map(|t| program.engine.reconstruct_substituting(gensubs, *t)) 353 + .map(|t| program.engine.reify(gensubs, *t)) 330 354 .collect::<Result<Vec<_>, _>>() 331 355 .unwrap(); 332 356 let outs = node 333 357 .outs 334 358 .iter() 335 - .map(|t| program.engine.reconstruct_substituting(gensubs, *t)) 359 + .map(|t| program.engine.reify(gensubs, *t)) 336 360 .collect::<Result<Vec<_>, _>>() 337 361 .unwrap(); 338 362 339 363 if !self.consts.contains_key(const_name) { 340 364 self.consts.insert(const_name.clone(), None); 341 - let body: Vec<TypedNode<Type>> = 365 + let body: Vec<TypedNode<ReifiedType>> = 342 366 self.walk_body(program, &const_.body, local_vars, &Default::default())?; 343 367 let const_ = KConst { 344 368 outs: const_.outs.clone(), ··· 358 382 TypedIr::Call(p) => { 359 383 let callee = program.procs.get(p).unwrap(); 360 384 361 - let ins = node.ins.iter().map(|t| { 362 - match program.engine.reconstruct_substituting(gensubs, *t) { 385 + let ins = node 386 + .ins 387 + .iter() 388 + .map(|t| match program.engine.reify(gensubs, *t) { 363 389 Ok(t) => Ok(t), 364 390 Err(e) => typecheck::error( 365 391 node.span, 366 392 typecheck::ErrorKind::UnificationError(e), 367 393 format!("Failure resolving term {t:?}"), 368 394 ), 369 - } 370 - }); 395 + }); 371 396 372 - let outs = node.outs.iter().map(|t| { 373 - match program.engine.reconstruct_substituting(gensubs, *t) { 397 + let outs = node 398 + .outs 399 + .iter() 400 + .map(|t| match program.engine.reify(gensubs, *t) { 374 401 Ok(t) => Ok(t), 375 402 Err(e) => typecheck::error( 376 403 node.span, 377 404 typecheck::ErrorKind::UnificationError(e), 378 405 format!("Failure resolving term {t:?}"), 379 406 ), 380 - } 381 - }); 407 + }); 382 408 383 409 let mut gensubs = FnvHashMap::default(); 384 410 let mut ins2 = Vec::new(); 385 411 let mut outs2 = Vec::new(); 386 412 for (generic, instantiated) in callee.ins.iter().zip(ins) { 387 413 let instantiated = instantiated?; 414 + let generic = program.engine.reconstruct_lossy(*generic); 388 415 ins2.push(instantiated.clone()); 389 - substitutions(&mut gensubs, generic, &instantiated) 416 + substitutions(&mut gensubs, &generic, &instantiated) 390 417 } 391 418 for (generic, instantiated) in callee.outs.iter().zip(outs) { 392 419 let instantiated = instantiated?; 420 + let generic = program.engine.reconstruct_lossy(*generic); 393 421 outs2.push(instantiated.clone()); 394 - substitutions(&mut gensubs, generic, &instantiated) 422 + substitutions(&mut gensubs, &generic, &instantiated) 395 423 } 396 424 397 425 let mut substr = String::new(); ··· 408 436 409 437 if !self.procs.contains_key(&callee_name) { 410 438 self.procs.insert(callee_name.clone(), None); 411 - let body: Vec<TypedNode<Type>> = 412 - self.walk_body(program, &callee.body, &callee.vars, &gensubs)?; 413 - let callee = KProc { 414 - generics: Default::default(), 415 - vars: callee.vars.clone(), 416 - span: callee.span, 417 - ins: ins2.clone(), 418 - outs: outs2.clone(), 419 - body, 420 - }; 439 + let callee = self.walk_proc(program, p, &gensubs)?; 421 440 self.procs.insert(callee_name.clone(), Some(callee)); 422 441 } 423 442 ··· 432 451 let ins = node 433 452 .ins 434 453 .iter() 435 - .map(|t| program.engine.reconstruct_substituting(gensubs, *t)) 454 + .map(|t| program.engine.reify(gensubs, *t)) 436 455 .collect::<Result<Vec<_>, _>>() 437 456 .unwrap(); 438 457 let outs = node 439 458 .outs 440 459 .iter() 441 - .map(|t| program.engine.reconstruct_substituting(gensubs, *t)) 460 + .map(|t| program.engine.reify(gensubs, *t)) 442 461 .collect::<Result<Vec<_>, _>>() 443 462 .unwrap(); 444 463 ··· 453 472 let ins = node 454 473 .ins 455 474 .iter() 456 - .map(|t| program.engine.reconstruct_substituting(gensubs, *t)) 475 + .map(|t| program.engine.reify(gensubs, *t)) 457 476 .collect::<Result<Vec<_>, _>>() 458 477 .unwrap(); 459 478 let outs = node 460 479 .outs 461 480 .iter() 462 - .map(|t| program.engine.reconstruct_substituting(gensubs, *t)) 481 + .map(|t| program.engine.reify(gensubs, *t)) 463 482 .collect::<Result<Vec<_>, _>>() 464 483 .unwrap(); 465 484 let body = self.walk_body(program, body, local_vars, gensubs)?; ··· 478 497 let ins = node 479 498 .ins 480 499 .iter() 481 - .map(|t| program.engine.reconstruct_substituting(gensubs, *t)) 500 + .map(|t| program.engine.reify(gensubs, *t)) 482 501 .collect::<Result<Vec<_>, _>>() 483 502 .unwrap(); 484 503 let outs = node 485 504 .outs 486 505 .iter() 487 - .map(|t| program.engine.reconstruct_substituting(gensubs, *t)) 506 + .map(|t| program.engine.reify(gensubs, *t)) 488 507 .collect::<Result<Vec<_>, _>>() 489 508 .unwrap(); 490 509 let cond = self.walk_body(program, cond, local_vars, gensubs)?; ··· 501 520 let ins = node 502 521 .ins 503 522 .iter() 504 - .map(|t| program.engine.reconstruct_substituting(gensubs, *t)) 523 + .map(|t| program.engine.reify(gensubs, *t)) 505 524 .collect::<Result<Vec<_>, _>>() 506 525 .unwrap(); 507 526 let outs = node 508 527 .outs 509 528 .iter() 510 - .map(|t| program.engine.reconstruct_substituting(gensubs, *t)) 529 + .map(|t| program.engine.reify(gensubs, *t)) 511 530 .collect::<Result<Vec<_>, _>>() 512 531 .unwrap(); 513 532 let truth = self.walk_body(program, truth, local_vars, gensubs)?; ··· 528 547 let ins = node 529 548 .ins 530 549 .iter() 531 - .map(|t| program.engine.reconstruct_substituting(gensubs, *t)) 550 + .map(|t| program.engine.reify(gensubs, *t)) 532 551 .collect::<Result<Vec<_>, _>>() 533 552 .unwrap(); 534 553 let outs = node 535 554 .outs 536 555 .iter() 537 - .map(|t| program.engine.reconstruct_substituting(gensubs, *t)) 556 + .map(|t| program.engine.reify(gensubs, *t)) 538 557 .collect::<Result<Vec<_>, _>>() 539 558 .unwrap(); 540 559 let mut concrete_branches = Vec::new(); ··· 556 575 let ins = node 557 576 .ins 558 577 .iter() 559 - .map(|t| program.engine.reconstruct_substituting(gensubs, *t)) 578 + .map(|t| program.engine.reify(gensubs, *t)) 560 579 .collect::<Result<Vec<_>, _>>() 561 580 .unwrap(); 562 581 let outs = node 563 582 .outs 564 583 .iter() 565 - .map(|t| program.engine.reconstruct_substituting(gensubs, *t)) 584 + .map(|t| program.engine.reify(gensubs, *t)) 566 585 .collect::<Result<Vec<_>, _>>() 567 586 .unwrap(); 568 587 Ok(TypedNode { ··· 576 595 let ins = node 577 596 .ins 578 597 .iter() 579 - .map(|t| program.engine.reconstruct_substituting(gensubs, *t)) 598 + .map(|t| program.engine.reify(gensubs, *t)) 580 599 .collect::<Result<Vec<_>, _>>() 581 600 .unwrap(); 582 601 let outs = node 583 602 .outs 584 603 .iter() 585 - .map(|t| program.engine.reconstruct_substituting(gensubs, *t)) 604 + .map(|t| program.engine.reify(gensubs, *t)) 586 605 .collect::<Result<Vec<_>, _>>() 587 606 .unwrap(); 588 607 Ok(TypedNode { ··· 596 615 let ins = node 597 616 .ins 598 617 .iter() 599 - .map(|t| program.engine.reconstruct_substituting(gensubs, *t)) 618 + .map(|t| program.engine.reify(gensubs, *t)) 600 619 .collect::<Result<Vec<_>, _>>() 601 620 .unwrap(); 602 621 let outs = node 603 622 .outs 604 623 .iter() 605 - .map(|t| program.engine.reconstruct_substituting(gensubs, *t)) 624 + .map(|t| program.engine.reify(gensubs, *t)) 606 625 .collect::<Result<Vec<_>, _>>() 607 626 .unwrap(); 608 627 Ok(TypedNode { ··· 616 635 let ins = node 617 636 .ins 618 637 .iter() 619 - .map(|t| program.engine.reconstruct_substituting(gensubs, *t)) 638 + .map(|t| program.engine.reify(gensubs, *t)) 620 639 .collect::<Result<Vec<_>, _>>() 621 640 .unwrap(); 622 641 let outs = node 623 642 .outs 624 643 .iter() 625 - .map(|t| program.engine.reconstruct_substituting(gensubs, *t)) 644 + .map(|t| program.engine.reify(gensubs, *t)) 626 645 .collect::<Result<Vec<_>, _>>() 627 646 .unwrap(); 628 647 629 648 let ty = match &ins[0] { 630 - Type::Concrete(ConcreteType::Ptr(box t)) => t.clone(), 649 + ReifiedType::Ptr(box t) => t.clone(), 631 650 ty => todo!("{ty:?}"), 632 651 }; 633 652 Ok(TypedNode {
-25
rotth/src/emit.rs
··· 23 23 _start: 24 24 mov QWORD [ret_stack_rsp], ret_stack_end 25 25 mov QWORD [locals_stack_sp], locals_stack_end 26 - mov QWORD [escaping_stack_sp], escaping_stack_end 27 26 ; set up args 28 27 pop rax 29 28 mov [argc], rax ··· 150 149 pop rax 151 150 "}, 152 151 op 153 - )?, 154 - 155 - ReserveEscaping(n) => write!( 156 - sink, 157 - indoc! {" 158 - ; {:?} 159 - mov rax, {} 160 - sub [escaping_stack_sp], rax 161 - "}, 162 - op, n 163 - )?, 164 - PushEscaping(n) => write!( 165 - sink, 166 - indoc! {" 167 - ; {:?} 168 - mov rax, {} 169 - mov rbx, [escaping_stack_sp] 170 - add rbx, rax 171 - push rbx 172 - "}, 173 - op, n 174 152 )?, 175 153 176 154 ReserveLocals(n) => write!( ··· 639 617 locals_stack_sp: resq 1 640 618 locals_stack: resb 65536 641 619 locals_stack_end: 642 - escaping_stack_sp: resq 1 643 - escaping_stack: resb 65536 644 - escaping_stack_end: 645 620 argc: resq 1 646 621 argv: resq 1 647 622 "},
-2
rotth/src/eval.rs
··· 148 148 Op::PushLvar(_) => todo!(), 149 149 Op::ReserveLocals(_) => todo!(), 150 150 Op::FreeLocals(_) => todo!(), 151 - Op::ReserveEscaping(_) => todo!(), 152 - Op::PushEscaping(_) => todo!(), 153 151 } 154 152 i += 1; 155 153 }
+232 -33
rotth/src/inference.rs
··· 1 + use std::rc::Rc; 2 + 1 3 use fnv::FnvHashMap; 2 - use rotth_parser::types::Primitive; 4 + use rotth_parser::{ast::ItemPathBuf, types::Primitive}; 5 + use smol_str::SmolStr; 3 6 4 7 use crate::{ 5 - tir::{ConcreteType, GenId, Type, TypeId}, 8 + ctir::{CStruct, Field}, 9 + tir::{ConcreteType, GenId, KStruct, Type, TypeId}, 6 10 typecheck::{THeap, TypeStack}, 7 11 }; 8 12 ///! # Type inference in less than 100 lines of Rust ··· 51 55 Struct(TypeId), 52 56 } 53 57 58 + #[derive(Clone, Debug)] 59 + pub enum ReifiedType { 60 + Ptr(Box<ReifiedType>), 61 + Primitive(Primitive), 62 + Custom(CStruct), 63 + } 64 + 65 + impl ReifiedType { 66 + pub const BOOL: Self = Self::Primitive(Primitive::Bool); 67 + pub const CHAR: Self = Self::Primitive(Primitive::Char); 68 + pub const U64: Self = Self::Primitive(Primitive::U64); 69 + pub const U32: Self = Self::Primitive(Primitive::U32); 70 + pub const U16: Self = Self::Primitive(Primitive::U16); 71 + pub const U8: Self = Self::Primitive(Primitive::U8); 72 + 73 + pub const I64: Self = Self::Primitive(Primitive::I64); 74 + pub const I32: Self = Self::Primitive(Primitive::I32); 75 + pub const I16: Self = Self::Primitive(Primitive::I16); 76 + pub const I8: Self = Self::Primitive(Primitive::I8); 77 + 78 + pub const VOID: Self = Self::Primitive(Primitive::Void); 79 + 80 + pub fn size(&self) -> usize { 81 + match self { 82 + ReifiedType::Ptr(_) => 8, 83 + ReifiedType::Primitive(p) => p.size(), 84 + ReifiedType::Custom(c) => c.size(), 85 + } 86 + } 87 + } 88 + #[derive(Debug)] 89 + pub struct StructInfo { 90 + pub fields: FnvHashMap<SmolStr, TermId>, 91 + } 92 + 54 93 pub fn type_to_info_with_generic_substitution_table( 55 94 engine: &mut Engine, 56 95 generics: &mut FnvHashMap<GenId, TermId>, 96 + structs: &FnvHashMap<ItemPathBuf, Rc<KStruct>>, 57 97 term: &Type, 58 98 ) -> TypeInfo { 59 99 let mut type_to_id = |term| { 60 - let info = type_to_info_with_generic_substitution_table(engine, generics, term); 100 + let info = type_to_info_with_generic_substitution_table(engine, generics, structs, term); 61 101 engine.insert(info) 62 102 }; 103 + let find_struct = |id| { 104 + structs 105 + .iter() 106 + .find_map(|(_, s)| if s.id == id { Some(s) } else { None }) 107 + .unwrap() 108 + }; 63 109 match term { 64 110 Type::Generic(g) => { 65 111 if let Some(id) = generics.get(g) { ··· 85 131 Primitive::I16 => TypeInfo::I16, 86 132 Primitive::I8 => TypeInfo::I8, 87 133 }, 88 - ConcreteType::Custom(t) => TypeInfo::Struct(*t), 134 + ConcreteType::Custom(t) => { 135 + let s = find_struct(*t); 136 + 137 + let fields = s 138 + .fields 139 + .iter() 140 + .map(|(n, t)| { 141 + let t = type_to_info_with_generic_substitution_table( 142 + engine, generics, structs, t, 143 + ); 144 + let t = engine.insert(t); 145 + (n.clone(), t) 146 + }) 147 + .collect(); 148 + let s = StructInfo { fields }; 149 + engine.structs.insert(*t, s); 150 + 151 + TypeInfo::Struct(*t) 152 + } 89 153 }, 90 154 } 91 155 } 92 156 93 - pub fn type_to_info(engine: &mut Engine, term: &Type, generics_are_unknown: bool) -> TypeInfo { 157 + pub fn type_to_info( 158 + engine: &mut Engine, 159 + structs: &FnvHashMap<ItemPathBuf, Rc<KStruct>>, 160 + term: &Type, 161 + generics_are_unknown: bool, 162 + ) -> TypeInfo { 94 163 let mut type_to_id = |term| { 95 - let info = type_to_info(engine, term, generics_are_unknown); 164 + let info = type_to_info(engine, structs, term, generics_are_unknown); 96 165 engine.insert(info) 97 166 }; 167 + let find_struct = |id| { 168 + structs 169 + .iter() 170 + .find_map(|(_, s)| if s.id == id { Some(&**s) } else { None }) 171 + .unwrap() 172 + }; 98 173 match term { 99 174 Type::Generic(_) if generics_are_unknown => TypeInfo::Unknown, 100 175 Type::Generic(g) => TypeInfo::Generic(*g), ··· 113 188 Primitive::I16 => TypeInfo::I16, 114 189 Primitive::I8 => TypeInfo::I8, 115 190 }, 116 - ConcreteType::Custom(t) => TypeInfo::Struct(*t), 191 + ConcreteType::Custom(t) => { 192 + let s = find_struct(*t); 193 + 194 + let fields = s 195 + .fields 196 + .iter() 197 + .map(|(n, t)| { 198 + let t = type_to_info(engine, structs, t, generics_are_unknown); 199 + let t = engine.insert(t); 200 + (n.clone(), t) 201 + }) 202 + .collect(); 203 + let s = StructInfo { fields }; 204 + engine.structs.insert(*t, s); 205 + 206 + TypeInfo::Struct(*t) 207 + } 117 208 }, 118 209 } 119 210 } ··· 121 212 #[derive(Default)] 122 213 pub struct Engine { 123 214 hash: FnvHashMap<TypeInfo, TermId>, 215 + structs: FnvHashMap<TypeId, StructInfo>, 124 216 vars: Vec<TypeInfo>, 125 217 } 126 218 127 219 impl std::fmt::Debug for Engine { 128 220 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 221 + fn write_info( 222 + info: &TypeInfo, 223 + vars: &[TypeInfo], 224 + structs: &FnvHashMap<TypeId, StructInfo>, 225 + f: &mut std::fmt::Formatter<'_>, 226 + ) -> std::fmt::Result { 227 + match info { 228 + TypeInfo::Unknown => write!(f, "Unknown"), 229 + TypeInfo::Ref(id) => { 230 + write!(f, "Ref({:?})", id.0) 231 + } 232 + TypeInfo::Ptr(id) => { 233 + write!(f, "&>")?; 234 + write_info(&vars[id.0], vars, structs, f) 235 + } 236 + TypeInfo::Generic(g) => { 237 + write!(f, "{:?}", g) 238 + } 239 + TypeInfo::Void => write!(f, "void"), 240 + TypeInfo::Bool => write!(f, "bool"), 241 + TypeInfo::Char => write!(f, "char"), 242 + TypeInfo::U64 => write!(f, "u64"), 243 + TypeInfo::U32 => write!(f, "u32"), 244 + TypeInfo::U16 => write!(f, "u16"), 245 + TypeInfo::U8 => write!(f, "u8"), 246 + TypeInfo::I64 => write!(f, "i64"), 247 + TypeInfo::I32 => write!(f, "i32"), 248 + TypeInfo::I16 => write!(f, "i16"), 249 + TypeInfo::I8 => write!(f, "i8"), 250 + TypeInfo::Struct(s) => { 251 + writeln!(f, "struct {:?}: {{", s)?; 252 + for (n, t) in &structs[s].fields { 253 + write!(f, "\t\t{n}: ")?; 254 + write_info(&vars[t.0], vars, structs, f)?; 255 + writeln!(f)?; 256 + } 257 + write!(f, "\t}}") 258 + } 259 + } 260 + } 261 + 129 262 if f.alternate() { 130 263 writeln!(f, "Engine {{")?; 131 264 } else { 132 265 write!(f, "Engine {{")?; 133 266 } 267 + 134 268 for (id, info) in self.vars.iter().enumerate() { 135 269 if f.alternate() { 136 - writeln!(f, "\t{:?}: {:?},", id, info)?; 270 + write!(f, "\t{:?}: ", id)?; 271 + write_info(info, &self.vars, &self.structs, f)?; 272 + write!(f, ", ")?; 273 + writeln!(f)?; 137 274 } else { 138 275 write!(f, "{:?}: {:?},", id, info)?; 139 276 } 140 277 } 278 + 141 279 write!(f, "}}") 142 280 } 143 281 } ··· 257 395 } 258 396 } 259 397 398 + pub fn get_struct(&self, id: TermId) -> Result<&StructInfo, String> { 399 + use TypeInfo::*; 400 + match self.vars[id.0] { 401 + Struct(id) => Ok(&self.structs[&id]), 402 + _ => Err(format!("{id:?} is not a struct")), 403 + } 404 + } 405 + 406 + pub fn get_struct_ptr(&self, id: TermId) -> Result<&StructInfo, String> { 407 + use TypeInfo::*; 408 + match self.vars[id.0] { 409 + Ptr(id) => self.get_struct(id), 410 + _ => Err(format!("{id:?} is not a pointer")), 411 + } 412 + } 413 + 260 414 /// Attempt to reconstruct a concrete type from the given type term ID. This 261 415 /// may fail if we don't yet have enough information to figure out what the 262 416 /// type is. ··· 282 436 } 283 437 } 284 438 285 - pub fn reconstruct_substituting( 439 + pub fn reconstruct_lossy(&self, id: TermId) -> Type { 440 + use TypeInfo::*; 441 + match self.vars[id.0] { 442 + Unknown => Type::VOID, 443 + Ref(id) => self.reconstruct_lossy(id), 444 + Ptr(v) => Type::Concrete(ConcreteType::Ptr(box self.reconstruct_lossy(v))), 445 + Generic(id) => Type::Generic(id), 446 + Void => Type::VOID, 447 + Bool => Type::BOOL, 448 + Char => Type::CHAR, 449 + U64 => Type::U64, 450 + U32 => Type::U32, 451 + U16 => Type::U16, 452 + U8 => Type::U8, 453 + I64 => Type::I64, 454 + I32 => Type::I32, 455 + I16 => Type::I16, 456 + I8 => Type::I8, 457 + Struct(id) => Type::Concrete(ConcreteType::Custom(id)), 458 + } 459 + } 460 + 461 + pub fn reify( 286 462 &self, 287 - subs: &FnvHashMap<GenId, Type>, 463 + subs: &FnvHashMap<GenId, ReifiedType>, 288 464 id: TermId, 289 - ) -> Result<Type, String> { 465 + ) -> Result<ReifiedType, String> { 290 466 use TypeInfo::*; 291 467 match self.vars[id.0] { 292 468 Unknown => Err("Cannot infer".to_string()), 293 - Ref(id) => self.reconstruct_substituting(subs, id), 294 - Ptr(v) => Ok(Type::Concrete(ConcreteType::Ptr( 295 - box self.reconstruct_substituting(subs, v)?, 296 - ))), 297 - Generic(id) => { 298 - if let Some(t) = subs.get(&id) { 299 - Ok(t.clone()) 300 - } else { 301 - Err("Cannot substitute generic".to_string()) 302 - } 469 + Ref(id) => self.reify(subs, id), 470 + Ptr(v) => Ok(ReifiedType::Ptr(box self.reify(subs, v)?)), 471 + Generic(id) => Ok(subs[&id].clone()), 472 + Void => Ok(ReifiedType::VOID), 473 + Bool => Ok(ReifiedType::BOOL), 474 + Char => Ok(ReifiedType::CHAR), 475 + U64 => Ok(ReifiedType::U64), 476 + U32 => Ok(ReifiedType::U32), 477 + U16 => Ok(ReifiedType::U16), 478 + U8 => Ok(ReifiedType::U8), 479 + I64 => Ok(ReifiedType::I64), 480 + I32 => Ok(ReifiedType::I32), 481 + I16 => Ok(ReifiedType::I16), 482 + I8 => Ok(ReifiedType::I8), 483 + Struct(id) => { 484 + let mut offset = 0; 485 + let fields = self.structs[&id] 486 + .fields 487 + .iter() 488 + .map(|(n, t)| { 489 + let ty = self.reify(subs, *t)?; 490 + 491 + let f_offset = offset; 492 + offset += ty.size(); 493 + Ok(( 494 + n.clone(), 495 + Field { 496 + ty, 497 + offset: f_offset, 498 + }, 499 + )) 500 + }) 501 + .collect::<Result<_, String>>()?; 502 + Ok(ReifiedType::Custom(CStruct { fields })) 303 503 } 304 - Void => Ok(Type::VOID), 305 - Bool => Ok(Type::BOOL), 306 - Char => Ok(Type::CHAR), 307 - U64 => Ok(Type::U64), 308 - U32 => Ok(Type::U32), 309 - U16 => Ok(Type::U16), 310 - U8 => Ok(Type::U8), 311 - I64 => Ok(Type::I64), 312 - I32 => Ok(Type::I32), 313 - I16 => Ok(Type::I16), 314 - I8 => Ok(Type::I8), 315 - Struct(id) => Ok(Type::Concrete(ConcreteType::Custom(id))), 504 + } 505 + } 506 + 507 + pub fn anonymize_generics(&mut self, term: TermId, subs: &FnvHashMap<GenId, TermId>) -> TermId { 508 + match self.vars[term.0] { 509 + TypeInfo::Generic(g) => subs[&g], 510 + TypeInfo::Ptr(id) => { 511 + let inner = self.anonymize_generics(id, subs); 512 + self.insert(TypeInfo::Ptr(inner)) 513 + } 514 + _ => term, 316 515 } 317 516 } 318 517 }
+31 -57
rotth/src/lir.rs
··· 8 8 use Op::*; 9 9 10 10 use crate::{ 11 - ctir::{CStruct, ConcreteProgram}, 11 + ctir::{CProc, ConcreteProgram}, 12 12 eval::eval, 13 - tir::{ 14 - self, Cond, CondBranch, FieldAccess, If, KConst, KMem, KProc, Type, TypeId, TypedIr, 15 - TypedNode, Var, While, 16 - }, 13 + inference::ReifiedType, 14 + tir::{self, Cond, CondBranch, FieldAccess, If, KConst, KMem, Type, TypedIr, TypedNode, While}, 17 15 }; 18 16 19 17 #[derive(Default, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] ··· 43 41 ReadU8, 44 42 WriteU64, 45 43 WriteU8, 46 - 47 - ReserveEscaping(usize), 48 - PushEscaping(usize), 49 44 50 45 ReserveLocals(usize), 51 46 FreeLocals(usize), ··· 90 85 #[derive(Clone)] 91 86 pub enum ComConst { 92 87 Compiled(Vec<Literal>), 93 - NotCompiled(KConst<Type>), 88 + NotCompiled(KConst<ReifiedType>), 94 89 } 95 90 96 91 #[derive(Clone)] 97 92 pub enum ComMem { 98 93 Compiled(usize), 99 - NotCompiled(KMem<Type>), 94 + NotCompiled(KMem<ReifiedType>), 100 95 } 101 96 102 97 #[derive(Clone)] 103 98 pub enum ComVar { 104 99 Compiled(usize), 105 - NotCompiled(Var<Type>), 100 + NotCompiled(ReifiedType), 106 101 } 107 102 103 + #[derive(Default)] 108 104 pub struct Compiler { 109 105 label: usize, 110 106 mangle_table: FnvHashMap<ItemPathBuf, Mangled>, ··· 116 112 strings: Vec<String>, 117 113 bindings: Vec<Vec<ItemPathBuf>>, 118 114 mems: FnvHashMap<ItemPathBuf, ComMem>, 119 - vars: FnvHashMap<ItemPathBuf, ComVar>, 120 - local_vars: FnvHashMap<ItemPathBuf, (usize, Var<Type>)>, 115 + local_vars: FnvHashMap<ItemPathBuf, (usize, ReifiedType)>, 121 116 local_vars_size: usize, 122 117 _escaping_size: usize, 123 - structs: FnvHashMap<TypeId, CStruct>, 118 + // structs: FnvHashMap<TypeId, CStruct>, 124 119 } 125 120 126 121 impl Compiler { 127 122 pub fn compile(program: ConcreteProgram) -> (Vec<Op>, Vec<String>, FnvHashMap<Mangled, usize>) { 128 - let mut this = Self::new(program.structs); 123 + let mut this = Self::default(); 129 124 130 125 this.emit(Call(Mangled("main".into()))); 131 126 this.emit(Exit); ··· 148 143 let mangled = this.mangle(&name); 149 144 this.mangle_table.insert(name.clone(), mangled.clone()); 150 145 this.unmangle_table.insert(mangled.clone(), name.clone()); 151 - this.vars.insert(name, ComVar::NotCompiled(var)); 146 + this.mems.insert(name, ComMem::Compiled(var.ty.size())); 152 147 } 153 148 154 149 let procs = program 155 150 .procs 156 151 .into_iter() 157 152 .map(|(name, proc)| { 153 + this.inc_proc_id(); 158 154 let mangled = this.mangle(&name); 159 155 this.mangle_table.insert(name.clone(), mangled.clone()); 160 156 this.unmangle_table.insert(mangled.clone(), name); ··· 177 173 (this.result, this.strings, mems) 178 174 } 179 175 180 - fn compile_proc(&mut self, name: Mangled, proc: KProc<TypedNode<Type>>) { 176 + fn compile_proc(&mut self, name: Mangled, proc: CProc) { 181 177 self.label = 0; 182 - self.inc_proc_id(); 183 178 self.current_name = name.clone(); 184 179 let label = name; 185 180 self.emit(Proc(label)); 186 181 187 182 let mut i = 0; 188 183 for (name, var) in proc.vars { 189 - let offset = 0; //var.ty.size(&self.structs); 184 + let offset = var.size(); 190 185 self.local_vars.insert(name, (i, var)); 191 186 i += offset 192 187 } ··· 316 311 self.mems.insert(name.to_owned(), ComMem::Compiled(size)); 317 312 } 318 313 319 - fn compile_body(&mut self, body: Vec<TypedNode<Type>>) { 314 + fn compile_body(&mut self, body: Vec<TypedNode<ReifiedType>>) { 320 315 for node in body { 321 316 match node.node { 322 317 TypedIr::Cond(cond) => self.compile_cond(cond), ··· 343 338 self.emit(Push(c)) 344 339 } 345 340 } 346 - TypedIr::MemUse(w) => { 347 - self.compile_mem(&w); 348 - let mangled = self.mangle_table.get(&w).unwrap().clone(); 341 + TypedIr::MemUse(mem_name) => { 342 + self.compile_mem(&mem_name); 343 + let mangled = self.mangle_table.get(&mem_name).unwrap().clone(); 349 344 self.emit(PushMem(mangled)) 350 345 } 351 346 TypedIr::GVarUse(var_name) => { ··· 366 361 .unwrap(); 367 362 self.emit(UseBinding(offset)) 368 363 } 369 - // TypedIr::Path(w) if self.is_lvar(&w) => { 370 - // let &(offset, ref var) = &self.local_vars[&w]; 371 - // self.emit(PushLvar(offset)) 372 - // } 373 - // TypedIr::Path(w) if self.is_gvar(&w) => self.emit(PushMem(w)), 374 364 TypedIr::Call(w) => { 375 365 let mangled = self.mangle_table.get(&w).unwrap().clone(); 376 366 self.emit(Call(mangled)) ··· 421 411 TypedIr::Bind(bind) => self.compile_bind(bind), 422 412 TypedIr::IgnorePattern => unreachable!(), // this is a noop 423 413 TypedIr::FieldAccess(FieldAccess { ty, field }) => { 424 - let ty = if let Type::Concrete(tir::ConcreteType::Custom(ty)) = ty { 425 - &self.structs[&ty] 414 + let ty = if let ReifiedType::Custom(ty) = ty { 415 + ty 426 416 } else { 427 417 todo!("{ty:?}") 428 418 }; ··· 434 424 } 435 425 } 436 426 437 - fn compile_bind(&mut self, bind: tir::Bind<Type>) { 427 + fn compile_bind(&mut self, bind: tir::Bind<ReifiedType>) { 438 428 let mut new_bindings = Vec::new(); 439 429 for binding in bind.bindings.iter().rev() { 440 430 match &binding.inner { ··· 456 446 self.bindings.pop(); 457 447 } 458 448 459 - fn compile_while(&mut self, while_: While<Type>) { 449 + fn compile_while(&mut self, while_: While<ReifiedType>) { 460 450 let cond_label = self.gen_label(); 461 451 let end_label = self.gen_label(); 462 452 self.emit(Label(cond_label.clone())); ··· 467 457 self.emit(Label(end_label)) 468 458 } 469 459 470 - fn compile_if(&mut self, if_: If<Type>) { 460 + fn compile_if(&mut self, if_: If<ReifiedType>) { 471 461 let lie_label = self.gen_label(); 472 462 let mut end_label = None; 473 463 self.emit(JumpF(lie_label.clone())); ··· 486 476 } 487 477 } 488 478 489 - fn compile_cond(&mut self, cond: Cond<Type>) { 479 + fn compile_cond(&mut self, cond: Cond<ReifiedType>) { 490 480 let phi_label = self.gen_label(); 491 481 let num_branches = cond.branches.len() - 1; 492 482 let mut this_branch_label = self.gen_label(); ··· 548 538 strings, 549 539 bindings: Default::default(), 550 540 mems: Default::default(), 551 - vars: Default::default(), 552 541 local_vars: Default::default(), 553 542 local_vars_size: Default::default(), 554 543 _escaping_size: Default::default(), 555 - structs: Default::default(), 556 - } 557 - } 558 - 559 - fn new(structs: FnvHashMap<TypeId, CStruct>) -> Self { 560 - Self { 561 - label: 0, 562 - mangle_table: Default::default(), 563 - unmangle_table: Default::default(), 564 - proc_id: 0, 565 - current_name: Default::default(), 566 - result: Default::default(), 567 - consts: Default::default(), 568 - strings: Default::default(), 569 - bindings: Default::default(), 570 - mems: Default::default(), 571 - vars: Default::default(), 572 - local_vars: Default::default(), 573 - local_vars_size: Default::default(), 574 - _escaping_size: Default::default(), 575 - structs, 544 + // structs: Default::default(), 576 545 } 577 546 } 578 547 ··· 581 550 let name = name 582 551 .iter() 583 552 .intersperse(&joiner) 584 - .map(|s| s.replace(|c: char| !c.is_alphanumeric(), &format!("{}", self.proc_id))) 553 + .map(|s| { 554 + s.replace( 555 + |c: char| !c.is_alphanumeric() && c != '_', 556 + &format!("{}", self.proc_id), 557 + ) 558 + }) 585 559 .collect::<String>(); 586 560 Mangled(name) 587 561 }
+124 -108
rotth/src/tir.rs
··· 10 10 use std::rc::Rc; 11 11 12 12 use crate::{ 13 - inference::{ 14 - type_to_info, type_to_info_with_generic_substitution_table, Engine, TermId, TypeInfo, 15 - }, 13 + inference::{type_to_info, Engine, ReifiedType, TermId, TypeInfo}, 16 14 typecheck::{self, error, ErrorKind, THeap, TypeStack}, 17 15 Error, 18 16 }; ··· 198 196 #[derive(Debug, Clone)] 199 197 pub struct KProc<T> { 200 198 pub generics: FnvHashMap<SmolStr, GenId>, 201 - pub vars: FnvHashMap<ItemPathBuf, Var<Type>>, 199 + pub vars: FnvHashMap<ItemPathBuf, Var<TermId>>, 202 200 pub span: Span, 203 - pub ins: Vec<Type>, 204 - pub outs: Vec<Type>, 201 + pub ins: Vec<TermId>, 202 + pub outs: Vec<TermId>, 205 203 pub body: Vec<T>, 206 204 } 207 205 #[derive(Debug, Clone)] ··· 239 237 #[derive(Debug)] 240 238 pub struct Walker { 241 239 known_procs: FnvHashMap<ItemPathBuf, Rc<KProc<Spanned<Hir>>>>, 242 - known_gvars: FnvHashMap<ItemPathBuf, Var<Type>>, 240 + known_gvars: FnvHashMap<ItemPathBuf, ReifiedType>, 243 241 known_mems: FnvHashMap<ItemPathBuf, Rc<KMem<TermId>>>, 244 242 known_structs: FnvHashMap<ItemPathBuf, Rc<KStruct>>, 245 243 checked_consts: FnvHashMap<ItemPathBuf, Rc<KConst<TermId>>>, ··· 257 255 pub procs: FnvHashMap<ItemPathBuf, KProc<TypedNode<TermId>>>, 258 256 pub consts: FnvHashMap<ItemPathBuf, KConst<TermId>>, 259 257 pub mems: FnvHashMap<ItemPathBuf, KMem<TermId>>, 260 - pub vars: FnvHashMap<ItemPathBuf, Var<Type>>, 258 + pub vars: FnvHashMap<ItemPathBuf, ReifiedType>, 261 259 pub structs: FnvHashMap<ItemPathBuf, KStruct>, 262 260 pub engine: Engine, 263 261 } ··· 282 280 next_gen_id: Default::default(), 283 281 }; 284 282 285 - for ty in this.structs.clone() { 283 + for struct_ in this.structs.clone() { 284 + let generics = struct_ 285 + .generics 286 + .into_iter() 287 + .map(|ty| (ty.inner, this.gen_id())) 288 + .collect(); 286 289 let mut fields = FnvHashMap::default(); 287 - for (n, ty) in &ty.fields { 288 - let ty = this.abstract_to_concrete_type(ty, None)?; 290 + for (n, ty) in &struct_.fields { 291 + let ty = this.abstract_to_concrete_type(ty, Some(&generics))?; 289 292 fields.insert(n.clone(), ty); 290 293 } 291 294 let id = this.type_id(); 292 295 this.known_structs 293 - .insert(ty.name, Rc::new(KStruct { id, fields })); 296 + .insert(struct_.name, Rc::new(KStruct { id, fields })); 294 297 } 298 + 295 299 for (path, def) in ast { 296 300 match def { 297 301 hir::TopLevel::Ref(referee) => { ··· 300 304 hir::TopLevel::Proc(proc) => this.register_proc(path, proc)?, 301 305 hir::TopLevel::Const(const_) => this.register_const(path, const_)?, 302 306 hir::TopLevel::Mem(mem) => this.register_mem(path, mem)?, 303 - hir::TopLevel::Var(_) => todo!(), 307 + hir::TopLevel::Var(var) => this.register_var(path, var)?, 304 308 } 305 309 } 306 310 this.resolve_refs()?; ··· 371 375 let ins = proc 372 376 .ins 373 377 .into_iter() 374 - .map(|ty| self.abstract_to_concrete_type(&ty, Some(&generics))) 375 - .collect::<Result<Vec<_>, _>>()?; 378 + .map(|ty| { 379 + let ty = self.abstract_to_concrete_type(&ty, Some(&generics))?; 380 + let ty = type_to_info(&mut self.engine, &self.known_structs, &ty, false); 381 + let ty = self.engine.insert(ty); 382 + Ok(ty) 383 + }) 384 + .collect::<Result<Vec<_>, Error>>()?; 376 385 let outs = proc 377 386 .outs 378 387 .into_iter() 379 - .map(|ty| self.abstract_to_concrete_type(&ty, Some(&generics))) 380 - .collect::<Result<Vec<_>, _>>()?; 388 + .map(|ty| { 389 + let ty = self.abstract_to_concrete_type(&ty, Some(&generics))?; 390 + let ty = type_to_info(&mut self.engine, &self.known_structs, &ty, false); 391 + let ty = self.engine.insert(ty); 392 + Ok(ty) 393 + }) 394 + .collect::<Result<Vec<_>, Error>>()?; 381 395 let vars = proc 382 396 .vars 383 397 .into_iter() 384 398 .map(|(k, hir::Var { ty, span: _ })| { 385 399 Ok((k, { 386 400 let ty = self.abstract_to_concrete_type(&ty, Some(&generics))?; 401 + let ty = type_to_info(&mut self.engine, &self.known_structs, &ty, true); 402 + let ty = self.engine.insert(ty); 387 403 Var { ty } 388 404 })) 389 405 }) ··· 470 486 } 471 487 } 472 488 489 + fn register_var(&mut self, path: ItemPathBuf, var: hir::Var) -> Result<(), Error> { 490 + if self.known_gvars.contains_key(&path) { 491 + return Ok(()); 492 + } 493 + let hir::Var { ty, span } = var; 494 + let ty = self.abstract_to_concrete_type(&ty, None)?; 495 + let ty = type_to_info(&mut self.engine, &self.known_structs, &ty, true); 496 + let ty = self.engine.insert(ty); 497 + let ty = self.engine.reify(&Default::default(), ty); 498 + let ty = match ty { 499 + Ok(ty) => ty, 500 + Err(message) => { 501 + return error( 502 + span, 503 + ErrorKind::UnificationError(message), 504 + "Can't reify the type of this var", 505 + ) 506 + } 507 + }; 508 + 509 + self.known_gvars.insert(path, ty); 510 + 511 + Ok(()) 512 + } 513 + 473 514 fn register_const(&mut self, path: ItemPathBuf, const_: hir::Const) -> Result<(), Error> { 474 515 if self.checked_consts.contains_key(&path) { 475 516 return Ok(()); ··· 517 558 fn typecheck_proc(&mut self, heap: &mut THeap, path: &ItemPath) -> Result<(), Error> { 518 559 let proc = self.known_procs.get(path).map(|p| (&**p).clone()).unwrap(); 519 560 520 - let mut ins = TypeStack::from_iter( 521 - proc.ins.iter().map(|term| { 522 - let info = type_to_info(&mut self.engine, term, false); 523 - self.engine.insert(info) 524 - }), 525 - heap, 526 - ); 527 - 528 - let outs = proc.outs.iter().map(|term| { 529 - let info = type_to_info(&mut self.engine, term, false); 530 - self.engine.insert(info) 531 - }); 532 - let outs = TypeStack::from_iter(outs, heap); 561 + let mut ins = TypeStack::from_iter(proc.ins.iter().copied(), heap); 562 + let outs = TypeStack::from_iter(proc.outs.iter().copied(), heap); 533 563 534 564 let body = self.typecheck_body( 535 565 &mut ins, ··· 581 611 ); 582 612 } 583 613 let (ins, outs) = { 584 - let mut generics = Default::default(); 614 + let generics = proc 615 + .generics 616 + .iter() 617 + .map(|(_, g)| (*g, self.engine.insert(TypeInfo::Unknown))) 618 + .collect(); 585 619 let expected_ins = proc 586 620 .ins 587 621 .iter() 588 - .map(|ty| { 589 - let info = type_to_info_with_generic_substitution_table( 590 - &mut self.engine, 591 - &mut generics, 592 - ty, 593 - ); 594 - self.engine.insert(info) 595 - }) 622 + .map(|term| self.engine.anonymize_generics(*term, &generics)) 596 623 .rev() 597 624 .collect::<Vec<_>>(); 598 625 for expected_ty in &expected_ins { ··· 615 642 let outs = proc 616 643 .outs 617 644 .iter() 618 - .map(|ty| { 619 - let info = type_to_info_with_generic_substitution_table( 620 - &mut self.engine, 621 - &mut generics, 622 - ty, 623 - ); 624 - self.engine.insert(info) 625 - }) 645 + .map(|term| self.engine.anonymize_generics(*term, &generics)) 646 + .rev() 626 647 .collect::<Vec<_>>(); 627 648 for out_t in &outs { 628 649 ins.push(heap, *out_t); ··· 650 671 .outs 651 672 .iter() 652 673 .map(|term| { 653 - let info = type_to_info(&mut self.engine, term, false); 674 + let info = type_to_info(&mut self.engine, &self.known_structs, term, false); 654 675 self.engine.insert(info) 655 676 }) 656 677 .collect(); ··· 673 694 ins: &mut TypeStack, 674 695 heap: &mut THeap, 675 696 body: &[Spanned<Hir>], 676 - vars: &FnvHashMap<ItemPathBuf, Var<Type>>, 697 + vars: &FnvHashMap<ItemPathBuf, Var<TermId>>, 677 698 bindings_in_scope: Option<&FnvHashMap<ItemPathBuf, TermId>>, 678 699 generics: Option<&FnvHashMap<SmolStr, GenId>>, 679 700 expected_outs: Option<&TypeStack>, ··· 697 718 } 698 719 Hir::Path(path) if vars.contains_key(path) => { 699 720 let var = vars.get(path).unwrap(); 700 - let ty = type_to_info(&mut self.engine, &var.ty, false); 701 - let ty = self.engine.insert(ty); 702 - let ty = self.engine.insert(TypeInfo::Ptr(ty)); 721 + // let ty = type_to_info(&mut self.engine, &self.known_structs, &var.ty, true); 722 + // let ty = self.engine.insert(ty); 723 + let ty = self.engine.insert(TypeInfo::Ptr(var.ty)); 703 724 ins.push(heap, ty); 704 725 TypedNode { 705 726 span: node.span, ··· 840 861 } 841 862 Intrinsic::Cast(o_ty) => { 842 863 let o_type = self.abstract_to_concrete_type(o_ty, generics)?; 843 - let o_type = type_to_info(&mut self.engine, &o_type, false); 864 + let o_type = 865 + type_to_info(&mut self.engine, &self.known_structs, &o_type, false); 844 866 let o_type = self.engine.insert(o_type); 845 867 if let Some(in_t) = ins.pop(heap) { 846 868 ins.push(heap, o_type); ··· 985 1007 } 986 1008 } 987 1009 Intrinsic::CompStop => { 1010 + dbg! {&self.engine}; 988 1011 return error( 989 1012 node.span, 990 1013 ErrorKind::CompStop, ··· 996 1019 .map(|t| self.engine.reconstruct(t)) 997 1020 .collect::<Vec<_>>() 998 1021 ), 999 - ) 1022 + ); 1000 1023 } 1001 1024 Intrinsic::Dump => todo!(), 1002 1025 Intrinsic::Print => { ··· 1169 1192 ); 1170 1193 } 1171 1194 } 1172 - Intrinsic::Mul => todo!(), 1195 + Intrinsic::Mul => { 1196 + if let Some(a) = ins.pop(heap) { 1197 + if let Some(b) = ins.pop(heap) { 1198 + if let Err(msg) = self.engine.unify(a, b) { 1199 + return error( 1200 + node.span, 1201 + ErrorKind::UnificationError(msg), 1202 + "`mul` intrinsic expects it's inputs to be of the same type", 1203 + ); 1204 + } 1205 + w_ins.push(a); 1206 + w_ins.push(a); 1207 + w_outs.push(a); 1208 + ins.push(heap, a); 1209 + } else { 1210 + return error( 1211 + node.span, 1212 + ErrorKind::NotEnoughData, 1213 + "Not enough data in the stack for `mul` intrinsic", 1214 + ); 1215 + } 1216 + } else { 1217 + return error( 1218 + node.span, 1219 + ErrorKind::NotEnoughData, 1220 + "Not enough data in the stack for `mul` intrinsic", 1221 + ); 1222 + } 1223 + } 1173 1224 Intrinsic::Eq => { 1174 1225 if let Some(a) = ins.pop(heap) { 1175 1226 if let Some(b) = ins.pop(heap) { ··· 1370 1421 generics, 1371 1422 ) 1372 1423 .map(|ty| { 1373 - let info = 1374 - type_to_info(&mut self.engine, &ty, false); 1424 + let info = type_to_info( 1425 + &mut self.engine, 1426 + &self.known_structs, 1427 + &ty, 1428 + false, 1429 + ); 1375 1430 self.engine.insert(info) 1376 1431 }); 1377 1432 ··· 1671 1726 w_outs.push(u64) 1672 1727 } 1673 1728 Literal::String(_) => { 1674 - let cptr = 1675 - type_to_info(&mut self.engine, &Type::ptr_to(Type::CHAR), false); 1729 + let cptr = type_to_info( 1730 + &mut self.engine, 1731 + &self.known_structs, 1732 + &Type::ptr_to(Type::CHAR), 1733 + false, 1734 + ); 1676 1735 let cptr = self.engine.insert(cptr); 1677 1736 let u64 = self.engine.insert(TypeInfo::U64); 1678 1737 ins.push(heap, u64); ··· 1720 1779 } 1721 1780 Hir::FieldAccess(hir::FieldAccess { field }) => { 1722 1781 let (in_ty, out_ty) = if let Some(ty) = ins.pop(heap) { 1723 - let out_ty = match self.engine.reconstruct(ty) { 1724 - Ok(ty) => match ty { 1725 - Type::Generic(_) => todo!(), 1726 - Type::Concrete(ty) => match ty { 1727 - ConcreteType::Ptr(box ty) => match ty { 1728 - Type::Generic(_) => todo!(), 1729 - Type::Concrete(ty) => match ty { 1730 - ConcreteType::Ptr(_) => todo!(), 1731 - ConcreteType::Primitive(_) => todo!(), 1732 - ConcreteType::Custom(id) => { 1733 - if let Some(KStruct { id: _, fields }) = 1734 - self.known_structs.iter().find_map(|(_, v)| { 1735 - if v.id == id { 1736 - Some(&**v) 1737 - } else { 1738 - None 1739 - } 1740 - }) 1741 - { 1742 - if let Some(ty) = fields.get(field) { 1743 - let info = type_to_info( 1744 - &mut self.engine, 1745 - ty, 1746 - true, 1747 - ); 1748 - let ty = self.engine.insert(info); 1749 - self.engine.insert(TypeInfo::Ptr(ty)) 1750 - } else { 1751 - return error( 1752 - node.span, 1753 - ErrorKind::Undefined, 1754 - "No suchfield on this type", 1755 - ); 1756 - } 1757 - } else { 1758 - return error( 1759 - node.span, 1760 - ErrorKind::Undefined, 1761 - "Undefined type", 1762 - ); 1763 - } 1764 - } 1765 - }, 1766 - }, 1767 - ConcreteType::Primitive(_) => todo!(), 1768 - ConcreteType::Custom(_) => todo!(), 1769 - }, 1770 - }, 1771 - Err(_) => todo!(), 1782 + let field_ty = match self.engine.get_struct_ptr(ty) { 1783 + Ok(t) => *t.fields.get(field).unwrap(), 1784 + Err(msg) => { 1785 + return error(node.span, ErrorKind::UnsupportedOperation, msg) 1786 + } 1772 1787 }; 1788 + let out_ty = self.engine.insert(TypeInfo::Ptr(field_ty)); 1773 1789 ins.push(heap, out_ty); 1774 1790 (ty, out_ty) 1775 1791 } else {