Separate pass-common code to pass.rs
This commit is contained in:
		
							parent
							
								
									2e99ec3a80
								
							
						
					
					
						commit
						14283afe59
					
				| @ -9,5 +9,5 @@ fn fibonacci(value: i32) -> i32 { | ||||
|     if value < 3 { | ||||
|         return 1; | ||||
|     } | ||||
|     return fibonacci(value - 1) + fibonacci(value - 2); | ||||
|     return 5 + fibonacci(value - 2); | ||||
| } | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| use reid::mir::*; | ||||
| use reid::mir::{self, *}; | ||||
| use reid_lib::Context; | ||||
| 
 | ||||
| fn main() { | ||||
| @ -152,21 +152,22 @@ fn main() { | ||||
|         ), | ||||
|     }; | ||||
| 
 | ||||
|     let mir_context = mir::Context { | ||||
|         modules: vec![Module { | ||||
|             name: "test module".to_owned(), | ||||
|             imports: vec![], | ||||
|             functions: vec![fibonacci, main], | ||||
|         }], | ||||
|     }; | ||||
|     println!("test1"); | ||||
| 
 | ||||
|     let module = Module { | ||||
|         name: "test module".to_owned(), | ||||
|         imports: vec![], | ||||
|         functions: vec![fibonacci, main], | ||||
|     }; | ||||
| 
 | ||||
|     println!("test2"); | ||||
|     let context = Context::new(); | ||||
|     let codegen_module = module.codegen(&context); | ||||
|     let codegen = mir_context.codegen(&context); | ||||
|     println!("test2"); | ||||
| 
 | ||||
|     codegen.compile(); | ||||
|     println!("test3"); | ||||
| 
 | ||||
|     codegen_module.context.compile(); | ||||
|     // match codegen_module.module.print_to_string() {
 | ||||
|     //     Ok(v) => println!("{}", v),
 | ||||
|     //     Err(e) => println!("Err: {:?}", e),
 | ||||
|  | ||||
| @ -3,8 +3,16 @@ use crate::{ | ||||
|     mir::{self, StmtKind, VariableReference}, | ||||
| }; | ||||
| 
 | ||||
| impl mir::Context { | ||||
|     pub fn from(modules: Vec<ast::Module>) -> mir::Context { | ||||
|         mir::Context { | ||||
|             modules: modules.iter().map(|m| m.process()).collect(), | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl ast::Module { | ||||
|     pub fn process(&self) -> mir::Module { | ||||
|     fn process(&self) -> mir::Module { | ||||
|         let mut imports = Vec::new(); | ||||
|         let mut functions = Vec::new(); | ||||
| 
 | ||||
|  | ||||
| @ -7,13 +7,42 @@ use reid_lib::{ | ||||
| 
 | ||||
| use crate::mir::{self, types::ReturnType, TypeKind, VariableReference}; | ||||
| 
 | ||||
| #[derive(Debug)] | ||||
| pub struct CodegenContext<'ctx> { | ||||
|     pub modules: Vec<ModuleCodegen<'ctx>>, | ||||
| } | ||||
| 
 | ||||
| impl<'ctx> CodegenContext<'ctx> { | ||||
|     pub fn compile(&self) { | ||||
|         for module in &self.modules { | ||||
|             module.context.compile(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl mir::Context { | ||||
|     pub fn codegen<'ctx>(&self, context: &'ctx Context) -> CodegenContext<'ctx> { | ||||
|         let mut modules = Vec::new(); | ||||
|         for module in &self.modules { | ||||
|             modules.push(module.codegen(context)); | ||||
|         } | ||||
|         CodegenContext { modules } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub struct ModuleCodegen<'ctx> { | ||||
|     pub context: &'ctx Context, | ||||
|     pub module: Module<'ctx>, | ||||
| } | ||||
| 
 | ||||
| impl<'ctx> std::fmt::Debug for ModuleCodegen<'ctx> { | ||||
|     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||||
|         self.context.fmt(f) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl mir::Module { | ||||
|     pub fn codegen<'ctx>(&self, context: &'ctx Context) -> ModuleCodegen<'ctx> { | ||||
|     fn codegen<'ctx>(&self, context: &'ctx Context) -> ModuleCodegen<'ctx> { | ||||
|         let mut module = context.module(&self.name); | ||||
| 
 | ||||
|         let mut functions = HashMap::new(); | ||||
|  | ||||
| @ -1,3 +1,4 @@ | ||||
| use mir::typecheck::TypeCheck; | ||||
| use reid_lib::Context; | ||||
| 
 | ||||
| use crate::{ast::TopLevelStatement, lexer::Token, token_stream::TokenStream}; | ||||
| @ -22,7 +23,7 @@ pub enum ReidError { | ||||
|     #[error(transparent)] | ||||
|     ParserError(#[from] token_stream::Error), | ||||
|     #[error("Errors during typecheck: {0:?}")] | ||||
|     TypeCheckErrors(Vec<mir::typecheck::Error>), | ||||
|     TypeCheckErrors(Vec<mir::pass::Error<mir::typecheck::ErrorKind>>), | ||||
|     // #[error(transparent)]
 | ||||
|     // CodegenError(#[from] codegen::Error),
 | ||||
| } | ||||
| @ -48,24 +49,24 @@ pub fn compile(source: &str) -> Result<String, ReidError> { | ||||
|     }; | ||||
| 
 | ||||
|     dbg!(&ast_module); | ||||
|     let mut mir_module = ast_module.process(); | ||||
|     let mut mir_context = mir::Context::from(vec![ast_module]); | ||||
| 
 | ||||
|     dbg!(&mir_module); | ||||
|     dbg!(&mir_context); | ||||
| 
 | ||||
|     let state = mir_module.typecheck(); | ||||
|     dbg!(&mir_module); | ||||
|     let state = mir_context.pass(&mut TypeCheck {}); | ||||
|     dbg!(&mir_context); | ||||
|     dbg!(&state); | ||||
|     if !state.errors.is_empty() { | ||||
|         return Err(ReidError::TypeCheckErrors(state.errors)); | ||||
|     } | ||||
| 
 | ||||
|     dbg!(&mir_module); | ||||
|     dbg!(&mir_context); | ||||
| 
 | ||||
|     let mut context = Context::new(); | ||||
|     let codegen_module = mir_module.codegen(&mut context); | ||||
|     let codegen_modules = mir_context.codegen(&mut context); | ||||
| 
 | ||||
|     dbg!(&codegen_module.context); | ||||
|     codegen_module.context.compile(); | ||||
|     dbg!(&codegen_modules); | ||||
|     codegen_modules.compile(); | ||||
| 
 | ||||
|     Ok(String::new()) | ||||
| 
 | ||||
|  | ||||
| @ -3,6 +3,7 @@ | ||||
| /// type-checked beforehand.
 | ||||
| use crate::token_stream::TokenRange; | ||||
| 
 | ||||
| pub mod pass; | ||||
| pub mod typecheck; | ||||
| pub mod types; | ||||
| 
 | ||||
| @ -215,3 +216,8 @@ pub struct Module { | ||||
|     pub imports: Vec<Import>, | ||||
|     pub functions: Vec<FunctionDefinition>, | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug)] | ||||
| pub struct Context { | ||||
|     pub modules: Vec<Module>, | ||||
| } | ||||
|  | ||||
							
								
								
									
										279
									
								
								reid/src/mir/pass.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										279
									
								
								reid/src/mir/pass.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,279 @@ | ||||
| use std::collections::HashMap; | ||||
| use std::error::Error as STDError; | ||||
| 
 | ||||
| use super::*; | ||||
| 
 | ||||
| #[derive(thiserror::Error, Debug, Clone)] | ||||
| pub enum SimplePassError { | ||||
|     #[error("Function not defined: {0}")] | ||||
|     FunctionAlreadyDefined(String), | ||||
|     #[error("Variable not defined: {0}")] | ||||
|     VariableAlreadyDefined(String), | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone)] | ||||
| pub struct Error<TErr: STDError> { | ||||
|     metadata: Metadata, | ||||
|     kind: TErr, | ||||
| } | ||||
| 
 | ||||
| impl<TErr: STDError> std::fmt::Display for Error<TErr> { | ||||
|     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||||
|         write!(f, "Error at {}: {}", self.metadata, self.kind) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl<TErr: STDError> STDError for Error<TErr> { | ||||
|     fn source(&self) -> Option<&(dyn STDError + 'static)> { | ||||
|         self.kind.source() | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Clone, Debug)] | ||||
| pub struct Storage<T: std::fmt::Debug>(HashMap<String, T>); | ||||
| 
 | ||||
| #[derive(Debug)] | ||||
| pub struct State<TErr: STDError> { | ||||
|     pub errors: Vec<Error<TErr>>, | ||||
| } | ||||
| 
 | ||||
| impl<TErr: STDError> State<TErr> { | ||||
|     fn new() -> State<TErr> { | ||||
|         State { | ||||
|             errors: Default::default(), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn or_else<U, T: Into<Metadata> + Clone + Copy>( | ||||
|         &mut self, | ||||
|         result: Result<U, TErr>, | ||||
|         default: U, | ||||
|         meta: T, | ||||
|     ) -> U { | ||||
|         match result { | ||||
|             Ok(t) => t, | ||||
|             Err(e) => { | ||||
|                 self.errors.push(Error { | ||||
|                     metadata: meta.into(), | ||||
|                     kind: e, | ||||
|                 }); | ||||
|                 default | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn ok<T: Into<Metadata> + Clone + Copy, U>( | ||||
|         &mut self, | ||||
|         result: Result<U, TErr>, | ||||
|         meta: T, | ||||
|     ) -> Option<U> { | ||||
|         match result { | ||||
|             Ok(v) => Some(v), | ||||
|             Err(e) => { | ||||
|                 self.errors.push(Error { | ||||
|                     metadata: meta.into(), | ||||
|                     kind: e, | ||||
|                 }); | ||||
|                 None | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl<T: std::fmt::Debug> Default for Storage<T> { | ||||
|     fn default() -> Self { | ||||
|         Self(Default::default()) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl<T: Clone + std::fmt::Debug> Storage<T> { | ||||
|     pub fn set(&mut self, key: String, value: T) -> Result<T, ()> { | ||||
|         if let Some(_) = self.0.get(&key) { | ||||
|             Err(()) | ||||
|         } else { | ||||
|             self.0.insert(key, value.clone()); | ||||
|             Ok(value) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn get(&self, key: &String) -> Option<&T> { | ||||
|         self.0.get(key) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Clone, Default, Debug)] | ||||
| pub struct Scope { | ||||
|     pub function_returns: Storage<ScopeFunction>, | ||||
|     pub variables: Storage<TypeKind>, | ||||
|     /// Hard Return type of this scope, if inside a function
 | ||||
|     pub return_type_hint: Option<TypeKind>, | ||||
| } | ||||
| 
 | ||||
| #[derive(Clone, Debug)] | ||||
| pub struct ScopeFunction { | ||||
|     pub ret: TypeKind, | ||||
|     pub params: Vec<TypeKind>, | ||||
| } | ||||
| 
 | ||||
| impl Scope { | ||||
|     pub fn inner(&self) -> Scope { | ||||
|         Scope { | ||||
|             function_returns: self.function_returns.clone(), | ||||
|             variables: self.variables.clone(), | ||||
|             return_type_hint: self.return_type_hint, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub struct PassState<'st, 'sc, TError: STDError + Clone> { | ||||
|     state: &'st mut State<TError>, | ||||
|     pub scope: &'sc mut Scope, | ||||
|     inner: Vec<Scope>, | ||||
| } | ||||
| 
 | ||||
| impl<'st, 'sc, TError: STDError + Clone> PassState<'st, 'sc, TError> { | ||||
|     fn from(state: &'st mut State<TError>, scope: &'sc mut Scope) -> Self { | ||||
|         PassState { | ||||
|             state, | ||||
|             scope, | ||||
|             inner: Vec::new(), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn or_else<U, TMeta: Into<Metadata> + Clone + Copy>( | ||||
|         &mut self, | ||||
|         result: Result<U, TError>, | ||||
|         default: U, | ||||
|         meta: TMeta, | ||||
|     ) -> U { | ||||
|         self.state.or_else(result, default, meta) | ||||
|     } | ||||
| 
 | ||||
|     pub fn ok<TMeta: Into<Metadata> + Clone + Copy, U>( | ||||
|         &mut self, | ||||
|         result: Result<U, TError>, | ||||
|         meta: TMeta, | ||||
|     ) -> Option<U> { | ||||
|         self.state.ok(result, meta) | ||||
|     } | ||||
| 
 | ||||
|     pub fn inner(&mut self) -> PassState<TError> { | ||||
|         self.inner.push(self.scope.inner()); | ||||
|         let scope = self.inner.last_mut().unwrap(); | ||||
|         PassState { | ||||
|             state: self.state, | ||||
|             scope, | ||||
|             inner: Vec::new(), | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub trait Pass { | ||||
|     type TError: STDError + Clone; | ||||
| 
 | ||||
|     fn module(&mut self, _module: &mut Module, mut _state: PassState<Self::TError>) {} | ||||
|     fn function( | ||||
|         &mut self, | ||||
|         _function: &mut FunctionDefinition, | ||||
|         mut _state: PassState<Self::TError>, | ||||
|     ) { | ||||
|     } | ||||
|     fn block(&mut self, _block: &mut Block, mut _state: PassState<Self::TError>) {} | ||||
|     fn stmt(&mut self, _stmt: &mut Statement, mut _state: PassState<Self::TError>) {} | ||||
|     fn expr(&mut self, _expr: &mut Expression, mut _state: PassState<Self::TError>) {} | ||||
| } | ||||
| 
 | ||||
| impl Context { | ||||
|     pub fn pass<T: Pass>(&mut self, pass: &mut T) -> State<T::TError> { | ||||
|         let mut state = State::new(); | ||||
|         let mut scope = Scope::default(); | ||||
|         for module in &mut self.modules { | ||||
|             module.pass(pass, &mut state, &mut scope); | ||||
|         } | ||||
|         state | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Module { | ||||
|     fn pass<T: Pass>(&mut self, pass: &mut T, state: &mut State<T::TError>, scope: &mut Scope) { | ||||
|         for function in &self.functions { | ||||
|             scope | ||||
|                 .function_returns | ||||
|                 .set( | ||||
|                     function.name.clone(), | ||||
|                     ScopeFunction { | ||||
|                         ret: function.return_type, | ||||
|                         params: function.parameters.iter().map(|v| v.1).collect(), | ||||
|                     }, | ||||
|                 ) | ||||
|                 .ok(); | ||||
|         } | ||||
| 
 | ||||
|         pass.module(self, PassState::from(state, scope)); | ||||
| 
 | ||||
|         for function in &mut self.functions { | ||||
|             function.pass(pass, state, scope); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl FunctionDefinition { | ||||
|     fn pass<T: Pass>(&mut self, pass: &mut T, state: &mut State<T::TError>, scope: &mut Scope) { | ||||
|         for param in &self.parameters { | ||||
|             scope.variables.set(param.0.clone(), param.1).ok(); | ||||
|         } | ||||
| 
 | ||||
|         pass.function(self, PassState::from(state, scope)); | ||||
| 
 | ||||
|         match &mut self.kind { | ||||
|             FunctionDefinitionKind::Local(block, _) => { | ||||
|                 scope.return_type_hint = Some(self.return_type); | ||||
|                 block.pass(pass, state, scope); | ||||
|             } | ||||
|             FunctionDefinitionKind::Extern => {} | ||||
|         }; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Block { | ||||
|     fn pass<T: Pass>(&mut self, pass: &mut T, state: &mut State<T::TError>, scope: &mut Scope) { | ||||
|         let mut scope = scope.inner(); | ||||
| 
 | ||||
|         for statement in &mut self.statements { | ||||
|             statement.pass(pass, state, &mut scope); | ||||
|         } | ||||
| 
 | ||||
|         pass.block(self, PassState::from(state, &mut scope)); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Statement { | ||||
|     fn pass<T: Pass>(&mut self, pass: &mut T, state: &mut State<T::TError>, scope: &mut Scope) { | ||||
|         match &mut self.0 { | ||||
|             StmtKind::Let(_, expression) => { | ||||
|                 expression.pass(pass, state, scope); | ||||
|             } | ||||
|             StmtKind::Import(_) => todo!(), | ||||
|             StmtKind::Expression(expression) => { | ||||
|                 expression.pass(pass, state, scope); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         pass.stmt(self, PassState::from(state, scope)); | ||||
| 
 | ||||
|         match &mut self.0 { | ||||
|             StmtKind::Let(variable_reference, _) => scope | ||||
|                 .variables | ||||
|                 .set(variable_reference.1.clone(), variable_reference.0) | ||||
|                 .ok(), | ||||
|             StmtKind::Import(_) => todo!(), | ||||
|             StmtKind::Expression(_) => None, | ||||
|         }; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Expression { | ||||
|     fn pass<T: Pass>(&mut self, pass: &mut T, state: &mut State<T::TError>, scope: &mut Scope) { | ||||
|         pass.expr(self, PassState::from(state, scope)); | ||||
|     } | ||||
| } | ||||
| @ -1,27 +1,11 @@ | ||||
| use std::{collections::HashMap, convert::Infallible, iter}; | ||||
| use std::{convert::Infallible, iter}; | ||||
| 
 | ||||
| /// This module contains code relevant to doing a type checking pass on the MIR.
 | ||||
| use crate::{mir::*, util::try_all}; | ||||
| use TypeKind::*; | ||||
| use VagueType::*; | ||||
| 
 | ||||
| #[derive(Debug, Clone)] | ||||
| pub struct Error { | ||||
|     metadata: Metadata, | ||||
|     kind: ErrorKind, | ||||
| } | ||||
| 
 | ||||
| impl std::fmt::Display for Error { | ||||
|     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||||
|         write!(f, "Error at {}: {}", self.metadata, self.kind) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl std::error::Error for Error { | ||||
|     fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { | ||||
|         self.kind.source() | ||||
|     } | ||||
| } | ||||
| use super::pass::{Pass, PassState, ScopeFunction}; | ||||
| 
 | ||||
| #[derive(thiserror::Error, Debug, Clone)] | ||||
| pub enum ErrorKind { | ||||
| @ -29,6 +13,8 @@ pub enum ErrorKind { | ||||
|     Null, | ||||
|     #[error("Type is vague: {0}")] | ||||
|     TypeIsVague(VagueType), | ||||
|     #[error("Can not coerce {0} to vague type {1}")] | ||||
|     HintIsVague(TypeKind, VagueType), | ||||
|     #[error("Types {0} and {1} are incompatible")] | ||||
|     TypesIncompatible(TypeKind, TypeKind), | ||||
|     #[error("Variable not defined: {0}")] | ||||
| @ -37,150 +23,42 @@ pub enum ErrorKind { | ||||
|     FunctionNotDefined(String), | ||||
|     #[error("Type is vague: {0}")] | ||||
|     ReturnTypeMismatch(TypeKind, TypeKind), | ||||
|     #[error("Function not defined: {0}")] | ||||
|     FunctionAlreadyDefined(String), | ||||
|     #[error("Variable not defined: {0}")] | ||||
|     VariableAlreadyDefined(String), | ||||
| } | ||||
| 
 | ||||
| #[derive(Clone)] | ||||
| pub struct TypeStorage<T>(HashMap<String, T>); | ||||
| pub struct TypeCheck {} | ||||
| 
 | ||||
| impl<T> Default for TypeStorage<T> { | ||||
|     fn default() -> Self { | ||||
|         Self(Default::default()) | ||||
|     } | ||||
| } | ||||
| impl Pass for TypeCheck { | ||||
|     type TError = ErrorKind; | ||||
| 
 | ||||
| impl<T: Collapsable> TypeStorage<T> { | ||||
|     fn set(&mut self, key: String, value: T) -> Result<T, ErrorKind> { | ||||
|         if let Some(inner) = self.0.get(&key) { | ||||
|             match value.collapse_into(inner) { | ||||
|                 Ok(collapsed) => { | ||||
|                     self.0.insert(key, collapsed.clone()); | ||||
|                     Ok(collapsed) | ||||
|                 } | ||||
|                 Err(e) => Err(e), | ||||
|             } | ||||
|         } else { | ||||
|             self.0.insert(key, value.clone()); | ||||
|             Ok(value) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn get(&self, key: &String) -> Option<&T> { | ||||
|         self.0.get(key) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug)] | ||||
| pub struct State { | ||||
|     pub errors: Vec<Error>, | ||||
| } | ||||
| 
 | ||||
| impl State { | ||||
|     fn new() -> State { | ||||
|         State { | ||||
|             errors: Default::default(), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn or_else<T: Into<Metadata> + Clone + Copy>( | ||||
|         &mut self, | ||||
|         result: Result<TypeKind, ErrorKind>, | ||||
|         default: TypeKind, | ||||
|         meta: T, | ||||
|     ) -> TypeKind { | ||||
|         match result { | ||||
|             Ok(t) => t, | ||||
|             Err(e) => { | ||||
|                 self.errors.push(Error { | ||||
|                     metadata: meta.into(), | ||||
|                     kind: e, | ||||
|                 }); | ||||
|                 default | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn ok<T: Into<Metadata> + Clone + Copy, U>(&mut self, result: Result<U, ErrorKind>, meta: T) { | ||||
|         if let Err(e) = result { | ||||
|             self.errors.push(Error { | ||||
|                 metadata: meta.into(), | ||||
|                 kind: e, | ||||
|             }); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Clone, Default)] | ||||
| pub struct Scope { | ||||
|     function_returns: TypeStorage<ScopeFunction>, | ||||
|     variables: TypeStorage<TypeKind>, | ||||
|     /// Hard Return type of this scope, if inside a function
 | ||||
|     return_type_hint: Option<TypeKind>, | ||||
| } | ||||
| 
 | ||||
| #[derive(Clone)] | ||||
| pub struct ScopeFunction { | ||||
|     ret: TypeKind, | ||||
|     params: Vec<TypeKind>, | ||||
| } | ||||
| 
 | ||||
| impl Scope { | ||||
|     fn inner(&self) -> Scope { | ||||
|         Scope { | ||||
|             function_returns: self.function_returns.clone(), | ||||
|             variables: self.variables.clone(), | ||||
|             return_type_hint: self.return_type_hint, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Clone)] | ||||
| pub enum Inferred { | ||||
|     Type(TypeKind), | ||||
|     Unresolved(u32), | ||||
| } | ||||
| 
 | ||||
| impl Module { | ||||
|     pub fn typecheck(&mut self) -> State { | ||||
|         let mut state = State::new(); | ||||
|         let mut scope = Scope::default(); | ||||
| 
 | ||||
|         for function in &self.functions { | ||||
|             state.ok( | ||||
|                 scope.function_returns.set( | ||||
|                     function.name.clone(), | ||||
|                     ScopeFunction { | ||||
|                         ret: function.return_type, | ||||
|                         params: function.parameters.iter().map(|v| v.1).collect(), | ||||
|                     }, | ||||
|                 ), | ||||
|                 function.signature(), | ||||
|             ); | ||||
|         } | ||||
| 
 | ||||
|         for function in &mut self.functions { | ||||
|             let res = function.typecheck(&mut state, &mut scope); | ||||
|     fn module(&mut self, module: &mut Module, mut state: PassState<ErrorKind>) { | ||||
|         for function in &mut module.functions { | ||||
|             let res = function.typecheck(&mut state); | ||||
|             state.ok(res, function.block_meta()); | ||||
|         } | ||||
| 
 | ||||
|         state | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl FunctionDefinition { | ||||
|     fn typecheck(&mut self, state: &mut State, scope: &mut Scope) -> Result<TypeKind, ErrorKind> { | ||||
|     fn typecheck(&mut self, state: &mut PassState<ErrorKind>) -> Result<TypeKind, ErrorKind> { | ||||
|         for param in &self.parameters { | ||||
|             let param_t = state.or_else(param.1.assert_known(), Vague(Unknown), self.signature()); | ||||
|             state.ok( | ||||
|                 scope.variables.set(param.0.clone(), param_t), | ||||
|                 self.signature(), | ||||
|             ); | ||||
|             let res = state | ||||
|                 .scope | ||||
|                 .variables | ||||
|                 .set(param.0.clone(), param_t) | ||||
|                 .or(Err(ErrorKind::VariableAlreadyDefined(param.0.clone()))); | ||||
|             state.ok(res, self.signature()); | ||||
|         } | ||||
| 
 | ||||
|         let return_type = self.return_type.clone(); | ||||
|         let inferred = match &mut self.kind { | ||||
|             FunctionDefinitionKind::Local(block, _) => { | ||||
|                 scope.return_type_hint = Some(self.return_type); | ||||
|                 block.typecheck(state, scope, Some(return_type)) | ||||
|                 state.scope.return_type_hint = Some(self.return_type); | ||||
|                 block.typecheck(state, Some(return_type)) | ||||
|             } | ||||
|             FunctionDefinitionKind::Extern => Ok(Vague(Unknown)), | ||||
|         }; | ||||
| @ -196,16 +74,15 @@ impl FunctionDefinition { | ||||
| impl Block { | ||||
|     fn typecheck( | ||||
|         &mut self, | ||||
|         state: &mut State, | ||||
|         scope: &mut Scope, | ||||
|         state: &mut PassState<ErrorKind>, | ||||
|         hint_t: Option<TypeKind>, | ||||
|     ) -> Result<TypeKind, ErrorKind> { | ||||
|         let mut scope = scope.inner(); | ||||
|         let mut state = state.inner(); | ||||
| 
 | ||||
|         for statement in &mut self.statements { | ||||
|             match &mut statement.0 { | ||||
|                 StmtKind::Let(variable_reference, expression) => { | ||||
|                     let res = expression.typecheck(state, &mut scope, Some(variable_reference.0)); | ||||
|                     let res = expression.typecheck(&mut state, Some(variable_reference.0)); | ||||
| 
 | ||||
|                     // If expression resolution itself was erronous, resolve as
 | ||||
|                     // Unknown.
 | ||||
| @ -220,22 +97,24 @@ impl Block { | ||||
| 
 | ||||
|                     // Make sure expression/variable type is NOT vague anymore
 | ||||
|                     let res_t = | ||||
|                         state.or_else(res_t.assert_known(), Vague(Unknown), variable_reference.2); | ||||
|                         state.or_else(res_t.or_default(), Vague(Unknown), variable_reference.2); | ||||
| 
 | ||||
|                     // Update typing to be more accurate
 | ||||
|                     variable_reference.0 = res_t; | ||||
| 
 | ||||
|                     // Variable might already be defined, note error
 | ||||
|                     state.ok( | ||||
|                         scope | ||||
|                             .variables | ||||
|                             .set(variable_reference.1.clone(), variable_reference.0), | ||||
|                         variable_reference.2, | ||||
|                     ); | ||||
|                     let res = state | ||||
|                         .scope | ||||
|                         .variables | ||||
|                         .set(variable_reference.1.clone(), variable_reference.0) | ||||
|                         .or(Err(ErrorKind::VariableAlreadyDefined( | ||||
|                             variable_reference.1.clone(), | ||||
|                         ))); | ||||
|                     state.ok(res, variable_reference.2); | ||||
|                 } | ||||
|                 StmtKind::Import(_) => todo!(), | ||||
|                 StmtKind::Expression(expression) => { | ||||
|                     let res = expression.typecheck(state, &mut scope, hint_t); | ||||
|                     let res = expression.typecheck(&mut state, None); | ||||
|                     state.ok(res, expression.1); | ||||
|                 } | ||||
|             } | ||||
| @ -243,10 +122,10 @@ impl Block { | ||||
| 
 | ||||
|         if let Some((return_kind, expr)) = &mut self.return_expression { | ||||
|             let ret_hint_t = match return_kind { | ||||
|                 ReturnKind::Hard => scope.return_type_hint, | ||||
|                 ReturnKind::Hard => state.scope.return_type_hint, | ||||
|                 ReturnKind::Soft => hint_t, | ||||
|             }; | ||||
|             let res = expr.typecheck(state, &mut scope, ret_hint_t); | ||||
|             let res = expr.typecheck(&mut state, ret_hint_t); | ||||
|             Ok(state.or_else(res, Vague(Unknown), expr.1)) | ||||
|         } else { | ||||
|             Ok(Void) | ||||
| @ -257,14 +136,16 @@ impl Block { | ||||
| impl Expression { | ||||
|     fn typecheck( | ||||
|         &mut self, | ||||
|         state: &mut State, | ||||
|         scope: &mut Scope, | ||||
|         state: &mut PassState<ErrorKind>, | ||||
|         hint_t: Option<TypeKind>, | ||||
|     ) -> Result<TypeKind, ErrorKind> { | ||||
|         match &mut self.0 { | ||||
|             ExprKind::Variable(var_ref) => { | ||||
|                 dbg!(&state.scope); | ||||
| 
 | ||||
|                 let existing = state.or_else( | ||||
|                     scope | ||||
|                     state | ||||
|                         .scope | ||||
|                         .variables | ||||
|                         .get(&var_ref.1) | ||||
|                         .copied() | ||||
| @ -289,15 +170,23 @@ impl Expression { | ||||
|             ExprKind::BinOp(op, lhs, rhs) => { | ||||
|                 // TODO make sure lhs and rhs can actually do this binary
 | ||||
|                 // operation once relevant
 | ||||
|                 let lhs_res = lhs.typecheck(state, scope, None); // TODO
 | ||||
|                 let lhs_res = lhs.typecheck(state, None); // TODO
 | ||||
|                 let lhs_type = state.or_else(lhs_res, Vague(Unknown), lhs.1); | ||||
|                 let rhs_res = rhs.typecheck(state, scope, Some(lhs_type)); // TODO
 | ||||
|                 let rhs_res = rhs.typecheck(state, Some(lhs_type)); // TODO
 | ||||
|                 let rhs_type = state.or_else(rhs_res, Vague(Unknown), rhs.1); | ||||
| 
 | ||||
|                 if let Some(collapsed) = state.ok(rhs_type.collapse_into(&rhs_type), self.1) { | ||||
|                     // Try to coerce both sides again with collapsed type
 | ||||
|                     lhs.typecheck(state, Some(collapsed)).ok(); | ||||
|                     rhs.typecheck(state, Some(collapsed)).ok(); | ||||
|                 } | ||||
| 
 | ||||
|                 let res = lhs_type.binop_type(&op, &rhs_type)?; | ||||
|                 Ok(res) | ||||
|             } | ||||
|             ExprKind::FunctionCall(function_call) => { | ||||
|                 let true_function = scope | ||||
|                 let true_function = state | ||||
|                     .scope | ||||
|                     .function_returns | ||||
|                     .get(&function_call.name) | ||||
|                     .cloned() | ||||
| @ -313,7 +202,7 @@ impl Expression { | ||||
|                     for (param, true_param_t) in | ||||
|                         function_call.parameters.iter_mut().zip(true_params_iter) | ||||
|                     { | ||||
|                         let param_res = param.typecheck(state, scope, Some(true_param_t)); | ||||
|                         let param_res = param.typecheck(state, Some(true_param_t)); | ||||
|                         let param_t = state.or_else(param_res, Vague(Unknown), param.1); | ||||
|                         state.ok(param_t.collapse_into(&true_param_t), param.1); | ||||
|                     } | ||||
| @ -330,21 +219,21 @@ impl Expression { | ||||
|             } | ||||
|             ExprKind::If(IfExpression(cond, lhs, rhs)) => { | ||||
|                 // TODO make sure cond_res is Boolean here
 | ||||
|                 let cond_res = cond.typecheck(state, scope, Some(Bool)); | ||||
|                 let cond_res = cond.typecheck(state, Some(Bool)); | ||||
|                 let cond_t = state.or_else(cond_res, Vague(Unknown), cond.1); | ||||
|                 state.ok(cond_t.collapse_into(&Bool), cond.1); | ||||
| 
 | ||||
|                 let lhs_res = lhs.typecheck(state, scope, hint_t); | ||||
|                 let lhs_res = lhs.typecheck(state, hint_t); | ||||
|                 let lhs_type = state.or_else(lhs_res, Vague(Unknown), lhs.meta); | ||||
|                 let rhs_type = if let Some(rhs) = rhs { | ||||
|                     let res = rhs.typecheck(state, scope, hint_t); | ||||
|                     let res = rhs.typecheck(state, hint_t); | ||||
|                     state.or_else(res, Vague(Unknown), rhs.meta) | ||||
|                 } else { | ||||
|                     Vague(Unknown) | ||||
|                 }; | ||||
|                 lhs_type.collapse_into(&rhs_type) | ||||
|             } | ||||
|             ExprKind::Block(block) => block.typecheck(state, scope, hint_t), | ||||
|             ExprKind::Block(block) => block.typecheck(state, hint_t), | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -359,6 +248,9 @@ impl Literal { | ||||
|                 (L::I16(_), I16) => self, | ||||
|                 (L::Vague(VagueL::Number(v)), I32) => L::I32(v as i32), | ||||
|                 (L::Vague(VagueL::Number(v)), I16) => L::I16(v as i16), | ||||
|                 // Default type for number literal if unable to find true type.
 | ||||
|                 (L::Vague(VagueL::Number(v)), Vague(Number)) => L::I32(v as i32), | ||||
|                 (_, Vague(_)) => self, | ||||
|                 _ => Err(ErrorKind::TypesIncompatible(self.as_type(), hint))?, | ||||
|             }) | ||||
|         } else { | ||||
| @ -368,10 +260,24 @@ impl Literal { | ||||
| } | ||||
| 
 | ||||
| impl TypeKind { | ||||
|     /// Assert that a type is already known and not vague. Return said type or
 | ||||
|     /// error.
 | ||||
|     fn assert_known(&self) -> Result<TypeKind, ErrorKind> { | ||||
|         self.is_known().map_err(ErrorKind::TypeIsVague) | ||||
|     } | ||||
| 
 | ||||
|     /// Try to collapse a type on itself producing a default type if one exists,
 | ||||
|     /// Error if not.
 | ||||
|     fn or_default(&self) -> Result<TypeKind, ErrorKind> { | ||||
|         match self { | ||||
|             Vague(vague_type) => match vague_type { | ||||
|                 Unknown => Err(ErrorKind::TypeIsVague(*vague_type)), | ||||
|                 Number => Ok(TypeKind::I32), | ||||
|             }, | ||||
|             _ => Ok(*self), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn binop_type(&self, op: &BinaryOperator, other: &TypeKind) -> Result<TypeKind, ErrorKind> { | ||||
|         let res = self.collapse_into(other)?; | ||||
|         Ok(match op { | ||||
| @ -401,6 +307,13 @@ impl Collapsable for TypeKind { | ||||
|         } | ||||
| 
 | ||||
|         match (self, other) { | ||||
|             (Vague(Number), other) | (other, Vague(Number)) => match other { | ||||
|                 Vague(Unknown) => Ok(Vague(Number)), | ||||
|                 Vague(Number) => Ok(Vague(Number)), | ||||
|                 I32 => Ok(I32), | ||||
|                 I16 => Ok(I16), | ||||
|                 _ => Err(ErrorKind::TypesIncompatible(*self, *other)), | ||||
|             }, | ||||
|             (Vague(Unknown), other) | (other, Vague(Unknown)) => Ok(other.clone()), | ||||
|             _ => Err(ErrorKind::TypesIncompatible(*self, *other)), | ||||
|         } | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user