chewker done ^w^
This commit is contained in:
		
							parent
							
								
									5f41342a16
								
							
						
					
					
						commit
						d55e9b3c70
					
				
							
								
								
									
										91
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										91
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							| @ -2,6 +2,97 @@ | |||||||
| # It is not intended for manual editing. | # It is not intended for manual editing. | ||||||
| version = 3 | version = 3 | ||||||
| 
 | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "cfg-if" | ||||||
|  | version = "1.0.0" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" | ||||||
|  | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "diff" | ||||||
|  | version = "0.1.13" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" | ||||||
|  | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "getrandom" | ||||||
|  | version = "0.2.15" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" | ||||||
|  | dependencies = [ | ||||||
|  |  "cfg-if", | ||||||
|  |  "libc", | ||||||
|  |  "wasi", | ||||||
|  | ] | ||||||
|  | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "libc" | ||||||
|  | version = "0.2.155" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" | ||||||
|  | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "ppv-lite86" | ||||||
|  | version = "0.2.17" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" | ||||||
|  | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "pretty_assertions" | ||||||
|  | version = "1.4.0" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "af7cee1a6c8a5b9208b3cb1061f10c0cb689087b3d8ce85fb9d2dd7a29b6ba66" | ||||||
|  | dependencies = [ | ||||||
|  |  "diff", | ||||||
|  |  "yansi", | ||||||
|  | ] | ||||||
|  | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "rand" | ||||||
|  | version = "0.8.5" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" | ||||||
|  | dependencies = [ | ||||||
|  |  "libc", | ||||||
|  |  "rand_chacha", | ||||||
|  |  "rand_core", | ||||||
|  | ] | ||||||
|  | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "rand_chacha" | ||||||
|  | version = "0.3.1" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" | ||||||
|  | dependencies = [ | ||||||
|  |  "ppv-lite86", | ||||||
|  |  "rand_core", | ||||||
|  | ] | ||||||
|  | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "rand_core" | ||||||
|  | version = "0.6.4" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" | ||||||
|  | dependencies = [ | ||||||
|  |  "getrandom", | ||||||
|  | ] | ||||||
|  | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "wasi" | ||||||
|  | version = "0.11.0+wasi-snapshot-preview1" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" | ||||||
|  | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "yansi" | ||||||
|  | version = "0.5.1" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" | ||||||
|  | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "yapping" | name = "yapping" | ||||||
| version = "0.1.0" | version = "0.1.0" | ||||||
|  | dependencies = [ | ||||||
|  |  "pretty_assertions", | ||||||
|  |  "rand", | ||||||
|  | ] | ||||||
|  | |||||||
| @ -6,3 +6,5 @@ edition = "2021" | |||||||
| # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||||||
| 
 | 
 | ||||||
| [dependencies] | [dependencies] | ||||||
|  | pretty_assertions = "1.4.0" | ||||||
|  | rand = "0.8.5" | ||||||
|  | |||||||
| @ -2,6 +2,7 @@ | |||||||
| pub struct Node { | pub struct Node { | ||||||
|     pub kind: NodeKind, |     pub kind: NodeKind, | ||||||
|     pub typ: Type, |     pub typ: Type, | ||||||
|  |     pub table_id: usize, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[derive(Clone, PartialEq, Debug)] | #[derive(Clone, PartialEq, Debug)] | ||||||
| @ -36,7 +37,7 @@ pub enum NodeKind { | |||||||
|     Fn { |     Fn { | ||||||
|         subject: Box<Node>, |         subject: Box<Node>, | ||||||
|         params: Vec<Node>, |         params: Vec<Node>, | ||||||
|         return_typ: Box<Node>, |         return_typ: Type, | ||||||
|         body: Box<Node>, |         body: Box<Node>, | ||||||
|     }, |     }, | ||||||
|     Return { |     Return { | ||||||
|  | |||||||
							
								
								
									
										379
									
								
								src/checker.rs
									
									
									
									
									
								
							
							
						
						
									
										379
									
								
								src/checker.rs
									
									
									
									
									
								
							| @ -1,79 +1,130 @@ | |||||||
| #![allow(unused_variables)] | #![allow(unused_variables)] | ||||||
| 
 | 
 | ||||||
|  | use rand::random; | ||||||
|  | 
 | ||||||
| use crate::{ | use crate::{ | ||||||
|     checked::{Node, NodeKind, Type}, |     checked::{Node, NodeKind, Type}, | ||||||
|     hash::hash, |  | ||||||
|     itertewls::Itertewls, |     itertewls::Itertewls, | ||||||
|     parsed, |     parsed, | ||||||
|     sym::Syms, |     sym::Syms, | ||||||
|  |     util::hash, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| pub struct Checker {} | pub trait IdGen { | ||||||
|  |     fn new() -> Self; | ||||||
|  |     fn gen(&mut self) -> u64; | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
|  | pub struct RandIdGen; | ||||||
|  | impl IdGen for RandIdGen { | ||||||
|  |     fn new() -> Self { | ||||||
|  |         Self | ||||||
|  |     } | ||||||
|  |     fn gen(&mut self) -> u64 { | ||||||
|  |         random() | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub struct Checker<FnIdGen: IdGen = RandIdGen> { | ||||||
|  |     syms: Syms, | ||||||
|  |     fn_id_gen: FnIdGen, | ||||||
|  | } | ||||||
| impl Checker { | impl Checker { | ||||||
|     pub fn new() -> Self { |     pub fn new() -> Self { | ||||||
|         Self {} |         Self { | ||||||
|  |             syms: Syms::new(), | ||||||
|  |             fn_id_gen: RandIdGen::new(), | ||||||
|  |         } | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|     pub fn check(&mut self, ast: &Vec<parsed::Node>) -> Vec<Node> { | impl<FnIdGen: IdGen> Checker<FnIdGen> { | ||||||
|         let mut syms = Syms::new(); |     pub fn new_with_fn_id_gen() -> Self { | ||||||
|         ast.into_iter() |         Self { | ||||||
|             .map(|stmt| self.check_expr(stmt, &mut syms)) |             syms: Syms::new(), | ||||||
|             .collect() |             fn_id_gen: FnIdGen::new(), | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn fn_scan<'syms>( |     pub fn check(&mut self, ast: &[parsed::Node]) -> Vec<Node> { | ||||||
|         &mut self, |         self.fn_scan(ast); | ||||||
|         ast: &Vec<parsed::Node>, |         ast.iter().map(|stmt| self.check_expr(stmt)).collect() | ||||||
|         syms: &mut Syms<'syms>, |     } | ||||||
|     ) -> Result<(), ()> { | 
 | ||||||
|  |     fn fn_scan(&mut self, ast: &[parsed::Node]) { | ||||||
|         for node in ast { |         for node in ast { | ||||||
|             match node { |             if let parsed::Node::Fn { | ||||||
|                 parsed::Node::Fn { |  | ||||||
|                 subject, |                 subject, | ||||||
|                 params, |                 params, | ||||||
|                 return_typ, |                 return_typ, | ||||||
|                 body, |                 body, | ||||||
|                 } => { |             } = node | ||||||
|                     let params = params.into_iter().map(|param| { |             { | ||||||
|                         let parsed::Node::Param { subject, typ } = param else { unreachable!() }; |                 let Ok(params) = self.fn_scan_params(params) else { | ||||||
|                         let parsed::Node::Id(id) = subject.as_ref() else { unreachable!() }; |                     continue; | ||||||
|                         let typ = self.check_type(typ.as_ref().ok_or(())?); |                 }; | ||||||
|                         Ok((*id, self.node(NodeKind::Param { subject: Box::new(self.node(NodeKind::Id(*id), Type::Unit)), typ: Some(typ) }, Type::Unit))) |  | ||||||
|                     }).collect::<Result<Vec<_>, _>>()?; |  | ||||||
| 
 | 
 | ||||||
|                 if let Some(id) = params.iter().map(|(id, _)| *id).find_first_duplicate() { |                 if let Some(id) = params.iter().map(|(id, _)| *id).find_first_duplicate() { | ||||||
|                     self.error("redefinition param"); |                     self.error("redefinition param"); | ||||||
|                         return Err(()); |                     continue; | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|  |                 let params = params.into_iter().map(|(_, param)| param).collect(); | ||||||
|  | 
 | ||||||
|                 let parsed::Node::Id(id) = subject.as_ref() else { unreachable!() }; |                 let parsed::Node::Id(id) = subject.as_ref() else { unreachable!() }; | ||||||
| 
 | 
 | ||||||
|                     if syms.defined_locally(*id) { |                 if self.syms.defined_locally(*id) { | ||||||
|                     self.error("redefinition fn"); |                     self.error("redefinition fn"); | ||||||
|                         return Err(()); |                     continue; | ||||||
|                     } |  | ||||||
|                     //syms.define(*id, typ.clone());
 |  | ||||||
|                 } |  | ||||||
|                 _ => {} |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         Ok(()) |  | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|     fn check_expr<'syms>(&mut self, node: &parsed::Node, syms: &mut Syms<'syms>) -> Node { |                 let return_typ = self.check_type(return_typ); | ||||||
|  | 
 | ||||||
|  |                 let typ = Type::Fn { | ||||||
|  |                     id: self.fn_id_gen.gen(), | ||||||
|  |                     params, | ||||||
|  |                     return_typ: Box::new(return_typ), | ||||||
|  |                 }; | ||||||
|  | 
 | ||||||
|  |                 self.syms.define(*id, typ.clone()); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn fn_scan_params(&self, params: &[parsed::Node]) -> Result<Vec<(u64, Node)>, ()> { | ||||||
|  |         params | ||||||
|  |             .iter() | ||||||
|  |             .map(|param| { | ||||||
|  |                 let parsed::Node::Param { subject, typ } = param else { unreachable!() }; | ||||||
|  |                 let parsed::Node::Id(id) = subject.as_ref() else { unreachable!() }; | ||||||
|  |                 let typ = self.check_type(typ.as_ref().ok_or(())?); | ||||||
|  |                 Ok(( | ||||||
|  |                     *id, | ||||||
|  |                     self.node( | ||||||
|  |                         NodeKind::Param { | ||||||
|  |                             subject: Box::new(self.node(NodeKind::Id(*id), Type::Unit)), | ||||||
|  |                             typ: Some(typ), | ||||||
|  |                         }, | ||||||
|  |                         Type::Unit, | ||||||
|  |                     ), | ||||||
|  |                 )) | ||||||
|  |             }) | ||||||
|  |             .collect::<Result<Vec<_>, _>>() | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn check_expr(&mut self, node: &parsed::Node) -> Node { | ||||||
|         match node { |         match node { | ||||||
|             parsed::Node::Error => self.node(NodeKind::Error, Type::Unit), |             parsed::Node::Error => self.node(NodeKind::Error, Type::Unit), | ||||||
|             parsed::Node::Id(id) => { |             parsed::Node::Id(id) => { | ||||||
|                 let Some(sym) = syms.get(*id) else { |                 let Some(sym) = self.syms.get(*id) else { | ||||||
|                     self.error("undefined >~<"); |                     self.error("undefined >~<"); | ||||||
|                     return self.node(NodeKind::Error, Type::Error); |                     return self.node(NodeKind::Error, Type::Error); | ||||||
|                 }; |                 }; | ||||||
|                 self.node(NodeKind::Id(*id), sym.typ) |                 self.node(NodeKind::Id(*id), sym.typ.clone()) | ||||||
|             } |             } | ||||||
|             parsed::Node::Int(value) => self.node( |             parsed::Node::Int(value) => self.node( | ||||||
|                 NodeKind::Int(*value), |                 NodeKind::Int(*value), | ||||||
|                 if *value as i32 > i32::MAX { |                 if *value > i32::MAX as i64 { | ||||||
|                     Type::U32 |                     Type::U32 | ||||||
|                 } else { |                 } else { | ||||||
|                     Type::I32 |                     Type::I32 | ||||||
| @ -81,16 +132,17 @@ impl Checker { | |||||||
|             ), |             ), | ||||||
|             parsed::Node::String(value) => self.node(NodeKind::String(value.clone()), Type::String), |             parsed::Node::String(value) => self.node(NodeKind::String(value.clone()), Type::String), | ||||||
|             parsed::Node::Group(expr) => { |             parsed::Node::Group(expr) => { | ||||||
|                 let expr = self.check_expr(expr, syms); |                 let expr = self.check_expr(expr); | ||||||
|                 let typ = expr.typ.clone(); |                 let typ = expr.typ.clone(); | ||||||
|                 self.node(NodeKind::Group(Box::new(expr)), typ) |                 self.node(NodeKind::Group(Box::new(expr)), typ) | ||||||
|             } |             } | ||||||
|             parsed::Node::Block(stmts) => { |             parsed::Node::Block(stmts) => { | ||||||
|                 let mut child_syms = syms.child(); |                 self.syms.enter_scope(); | ||||||
|                 let stmts = stmts |                 let stmts = stmts | ||||||
|                     .into_iter() |                     .iter() | ||||||
|                     .map(|stmt| self.check_expr(stmt, &mut child_syms)) |                     .map(|stmt| self.check_expr(stmt)) | ||||||
|                     .collect::<Vec<_>>(); |                     .collect::<Vec<_>>(); | ||||||
|  |                 self.syms.leave_scope().unwrap(); | ||||||
|                 let typ = stmts |                 let typ = stmts | ||||||
|                     .last() |                     .last() | ||||||
|                     .map(|stmt| stmt.typ.clone()) |                     .map(|stmt| stmt.typ.clone()) | ||||||
| @ -98,11 +150,11 @@ impl Checker { | |||||||
|                 self.node(NodeKind::Block(stmts), typ) |                 self.node(NodeKind::Block(stmts), typ) | ||||||
|             } |             } | ||||||
|             parsed::Node::Call { subject, args } => { |             parsed::Node::Call { subject, args } => { | ||||||
|                 let subject = Box::new(self.check_expr(subject, syms)); |                 let subject = Box::new(self.check_expr(subject)); | ||||||
| 
 | 
 | ||||||
|                 let args = args |                 let args = args | ||||||
|                     .into_iter() |                     .iter() | ||||||
|                     .map(|arg| self.check_expr(arg, syms)) |                     .map(|arg| self.check_expr(arg)) | ||||||
|                     .collect::<Vec<_>>(); |                     .collect::<Vec<_>>(); | ||||||
|                 let typ = 'br: { |                 let typ = 'br: { | ||||||
|                     match subject.typ.clone() { |                     match subject.typ.clone() { | ||||||
| @ -139,11 +191,9 @@ impl Checker { | |||||||
|                 truthy, |                 truthy, | ||||||
|                 falsy, |                 falsy, | ||||||
|             } => { |             } => { | ||||||
|                 let cond = Box::new(self.check_expr(cond, syms)); |                 let cond = Box::new(self.check_expr(cond)); | ||||||
|                 let truthy = Box::new(self.check_expr(truthy, syms)); |                 let truthy = Box::new(self.check_expr(truthy)); | ||||||
|                 let falsy = falsy |                 let falsy = falsy.as_ref().map(|block| Box::new(self.check_expr(block))); | ||||||
|                     .as_ref() |  | ||||||
|                     .map(|block| Box::new(self.check_expr(block, syms))); |  | ||||||
|                 let typ = 'br: { |                 let typ = 'br: { | ||||||
|                     match falsy.as_ref().map(|block| block.typ.clone()) { |                     match falsy.as_ref().map(|block| block.typ.clone()) { | ||||||
|                         Some(falsy_typ) => { |                         Some(falsy_typ) => { | ||||||
| @ -166,14 +216,15 @@ impl Checker { | |||||||
|                 ) |                 ) | ||||||
|             } |             } | ||||||
|             parsed::Node::Loop { body } => { |             parsed::Node::Loop { body } => { | ||||||
|                 let body = Box::new(self.check_expr(body, &mut syms.child())); |                 self.syms.enter_scope(); | ||||||
|  |                 let body = Box::new(self.check_expr(body)); | ||||||
|                 let typ = body.typ.clone(); |                 let typ = body.typ.clone(); | ||||||
|                 self.node(NodeKind::Loop { body }, typ) |                 self.node(NodeKind::Loop { body }, typ) | ||||||
|             } |             } | ||||||
|             parsed::Node::Break => self.node(NodeKind::Break, Type::Unit), |             parsed::Node::Break => self.node(NodeKind::Break, Type::Unit), | ||||||
|             parsed::Node::Assign { subject, value } => { |             parsed::Node::Assign { subject, value } => { | ||||||
|                 let subject = Box::new(self.check_expr(subject, syms)); |                 let subject = Box::new(self.check_expr(subject)); | ||||||
|                 let value = Box::new(self.check_expr(value, syms)); |                 let value = Box::new(self.check_expr(value)); | ||||||
| 
 | 
 | ||||||
|                 let typ = if !self.compatible(&subject.typ, &value.typ) { |                 let typ = if !self.compatible(&subject.typ, &value.typ) { | ||||||
|                     self.error("incompatible types #3"); |                     self.error("incompatible types #3"); | ||||||
| @ -191,7 +242,7 @@ impl Checker { | |||||||
|                     _ => unreachable!(), |                     _ => unreachable!(), | ||||||
|                 }; |                 }; | ||||||
| 
 | 
 | ||||||
|                 let value = Box::new(self.check_expr(value, syms)); |                 let value = Box::new(self.check_expr(value)); | ||||||
|                 let typ = value.typ.clone(); |                 let typ = value.typ.clone(); | ||||||
| 
 | 
 | ||||||
|                 if subject_typ |                 if subject_typ | ||||||
| @ -205,11 +256,11 @@ impl Checker { | |||||||
| 
 | 
 | ||||||
|                 let subject = match subject.as_ref() { |                 let subject = match subject.as_ref() { | ||||||
|                     parsed::Node::Id(id) => { |                     parsed::Node::Id(id) => { | ||||||
|                         if syms.defined_locally(*id) { |                         if self.syms.defined_locally(*id) { | ||||||
|                             self.error("redefinition"); |                             self.error("redefinition"); | ||||||
|                             return self.node(NodeKind::Error, Type::Error); |                             return self.node(NodeKind::Error, Type::Error); | ||||||
|                         } |                         } | ||||||
|                         syms.define(*id, typ.clone()); |                         self.syms.define(*id, typ.clone()); | ||||||
|                         Box::new(self.node( |                         Box::new(self.node( | ||||||
|                             NodeKind::Param { |                             NodeKind::Param { | ||||||
|                                 subject: Box::new(self.node(NodeKind::Id(*id), Type::Unit)), |                                 subject: Box::new(self.node(NodeKind::Id(*id), Type::Unit)), | ||||||
| @ -225,16 +276,53 @@ impl Checker { | |||||||
|             } |             } | ||||||
|             parsed::Node::Fn { |             parsed::Node::Fn { | ||||||
|                 subject, |                 subject, | ||||||
|                 params, |                 params: _, | ||||||
|                 return_typ, |                 return_typ: _, | ||||||
|                 body, |                 body, | ||||||
|             } => { |             } => { | ||||||
|                 todo!("symbol lookup"); |                 let parsed::Node::Id(id) = subject.as_ref() else { unreachable!() }; | ||||||
|  | 
 | ||||||
|  |                 let Some(sym) = self.syms.get(*id).cloned() else { | ||||||
|  |                     // rejected in fn scanner
 | ||||||
|  |                     return self.node(NodeKind::Error,Type::Error); | ||||||
|  |                 }; | ||||||
|  | 
 | ||||||
|  |                 let Type::Fn { id: fn_id, params, return_typ } = sym.typ else { | ||||||
|  |                     self.error("redefintion"); | ||||||
|  |                     return self.node(NodeKind::Error,Type::Error); | ||||||
|  |                 }; | ||||||
|  | 
 | ||||||
|  |                 self.syms.enter_scope(); | ||||||
|  | 
 | ||||||
|  |                 for param in ¶ms { | ||||||
|  |                     let NodeKind::Param { | ||||||
|  |                         ref subject, | ||||||
|  |                         typ: Some(ref typ), | ||||||
|  |                     } = param.kind else { unreachable!() }; | ||||||
|  |                     let NodeKind::Id(id) = subject.kind else { unreachable!() }; | ||||||
|  |                     self.syms.define(id, typ.clone()); | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 let body = Box::new(self.check_expr(body)); | ||||||
|  | 
 | ||||||
|  |                 if !self.compatible(&return_typ, &body.typ) { | ||||||
|  |                     self.error("return type violated"); | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 self.syms.leave_scope().unwrap(); | ||||||
|  | 
 | ||||||
|  |                 self.node( | ||||||
|  |                     NodeKind::Fn { | ||||||
|  |                         subject: Box::new(self.node(NodeKind::Id(*id), Type::Unit)), | ||||||
|  |                         params, | ||||||
|  |                         return_typ: *return_typ, | ||||||
|  |                         body, | ||||||
|  |                     }, | ||||||
|  |                     Type::Unit, | ||||||
|  |                 ) | ||||||
|             } |             } | ||||||
|             parsed::Node::Return { value } => { |             parsed::Node::Return { value } => { | ||||||
|                 let value = value |                 let value = value.as_ref().map(|value| Box::new(self.check_expr(value))); | ||||||
|                     .as_ref() |  | ||||||
|                     .map(|value| Box::new(self.check_expr(value, syms))); |  | ||||||
|                 let typ = value |                 let typ = value | ||||||
|                     .as_ref() |                     .as_ref() | ||||||
|                     .map(|value| value.typ.clone()) |                     .map(|value| value.typ.clone()) | ||||||
| @ -266,7 +354,11 @@ impl Checker { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn node(&self, kind: NodeKind, typ: Type) -> Node { |     fn node(&self, kind: NodeKind, typ: Type) -> Node { | ||||||
|         Node { kind, typ } |         Node { | ||||||
|  |             kind, | ||||||
|  |             typ, | ||||||
|  |             table_id: self.syms.table_id(), | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn error<S: Into<String>>(&mut self, msg: S) { |     fn error<S: Into<String>>(&mut self, msg: S) { | ||||||
| @ -278,10 +370,24 @@ impl Checker { | |||||||
| #[test] | #[test] | ||||||
| fn test_checker() { | fn test_checker() { | ||||||
|     use crate::parser::Parser; |     use crate::parser::Parser; | ||||||
|     use NodeKind::{Block, Id, Int, Let, Param}; |     use pretty_assertions::assert_eq; | ||||||
|  |     use NodeKind::{Block, Call, Error, Fn, Id, Int, Let, Param, Return}; | ||||||
|     use Type::{Unit, I32}; |     use Type::{Unit, I32}; | ||||||
| 
 | 
 | ||||||
|     let check = |text| Checker::new().check(&Parser::new(text).parse()); |     struct SeqIdGen(u64); | ||||||
|  |     impl IdGen for SeqIdGen { | ||||||
|  |         fn new() -> Self { | ||||||
|  |             Self(0) | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         fn gen(&mut self) -> u64 { | ||||||
|  |             let v = self.0; | ||||||
|  |             self.0 += 1; | ||||||
|  |             v | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     let check = |text| Checker::<SeqIdGen>::new_with_fn_id_gen().check(&Parser::new(text).parse()); | ||||||
| 
 | 
 | ||||||
|     assert_eq!( |     assert_eq!( | ||||||
|         check("let a = 5; a;"), |         check("let a = 5; a;"), | ||||||
| @ -292,26 +398,69 @@ fn test_checker() { | |||||||
|                         kind: Param { |                         kind: Param { | ||||||
|                             subject: Box::new(Node { |                             subject: Box::new(Node { | ||||||
|                                 kind: Id(hash("a")), |                                 kind: Id(hash("a")), | ||||||
|                                 typ: Unit |                                 typ: Unit, | ||||||
|  |                                 table_id: 0, | ||||||
|                             }), |                             }), | ||||||
|                             typ: Some(Unit) |                             typ: Some(Unit) | ||||||
|                         }, |                         }, | ||||||
|                         typ: Unit |                         typ: Unit, | ||||||
|  |                         table_id: 0, | ||||||
|                     }), |                     }), | ||||||
|                     value: Box::new(Node { |                     value: Box::new(Node { | ||||||
|                         kind: Int(5), |                         kind: Int(5), | ||||||
|                         typ: I32 |                         typ: I32, | ||||||
|  |                         table_id: 0, | ||||||
|                     }) |                     }) | ||||||
|                 }, |                 }, | ||||||
|                 typ: I32 |                 typ: I32, | ||||||
|  |                 table_id: 0, | ||||||
|             }, |             }, | ||||||
|             Node { |             Node { | ||||||
|                 kind: Id(hash("a")), |                 kind: Id(hash("a")), | ||||||
|                 typ: I32 |                 typ: I32, | ||||||
|  |                 table_id: 0, | ||||||
|             } |             } | ||||||
|         ] |         ] | ||||||
|     ); |     ); | ||||||
| 
 | 
 | ||||||
|  |     assert_eq!( | ||||||
|  |         check("let a = 5; { a; }"), | ||||||
|  |         vec![ | ||||||
|  |             Node { | ||||||
|  |                 kind: Let { | ||||||
|  |                     subject: Box::new(Node { | ||||||
|  |                         kind: Param { | ||||||
|  |                             subject: Box::new(Node { | ||||||
|  |                                 kind: Id(hash("a")), | ||||||
|  |                                 typ: Unit, | ||||||
|  |                                 table_id: 0, | ||||||
|  |                             }), | ||||||
|  |                             typ: Some(Unit) | ||||||
|  |                         }, | ||||||
|  |                         typ: Unit, | ||||||
|  |                         table_id: 0, | ||||||
|  |                     }), | ||||||
|  |                     value: Box::new(Node { | ||||||
|  |                         kind: Int(5), | ||||||
|  |                         typ: I32, | ||||||
|  |                         table_id: 0, | ||||||
|  |                     }) | ||||||
|  |                 }, | ||||||
|  |                 typ: I32, | ||||||
|  |                 table_id: 0, | ||||||
|  |             }, | ||||||
|  |             Node { | ||||||
|  |                 kind: Block(vec![Node { | ||||||
|  |                     kind: Id(hash("a")), | ||||||
|  |                     typ: I32, | ||||||
|  |                     table_id: 1, | ||||||
|  |                 },]), | ||||||
|  |                 typ: I32, | ||||||
|  |                 table_id: 0, | ||||||
|  |             }, | ||||||
|  |         ] | ||||||
|  |     ); | ||||||
|  | 
 | ||||||
|     assert_eq!( |     assert_eq!( | ||||||
|         check("let a = 5; a; { a; let b = 5; b; } a; b;"), |         check("let a = 5; a; { a; let b = 5; b; } a; b;"), | ||||||
|         vec![ |         vec![ | ||||||
| @ -321,28 +470,34 @@ fn test_checker() { | |||||||
|                         kind: Param { |                         kind: Param { | ||||||
|                             subject: Box::new(Node { |                             subject: Box::new(Node { | ||||||
|                                 kind: Id(hash("a")), |                                 kind: Id(hash("a")), | ||||||
|                                 typ: Unit |                                 typ: Unit, | ||||||
|  |                                 table_id: 0, | ||||||
|                             }), |                             }), | ||||||
|                             typ: Some(Unit) |                             typ: Some(Unit) | ||||||
|                         }, |                         }, | ||||||
|                         typ: Unit |                         typ: Unit, | ||||||
|  |                         table_id: 0, | ||||||
|                     }), |                     }), | ||||||
|                     value: Box::new(Node { |                     value: Box::new(Node { | ||||||
|                         kind: Int(5), |                         kind: Int(5), | ||||||
|                         typ: I32 |                         typ: I32, | ||||||
|  |                         table_id: 0, | ||||||
|                     }) |                     }) | ||||||
|                 }, |                 }, | ||||||
|                 typ: I32 |                 typ: I32, | ||||||
|  |                 table_id: 0, | ||||||
|             }, |             }, | ||||||
|             Node { |             Node { | ||||||
|                 kind: Id(hash("a")), |                 kind: Id(hash("a")), | ||||||
|                 typ: I32 |                 typ: I32, | ||||||
|  |                 table_id: 0, | ||||||
|             }, |             }, | ||||||
|             Node { |             Node { | ||||||
|                 kind: Block(vec![ |                 kind: Block(vec![ | ||||||
|                     Node { |                     Node { | ||||||
|                         kind: Id(hash("a")), |                         kind: Id(hash("a")), | ||||||
|                         typ: I32 |                         typ: I32, | ||||||
|  |                         table_id: 1, | ||||||
|                     }, |                     }, | ||||||
|                     Node { |                     Node { | ||||||
|                         kind: Let { |                         kind: Let { | ||||||
| @ -350,34 +505,92 @@ fn test_checker() { | |||||||
|                                 kind: Param { |                                 kind: Param { | ||||||
|                                     subject: Box::new(Node { |                                     subject: Box::new(Node { | ||||||
|                                         kind: Id(hash("b")), |                                         kind: Id(hash("b")), | ||||||
|                                         typ: Unit |                                         typ: Unit, | ||||||
|  |                                         table_id: 1, | ||||||
|                                     }), |                                     }), | ||||||
|                                     typ: Some(Unit) |                                     typ: Some(Unit) | ||||||
|                                 }, |                                 }, | ||||||
|                                 typ: Unit |                                 typ: Unit, | ||||||
|  |                                 table_id: 1, | ||||||
|                             }), |                             }), | ||||||
|                             value: Box::new(Node { |                             value: Box::new(Node { | ||||||
|                                 kind: Int(5), |                                 kind: Int(5), | ||||||
|                                 typ: I32 |                                 typ: I32, | ||||||
|  |                                 table_id: 1, | ||||||
|                             }) |                             }) | ||||||
|                         }, |                         }, | ||||||
|                         typ: I32 |                         typ: I32, | ||||||
|  |                         table_id: 1, | ||||||
|                     }, |                     }, | ||||||
|                     Node { |                     Node { | ||||||
|                         kind: Id(hash("b")), |                         kind: Id(hash("b")), | ||||||
|                         typ: I32 |                         typ: I32, | ||||||
|  |                         table_id: 1, | ||||||
|                     } |                     } | ||||||
|                 ]), |                 ]), | ||||||
|                 typ: I32 |                 typ: I32, | ||||||
|  |                 table_id: 0, | ||||||
|             }, |             }, | ||||||
|             Node { |             Node { | ||||||
|                 kind: Id(hash("a")), |                 kind: Id(hash("a")), | ||||||
|                 typ: I32 |                 typ: I32, | ||||||
|  |                 table_id: 0, | ||||||
|             }, |             }, | ||||||
|             Node { |             Node { | ||||||
|                 kind: NodeKind::Error, |                 kind: Error, | ||||||
|                 typ: Type::Error |                 typ: Type::Error, | ||||||
|  |                 table_id: 0, | ||||||
|             } |             } | ||||||
|         ] |         ] | ||||||
|     ); |     ); | ||||||
|  | 
 | ||||||
|  |     assert_eq!( | ||||||
|  |         check("fn a() -> i32 { return 0; } \n a();"), | ||||||
|  |         vec![ | ||||||
|  |             Node { | ||||||
|  |                 kind: Fn { | ||||||
|  |                     subject: Box::new(Node { | ||||||
|  |                         kind: Id(hash("a")), | ||||||
|  |                         typ: Unit, | ||||||
|  |                         table_id: 0, | ||||||
|  |                     }), | ||||||
|  |                     params: vec![], | ||||||
|  |                     return_typ: I32, | ||||||
|  |                     body: Box::new(Node { | ||||||
|  |                         kind: Block(vec![Node { | ||||||
|  |                             kind: Return { | ||||||
|  |                                 value: Some(Box::new(Node { | ||||||
|  |                                     kind: Int(0), | ||||||
|  |                                     typ: I32, | ||||||
|  |                                     table_id: 2, | ||||||
|  |                                 }),), | ||||||
|  |                             }, | ||||||
|  |                             typ: I32, | ||||||
|  |                             table_id: 2, | ||||||
|  |                         },],), | ||||||
|  |                         typ: I32, | ||||||
|  |                         table_id: 1, | ||||||
|  |                     }), | ||||||
|  |                 }, | ||||||
|  |                 typ: Unit, | ||||||
|  |                 table_id: 0, | ||||||
|  |             }, | ||||||
|  |             Node { | ||||||
|  |                 kind: Call { | ||||||
|  |                     subject: Box::new(Node { | ||||||
|  |                         kind: Id(hash("a")), | ||||||
|  |                         typ: Type::Fn { | ||||||
|  |                             id: 0, | ||||||
|  |                             params: vec![], | ||||||
|  |                             return_typ: Box::new(I32) | ||||||
|  |                         }, | ||||||
|  |                         table_id: 0 | ||||||
|  |                     }), | ||||||
|  |                     args: vec![] | ||||||
|  |                 }, | ||||||
|  |                 typ: I32, | ||||||
|  |                 table_id: 0, | ||||||
|  |             }, | ||||||
|  |         ] | ||||||
|  |     ); | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,6 +1,6 @@ | |||||||
| use crate::{ | use crate::{ | ||||||
|     hash::hash, |  | ||||||
|     token::{Token, TokenKind, TokenValue}, |     token::{Token, TokenKind, TokenValue}, | ||||||
|  |     util::hash, | ||||||
| }; | }; | ||||||
| use std::{collections::HashMap, str::Chars}; | use std::{collections::HashMap, str::Chars}; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -2,13 +2,13 @@ | |||||||
| 
 | 
 | ||||||
| mod checked; | mod checked; | ||||||
| mod checker; | mod checker; | ||||||
| mod hash; |  | ||||||
| mod itertewls; | mod itertewls; | ||||||
| mod lexer; | mod lexer; | ||||||
| mod parsed; | mod parsed; | ||||||
| mod parser; | mod parser; | ||||||
| mod sym; | mod sym; | ||||||
| mod token; | mod token; | ||||||
|  | mod util; | ||||||
| 
 | 
 | ||||||
| fn main() { | fn main() { | ||||||
|     println!("Hello, world!"); |     println!("Hello, world!"); | ||||||
|  | |||||||
| @ -205,7 +205,7 @@ impl<'a> Parser<'a> { | |||||||
|                     self.step(); |                     self.step(); | ||||||
|                     let mut args = Vec::new(); |                     let mut args = Vec::new(); | ||||||
|                     match self.curr_kind() { |                     match self.curr_kind() { | ||||||
|                         None | Some(TokenKind::LParen) => {} |                         None | Some(TokenKind::RParen) => {} | ||||||
|                         Some(_) => { |                         Some(_) => { | ||||||
|                             args.push(self.parse_expr()); |                             args.push(self.parse_expr()); | ||||||
|                             while let Some(TokenKind::Comma) = self.curr_kind() { |                             while let Some(TokenKind::Comma) = self.curr_kind() { | ||||||
| @ -378,7 +378,7 @@ impl<'a> Parser<'a> { | |||||||
| 
 | 
 | ||||||
| #[test] | #[test] | ||||||
| fn test_parser() { | fn test_parser() { | ||||||
|     use crate::hash::hash; |     use crate::util::hash; | ||||||
|     use Node::*; |     use Node::*; | ||||||
| 
 | 
 | ||||||
|     let parse = |text| Parser::new(text).parse(); |     let parse = |text| Parser::new(text).parse(); | ||||||
|  | |||||||
							
								
								
									
										98
									
								
								src/sym.rs
									
									
									
									
									
								
							
							
						
						
									
										98
									
								
								src/sym.rs
									
									
									
									
									
								
							| @ -9,40 +9,106 @@ pub struct Sym { | |||||||
|     pub typ: Type, |     pub typ: Type, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub struct Syms<'syms> { | #[derive(Debug)] | ||||||
|     parent: Option<&'syms Syms<'syms>>, | pub struct Syms { | ||||||
|     map: HashMap<u64, Sym>, |     tables: Vec<SymTable>, | ||||||
|  |     current_id: usize, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl<'syms> Syms<'syms> { | impl Syms { | ||||||
|     pub fn new() -> Self { |     pub fn new() -> Self { | ||||||
|         Self { |         Self { | ||||||
|             parent: None, |             tables: vec![SymTable::new()], | ||||||
|             map: HashMap::new(), |             current_id: 0, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn child(&'syms self) -> Self { |     pub fn enter_scope(&mut self) { | ||||||
|         Self { |         let new_id = self.tables.len(); | ||||||
|             parent: Some(self), |         self.tables.push(SymTable::from(self.current_id)); | ||||||
|             map: HashMap::new(), |         self.current_id = new_id; | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn get(&self, id: u64) -> Option<Sym> { |     pub fn leave_scope(&mut self) -> Result<(), ()> { | ||||||
|         if let Some(sym) = self.map.get(&id) { |         let parent = self.tables[self.current_id].parent.ok_or(())?; | ||||||
|             return Some(sym.clone()); |         self.current_id = parent; | ||||||
|  |         Ok(()) | ||||||
|     } |     } | ||||||
|         if let Some(parent) = self.parent { | 
 | ||||||
|             return parent.get(id); |     pub fn get(&self, id: u64) -> Option<&Sym> { | ||||||
|  |         self.get_rec(self.current_id, id) | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     fn get_rec(&self, table_id: usize, id: u64) -> Option<&Sym> { | ||||||
|  |         if let Some(sym) = self.tables[table_id].get(id) { | ||||||
|  |             return Some(sym); | ||||||
|  |         } | ||||||
|  |         if let Some(parent_id) = self.tables[table_id].parent { | ||||||
|  |             return self.get_rec(parent_id, id); | ||||||
|  |         }; | ||||||
|         None |         None | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn defined_locally(&self, id: u64) -> bool { |     pub fn defined_locally(&self, id: u64) -> bool { | ||||||
|  |         self.tables[self.current_id].defined(id) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn define(&mut self, id: u64, typ: Type) { | ||||||
|  |         self.tables[self.current_id].define(id, typ); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn table_id(&self) -> usize { | ||||||
|  |         self.current_id | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn view(&self, table_id: usize) -> SymView { | ||||||
|  |         SymView { | ||||||
|  |             syms: self, | ||||||
|  |             current_id: table_id, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub struct SymView<'a> { | ||||||
|  |     syms: &'a Syms, | ||||||
|  |     current_id: usize, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<'a> SymView<'a> { | ||||||
|  |     pub fn get(&self, id: u64) -> Option<&Sym> { | ||||||
|  |         self.syms.get_rec(self.current_id, id) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[derive(Debug)] | ||||||
|  | struct SymTable { | ||||||
|  |     map: HashMap<u64, Sym>, | ||||||
|  |     parent: Option<usize>, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl SymTable { | ||||||
|  |     pub fn new() -> Self { | ||||||
|  |         Self { | ||||||
|  |             map: HashMap::new(), | ||||||
|  |             parent: None, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn from(parent: usize) -> Self { | ||||||
|  |         Self { | ||||||
|  |             map: HashMap::new(), | ||||||
|  |             parent: Some(parent), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn defined(&self, id: u64) -> bool { | ||||||
|         self.map.contains_key(&id) |         self.map.contains_key(&id) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     pub fn get(&self, id: u64) -> Option<&Sym> { | ||||||
|  |         self.map.get(&id) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     pub fn define(&mut self, id: u64, typ: Type) { |     pub fn define(&mut self, id: u64, typ: Type) { | ||||||
|         self.map.insert(id, Sym { id, typ }); |         self.map.insert(id, Sym { id, typ }); | ||||||
|     } |     } | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user