diff --git a/src/analysis_a/dependency_res.rs b/src/analysis_a/dependency_res.rs deleted file mode 100644 index ea4c95f..0000000 --- a/src/analysis_a/dependency_res.rs +++ /dev/null @@ -1,214 +0,0 @@ -use std::{ - collections::HashMap, - path::{Path, PathBuf}, -}; - -use crate::{ - frontend::{ - ast::{DependencyPath, PathAction}, - source::SourceRef, - }, - pir::ir::{ExprRef, InsRef, KeyValueBindings, PIRIns, PIRModule, PIRModulePass}, -}; - -#[derive(Clone)] -#[allow(dead_code)] -pub struct DependencyResolvr<'a> { - module: Option<&'a PIRModule>, - file_path: String, - resolution_errors: Vec<(String, SourceRef)>, -} - -// expect to first process the module and get a Vec as the result -// we can then use these indices to get the corresponding ins from the module -// for each of these dependencies, we will: -// - process the actions until we get to a file path. The remainder of the actions will -// be the path to the dependency. -impl<'a> DependencyResolvr<'a> { - pub fn resolve( - &mut self, - dependencies: Vec, - ) -> HashMap> { - let module = self.get_module(); - let ins_pool = &module.ins_pool.pool; - - // for each dependency, we will: - // - get the Instruction (UseDependency) - // - each UseDependency has a list of DependencyPaths: - // - each of the DependencyPaths has a list of actions which will be used to get - // the path - // - we will process the actions (while updating depenedency path) until we: - // * get to a file path. Stop. - // * get to a folder. Continue. - // * path is invalid. Error. - // - once we have a valid file path, whatever is left of the actions - // will be the path to the dependency - // - cluster the dependencies by their paths and return that structure - - let mut res: HashMap> = HashMap::new(); - - for index in dependencies { - let dep = ins_pool.get(index).unwrap(); - if let PIRIns::UseDependency { paths, src: _ } = dep { - for path in paths { - let resolved_res = self.evaluate_dependency_path(path); - match resolved_res { - Ok((res_path, rem_actions)) => { - // add to res - let res_vec = res.entry(index).or_insert(Vec::new()); - res_vec.push((res_path, rem_actions)); - } - Err(msg) => { - self.resolution_errors.push((msg, path.source_ref())); - } - } - } - } - } - - // show contents of res array - for (index, m) in &res { - let dep = ins_pool.get(*index).unwrap(); - println!("{} resolves to the following path:", dep.as_str()); - for (path, actions) in m { - println!("\t{}: {}", path.display(), actions.as_str()); - } - } - - return res; - } - - fn evaluate_dependency_path( - &mut self, - dep: &DependencyPath, - ) -> Result<(PathBuf, DependencyPath), String> { - let mut start_dir = PathBuf::from(&self.file_path.clone()); - start_dir.pop(); - let mut search_dep_path = start_dir; - let mut skip_to = 0; - - for action in &dep.actions { - match action { - PathAction::ToParentDir(_) => { - search_dep_path.pop(); - } - PathAction::ImportAll(_) => { - break; - } - PathAction::SearchFor(path_section) => { - // append path_section to search_dep_path - search_dep_path.push(path_section.as_str()); - } - PathAction::SearchCoreModulesFor(_) => todo!(), - PathAction::SearchProjectRootFor(_) => todo!(), - PathAction::SearchCurrentFileFor(_) => { - search_dep_path = PathBuf::from(&self.file_path); - search_dep_path.set_extension("pr"); - break; - } - PathAction::NameLastItemAs(_) => todo!(), - } - - // check that updated path exists - let (path_exists, is_file, is_dir) = self.path_exists(&search_dep_path); - if !path_exists { - // report error - let msg = format!("Unable to resolve dependency path: {}", dep.as_str()); - return Err(msg); - } - - // update skip_to by 1, with a max of actions.len() - skip_to += 1; - if skip_to >= dep.actions.len() { - break; - } - - if is_dir { - // continue - continue; - } - - if is_file { - // stop - search_dep_path.set_extension("pr"); - break; - } else { - } - } - - // we have to verify that the path is a file - let (path_exists, is_file, _) = self.path_exists(&search_dep_path); - if !path_exists { - // report error - let msg = format!("Unable to resolve dependency path: {}", dep.as_str()); - return Err(msg); - } - - if !is_file { - // report error - let msg = format!("Dependency path must contain a file: {}", dep.as_str()); - return Err(msg); - } - - search_dep_path.set_extension("pr"); - - // we have a valid file path - // we need to collect the remainder of the actions into a Vector of PathActions - let mut remainder = Vec::new(); - for action in &dep.actions[skip_to..] { - remainder.push(action.clone()); - } - let remainder = DependencyPath { actions: remainder }; - Ok((search_dep_path, remainder)) - } - - // checks if path exists and also if it is a file - fn path_exists(&self, path: &PathBuf) -> (bool, bool, bool) { - let mut file_path = path.clone(); - file_path.set_extension("pr"); - let file_path = Path::new(&file_path); - let file_exists = file_path.exists(); - let dir_exists = path.exists(); - (dir_exists || file_exists, file_exists, dir_exists) - } -} - -impl<'a> PIRModulePass<'a, (), (), (), Vec, ()> for DependencyResolvr<'a> { - fn process_ins(&mut self, _: &InsRef) -> Result<(), ()> { - Ok(()) - } - - fn process_expr(&mut self, _: &ExprRef) -> Result<(), ()> { - Ok(()) - } - - fn process_pairs(&mut self, _: &KeyValueBindings) -> Result<(), ()> { - Ok(()) - } - - fn process(&mut self) -> Result, ()> { - let module = self.get_module(); - let ins_pool = &module.ins_pool.pool; - let mut dependencies = Vec::new(); - - for (index, ins) in ins_pool.iter().enumerate() { - if matches!(ins, PIRIns::UseDependency { paths: _, src: _ }) { - dependencies.push(index); - } - } - - Ok(dependencies) - } - - fn new(module: &'a PIRModule) -> Self { - Self { - module: Some(module), - file_path: module.path.clone(), - resolution_errors: Vec::new(), - } - } - - fn get_module(&mut self) -> &'a PIRModule { - self.module.unwrap() - } -} diff --git a/src/analysis_a/mod.rs b/src/analysis_a/mod.rs deleted file mode 100644 index bffc631..0000000 --- a/src/analysis_a/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod dependency_res; diff --git a/src/compilation/pipeline.rs b/src/compilation/pipeline.rs index 51fcf93..2ad216b 100644 --- a/src/compilation/pipeline.rs +++ b/src/compilation/pipeline.rs @@ -1,22 +1,17 @@ use std::{collections::HashMap, env, fs, path::PathBuf}; -use crate::{ - analysis_a::dependency_res::DependencyResolvr, - frontend::{ - lexer::Lexer, - parser::Parser, - source::{SourceFile, SourceReporter}, - token::Token, - }, - pir::ir::{PIRModule, PIRModulePass}, - tools::pfmt::Pfmt, +use crate::frontend::{ + lexer::Lexer, + parser::Parser, + source::{SourceFile, SourceReporter}, + token::Token, }; #[allow(dead_code)] pub enum Stage { Lexer, Parser, - DependencyResolvr, + UIRGen, } #[allow(dead_code)] @@ -51,7 +46,7 @@ impl PipelineConfig { cmd: None, backend: Backend::PIR, target_file: "".to_string(), - max_stage: Stage::DependencyResolvr, + max_stage: Stage::UIRGen, show_help: true, dbg_info: false, use_pfmt: true, @@ -72,7 +67,7 @@ impl PipelineConfig { cmd: None, backend: Backend::PIR, target_file: "".to_string(), - max_stage: Stage::DependencyResolvr, + max_stage: Stage::UIRGen, show_help: true, dbg_info: false, use_pfmt: false, @@ -80,7 +75,7 @@ impl PipelineConfig { } let target_file = args.next().unwrap(); let mut backend = Backend::PIR; - let mut max_stage = Stage::DependencyResolvr; + let mut max_stage = Stage::UIRGen; let mut show_help = false; let mut dbg_info = false; let mut use_pfmt = false; @@ -90,7 +85,7 @@ impl PipelineConfig { "cpp" => backend = Backend::CPP, "lex" => max_stage = Stage::Lexer, "parse" => max_stage = Stage::Parser, - "dep" => max_stage = Stage::DependencyResolvr, + "uir" => max_stage = Stage::UIRGen, "fmt" => use_pfmt = true, "dbg" => dbg_info = true, "help" => show_help = true, @@ -110,7 +105,7 @@ impl PipelineConfig { "h" | "help" => PipelineConfig { backend: Backend::PIR, target_file: "".to_string(), - max_stage: Stage::DependencyResolvr, + max_stage: Stage::UIRGen, show_help: true, dbg_info: false, cmd: None, @@ -119,7 +114,7 @@ impl PipelineConfig { _ => PipelineConfig { backend: Backend::PIR, target_file: "".to_string(), - max_stage: Stage::DependencyResolvr, + max_stage: Stage::UIRGen, show_help: true, dbg_info: false, cmd: None, @@ -131,7 +126,7 @@ impl PipelineConfig { pub struct Workspace { entry_file: String, - files: HashMap, + files: HashMap, config: PipelineConfig, } @@ -143,11 +138,19 @@ impl Workspace { let abs_entry_file = fs::canonicalize(PathBuf::from(abs_entry_file)).unwrap(); let abs_entry_file = abs_entry_file.to_str().unwrap().to_string(); - Workspace { + let w = Workspace { entry_file: abs_entry_file, files: HashMap::new(), config, - } + }; + + // TODO: add back when std is ready and we can handle directives + // w.process_file( + // "/Users/iwarilama/Desktop/Code/rust/proto/src/std/primitives.pr".to_string(), + // &mut vec![], + // ); + + return w; } pub fn compile_workspace(&mut self) { @@ -164,7 +167,7 @@ impl Workspace { fn process_file(&mut self, file_path: String, path_stack: &mut Vec) { // check if file is already processed and stored in files - if let Some((_, _)) = self.files.get(&file_path) { + if let Some(_) = self.files.get(&file_path) { return; } @@ -210,6 +213,7 @@ impl Workspace { for le in parser.lexer_errors { reporter.report_lexer_error(&le); } + return; } if self.config.dbg_info { reporter.show_info("lexing complete.".to_string()); @@ -219,47 +223,20 @@ impl Workspace { for pe in parser.parser_errors { reporter.report_parser_error(pe); } + return; } if self.config.dbg_info { + let _module = &parser.compilation_module; + + for ins in _module.instructions.iter() { + println!("{}", ins.as_str()); + } + reporter.show_info("parsing complete.".to_string()); } if let Stage::Parser = self.config.max_stage { return; } - - let module = parser.compilation_module; - let mut ir_mod = PIRModule::new(module, file_path.clone()); - self.files.insert(file_path.clone(), (src, ir_mod.clone())); - - if self.config.use_pfmt { - let mut pfmt = Pfmt::new(&mut ir_mod); - let res = pfmt.process(); - match res { - Ok(msg) if self.config.dbg_info => reporter.show_info(msg), - Err(e) => reporter.show_error(e), - _ => {} - } - } - - let mut dep_resolvr = DependencyResolvr::new(&mut ir_mod); - let res = dep_resolvr.process(); - match res { - Ok(indices) => { - let dependencies_bundl = dep_resolvr.resolve(indices); - path_stack.push(file_path.clone()); - for (_, bundl) in dependencies_bundl { - for (path, _) in bundl { - let path_str = path.to_str().unwrap().to_string(); - self.process_file(path_str, path_stack); - } - } - path_stack.pop(); - } - Err(_) => todo!(), - } - if self.config.dbg_info { - reporter.show_info("dependency resolution complete.".to_string()); - } } } diff --git a/src/frontend/ast.rs b/src/frontend/ast.rs index 79ea3f5..38c6871 100644 --- a/src/frontend/ast.rs +++ b/src/frontend/ast.rs @@ -1,98 +1,271 @@ -use super::{source::SourceRef, token::Token, types::Type}; +use super::{source::SourceRef, token::Token}; +use std::{ + collections::hash_map::DefaultHasher, + hash::{Hash, Hasher}, +}; + +#[derive(Debug, Clone, PartialEq, Eq)] +#[allow(dead_code)] +pub enum TypeReference { + Infer(SourceRef), + I8(SourceRef), + I16(SourceRef), + I32(SourceRef), + I64(SourceRef), + ISize(SourceRef), + U8(SourceRef), + U16(SourceRef), + U32(SourceRef), + U64(SourceRef), + USize(SourceRef), + Bool(SourceRef), + Char(SourceRef), + Str(SourceRef), + Void(SourceRef), + Type(SourceRef), + IdentifierType(String, SourceRef), + ArrayOf(Box, SourceRef), + StaticArrayOf(Box, usize, SourceRef), + TupleOf(Vec, SourceRef), +} + +impl Hash for TypeReference { + fn hash(&self, state: &mut H) { + match self { + TypeReference::Infer(_) => "infer".hash(state), + TypeReference::I8(_) => "i8".hash(state), + TypeReference::I16(_) => "i16".hash(state), + TypeReference::I32(_) => "i32".hash(state), + TypeReference::I64(_) => "i64".hash(state), + TypeReference::ISize(_) => "isize".hash(state), + TypeReference::U8(_) => "u8".hash(state), + TypeReference::U16(_) => "u16".hash(state), + TypeReference::U32(_) => "u32".hash(state), + TypeReference::U64(_) => "u64".hash(state), + TypeReference::USize(_) => "usize".hash(state), + TypeReference::Bool(_) => "bool".hash(state), + TypeReference::Char(_) => "char".hash(state), + TypeReference::Str(_) => "str".hash(state), + TypeReference::Void(_) => "void".hash(state), + TypeReference::Type(_) => "type".hash(state), + TypeReference::IdentifierType(s, _) => s.hash(state), + TypeReference::ArrayOf(t, _) => { + "array_of_".hash(state); + t.hash(state); + } + TypeReference::StaticArrayOf(t, n, _) => { + "static_array_of_".hash(state); + t.hash(state); + n.hash(state); + } + TypeReference::TupleOf(ts, _) => { + "tuple_of_".hash(state); + for t in ts { + t.hash(state); + } + } + } + } +} + +#[allow(dead_code)] +impl TypeReference { + pub fn get_hash(&self) -> u64 { + let mut hasher = DefaultHasher::new(); + self.hash(&mut hasher); + hasher.finish() + } + + pub fn as_str(&self) -> String { + match self { + TypeReference::Infer(_) => "infer".to_string(), + TypeReference::IdentifierType(s, _) => s.clone(), + TypeReference::I8(_) => "i8".to_string(), + TypeReference::I16(_) => "i16".to_string(), + TypeReference::I32(_) => "i32".to_string(), + TypeReference::I64(_) => "i64".to_string(), + TypeReference::ISize(_) => "isize".to_string(), + TypeReference::U8(_) => "u8".to_string(), + TypeReference::U16(_) => "u16".to_string(), + TypeReference::U32(_) => "u32".to_string(), + TypeReference::U64(_) => "u64".to_string(), + TypeReference::USize(_) => "usize".to_string(), + TypeReference::Bool(_) => "bool".to_string(), + TypeReference::Char(_) => "char".to_string(), + TypeReference::Str(_) => "str".to_string(), + TypeReference::Void(_) => "void".to_string(), + TypeReference::Type(_) => "type".to_string(), + TypeReference::ArrayOf(t, _) => format!("[{}]", t.as_str()), + TypeReference::TupleOf(ts, _) => { + let mut s = "(".to_string(); + for t in ts { + s.push_str(&t.as_str()); + s.push_str(", "); + } + s.push_str(")"); + s + } + TypeReference::StaticArrayOf(t, n, _) => format!("[{}; {}]", t.as_str(), n), + } + } + + pub fn eq(&self, other: &Self) -> bool { + match (self, other) { + (TypeReference::IdentifierType(s1, _), TypeReference::IdentifierType(s2, _)) => { + s1 == s2 + } + (TypeReference::I8(_), TypeReference::I8(_)) => true, + (TypeReference::I16(_), TypeReference::I16(_)) => true, + (TypeReference::I32(_), TypeReference::I32(_)) => true, + (TypeReference::I64(_), TypeReference::I64(_)) => true, + (TypeReference::ISize(_), TypeReference::ISize(_)) => true, + (TypeReference::U8(_), TypeReference::U8(_)) => true, + (TypeReference::U16(_), TypeReference::U16(_)) => true, + (TypeReference::U32(_), TypeReference::U32(_)) => true, + (TypeReference::U64(_), TypeReference::U64(_)) => true, + (TypeReference::USize(_), TypeReference::USize(_)) => true, + (TypeReference::Bool(_), TypeReference::Bool(_)) => true, + (TypeReference::Char(_), TypeReference::Char(_)) => true, + (TypeReference::Str(_), TypeReference::Str(_)) => true, + (TypeReference::Void(_), TypeReference::Void(_)) => true, + (TypeReference::Type(_), TypeReference::Type(_)) => true, + (TypeReference::ArrayOf(t1, _), TypeReference::ArrayOf(t2, _)) => t1.eq(t2), + (TypeReference::TupleOf(ts1, _), TypeReference::TupleOf(ts2, _)) => { + if ts1.len() != ts2.len() { + return false; + } + for (t1, t2) in ts1.iter().zip(ts2.iter()) { + if !t1.eq(t2) { + return false; + } + } + true + } + (TypeReference::StaticArrayOf(t1, n1, _), TypeReference::StaticArrayOf(t2, n2, _)) => { + t1.eq(t2) && n1 == n2 + } + _ => false, + } + } + + pub fn get_source_ref(&self) -> SourceRef { + match self { + TypeReference::Infer(s) => s.clone(), + TypeReference::IdentifierType(_, s) => s.clone(), + TypeReference::I8(s) => s.clone(), + TypeReference::I16(s) => s.clone(), + TypeReference::I32(s) => s.clone(), + TypeReference::I64(s) => s.clone(), + TypeReference::ISize(s) => s.clone(), + TypeReference::U8(s) => s.clone(), + TypeReference::U16(s) => s.clone(), + TypeReference::U32(s) => s.clone(), + TypeReference::U64(s) => s.clone(), + TypeReference::USize(s) => s.clone(), + TypeReference::Bool(s) => s.clone(), + TypeReference::Char(s) => s.clone(), + TypeReference::Str(s) => s.clone(), + TypeReference::Void(s) => s.clone(), + TypeReference::Type(s) => s.clone(), + TypeReference::ArrayOf(_, s) => s.clone(), + TypeReference::TupleOf(_, s) => s.clone(), + TypeReference::StaticArrayOf(_, _, s) => s.clone(), + } + } +} #[derive(Debug, Clone)] #[allow(dead_code)] pub enum Expr { - Id(Token, Option), - Number(Token, Option), - StringLiteral(Token, Option), - CharacterLiteral(Token, Option), - Binary(Token, Box, Box, Option), - Comparison(Token, Box, Box, Option), - Boolean(Token, Option), - Unary(Token, Box, Option), - Grouped(Box, Option, SourceRef), + TypeExpr(TypeReference, SourceRef), + Id(Token, Option, SourceRef), + Number(Token, SourceRef), + SingleLineStringLiteral(Token, SourceRef), + MultiLineStringLiteral(Vec, SourceRef), + CharacterLiteral(Token, SourceRef), + Binary(Token, Box, Box, SourceRef), + Comparison(Token, Box, Box, SourceRef), + Boolean(Token, SourceRef), + Unary(Token, Box, SourceRef), + Grouped(Box, SourceRef), FnCall { func: Box, args: Vec, span: SourceRef, - fn_type: Option, }, ScopeInto { module: Box, target: Box, src: SourceRef, - resolved_type: Option, }, DirectiveExpr { directive: Box, expr: Option>, - resolved_type: Option, src: SourceRef, }, - NamedStructInit { + NamedStructLiteral { + // using StructName { a bool, b char } or StructName { a = true, b = 'a' } name: Box, fields: KeyValueBindings, src: SourceRef, - resolved_type: Option, }, + AnonStructLiteral { + // using .{ a bool, b char } + fields: KeyValueBindings, + src: SourceRef, + }, + StructDecl { + src: SourceRef, + contents: Box, + }, + Integer(String, SourceRef), } #[allow(dead_code)] impl Expr { pub fn source_ref(&self) -> SourceRef { match &self { - Expr::Id(t, _) => t.get_source_ref(), - Expr::Number(t, _) => t.get_source_ref(), - Expr::Binary(_, lhs, rhs, _) => { - let lhs_ref = lhs.source_ref(); - let rhs_ref = rhs.source_ref(); - lhs_ref.combine(rhs_ref) - } - Expr::Boolean(t, _) => t.get_source_ref(), - Expr::Unary(operator, operand, _) => { - let operator_ref = operator.get_source_ref(); - let operand_ref = operand.source_ref(); - operator_ref.combine(operand_ref) - } - Expr::Comparison(_, lhs, rhs, _) => { - let lhs_ref = lhs.source_ref(); - let rhs_ref = rhs.source_ref(); - lhs_ref.combine(rhs_ref) - } + Expr::TypeExpr(_, s) => s.clone(), + Expr::Id(_, _, s) => s.clone(), + Expr::Number(_, s) => s.clone(), + Expr::Binary(_, _, _, s) => s.clone(), + Expr::Boolean(_, s) => s.clone(), + Expr::Unary(_, _, s) => s.clone(), + Expr::Comparison(_, _, _, s) => s.clone(), Expr::FnCall { func: _, args: _, span, - fn_type: _, } => span.clone(), - Expr::Grouped(_, _, src) => src.clone(), + Expr::Grouped(_, src) => src.clone(), Expr::ScopeInto { module: _, target: _, src, - resolved_type: _, } => src.clone(), Expr::DirectiveExpr { directive: _, expr: _, - resolved_type: _, src, } => src.clone(), - Expr::StringLiteral(t, _) => t.get_source_ref(), - Expr::CharacterLiteral(t, _) => t.get_source_ref(), - Expr::NamedStructInit { + Expr::SingleLineStringLiteral(_, s) => s.clone(), + Expr::CharacterLiteral(_, s) => s.clone(), + Expr::MultiLineStringLiteral(_, s) => s.clone(), + Expr::Integer(_, s) => s.clone(), + Expr::NamedStructLiteral { name: _, fields: _, src, - resolved_type: _, } => src.clone(), + Expr::AnonStructLiteral { fields: _, src } => src.clone(), + Expr::StructDecl { src, contents: _ } => src.clone(), } } pub fn as_str(&self) -> String { match self { - Expr::Id(tok, maybe_type) => { + Expr::TypeExpr(t, _) => t.as_str(), + Expr::Id(tok, maybe_type, _) => { let mut s = tok.as_str().to_string(); if let Some(t) = maybe_type { s.push_str(&format!(" {}", t.as_str())); @@ -112,7 +285,6 @@ impl Expr { func, args, span: _, - fn_type: _, } => { let mut fn_str = func.as_str(); fn_str.push('('); @@ -124,7 +296,7 @@ impl Expr { fn_str + &fn_args.join(", ") + ")" } - Expr::Grouped(e, _, _) => { + Expr::Grouped(e, _) => { let s = format!("({})", e.as_str()); s } @@ -132,12 +304,10 @@ impl Expr { module, target, src: _, - resolved_type: _, - } => format!("{}::{}", module.as_str(), target.as_str()), + } => format!("{}.{}", module.as_str(), target.as_str()), Expr::DirectiveExpr { directive, expr, - resolved_type: _, src: _, } => { if let Some(expr) = expr { @@ -146,167 +316,27 @@ impl Expr { format!("@{}", directive.as_str()) } } - Expr::StringLiteral(literal, _) => literal.as_str(), + Expr::SingleLineStringLiteral(literal, _) => literal.as_str(), Expr::CharacterLiteral(literal, _) => literal.as_str(), - Expr::NamedStructInit { - name, - fields, - src: _, - resolved_type: _, - } => { - let mut s = format!(":{} ", name.as_str()); - s.push_str(&fields.as_str()); + Expr::MultiLineStringLiteral(literals, _) => { + let mut s = String::new(); + // start each line with || + for (index, line) in literals.iter().enumerate() { + s.push_str("||"); + s.push_str(&line.as_str()); + if index < literals.len() - 1 { + s.push('\n'); + } + } s } - } - } - - pub fn type_info(&self) -> Option { - match &self { - Expr::Id(_, t) => t.clone(), - Expr::Number(_, t) => t.clone(), - Expr::Binary(_, _, _, t) => t.clone(), - Expr::Boolean(_, t) => t.clone(), - Expr::Unary(_, _, t) => t.clone(), - Expr::Comparison(_, _, _, t) => t.clone(), - Expr::FnCall { - func: _, - args: _, - span: _, - fn_type, - } => fn_type.clone(), - Expr::Grouped(_, t, _) => t.clone(), - Expr::ScopeInto { - module: _, - target: _, - src: _, - resolved_type, - } => resolved_type.clone(), - Expr::DirectiveExpr { - directive: _, - expr: _, - resolved_type, - src: _, - } => resolved_type.clone(), - Expr::StringLiteral(_, t) => t.clone(), - Expr::CharacterLiteral(_, t) => t.clone(), - Expr::NamedStructInit { - name: _, - fields: _, - src: _, - resolved_type, - } => resolved_type.clone(), - } - } -} - -#[derive(Debug, Clone)] -#[allow(dead_code)] -pub enum PathAction { - ToParentDir(SourceRef), - ImportAll(SourceRef), - SearchFor(Expr), - SearchCoreModulesFor(Expr), - SearchProjectRootFor(Expr), - SearchCurrentFileFor(Expr), - NameLastItemAs(Expr), -} - -#[allow(dead_code)] -impl PathAction { - pub fn is_search_action(&self) -> bool { - match self { - PathAction::ToParentDir(_) => false, - PathAction::NameLastItemAs(_) => false, - PathAction::SearchFor(_) => true, - PathAction::SearchCoreModulesFor(_) => true, - PathAction::SearchProjectRootFor(_) => true, - PathAction::SearchCurrentFileFor(_) => true, - PathAction::ImportAll(_) => false, - } - } - - pub fn is_terminating_action(&self) -> bool { - match self { - PathAction::ToParentDir(_) => false, - PathAction::SearchFor(_) => true, - PathAction::NameLastItemAs(_) => true, - PathAction::SearchCoreModulesFor(_) => true, - PathAction::SearchProjectRootFor(_) => true, - PathAction::SearchCurrentFileFor(_) => false, - PathAction::ImportAll(_) => true, - } - } - - pub fn allows_naming_last(&self) -> bool { - match self { - PathAction::ToParentDir(_) => false, - PathAction::SearchFor(_) => true, - PathAction::NameLastItemAs(_) => false, - PathAction::SearchCoreModulesFor(_) => true, - PathAction::SearchProjectRootFor(_) => true, - PathAction::SearchCurrentFileFor(_) => false, - PathAction::ImportAll(_) => false, - } - } - - pub fn as_str(&self) -> String { - match self { - PathAction::ToParentDir(_) => "^".to_string(), - PathAction::SearchFor(e) => e.as_str(), - PathAction::NameLastItemAs(alias) => format!(" as {}", alias.as_str()), - PathAction::SearchCoreModulesFor(e) => format!("@{}", e.as_str()), - PathAction::SearchProjectRootFor(m) => format!("${}", m.as_str()), - PathAction::SearchCurrentFileFor(inner_m) => format!("!{}", inner_m.as_str()), - PathAction::ImportAll(_) => "*".to_string(), - } - } - - pub fn source_ref(&self) -> SourceRef { - match self { - PathAction::ToParentDir(src) => src.clone(), - PathAction::SearchFor(e) => e.source_ref(), - PathAction::SearchCoreModulesFor(e) => e.source_ref(), - PathAction::SearchProjectRootFor(e) => e.source_ref(), - PathAction::SearchCurrentFileFor(e) => e.source_ref(), - PathAction::NameLastItemAs(e) => e.source_ref(), - PathAction::ImportAll(src) => src.clone(), - } - } -} - -#[derive(Debug, Clone)] -#[allow(dead_code)] -pub struct DependencyPath { - pub actions: Vec, -} - -#[allow(dead_code)] -impl DependencyPath { - pub fn combine(&self, sub_path: &DependencyPath) -> DependencyPath { - let mut actions = self.actions.clone(); - let mut sub_path_actions = sub_path.actions.clone(); - actions.append(&mut sub_path_actions); - DependencyPath { actions } - } - - pub fn source_ref(&self) -> SourceRef { - // get first action - let first_action = self.actions.first().unwrap(); - // get last action - let last_action = self.actions.last().unwrap(); - first_action.source_ref().combine(last_action.source_ref()) - } - - pub fn as_str(&self) -> String { - let mut s = String::new(); - for (index, action) in self.actions.iter().enumerate() { - s.push_str(&action.as_str()); - if index < self.actions.len() - 1 { - s.push_str("::"); + Expr::Integer(num, _) => num.clone(), + Expr::NamedStructLiteral { name, fields, .. } => { + format!("{} {}", name.as_str(), fields.as_str()) } + Expr::AnonStructLiteral { fields, .. } => format!(".{}", fields.as_str()), + Expr::StructDecl { src: _, contents } => format!("struct {}", contents.as_str()), } - s } } @@ -351,18 +381,25 @@ pub enum Instruction { }, ConstantDecl { const_name: Token, - const_type: Option, - init_expr: Expr, + const_type: Option, + init_expr: Option, src_ref: SourceRef, is_public: bool, }, - VariableDecl(Token, Option, Option, SourceRef), - AssignmentIns(Expr, Expr), - ExpressionIns(Expr, Token), + VariableDecl(Token, Option, Option, SourceRef), + AssignmentIns(Expr, Expr, SourceRef), + ExpressionIns(Expr, SourceRef), + FunctionPrototype { + name: Token, + params: Vec, + return_type: TypeReference, + is_public: bool, + src: SourceRef, + }, FunctionDef { name: Token, params: Vec, - return_type: Type, + return_type: TypeReference, body: Box, is_public: bool, src: SourceRef, @@ -392,10 +429,6 @@ pub enum Instruction { }, Break(SourceRef), Continue(SourceRef), - UseDependency { - paths: Vec, - src: SourceRef, - }, DirectiveInstruction { directive: Expr, block: Option>, @@ -429,18 +462,18 @@ impl Instruction { init_expr, src_ref: _, is_public: _, - } => match t { - Some(c_type) => { - format!( - "let {} {} = {};", - const_name.as_str(), - c_type.as_str(), - init_expr.as_str() - ) - } - None => { - format!("let {} = {};", const_name.as_str(), init_expr.as_str()) + } => match (t, init_expr) { + (None, None) => unreachable!("constant decl with no type or init expr"), + (None, Some(init)) => format!("let {} = {};", const_name.as_str(), init.as_str()), + (Some(c_type), None) => { + format!("let {} {};", const_name.as_str(), c_type.as_str()) } + (Some(c_type), Some(init)) => format!( + "let {} {} = {};", + const_name.as_str(), + c_type.as_str(), + init.as_str() + ), }, Instruction::VariableDecl(name, t, init, _) => match (t, init) { (None, None) => format!("mut {};", name.as_str()), @@ -455,10 +488,36 @@ impl Instruction { init.as_str() ), }, - Instruction::AssignmentIns(target, value) => { + Instruction::AssignmentIns(target, value, _) => { format!("{} = {};", target.as_str(), value.as_str()) } Instruction::ExpressionIns(expr, _) => format!("{};", expr.as_str()), + Instruction::FunctionPrototype { + name, + params, + return_type, + is_public, + src: _, + } => { + // collect param strings + let mut param_strs = String::new(); + for (i, param) in params.iter().enumerate() { + param_strs.push_str(¶m.as_str()); + if i + 1 < params.len() { + param_strs.push_str(", "); + } + } + let str_rep = format!( + "fn {} ({param_strs}) {};", + name.as_str(), + return_type.as_str() + ); + if *is_public { + "pub ".to_string() + &str_rep + } else { + str_rep + } + } Instruction::FunctionDef { name, params, @@ -534,21 +593,6 @@ impl Instruction { } Instruction::Break(_) => "break;".to_string(), Instruction::Continue(_) => "continue;".to_string(), - Instruction::UseDependency { paths, src: _ } => { - let mut path_str = String::new(); - for (i, path) in paths.iter().enumerate() { - for (j, part) in path.actions.iter().enumerate() { - path_str.push_str(&part.as_str()); - if j + 1 < path.actions.len() { - path_str.push_str("::"); - } - } - if i + 1 < paths.len() { - path_str.push_str(", "); - } - } - format!("use {};", path_str) - } Instruction::DirectiveInstruction { directive, block, @@ -599,12 +643,17 @@ impl Instruction { is_public: _, } => src_ref.clone(), Instruction::VariableDecl(_, _, _, src) => src.clone(), - Instruction::AssignmentIns(target, value) => { + Instruction::AssignmentIns(target, value, _) => { target.source_ref().combine(value.source_ref()) } - Instruction::ExpressionIns(expr, terminator) => { - expr.source_ref().combine(terminator.get_source_ref()) - } + Instruction::ExpressionIns(_, src) => src.clone(), + Instruction::FunctionPrototype { + name: _, + params: _, + return_type: _, + is_public: _, + src, + } => src.clone(), Instruction::FunctionDef { name: _, params: _, @@ -632,7 +681,6 @@ impl Instruction { } => src.clone(), Instruction::Break(src) => src.clone(), Instruction::Continue(src) => src.clone(), - Instruction::UseDependency { paths: _, src } => src.clone(), Instruction::DirectiveInstruction { directive: _, block: _, diff --git a/src/frontend/directives.rs b/src/frontend/directives.rs index b38299d..6828b85 100644 --- a/src/frontend/directives.rs +++ b/src/frontend/directives.rs @@ -2,15 +2,16 @@ use phf::phf_map; #[allow(dead_code)] pub const DIRECTIVES_EXPRS: phf::Map<&str, bool> = phf_map!( - "run" => true, - "filename" => false, - "line" => false, - "col" => false, - "platform" => false, - "datetime" => false, - "date" => false, - "error" => true, + "run" => true, // type dependent on parameter + "filename" => false, // str + "line" => false, // usize + "col" => false, // usize + "platform" => false, // str + "datetime" => false, // str + "date" => false, // str + "error" => true, // void ); #[allow(dead_code)] -pub const DIRECTIVES_INS: phf::Map<&str, bool> = phf_map!("run" => true, "inline" => true); +pub const DIRECTIVES_INS: phf::Map<&str, bool> = + phf_map!("run" => true, "inline" => true, "register" => true); diff --git a/src/frontend/errors.rs b/src/frontend/errors.rs index d4a20b6..73aebe1 100644 --- a/src/frontend/errors.rs +++ b/src/frontend/errors.rs @@ -15,28 +15,21 @@ pub enum LexError { #[derive(serde::Deserialize, serde::Serialize, Debug, Clone)] pub enum ParseError { Expected(String, SourceRef, Option), - ConstantDeclarationNeedsInitValue(SourceRef), + ConstantDeclarationNeedsTypeOrInitValue(SourceRef), CannotParseAnExpression(SourceRef), TooManyFnArgs(SourceRef), TooManyFnParams(SourceRef), MalformedDeclaration(String, SourceRef), - NoVariableAtTopLevel(SourceRef), - NoCodeBlockAtTopLevel(SourceRef), + NoVariableAtCurrentScope(SourceRef), + NoCodeBlockAllowedInCurrentContext(SourceRef), NoLoopAtTopLevel(SourceRef), NoBreakOutsideLoop(SourceRef), NoContinueOutsideLoop(SourceRef), MisuseOfPubKeyword(SourceRef), UnterminatedCodeBlock(SourceRef, Option), ReturnInstructionOutsideFunction(SourceRef), - UnusualTokenInUsePath(SourceRef), - UnterminatedUsePath(SourceRef), UnknownCompilerDirective(SourceRef), TooManyErrors(SourceRef), -} - -#[allow(dead_code)] -#[derive(serde::Deserialize, serde::Serialize, Debug, Clone)] -pub enum NameResolutionError { - SymbolAlreadyExists(SourceRef), - UndefinedSymbol(SourceRef), + CannotParseType(SourceRef, Option), + TooManyTypes(SourceRef), } diff --git a/src/frontend/lexer.rs b/src/frontend/lexer.rs index e36731b..e146c44 100644 --- a/src/frontend/lexer.rs +++ b/src/frontend/lexer.rs @@ -98,7 +98,7 @@ impl Lexer { let maybe_token = match c { // operators '+' | '-' | '*' | '/' | '%' | '!' | '=' | '<' | '>' | '(' | ')' | '{' | '}' | '[' - | ']' | ',' | '.' | ':' | ';' | '^' | '$' | '@' => self.lex_operator(), + | ']' | ',' | '.' | ':' | ';' | '^' | '$' | '@' | '|' | '?' => self.lex_operator(), // numbers _ if c.is_ascii_digit() => self.lex_number(), // identifiers | keywords @@ -124,6 +124,30 @@ impl Lexer { maybe_token } + // a multi line string fragment is a string fragment that is + // preceded by "||". It goes till the end of the line + fn lex_multi_line_string_fragment(&mut self) -> Result { + let mut content = String::new(); + let mut span = self.src.get_ref(); + // skip both '|' characters + self.src.next_char(); + self.src.next_char(); + span = span.combine(self.src.get_ref()); + + while !self.src.is_eof() { + let cur = self.src.cur_char(); + span = span.combine(self.src.get_ref()); + self.src.next_char(); + if cur != '\n' { + content.push(cur); + continue; + } else { + break; + } + } + Ok(Token::MultiLineStringFragment(span, content)) + } + // lex a potential identifier // it might turn out to be either a: // - keyword @@ -156,16 +180,14 @@ impl Lexer { "else" => Ok(Token::Else(combined_ref)), "loop" => Ok(Token::Loop(combined_ref)), "while" => Ok(Token::While(combined_ref)), - "void" => Ok(Token::Void(combined_ref)), "true" => Ok(Token::True(combined_ref)), "false" => Ok(Token::False(combined_ref)), "break" => Ok(Token::Break(combined_ref)), "continue" => Ok(Token::Continue(combined_ref)), "return" => Ok(Token::Return(combined_ref)), - "use" => Ok(Token::Use(combined_ref)), + "comp" => Ok(Token::Comp(combined_ref)), + "struct" => Ok(Token::Struct(combined_ref)), "pub" => Ok(Token::Pub(combined_ref)), - "mod" => Ok(Token::Mod(combined_ref)), - "as" => Ok(Token::As(combined_ref)), "and" => Ok(Token::And(combined_ref)), "or" => Ok(Token::Or(combined_ref)), @@ -175,15 +197,18 @@ impl Lexer { "i16" => Ok(Token::I16(combined_ref)), "i32" => Ok(Token::I32(combined_ref)), "i64" => Ok(Token::I64(combined_ref)), - "isize" => Ok(Token::Isize(combined_ref)), + "isize" => Ok(Token::ISize(combined_ref)), "u8" => Ok(Token::U8(combined_ref)), "u16" => Ok(Token::U16(combined_ref)), "u32" => Ok(Token::U32(combined_ref)), "u64" => Ok(Token::U64(combined_ref)), - "usize" => Ok(Token::Usize(combined_ref)), + "usize" => Ok(Token::USize(combined_ref)), "bool" => Ok(Token::Bool(combined_ref)), "char" => Ok(Token::Char(combined_ref)), "str" => Ok(Token::Str(combined_ref)), + "void" => Ok(Token::Void(combined_ref)), + "type" => Ok(Token::Type(combined_ref)), + _ => Ok(Token::Identifier(id, combined_ref)), } } @@ -192,18 +217,6 @@ impl Lexer { fn lex_operator(&mut self) -> Result { let cur_ref = self.src.get_ref(); let cur = self.src.cur_char(); - // detect a signed number - if cur == '-' { - // if the next character is a digit, lex a signed number - let peek = self.src.peek_char(); - if peek.is_ascii_digit() { - return self.lex_signed_number(); - } else { - // otherwise, return a minus operator - self.src.next_char(); - return Ok(Token::Minus(cur_ref.combine(self.src.get_ref()))); - } - } // || (self.src.cur_char() == '/' && self.src.peek_char() == '/') @@ -229,23 +242,28 @@ impl Lexer { self.src.next_char(); Ok(Token::Slash(cur_ref.combine(self.src.get_ref()))) } + '|' => { + // if the next character is a '|', lex a multi line string fragment + if self.src.peek_char() == '|' { + return self.lex_multi_line_string_fragment(); + } + Err(LexError::InvalidCharacter( + cur_ref.combine(self.src.get_ref()), + )) + } '%' => { self.src.next_char(); Ok(Token::Modulo(cur_ref.combine(self.src.get_ref()))) } // special characters - '^' => { - self.src.next_char(); - Ok(Token::Caret(cur_ref.combine(self.src.get_ref()))) - } '@' => { self.src.next_char(); Ok(Token::At(cur_ref.combine(self.src.get_ref()))) } - '$' => { + '?' => { self.src.next_char(); - Ok(Token::Dollar(cur_ref.combine(self.src.get_ref()))) + Ok(Token::QuestionMark(cur_ref.combine(self.src.get_ref()))) } // logical operators @@ -297,18 +315,6 @@ impl Lexer { self.src.next_char(); Ok(Token::Greater(cur_ref.combine(self.src.get_ref()))) } - ':' => { - // if the next character is a ':', return a Scope operator - let c = self.src.peek_char(); - if c == ':' { - self.src.next_char(); - self.src.next_char(); - return Ok(Token::Scope(cur_ref.combine(self.src.get_ref()))); - } - // otherwise, return a Colon operator - self.src.next_char(); - Ok(Token::Colon(cur_ref.combine(self.src.get_ref()))) - } '(' => { self.src.next_char(); Ok(Token::LParen(cur_ref.combine(self.src.get_ref()))) @@ -354,6 +360,8 @@ impl Lexer { let mut content = String::new(); // read all characters until terminating " + // if a new line is encountered, return an error + // if a \ is encountered, read the next character while !self.src.is_eof() { let c = self.src.next_char(); span = span.combine(self.src.get_ref()); @@ -370,6 +378,8 @@ impl Lexer { content.push('\\'); content.push(c); } + } else if c == '\n' { + return Err(LexError::UnterminatedStringLiteral(span)); } else { content.push(c); } @@ -381,7 +391,7 @@ impl Lexer { } else { self.src.next_char(); span = span.combine(self.src.get_ref()); - Ok(Token::StringLiteral(span, content)) + Ok(Token::SingleLineStringLiteral(span, content)) } } @@ -424,24 +434,11 @@ impl Lexer { Ok(Token::CharLiteral(span, content.chars().next().unwrap())) } - // try to lex a number fn lex_number(&mut self) -> Result { - // by default, calling lex_number will lex a signed number - // since users tend to perform signed arithmetic more often - self.lex_signed_number() - } - - // try to lex an unsigned number which is one of: - // - i8 - // - i16 - // - i32 - // - i64 - // - isize - fn lex_signed_number(&mut self) -> Result { - let mut signed_number = String::new(); + let mut number = String::new(); let cur_ref = self.src.get_ref(); let cur = self.src.cur_char(); - signed_number.push(cur); + number.push(cur); // read all characters that are digits let mut end_ref; @@ -449,7 +446,7 @@ impl Lexer { let c = self.src.next_char(); end_ref = self.src.get_ref(); if c.is_ascii_digit() { - signed_number.push(c); + number.push(c); } else if c == '_' { // ignore underscores continue; @@ -459,84 +456,8 @@ impl Lexer { } let combined_ref = cur_ref.combine(end_ref); - // check if signed_number is i8 - if let Ok(num) = signed_number.parse::() { - return Ok(Token::I8Literal(num, combined_ref)); - } - - if let Ok(num) = signed_number.parse::() { - return Ok(Token::I16Literal(num, combined_ref)); - } - - if let Ok(num) = signed_number.parse::() { - return Ok(Token::I32Literal(num, combined_ref)); - } - - if let Ok(num) = signed_number.parse::() { - return Ok(Token::I64Literal(num, combined_ref)); - } - - if let Ok(num) = signed_number.parse::() { - return Ok(Token::IsizeLiteral(num, combined_ref)); - } - - // if signed_number's first character is not '-', - // then attempt to lex an unsigned number - self.src.jump_to(&cur_ref); - self.lex_unsigned_number() - } - - // try to lex an unsigned number which is one of: - // - u8 - // - u16 - // - u32 - // - u64 - // - usize - fn lex_unsigned_number(&mut self) -> Result { - let mut unsigned_number = String::new(); - let cur_ref = self.src.get_ref(); - let cur = self.src.cur_char(); - unsigned_number.push(cur); - - // read all characters that are digits - let mut end_ref; - loop { - let c = self.src.next_char(); - end_ref = self.src.get_ref(); - if c.is_ascii_digit() { - unsigned_number.push(c); - } else if c == '_' { - // ignore underscores - continue; - } else { - break; - } - } - - let combined_ref = cur_ref.combine(end_ref); - // check if unsigned_number is u8 - if let Ok(num) = unsigned_number.parse::() { - return Ok(Token::U8Literal(num, combined_ref)); - } - - if let Ok(num) = unsigned_number.parse::() { - return Ok(Token::U16Literal(num, combined_ref)); - } - - if let Ok(num) = unsigned_number.parse::() { - return Ok(Token::U32Literal(num, combined_ref)); - } - - if let Ok(num) = unsigned_number.parse::() { - return Ok(Token::U64Literal(num, combined_ref)); - } - - if let Ok(num) = unsigned_number.parse::() { - return Ok(Token::UsizeLiteral(num, combined_ref)); - } - // if it is not a valid unsigned number, return an error - Err(LexError::CannotMakeUnsignedNumber(combined_ref)) + return Ok(Token::Integer(number, combined_ref)); } } diff --git a/src/frontend/lexer_inputs/char_literals.pr b/src/frontend/lexer_inputs/char_literals.pr index 75a8902..4909281 100644 --- a/src/frontend/lexer_inputs/char_literals.pr +++ b/src/frontend/lexer_inputs/char_literals.pr @@ -9,3 +9,5 @@ "this is a string with \f form feed" "this is a string with \\ backslash" "this is a string with \0 null character" +|| this is a multiline string fragment +|| this is another part of the above string fragment diff --git a/src/frontend/lexer_inputs/keywords.pr b/src/frontend/lexer_inputs/keywords.pr index 33ede37..a9a3fca 100644 --- a/src/frontend/lexer_inputs/keywords.pr +++ b/src/frontend/lexer_inputs/keywords.pr @@ -3,4 +3,5 @@ loop while void true false and or not i8 i16 i32 i64 isize u8 u16 u32 u64 usize -bool char use return +bool char str return comp +struct diff --git a/src/frontend/lexer_inputs/numbers.pr b/src/frontend/lexer_inputs/numbers.pr index 3a5ce8a..2e7e77e 100644 --- a/src/frontend/lexer_inputs/numbers.pr +++ b/src/frontend/lexer_inputs/numbers.pr @@ -1 +1,3 @@ --128 127 -32_768 32_767 -2_147_483_648 2_147_483_647 -9_223_372_036_854_775_808 9_223_372_036_854_775_807 18_446_744_073_709_551_615 +128 127 32_768 32_767 2_147_483_648 +2_147_483_647 -9_223_372_036_854_775_808 +9_223_372_036_854_775_807 18_446_744_073_709_551_615 diff --git a/src/frontend/lexer_inputs/operators.pr b/src/frontend/lexer_inputs/operators.pr index 20402f6..a742f76 100644 --- a/src/frontend/lexer_inputs/operators.pr +++ b/src/frontend/lexer_inputs/operators.pr @@ -1,5 +1,5 @@ -+ - * / % ! ++ - * / % == != < > <= >= = and or not ! -( ) { } [ ] ; : , . -:: $ ^ @ as +( ) { } [ ] ; , . +@ ? diff --git a/src/frontend/mod.rs b/src/frontend/mod.rs index 057431e..b1eca41 100644 --- a/src/frontend/mod.rs +++ b/src/frontend/mod.rs @@ -5,4 +5,3 @@ pub mod lexer; pub mod parser; pub mod source; pub mod token; -pub mod types; diff --git a/src/frontend/parser.rs b/src/frontend/parser.rs index 6b5bc92..61cffae 100644 --- a/src/frontend/parser.rs +++ b/src/frontend/parser.rs @@ -1,11 +1,10 @@ use super::{ - ast::{CompilationModule, DependencyPath, Expr, Instruction, KeyValueBindings, PathAction}, + ast::{CompilationModule, Expr, Instruction, KeyValueBindings, TypeReference}, directives::{DIRECTIVES_EXPRS, DIRECTIVES_INS}, errors::{LexError, ParseError}, lexer::Lexer, source::SourceRef, token::Token, - types::Type, }; #[allow(dead_code)] @@ -15,7 +14,7 @@ enum ParseScope { FnBody, Loop, CodeBlock, - Module, + Struct, } #[allow(dead_code)] @@ -25,8 +24,8 @@ pub struct Parser { pub parser_errors: Vec, lexed_token: Option, parse_scope: ParseScope, - pub compilation_module: CompilationModule, allow_directive_expr_use: bool, + pub compilation_module: CompilationModule, } #[allow(dead_code)] @@ -117,9 +116,7 @@ impl Parser { src: src.clone(), }) } - Token::Colon(_) => self.parse_struct_decl(), Token::At(_) => self.parse_directive_instruction(), - Token::Use(_) => self.parse_use_dependency(), Token::If(_) => self.parse_conditional_branch_ins(), Token::Fn(_) => self.parse_fn_def(false, None), Token::Let(_) => self.parse_const_decl(false, None), @@ -131,9 +128,9 @@ impl Parser { // top level code Token::Mut(_) => { let var = self.parse_var_decl()?; - if matches!(self.parse_scope, ParseScope::TopLevel | ParseScope::Module) { + if matches!(self.parse_scope, ParseScope::Struct) { // declaring variables at the top level is not allowed - Err(ParseError::NoVariableAtTopLevel(var.source_ref())) + Err(ParseError::NoVariableAtCurrentScope(var.source_ref())) } else { Ok(var) } @@ -172,9 +169,11 @@ impl Parser { } Token::LCurly(_) => { let blk = self.parse_code_block()?; - if matches!(self.parse_scope, ParseScope::TopLevel | ParseScope::Module) { + if matches!(self.parse_scope, ParseScope::TopLevel | ParseScope::Struct) { // declaring code blocks at the top level is not allowed - Err(ParseError::NoCodeBlockAtTopLevel(blk.source_ref())) + Err(ParseError::NoCodeBlockAllowedInCurrentContext( + blk.source_ref(), + )) } else { Ok(blk) } @@ -184,6 +183,8 @@ impl Parser { self.advance_index(); let cur = self.cur_token(); let value = if let Token::Semicolon(_) = cur { + self.advance_index(); + ret_ref = ret_ref.combine(cur.get_source_ref()); // return with no value None } else { @@ -232,7 +233,6 @@ impl Parser { cur = self.cur_token(); match cur { Token::Fn(_) => self.parse_fn_def(true, Some(pub_ref)), - Token::Mod(_) => self.parse_module(true, Some(pub_ref)), Token::Let(_) => self.parse_const_decl(true, Some(pub_ref)), _ => { let ins = self.next_instruction()?; @@ -242,7 +242,6 @@ impl Parser { } } } - Token::Mod(_) => self.parse_module(false, None), _ => self.parse_assignment_or_expr_instruc(), } } @@ -272,31 +271,6 @@ impl Parser { matches!(self.cur_token(), Token::Eof(_)) } - fn parse_module( - &mut self, - is_public: bool, - pub_ref: Option, - ) -> Result { - let prev_scope = self.parse_scope; - self.parse_scope = ParseScope::Module; - let mut mod_ref = self.cur_token().get_source_ref(); - self.advance_index(); - - let mod_name = self.parse_id(false)?; - let body = self.parse_code_block()?; - mod_ref = mod_ref.combine(body.source_ref()); - if is_public { - mod_ref = mod_ref.combine(pub_ref.unwrap()); - } - self.parse_scope = prev_scope; - Ok(Instruction::Module { - name: mod_name, - body: Box::new(body), - src: mod_ref, - is_public, - }) - } - fn parse_code_block(&mut self) -> Result { let prev_scope = self.parse_scope; if !matches!(self.parse_scope, ParseScope::FnBody | ParseScope::Loop) { @@ -349,9 +323,9 @@ impl Parser { let mut ins = None; let mut span = start.get_source_ref(); if *needs_additional_ins { - let block = self.parse_code_block()?; - span = span.combine(block.source_ref()); - ins = Some(Box::new(block)); + let body = self.next_instruction()?; + span = span.combine(body.source_ref()); + ins = Some(Box::new(body)); } let direc = Instruction::DirectiveInstruction { directive, @@ -371,268 +345,6 @@ impl Parser { } } - fn parse_use_dependency(&mut self) -> Result { - let start = self.cur_token(); - // skip the 'use' keyword - self.advance_index(); - - let mut paths_to_import = vec![]; - while !self.no_more_tokens() { - let paths = self.parse_path()?; - paths_to_import.extend(paths); - - // expect a comma - let cur = self.cur_token(); - if matches!(cur, Token::Comma(_)) { - self.advance_index(); - } else if matches!(cur, Token::Semicolon(_)) { - break; - } else { - return Err(ParseError::Expected( - "Expected ',' to separate paths in use instruction. ".to_string(), - cur.get_source_ref(), - Some( - "Provide a ',' to separate paths. E.g: 'use kids::next::door, cartoon::network;'".to_string(), - ), - )); - } - } - - // expect a semicolon - let end = self.cur_token(); - if matches!(end, Token::Semicolon(_)) { - self.advance_index(); - let use_ins = Instruction::UseDependency { - paths: paths_to_import, - src: start.get_source_ref().combine(end.get_source_ref()), - }; - Ok(use_ins) - } else { - Err(ParseError::Expected( - "Expected ';' to terminate use instruction. ".to_string(), - end.get_source_ref(), - Some("Provide a ';'. E.g: 'use kids::next::door;'".to_string()), - )) - } - } - - fn parse_path(&mut self) -> Result, ParseError> { - let start = self.cur_token(); - // allow parsing: - // - immediate paths - // - ^ paths - // - ! paths - // - $ paths - // - @ paths - // all with or without the 'as' alias - match start { - Token::Identifier(_, _) | Token::Caret(_) => self.parse_simple_path_section(true), - Token::Exclamation(_) | Token::Dollar(_) | Token::At(_) => { - self.parse_directive_path_section() - } - _ => Err(ParseError::UnusualTokenInUsePath(start.get_source_ref())), - } - } - - fn parse_directive_path_section(&mut self) -> Result, ParseError> { - let cur = self.cur_token(); - let mut dep_paths = vec![]; - let mut path_actions = vec![]; - // this will parse one of the following directives: - // 1. !module_in_current_file - // 2. $module_in_project_root - // 3. @module_in_core_library - match cur { - Token::Exclamation(_) => { - // this is a module in the current file - // skip the '!' token - self.advance_index(); - let id = self.parse_id(false)?; - path_actions.push(PathAction::SearchCurrentFileFor(id)); - } - Token::Dollar(_) => { - // this is a module in the project root - // skip the '$' token - self.advance_index(); - let id = self.parse_id(false)?; - path_actions.push(PathAction::SearchProjectRootFor(id)); - } - Token::At(_) => { - // this is a module in the std - // skip the '@' token - self.advance_index(); - let id = self.parse_id(false)?; - path_actions.push(PathAction::SearchCoreModulesFor(id)); - } - _ => { - unreachable!("parse_directive_path_section called with invalid token"); - } - } - - if let Token::Scope(_) = self.cur_token() { - self.advance_index(); - let simple_dep_paths = self.parse_simple_path_section(false)?; - - for simple_dep_path in simple_dep_paths { - let t_dep_path = DependencyPath { - actions: path_actions.clone(), - }; - - let combined_path = t_dep_path.combine(&simple_dep_path); - dep_paths.push(combined_path); - } - Ok(dep_paths) - } else { - dep_paths.push(DependencyPath { - actions: path_actions, - }); - Ok(dep_paths) - } - } - - fn parse_simple_path_section( - &mut self, - allow_caret: bool, - ) -> Result, ParseError> { - let mut cur = self.cur_token(); - let mut dep_paths = vec![]; - - let mut match_condition = if allow_caret { - matches!(cur, Token::Identifier(_, _) | Token::Caret(_)) - } else { - matches!(cur, Token::Identifier(_, _)) - }; - // this will parse either an identifier or a caret - if match_condition { - let mut path_actions = vec![]; - let mut expects_path_section = false; - while match_condition { - if let Token::Identifier(_, _) = cur { - let id = self.parse_id(false)?; - path_actions.push(PathAction::SearchFor(id)); - } else { - path_actions.push(PathAction::ToParentDir(cur.get_source_ref())); - self.advance_index(); - } - - if let Token::Scope(_) = self.cur_token() { - self.advance_index(); - cur = self.cur_token(); - match_condition = if allow_caret { - matches!(cur, Token::Identifier(_, _) | Token::Caret(_)) - } else { - matches!(cur, Token::Identifier(_, _)) - }; - expects_path_section = true; - } else { - expects_path_section = false; - break; - } - } - - cur = self.cur_token(); - // look for one of: - // - * - // - as - // - [ to start a nested path - match cur { - Token::Star(_) => { - self.advance_index(); - path_actions.push(PathAction::ImportAll(cur.get_source_ref())); - dep_paths.push(DependencyPath { - actions: path_actions, - }); - } - Token::As(_) => { - self.advance_index(); - let alias = self.parse_id(false)?; - path_actions.push(PathAction::NameLastItemAs(alias)); - dep_paths.push(DependencyPath { - actions: path_actions, - }); - } - Token::LBracket(_) => { - self.advance_index(); - cur = self.cur_token(); - while !matches!(cur, Token::RBracket(_)) && !self.no_more_tokens() { - let inner_paths = self.parse_simple_path_section(allow_caret)?; - for inner_path in inner_paths { - let t_dep_path = DependencyPath { - actions: path_actions.clone(), - }; - - let combined_path = t_dep_path.combine(&inner_path); - dep_paths.push(combined_path); - } - cur = self.cur_token(); - if matches!(cur, Token::Comma(_)) { - self.advance_index(); - cur = self.cur_token(); - } else { - break; - } - } - if matches!(cur, Token::RBracket(_)) { - self.advance_index(); - } else { - return Err(ParseError::Expected( - "a ']' to terminate path section.".to_string(), - cur.get_source_ref(), - Some("Provide a ']'. E.g: '[kids::next::door]'".to_string()), - )); - } - } - _ => { - if expects_path_section { - let msg = if allow_caret { - "a '^', '*', 'as' or '[' to continue use path section.".to_string() - } else { - "a '*', 'as' or '[' to continue use path section.".to_string() - }; - let tip = if allow_caret { - let mut text = - "Provide a '^', '*', 'as' or '[' to continue use path section.'" - .to_string(); - text.push_str("E.g:\n"); - text.push_str("* use immediate_module::inner::other;\n"); - text.push_str("* use immediate_module::inner as alias;\n"); - text.push_str("* use immediate::[use_path1, use_path2, ...];\n"); - text.push_str("* use immediate_module;\n"); - text.push_str("* use import_everything::*;\n"); - text.push_str("* use ^::module_in_parent_dir;\n"); - text.push_str("* use ^::module_in_parent_dir::inner;\n"); - text.push_str("* use ^::^::module_in_grandparent_dir::inner;\n"); - text - } else { - let mut text = - "Provide a '*', 'as' or '[' to continue use path section.'" - .to_string(); - text.push_str("E.g:\n"); - text.push_str("* use @array::Array as core_array;\n"); - text.push_str("* use @array::Array;\n"); - text.push_str("* use @array::[Array, Array2D];\n"); - text.push_str("* use @array;\n"); - text.push_str("* use !my_module::*;\n"); - text.push_str("* use $some_module_in_root::[a, b]"); - text - }; - return Err(ParseError::Expected(msg, cur.get_source_ref(), Some(tip))); - } - dep_paths.push(DependencyPath { - actions: path_actions, - }); - } - } - Ok(dep_paths) - } else { - Err(ParseError::Expected( - "an identifier or caret (^) as path section.".to_string(), - cur.get_source_ref(), - None, - )) - } - } - fn parse_fn_def( &mut self, is_public: bool, @@ -680,6 +392,8 @@ impl Parser { too_many_params = true; } + // TODO: fn some_name(mut param type = init, param_b type = init, param_c type); reuse code from parse_var_decl + cur = self.cur_token(); if !matches!(cur, Token::RParen(_)) { let param = self.parse_id(true)?; @@ -711,9 +425,8 @@ impl Parser { // parse return type cur = self.cur_token(); let return_type; - if cur.is_type_token() { - return_type = Some(cur.to_type()); - self.advance_index(); + if let Ok(sem_type) = self.parse_type() { + return_type = Some(sem_type); } else { // report that a type is expected return Err(ParseError::Expected( @@ -722,6 +435,29 @@ impl Parser { Some("If it returns nothing, use the 'void' type as its return type.".into()), )); } + + // check if the next token is a semi-colon. If it is, + // then this is a function prototype, not a function definition + // so we just return a function prototype instruction + // and don't parse the function body + cur = self.cur_token(); + if matches!(cur, Token::Semicolon(_)) { + self.advance_index(); + self.parse_scope = temp_scope; + let ret_type = return_type.unwrap(); + let mut fn_ref = start.get_source_ref().combine(cur.get_source_ref()); + if is_public { + fn_ref = fn_ref.combine(pub_ref.unwrap()); + } + return Ok(Instruction::FunctionPrototype { + name: label.unwrap(), + params, + return_type: ret_type, + is_public, + src: fn_ref, + }); + } + // parse function body, which is just an instruction // set the scope of this instruction to be Fn (to allow parsing variables) let fn_body = self.next_instruction()?; @@ -741,6 +477,180 @@ impl Parser { }) } + fn parse_type(&mut self) -> Result { + let cur = self.cur_token(); + let start = cur.get_source_ref(); + + match cur { + Token::Identifier(_, _) => { + let id = cur.as_str(); + self.advance_index(); + Ok(TypeReference::IdentifierType(id, start)) + } + Token::LParen(_) => { + self.advance_index(); + let mut types = vec![]; + 'types: while !self.no_more_tokens() { + if types.len() > 256 { + return Err(ParseError::TooManyTypes( + start.combine(cur.get_source_ref()), + )); + } + + let cur = self.cur_token(); + if !matches!(cur, Token::RParen(_)) { + let ty = self.parse_type()?; + types.push(ty); + } + + match cur { + Token::RParen(_) => { + self.advance_index(); + break 'types; + } + Token::Comma(_) => { + self.advance_index(); + continue 'types; + } + _ => return Err(ParseError::Expected( + "a ',' to separate types or a ')' to terminate tuple type declaration." + .into(), + start.combine(cur.get_source_ref()), + None, + )), + } + } + Ok(TypeReference::TupleOf(types, start)) + } + Token::LBracket(_) => { + self.advance_index(); + let inner_type = self.parse_type()?; + let cur = self.cur_token(); + match cur { + Token::RBracket(_) => { + self.advance_index(); + return Ok(TypeReference::ArrayOf(Box::new(inner_type), start)); + } + Token::Semicolon(_) => { + // static array + self.advance_index(); + let cur = self.cur_token(); + let size; + if let Token::Integer(num, src) = cur { + self.advance_index(); + // convert to usize + let maybe_size = num.parse::(); + if let Ok(size_) = maybe_size { + size = size_; + } else { + return Err(ParseError::Expected( + "an integer to specify the size of the array.".into(), + start.combine(src.clone()), + None, + )); + } + } else { + return Err(ParseError::Expected( + "an integer to specify the size of the array.".into(), + start.combine(cur.get_source_ref()), + None, + )); + } + + let cur = self.cur_token(); + if let Token::RBracket(_) = cur { + self.advance_index(); + return Ok(TypeReference::StaticArrayOf( + Box::new(inner_type), + size, + start, + )); + } else { + return Err(ParseError::Expected( + "a ']' to terminate the array type declaration.".into(), + start.combine(cur.get_source_ref()), + None, + )); + } + } + _ => { + return Err(ParseError::Expected( + "a ']' to terminate the array type declaration or a ';' with a size to specify a static array." + .into(), + start.combine(cur.get_source_ref()), + None, + )) + } + } + } + Token::I8(_) => { + self.advance_index(); + Ok(TypeReference::I8(start)) + } + Token::I16(_) => { + self.advance_index(); + Ok(TypeReference::I16(start)) + } + Token::I32(_) => { + self.advance_index(); + Ok(TypeReference::I32(start)) + } + Token::I64(_) => { + self.advance_index(); + Ok(TypeReference::I64(start)) + } + Token::ISize(_) => { + self.advance_index(); + Ok(TypeReference::ISize(start)) + } + Token::U8(_) => { + self.advance_index(); + Ok(TypeReference::U8(start)) + } + Token::U16(_) => { + self.advance_index(); + Ok(TypeReference::U16(start)) + } + Token::U32(_) => { + self.advance_index(); + Ok(TypeReference::U32(start)) + } + Token::U64(_) => { + self.advance_index(); + Ok(TypeReference::U64(start)) + } + Token::USize(_) => { + self.advance_index(); + Ok(TypeReference::USize(start)) + } + Token::Bool(_) => { + self.advance_index(); + Ok(TypeReference::Bool(start)) + } + Token::Char(_) => { + self.advance_index(); + Ok(TypeReference::Char(start)) + } + Token::Str(_) => { + self.advance_index(); + Ok(TypeReference::Str(start)) + } + Token::Void(_) => { + self.advance_index(); + Ok(TypeReference::Void(start)) + } + Token::Type(_) => { + self.advance_index(); + Ok(TypeReference::Type(start)) + } + _ => Err(ParseError::Expected( + "a type.".into(), + start.combine(cur.get_source_ref()), + None, + )), + } + } + fn parse_const_decl( &mut self, is_public: bool, @@ -765,41 +675,45 @@ impl Parser { } let mut const_type = None; - // try to parse an optional type and/or an optional assignment - // this will be replaced with a call to parse_type(try: true) - // which will try to parse a type - if cur.is_type_token() { - const_type = Some(cur.to_type()); - self.advance_index(); + if !matches!(cur, Token::Assign(_)) { + // if it is not an assign (initialization), + // then it must be a type + const_type = Some(self.parse_type()?); cur = self.cur_token(); } + let mut init_value = None; + let mut end_ref = start.get_source_ref(); if let Token::Assign(_) = cur { self.advance_index(); + let val = self.parse_expr()?; + end_ref = end_ref.combine(val.source_ref()); + init_value = Some(val); } else { - return Err(ParseError::ConstantDeclarationNeedsInitValue( - self.cur_token() - .get_source_ref() - .combine(start.get_source_ref()), - )); + // if no type is provided, throw an error + if const_type.is_none() { + return Err(ParseError::ConstantDeclarationNeedsTypeOrInitValue( + self.cur_token() + .get_source_ref() + .combine(start.get_source_ref()), + )); + } } - let init_value = self.parse_expr()?; cur = self.cur_token(); match cur { Token::Semicolon(_) => { - let end_ref = cur.get_source_ref(); + end_ref = end_ref.combine(cur.get_source_ref()); self.advance_index(); let name = label.unwrap(); - let mut decl_ref = start.get_source_ref().combine(end_ref); if is_public { - decl_ref = decl_ref.combine(pub_ref.unwrap()); + end_ref = end_ref.combine(pub_ref.unwrap()); } Ok(Instruction::ConstantDecl { const_name: name, const_type, init_expr: init_value, - src_ref: decl_ref, + src_ref: end_ref, is_public: false, }) } @@ -807,19 +721,15 @@ impl Parser { let tip = match const_type { Some(type_t) => { format!( - "Terminate constant declaration: 'let {const_name} {} = {};'", + "Terminate constant declaration: 'let {const_name} {} = ...;'", type_t.as_str(), - init_value.as_str() ) } - None => format!( - "Terminate constant declaration: 'let {const_name} = {};'", - init_value.as_str() - ), + None => format!("Terminate constant declaration: 'let {const_name} = ...;'",), }; Err(ParseError::Expected( "';' to terminate constant declaration.".into(), - cur.get_source_ref(), + end_ref, Some(tip), )) } @@ -937,20 +847,6 @@ impl Parser { }) } - fn parse_struct_decl(&mut self) -> Result { - let mut span = self.cur_token().get_source_ref(); - self.advance_index(); // skip past ":" - let name = self.parse_id(false)?; - let key_value_pairs = self.parse_key_value_bindings(true)?; - span = span.combine(key_value_pairs.source_ref()); - let named_struct = Instruction::NamedStructDecl { - name, - fields: key_value_pairs, - src: span, - }; - Ok(named_struct) - } - // parses key-value bindings for structs fn parse_key_value_bindings( &mut self, @@ -1019,12 +915,10 @@ impl Parser { } let mut var_type = None; - // try to parse an optional type and/or an optional assignment - // this will be replaced with a call to parse_type(try: true) - // which will try to parse a type - if cur.is_type_token() { - var_type = Some(cur.to_type()); - self.advance_index(); + if !matches!(cur, Token::Assign(_)) { + // if it is not an assign (initialization) + // then it must be a type + var_type = Some(self.parse_type()?); cur = self.cur_token(); } @@ -1082,6 +976,18 @@ impl Parser { Token::Semicolon(_) => { let end_ref = cur.get_source_ref(); self.advance_index(); + + // if there is no type, report an error, since there is no + // way to infer the type of the variable ahead of its first use/assignment + if var_type.is_none() { + let tip = + format!("Provide a type for the variable. E.g: 'mut {var_name} type;'."); + return Err(ParseError::Expected( + "a type for the variable.".into(), + cur.get_source_ref(), + Some(tip), + )); + } let name = label.unwrap(); Ok(Instruction::VariableDecl( name, @@ -1121,11 +1027,13 @@ impl Parser { Some(tip), )); } - Ok(Instruction::AssignmentIns(target, value)) + let span = target.source_ref().combine(value.source_ref()); + Ok(Instruction::AssignmentIns(target, value, span)) } Token::Semicolon(_) => { + let span = target.source_ref().combine(cur.get_source_ref()); self.advance_index(); - Ok(Instruction::ExpressionIns(target, cur)) + Ok(Instruction::ExpressionIns(target, span)) } _ => Err(ParseError::Expected( "a terminated expression or an assignment instruction.".into(), @@ -1148,7 +1056,8 @@ impl Parser { Token::Or(_) => { self.advance_index(); let rhs = self.parse_and()?; - lhs = Expr::Comparison(cur, Box::new(lhs), Box::new(rhs), None); + let span = lhs.source_ref().combine(rhs.source_ref()); + lhs = Expr::Comparison(cur, Box::new(lhs), Box::new(rhs), span); } _ => return Ok(lhs), } @@ -1164,7 +1073,8 @@ impl Parser { Token::And(_) => { self.advance_index(); let rhs = self.parse_equality()?; - lhs = Expr::Comparison(cur, Box::new(lhs), Box::new(rhs), None); + let span = lhs.source_ref().combine(rhs.source_ref()); + lhs = Expr::Comparison(cur, Box::new(lhs), Box::new(rhs), span); } _ => return Ok(lhs), } @@ -1180,7 +1090,8 @@ impl Parser { Token::Equal(_) | Token::NotEqual(_) => { self.advance_index(); let rhs = self.parse_comparison()?; - lhs = Expr::Comparison(cur, Box::new(lhs), Box::new(rhs), None); + let span = lhs.source_ref().combine(rhs.source_ref()); + lhs = Expr::Comparison(cur, Box::new(lhs), Box::new(rhs), span); } _ => return Ok(lhs), } @@ -1199,7 +1110,8 @@ impl Parser { | Token::LessEqual(_) => { self.advance_index(); let rhs = self.parse_term()?; - lhs = Expr::Comparison(cur, Box::new(lhs), Box::new(rhs), None); + let span = lhs.source_ref().combine(rhs.source_ref()); + lhs = Expr::Comparison(cur, Box::new(lhs), Box::new(rhs), span); } _ => return Ok(lhs), } @@ -1215,7 +1127,8 @@ impl Parser { Token::Plus(_) | Token::Minus(_) => { self.advance_index(); let rhs = self.parse_factor()?; - lhs = Expr::Binary(cur, Box::new(lhs), Box::new(rhs), None); + let span = lhs.source_ref().combine(rhs.source_ref()); + lhs = Expr::Binary(cur, Box::new(lhs), Box::new(rhs), span); } _ => return Ok(lhs), } @@ -1231,7 +1144,8 @@ impl Parser { Token::Star(_) | Token::Modulo(_) | Token::Slash(_) => { self.advance_index(); let rhs = self.parse_unary()?; - lhs = Expr::Binary(cur, Box::new(lhs), Box::new(rhs), None); + let span = lhs.source_ref().combine(rhs.source_ref()); + lhs = Expr::Binary(cur, Box::new(lhs), Box::new(rhs), span); } _ => return Ok(lhs), } @@ -1244,7 +1158,8 @@ impl Parser { Token::Not(_) => { self.advance_index(); let operand = self.parse_unary()?; - Ok(Expr::Unary(cur, Box::new(operand), None)) + let span = cur.get_source_ref().combine(operand.source_ref()); + Ok(Expr::Unary(cur, Box::new(operand), span)) } _ => self.parse_index_like_exprs(), } @@ -1253,10 +1168,22 @@ impl Parser { fn parse_index_like_exprs(&mut self) -> Result { let mut lhs = self.parse_primary()?; - 'main_loop: loop { + loop { let mut cur = self.cur_token(); match cur { + Token::Dot(_) => { + // ScopeInto expr + self.advance_index(); + + let rhs = self.parse_id(false)?; + let span = lhs.source_ref().combine(rhs.source_ref()); + lhs = Expr::ScopeInto { + module: Box::new(lhs), + target: Box::new(rhs), + src: span, + }; + } Token::LParen(_) => { self.advance_index(); @@ -1285,7 +1212,6 @@ impl Parser { span: lhs.source_ref().combine(cur.get_source_ref()), func: Box::new(lhs), args, - fn_type: None, }; self.advance_index(); return Ok(lhs); @@ -1303,97 +1229,31 @@ impl Parser { } } } - Token::Scope(_) => { - // for now, we want to only allow: - // 1. `foo::bar()` (function call) - // 2. `foo::bar` (variable or constant) - // 3. `foo::bar::baz` (variable or constant) - // 4. `foo::bar::baz()` (function call) - // we cannot allow functions be referenced like variables, - // or constants. - // Make sure lhs is a Identifier or a ScopeInto - match lhs { - Expr::Id(_, _) => { - self.advance_index(); - let rhs = self.parse_primary()?; - match rhs { - Expr::Id(_, _) => { - lhs = Expr::ScopeInto { - src: lhs.source_ref().combine(rhs.source_ref()), - module: Box::new(lhs), - target: Box::new(rhs), - resolved_type: None, - }; - - continue 'main_loop; - } - _ => { - return Err(ParseError::Expected( - "an identifier after '::'.".into(), - rhs.source_ref(), - None, - )) - } - } - } - Expr::ScopeInto { .. } => { - self.advance_index(); - let rhs = self.parse_primary()?; - match rhs { - Expr::Id(_, _) => { - lhs = Expr::ScopeInto { - src: lhs.source_ref().combine(rhs.source_ref()), - module: Box::new(lhs), - target: Box::new(rhs), - resolved_type: None, - }; - continue 'main_loop; - } - _ => { - return Err(ParseError::Expected( - "an identifier after '::'.".into(), - rhs.source_ref(), - None, - )) - } - } - } - _ => { - return Err(ParseError::Expected( - "an identifier or scope into operation before '::'.".into(), - lhs.source_ref(), - None, - )) - } - } - } _ => return Ok(lhs), } } } fn parse_id(&mut self, with_type: bool) -> Result { - let mut cur = self.cur_token(); + let cur = self.cur_token(); if let Token::Identifier(_, _) = cur { self.advance_index(); if with_type { let id = cur; - cur = self.cur_token(); - if cur.is_type_token() { - self.advance_index(); - Ok(Expr::Id(id, Some(cur.to_type()))) + let sem_type = self.parse_type(); + if let Ok(sem_type) = sem_type { + let span = id.get_source_ref().combine(sem_type.get_source_ref()); + Ok(Expr::Id(id, Some(sem_type), span)) } else { Err(ParseError::Expected( - format!( - "to parse a type for the preceding identifier, '{}'.", - id.as_str() - ), + format!("a type for the preceding identifier, '{}'.", id.as_str()), id.get_source_ref(), Some("Please provide a type for this identifier.".into()), )) } } else { - Ok(Expr::Id(cur, None)) + let span = cur.get_source_ref(); + Ok(Expr::Id(cur, None, span)) } } else { Err(ParseError::Expected( @@ -1428,7 +1288,6 @@ impl Parser { directive: Box::new(directive), src: start.get_source_ref().combine(span), expr, - resolved_type: None, }; Ok(direc) } @@ -1443,96 +1302,101 @@ impl Parser { } } - fn parse_init_named_struct(&mut self) -> Result { + fn parse_named_struct_literal(&mut self, name: Expr) -> Result { let mut span = self.cur_token().get_source_ref(); - self.advance_index(); // consume ':' - - let name = self.parse_id(false)?; let fields = self.parse_key_value_bindings(false)?; span = span.combine(fields.source_ref()); - let init_named_struct = Expr::NamedStructInit { + let init_named_struct = Expr::NamedStructLiteral { name: Box::new(name), fields, src: span, - resolved_type: None, }; Ok(init_named_struct) } + // . {} where {} is a block + fn parse_anon_struct_literal(&mut self) -> Result { + // unlike struct {} and NameStruct {}, this should allow an + // optional type on the fields + let mut span = self.cur_token().get_source_ref(); + self.advance_index(); // consume '.' + let fields = self.parse_key_value_bindings(true)?; + span = span.combine(fields.source_ref()); + let init_anon_struct = Expr::AnonStructLiteral { fields, src: span }; + Ok(init_anon_struct) + } + + // struct {} // where {} is a block + fn parse_struct_decl(&mut self) -> Result { + let mut span = self.cur_token().get_source_ref(); + self.advance_index(); // consume 'struct' + + let prev_scope = self.parse_scope; + self.parse_scope = ParseScope::Struct; + + // parse block + let contents = self.parse_code_block()?; + span = span.combine(contents.source_ref()); + self.parse_scope = prev_scope; + Ok(Expr::StructDecl { + contents: Box::new(contents), + src: span, + }) + } + fn parse_primary(&mut self) -> Result { let cur = self.cur_token(); + let span = cur.get_source_ref(); match cur { - Token::Colon(_) => self.parse_init_named_struct(), + Token::Struct(_) => self.parse_struct_decl(), + Token::Dot(_) => self.parse_anon_struct_literal(), Token::At(_) => self.parse_directive_expr(), - Token::StringLiteral(_, _) => { - let res = Ok(Expr::StringLiteral(cur, Some(Type::Str))); + Token::SingleLineStringLiteral(_, _) => { + let res = Ok(Expr::SingleLineStringLiteral(cur, span)); self.advance_index(); res } - Token::CharLiteral(_, _) => { - let res = Ok(Expr::CharacterLiteral(cur, Some(Type::Char))); + Token::MultiLineStringFragment(..) => { + let mut span = cur.get_source_ref(); + let mut literals = vec![cur]; self.advance_index(); - res - } - Token::Identifier(_, _) => { - let res = Ok(Expr::Id(cur, None)); - self.advance_index(); - res - } - Token::I8Literal(_, _) => { - let res = Ok(Expr::Number(cur, Some(Type::I8))); - self.advance_index(); - res - } - Token::I16Literal(_, _) => { - let res = Ok(Expr::Number(cur, Some(Type::I16))); - self.advance_index(); - res - } - Token::I32Literal(_, _) => { - let res = Ok(Expr::Number(cur, Some(Type::I32))); - self.advance_index(); - res - } - Token::I64Literal(_, _) => { - let res = Ok(Expr::Number(cur, Some(Type::I64))); - self.advance_index(); - res - } - Token::IsizeLiteral(_, _) => { - let res = Ok(Expr::Number(cur, Some(Type::ISize))); - self.advance_index(); - res - } - Token::U8Literal(_, _) => { - let res = Ok(Expr::Number(cur, Some(Type::U8))); - self.advance_index(); - res - } - Token::U16Literal(_, _) => { - let res = Ok(Expr::Number(cur, Some(Type::U16))); - self.advance_index(); - res + + while let Token::MultiLineStringFragment(..) = self.cur_token() { + let frag = self.cur_token(); + span = span.combine(frag.get_source_ref()); + literals.push(frag); + self.advance_index(); + } // consume all fragments + + Ok(Expr::MultiLineStringLiteral(literals, span)) } - Token::U32Literal(_, _) => { - let res = Ok(Expr::Number(cur, Some(Type::U32))); + Token::CharLiteral(_, _) => { + let span = cur.get_source_ref(); + let res = Ok(Expr::CharacterLiteral(cur, span)); self.advance_index(); res } - Token::U64Literal(_, _) => { - let res = Ok(Expr::Number(cur, Some(Type::U64))); + Token::Identifier(_, _) => { + let id = Expr::Id(cur, None, span); self.advance_index(); - res + + if let Token::LCurly(_) = self.cur_token() { + // parse named struct literal + self.parse_named_struct_literal(id) + } else { + // parse identifier + Ok(id) + } } - Token::UsizeLiteral(_, _) => { - let res = Ok(Expr::Number(cur, Some(Type::USize))); + Token::Integer(num, src) => { + let res = Ok(Expr::Integer(num, src)); self.advance_index(); res } Token::True(_) | Token::False(_) => { self.advance_index(); - Ok(Expr::Boolean(cur, Some(Type::Bool))) + Ok(Expr::Boolean(cur, span)) } Token::LParen(_) => { // parse group @@ -1551,11 +1415,21 @@ impl Parser { } Ok(Expr::Grouped( Box::new(expr), - None, cur.get_source_ref().combine(maybe_rparen.get_source_ref()), )) } - _ => Err(ParseError::CannotParseAnExpression(cur.get_source_ref())), + _ => { + // try to parse type + let ty = self.parse_type(); + + if let Ok(ty) = ty { + // return a type expression + let span = ty.get_source_ref(); + Ok(Expr::TypeExpr(ty, span)) + } else { + Err(ParseError::CannotParseAnExpression(cur.get_source_ref())) + } + } } } } diff --git a/src/frontend/parser_inputs/directives.pr b/src/frontend/parser_inputs/directives.pr deleted file mode 100644 index f26c449..0000000 --- a/src/frontend/parser_inputs/directives.pr +++ /dev/null @@ -1,37 +0,0 @@ -fn main() void { - let a = @run 0 * 0; // expect file to contain "let a = 0;" - @inline { - mut sum = 0; - while a < 2 { - sum = sum + a; - a = a + 1; - } - } - // expects the file to contain the following generated lines - // mut sum = 0; - // sum = sum + a; // a = 0 so sum = 0 - // a = a + 1; // a = 1 - // sum = sum + a; // a = 1 so sum = 1 - // a = a + 1; // a = 2 so loop ends - - let filename = @filename; // expect file to contain "let filename = 'proto.pr';" - let text = "a piece of text"; // an array of utf-8 characters - let character = 'a'; // a utf-8 character - - @inline { - if @platform == "windows" { - a = 1; - } else if @platform == "linux" { - a = 2; - } else if @platform == "mac" { - a = 3; - // @cpp .{ include = "stdio.h", code = @run read_file_to_str("__inline.cpp") } - } else { - a = 4; - } - } // expect file to contain "a = 3;" - - @run { - if a != 3 {} //@error .{ msg = @datetime + ": Not a Mac!", verbose = false } - } -} diff --git a/src/frontend/parser_inputs/fn_def.pr b/src/frontend/parser_inputs/fn_def.pr index cdae86a..9ab100c 100644 --- a/src/frontend/parser_inputs/fn_def.pr +++ b/src/frontend/parser_inputs/fn_def.pr @@ -5,3 +5,9 @@ fn add(a i64, b i64) i64 { fn do_nothing() void {} fn do_nothing_() void return 1; + +fn prototype() i64; + +fn returns_nothing() void { + return; +} diff --git a/src/frontend/parser_inputs/methods.pr b/src/frontend/parser_inputs/methods.pr new file mode 100644 index 0000000..c6a7e22 --- /dev/null +++ b/src/frontend/parser_inputs/methods.pr @@ -0,0 +1,17 @@ +let Person = struct { + mut name str; + mut age i8; + + pub fn get_name(self Person) str { + return name; + } + + pub fn get_age(self Person) i8 { + return age; + } +}; + +let p = Person { + name = "John", + age = 32, +}; diff --git a/src/frontend/parser_inputs/modules.pr b/src/frontend/parser_inputs/modules.pr deleted file mode 100644 index b59efff..0000000 --- a/src/frontend/parser_inputs/modules.pr +++ /dev/null @@ -1,20 +0,0 @@ -mod some_fns { - pub fn public_fn() void { - } - - fn private_fn() void { - } -} - -pub mod some_mod { - pub fn public_fn() void { - } - - fn private_fn() void { - } -} - -fn main() void { - some_fns::public_fn(); - some_mod::public_fn(); -} diff --git a/src/frontend/parser_inputs/structs.pr b/src/frontend/parser_inputs/structs.pr index 79287b9..abb1d68 100644 --- a/src/frontend/parser_inputs/structs.pr +++ b/src/frontend/parser_inputs/structs.pr @@ -1,16 +1,41 @@ // This is a sample for user defined structs +// you can create a struct by either +// 1. using the struct keyword, which is for structs with methods and +// granular control over fields +// 2. using the .{ } syntax, which is for data-only structs (like C structs?) -// simple struct that uses defaults -:SourceFile { +// style 1 +// struct with methods +let SourceFile0 = struct { + mut path str; + mut text str; + mut flat_index usize; + mut col usize; + mut line usize; + + pub fn make_from_path(path str) SourceFile0 { + return SourceFile0 { + path = path, + text = "", + flat_index = 0, + col = 0, + line = 0, + }; + } +}; + +// style 2 +// data struct that uses defaults +let SourceFile1 = .{ path str, text str = "", flat_index usize = 0, col usize = 0, line usize = 0, -} +}; fn main() void { // since we allow defaults, we can focus on the // members we care about initializing - mut src = :SourceFile { path = "./using_constructor.pr" }; + mut src = SourceFile { path = "./using_constructor.pr" }; } diff --git a/src/frontend/parser_inputs/use_instructions.pr b/src/frontend/parser_inputs/use_instructions.pr deleted file mode 100644 index a4fda6e..0000000 --- a/src/frontend/parser_inputs/use_instructions.pr +++ /dev/null @@ -1,22 +0,0 @@ -use other::a::b::c::d::*; -use other::[a, b, c::[d, e, f], ^::other::g]; -use ^::prototyping::other::a::^::other::a; -use @arrays::Array::other::a; -use $some_module_at_root; - -mod some_fns { - pub fn public_fn() void { - private_fn(); - } - - fn private_fn() void { - println(1); - } -} - -use !some_fns::public_fn; - -fn main() void { - public_fn(); - other::some_mod::public_fn(); -} diff --git a/src/frontend/snapshots/proto__frontend__lexer__lexer@char_literals.pr.snap b/src/frontend/snapshots/proto__frontend__lexer__lexer@char_literals.pr.snap index 07284d7..b8d06d7 100644 --- a/src/frontend/snapshots/proto__frontend__lexer__lexer@char_literals.pr.snap +++ b/src/frontend/snapshots/proto__frontend__lexer__lexer@char_literals.pr.snap @@ -27,4 +27,6 @@ stringified_tokens: - "\"this is a string with \\f form feed\" at [start_line:8 start_col:0 end_line:8 end_col:36 flat_start:295 flat_end:331]" - "\"this is a string with \\\\ backslash\" at [start_line:9 start_col:0 end_line:9 end_col:36 flat_start:332 flat_end:368]" - "\"this is a string with \\0 null character\" at [start_line:10 start_col:0 end_line:10 end_col:41 flat_start:369 flat_end:410]" + - "|| this is a multiline string fragment at [start_line:11 start_col:0 end_line:11 end_col:38 flat_start:411 flat_end:449]" + - "|| this is another part of the above string fragment at [start_line:12 start_col:0 end_line:12 end_col:52 flat_start:450 flat_end:502]" diff --git a/src/frontend/snapshots/proto__frontend__lexer__lexer@keywords.pr.snap b/src/frontend/snapshots/proto__frontend__lexer__lexer@keywords.pr.snap index c1108d1..097be3a 100644 --- a/src/frontend/snapshots/proto__frontend__lexer__lexer@keywords.pr.snap +++ b/src/frontend/snapshots/proto__frontend__lexer__lexer@keywords.pr.snap @@ -29,6 +29,8 @@ stringified_tokens: - "usize at [start_line:4 start_col:15 end_line:4 end_col:20 flat_start:93 flat_end:98]" - "bool at [start_line:5 start_col:0 end_line:5 end_col:4 flat_start:99 flat_end:103]" - "char at [start_line:5 start_col:5 end_line:5 end_col:9 flat_start:104 flat_end:108]" - - "use at [start_line:5 start_col:10 end_line:5 end_col:13 flat_start:109 flat_end:112]" + - "str at [start_line:5 start_col:10 end_line:5 end_col:13 flat_start:109 flat_end:112]" - "return at [start_line:5 start_col:14 end_line:5 end_col:20 flat_start:113 flat_end:119]" + - "comp at [start_line:5 start_col:21 end_line:5 end_col:25 flat_start:120 flat_end:124]" + - "struct at [start_line:6 start_col:0 end_line:6 end_col:6 flat_start:125 flat_end:131]" diff --git a/src/frontend/snapshots/proto__frontend__lexer__lexer@numbers.pr.snap b/src/frontend/snapshots/proto__frontend__lexer__lexer@numbers.pr.snap index dc410ab..23deb2a 100644 --- a/src/frontend/snapshots/proto__frontend__lexer__lexer@numbers.pr.snap +++ b/src/frontend/snapshots/proto__frontend__lexer__lexer@numbers.pr.snap @@ -4,13 +4,14 @@ expression: res input_file: src/frontend/lexer_inputs/numbers.pr --- stringified_tokens: - - "-128 at [start_line:0 start_col:0 end_line:0 end_col:4 flat_start:0 flat_end:4]" - - "127 at [start_line:0 start_col:5 end_line:0 end_col:8 flat_start:5 flat_end:8]" - - "-32768 at [start_line:0 start_col:9 end_line:0 end_col:16 flat_start:9 flat_end:16]" - - "32767 at [start_line:0 start_col:17 end_line:0 end_col:23 flat_start:17 flat_end:23]" - - "-2147483648 at [start_line:0 start_col:24 end_line:0 end_col:38 flat_start:24 flat_end:38]" - - "2147483647 at [start_line:0 start_col:39 end_line:0 end_col:52 flat_start:39 flat_end:52]" - - "-9223372036854775808 at [start_line:0 start_col:53 end_line:0 end_col:79 flat_start:53 flat_end:79]" - - "9223372036854775807 at [start_line:0 start_col:80 end_line:0 end_col:105 flat_start:80 flat_end:105]" - - "18446744073709551615 at [start_line:0 start_col:106 end_line:0 end_col:132 flat_start:106 flat_end:132]" + - "128 at [start_line:0 start_col:0 end_line:0 end_col:3 flat_start:0 flat_end:3]" + - "127 at [start_line:0 start_col:4 end_line:0 end_col:7 flat_start:4 flat_end:7]" + - "32768 at [start_line:0 start_col:8 end_line:0 end_col:14 flat_start:8 flat_end:14]" + - "32767 at [start_line:0 start_col:15 end_line:0 end_col:21 flat_start:15 flat_end:21]" + - "2147483648 at [start_line:0 start_col:22 end_line:0 end_col:35 flat_start:22 flat_end:35]" + - "2147483647 at [start_line:1 start_col:0 end_line:1 end_col:13 flat_start:36 flat_end:49]" + - "- at [start_line:1 start_col:14 end_line:1 end_col:15 flat_start:50 flat_end:51]" + - "9223372036854775808 at [start_line:1 start_col:15 end_line:1 end_col:40 flat_start:51 flat_end:76]" + - "9223372036854775807 at [start_line:2 start_col:0 end_line:2 end_col:25 flat_start:77 flat_end:102]" + - "18446744073709551615 at [start_line:2 start_col:26 end_line:2 end_col:52 flat_start:103 flat_end:129]" diff --git a/src/frontend/snapshots/proto__frontend__lexer__lexer@operators.pr.snap b/src/frontend/snapshots/proto__frontend__lexer__lexer@operators.pr.snap index c01c883..f9113b4 100644 --- a/src/frontend/snapshots/proto__frontend__lexer__lexer@operators.pr.snap +++ b/src/frontend/snapshots/proto__frontend__lexer__lexer@operators.pr.snap @@ -9,31 +9,26 @@ stringified_tokens: - "* at [start_line:0 start_col:4 end_line:0 end_col:5 flat_start:4 flat_end:5]" - "/ at [start_line:0 start_col:6 end_line:0 end_col:7 flat_start:6 flat_end:7]" - "% at [start_line:0 start_col:8 end_line:0 end_col:9 flat_start:8 flat_end:9]" - - "! at [start_line:0 start_col:10 end_line:0 end_col:11 flat_start:10 flat_end:11]" - - "== at [start_line:1 start_col:0 end_line:1 end_col:2 flat_start:12 flat_end:14]" - - "!= at [start_line:1 start_col:3 end_line:1 end_col:5 flat_start:15 flat_end:17]" - - "< at [start_line:1 start_col:6 end_line:1 end_col:7 flat_start:18 flat_end:19]" - - "> at [start_line:1 start_col:8 end_line:1 end_col:9 flat_start:20 flat_end:21]" - - "<= at [start_line:1 start_col:10 end_line:1 end_col:12 flat_start:22 flat_end:24]" - - ">= at [start_line:1 start_col:13 end_line:1 end_col:15 flat_start:25 flat_end:27]" - - "= at [start_line:2 start_col:0 end_line:2 end_col:1 flat_start:28 flat_end:29]" - - "and at [start_line:2 start_col:2 end_line:2 end_col:5 flat_start:30 flat_end:33]" - - "or at [start_line:2 start_col:6 end_line:2 end_col:8 flat_start:34 flat_end:36]" - - "not at [start_line:2 start_col:9 end_line:2 end_col:12 flat_start:37 flat_end:40]" - - "! at [start_line:2 start_col:13 end_line:2 end_col:14 flat_start:41 flat_end:42]" - - "( at [start_line:3 start_col:0 end_line:3 end_col:1 flat_start:43 flat_end:44]" - - ") at [start_line:3 start_col:2 end_line:3 end_col:3 flat_start:45 flat_end:46]" - - "{ at [start_line:3 start_col:4 end_line:3 end_col:5 flat_start:47 flat_end:48]" - - "} at [start_line:3 start_col:6 end_line:3 end_col:7 flat_start:49 flat_end:50]" - - "[ at [start_line:3 start_col:8 end_line:3 end_col:9 flat_start:51 flat_end:52]" - - "] at [start_line:3 start_col:10 end_line:3 end_col:11 flat_start:53 flat_end:54]" - - "; at [start_line:3 start_col:12 end_line:3 end_col:13 flat_start:55 flat_end:56]" - - ": at [start_line:3 start_col:14 end_line:3 end_col:15 flat_start:57 flat_end:58]" - - ", at [start_line:3 start_col:16 end_line:3 end_col:17 flat_start:59 flat_end:60]" - - ". at [start_line:3 start_col:18 end_line:3 end_col:19 flat_start:61 flat_end:62]" - - ":: at [start_line:4 start_col:0 end_line:4 end_col:2 flat_start:63 flat_end:65]" - - "$ at [start_line:4 start_col:3 end_line:4 end_col:4 flat_start:66 flat_end:67]" - - "^ at [start_line:4 start_col:5 end_line:4 end_col:6 flat_start:68 flat_end:69]" - - "@ at [start_line:4 start_col:7 end_line:4 end_col:8 flat_start:70 flat_end:71]" - - "as at [start_line:4 start_col:9 end_line:4 end_col:11 flat_start:72 flat_end:74]" + - "== at [start_line:1 start_col:0 end_line:1 end_col:2 flat_start:10 flat_end:12]" + - "!= at [start_line:1 start_col:3 end_line:1 end_col:5 flat_start:13 flat_end:15]" + - "< at [start_line:1 start_col:6 end_line:1 end_col:7 flat_start:16 flat_end:17]" + - "> at [start_line:1 start_col:8 end_line:1 end_col:9 flat_start:18 flat_end:19]" + - "<= at [start_line:1 start_col:10 end_line:1 end_col:12 flat_start:20 flat_end:22]" + - ">= at [start_line:1 start_col:13 end_line:1 end_col:15 flat_start:23 flat_end:25]" + - "= at [start_line:2 start_col:0 end_line:2 end_col:1 flat_start:26 flat_end:27]" + - "and at [start_line:2 start_col:2 end_line:2 end_col:5 flat_start:28 flat_end:31]" + - "or at [start_line:2 start_col:6 end_line:2 end_col:8 flat_start:32 flat_end:34]" + - "not at [start_line:2 start_col:9 end_line:2 end_col:12 flat_start:35 flat_end:38]" + - "! at [start_line:2 start_col:13 end_line:2 end_col:14 flat_start:39 flat_end:40]" + - "( at [start_line:3 start_col:0 end_line:3 end_col:1 flat_start:41 flat_end:42]" + - ") at [start_line:3 start_col:2 end_line:3 end_col:3 flat_start:43 flat_end:44]" + - "{ at [start_line:3 start_col:4 end_line:3 end_col:5 flat_start:45 flat_end:46]" + - "} at [start_line:3 start_col:6 end_line:3 end_col:7 flat_start:47 flat_end:48]" + - "[ at [start_line:3 start_col:8 end_line:3 end_col:9 flat_start:49 flat_end:50]" + - "] at [start_line:3 start_col:10 end_line:3 end_col:11 flat_start:51 flat_end:52]" + - "; at [start_line:3 start_col:12 end_line:3 end_col:13 flat_start:53 flat_end:54]" + - ", at [start_line:3 start_col:14 end_line:3 end_col:15 flat_start:55 flat_end:56]" + - ". at [start_line:3 start_col:16 end_line:3 end_col:17 flat_start:57 flat_end:58]" + - "@ at [start_line:4 start_col:0 end_line:4 end_col:1 flat_start:59 flat_end:60]" + - "? at [start_line:4 start_col:2 end_line:4 end_col:3 flat_start:61 flat_end:62]" diff --git a/src/frontend/snapshots/proto__frontend__parser__parser@directives.pr.snap b/src/frontend/snapshots/proto__frontend__parser__parser@directives.pr.snap deleted file mode 100644 index 760f120..0000000 --- a/src/frontend/snapshots/proto__frontend__parser__parser@directives.pr.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: src/frontend/parser.rs -expression: res -input_file: src/frontend/parser_inputs/directives.pr ---- -module: - - "fn main () void { let a = @run 0 * 0; // expect file to contain \"let a = 0;\" @inline { mut sum = 0; while a < 2 { sum = sum + a; a = a + 1; } } // expects the file to contain the following generated lines // mut sum = 0; // sum = sum + a; // a = 0 so sum = 0 // a = a + 1; // a = 1 // sum = sum + a; // a = 1 so sum = 1 // a = a + 1; // a = 2 so loop ends let filename = @filename; // expect file to contain \"let filename = 'proto.pr';\" let text = \"a piece of text\"; // an array of utf-8 characters let character = 'a'; // a utf-8 character @inline { if @platform == \"windows\" { a = 1; } else if @platform == \"linux\" { a = 2; } else if @platform == \"mac\" { a = 3; // @cpp .{ include = \"stdio.h\", code = @run read_file_to_str(\"__inline.cpp\") } } else { a = 4; } } // expect file to contain \"a = 3;\" @run { if a != 3 { } //@error .{ msg = @datetime + \": Not a Mac!\", verbose = false } } }" -lexer_error: [] -parser_error: [] - diff --git a/src/frontend/snapshots/proto__frontend__parser__parser@fn_def.pr.snap b/src/frontend/snapshots/proto__frontend__parser__parser@fn_def.pr.snap index ac01fb4..020f435 100644 --- a/src/frontend/snapshots/proto__frontend__parser__parser@fn_def.pr.snap +++ b/src/frontend/snapshots/proto__frontend__parser__parser@fn_def.pr.snap @@ -7,6 +7,8 @@ module: - "fn add (a i64, b i64) i64 { return a + b; }" - "fn do_nothing () void { }" - fn do_nothing_ () void return 1; + - fn prototype () i64; + - "fn returns_nothing () void { return; }" lexer_error: [] parser_error: [] diff --git a/src/frontend/snapshots/proto__frontend__parser__parser@methods.pr.snap b/src/frontend/snapshots/proto__frontend__parser__parser@methods.pr.snap new file mode 100644 index 0000000..35ced0d --- /dev/null +++ b/src/frontend/snapshots/proto__frontend__parser__parser@methods.pr.snap @@ -0,0 +1,11 @@ +--- +source: src/frontend/parser.rs +expression: res +input_file: src/frontend/parser_inputs/methods.pr +--- +module: + - "let Person = struct { mut name str; mut age i8; pub fn get_name (self Person) str { return name; } pub fn get_age (self Person) i8 { return age; } };" + - "let p = Person { name = \"John\", age = 32 };" +lexer_error: [] +parser_error: [] + diff --git a/src/frontend/snapshots/proto__frontend__parser__parser@modules.pr.snap b/src/frontend/snapshots/proto__frontend__parser__parser@modules.pr.snap deleted file mode 100644 index 76fceb7..0000000 --- a/src/frontend/snapshots/proto__frontend__parser__parser@modules.pr.snap +++ /dev/null @@ -1,12 +0,0 @@ ---- -source: src/frontend/parser.rs -expression: res -input_file: src/frontend/parser_inputs/modules.pr ---- -module: - - "pub mod some_fns { pub fn public_fn () void { } fn private_fn () void { } }" - - "mod some_mod { pub fn public_fn () void { } fn private_fn () void { } }" - - "fn main () void { some_fns::public_fn(); some_mod::public_fn(); }" -lexer_error: [] -parser_error: [] - diff --git a/src/frontend/snapshots/proto__frontend__parser__parser@structs.pr.snap b/src/frontend/snapshots/proto__frontend__parser__parser@structs.pr.snap index dced8c0..b6c6bcf 100644 --- a/src/frontend/snapshots/proto__frontend__parser__parser@structs.pr.snap +++ b/src/frontend/snapshots/proto__frontend__parser__parser@structs.pr.snap @@ -5,9 +5,17 @@ input_file: src/frontend/parser_inputs/structs.pr --- module: - // This is a sample for user defined structs - - // simple struct that uses defaults - - ":SourceFile { path str, text str = \"\", flat_index usize = 0, col usize = 0, line usize = 0 }" - - "fn main () void { // since we allow defaults, we can focus on the // members we care about initializing mut src = :SourceFile { path = \"./using_constructor.pr\" }; }" + - // you can create a struct by either + - "// 1. using the struct keyword, which is for structs with methods and" + - // granular control over fields + - "// 2. using the .{ } syntax, which is for data-only structs (like C structs?)" + - // style 1 + - // struct with methods + - "let SourceFile0 = struct { mut path str; mut text str; mut flat_index usize; mut col usize; mut line usize; pub fn make_from_path (path str) SourceFile0 { return SourceFile0 { path = path, text = \"\", flat_index = 0, col = 0, line = 0 }; } };" + - // style 2 + - // data struct that uses defaults + - "let SourceFile1 = .{ path str, text str = \"\", flat_index usize = 0, col usize = 0, line usize = 0 };" + - "fn main () void { // since we allow defaults, we can focus on the // members we care about initializing mut src = SourceFile { path = \"./using_constructor.pr\" }; }" lexer_error: [] parser_error: [] diff --git a/src/frontend/snapshots/proto__frontend__parser__parser@use_instructions.pr.snap b/src/frontend/snapshots/proto__frontend__parser__parser@use_instructions.pr.snap deleted file mode 100644 index c1f3c1e..0000000 --- a/src/frontend/snapshots/proto__frontend__parser__parser@use_instructions.pr.snap +++ /dev/null @@ -1,17 +0,0 @@ ---- -source: src/frontend/parser.rs -expression: res -input_file: src/frontend/parser_inputs/use_instructions.pr ---- -module: - - "use other::a::b::c::d::*;" - - "use other::a, other::b, other::c::d, other::c::e, other::c::f, other::^::other::g;" - - "use ^::prototyping::other::a::^::other::a;" - - "use @arrays::Array::other::a;" - - use $some_module_at_root; - - "pub mod some_fns { pub fn public_fn () void { private_fn(); } fn private_fn () void { println(1); } }" - - "use !some_fns::public_fn;" - - "fn main () void { public_fn(); other::some_mod::public_fn(); }" -lexer_error: [] -parser_error: [] - diff --git a/src/frontend/source.rs b/src/frontend/source.rs index c24e490..91c2589 100644 --- a/src/frontend/source.rs +++ b/src/frontend/source.rs @@ -125,7 +125,7 @@ impl SourceFile { } #[allow(dead_code)] -#[derive(serde::Deserialize, serde::Serialize, Debug, Clone)] +#[derive(serde::Deserialize, serde::Serialize, Debug, Clone, Hash, PartialEq, Eq)] pub struct SourceRef { pub file: String, // file path pub start_line: usize, // start line @@ -170,32 +170,28 @@ impl SourceRef { ) } - // combine 2 SourceRefs to create a new one that: - // - has the same file - // - has the first occuring start_line and start_col - // - has the last occuring end_line and end_col - // - has the first occuring flat_start - // - has the last occuring flat_end pub fn combine(&self, other: SourceRef) -> SourceRef { - let start_line = if self.start_line < other.start_line { - self.start_line - } else { - other.start_line - }; - let start_col = if self.start_col < other.start_col { - self.start_col - } else { - other.start_col - }; - let end_line = if self.end_line > other.end_line { - self.end_line + let (start_line, start_col) = if self.start_line < other.start_line { + (self.start_line, self.start_col) + } else if self.start_line == other.start_line { + if self.start_col < other.start_col { + (self.start_line, self.start_col) + } else { + (other.start_line, other.start_col) + } } else { - other.end_line + (other.start_line, other.start_col) }; - let end_col = if self.end_col > other.end_col { - self.end_col + let (end_line, end_col) = if self.end_line > other.end_line { + (self.end_line, self.end_col) + } else if self.end_line == other.end_line { + if self.end_col > other.end_col { + (self.end_line, self.end_col) + } else { + (other.end_line, other.end_col) + } } else { - other.end_col + (other.end_line, other.end_col) }; let flat_start = if self.flat_start < other.flat_start { self.flat_start @@ -274,13 +270,15 @@ impl SourceReporter { ParseError::Expected(msg, src, tip) => { self.report_with_ref(&src, "Expected ".to_owned() + &msg, tip) } - ParseError::ConstantDeclarationNeedsInitValue(src) => { - let msg = "Constant declaration needs an initialization value.".to_string(); - let tip = "Constants are set on creation and cannot be modified after.".to_string(); + ParseError::ConstantDeclarationNeedsTypeOrInitValue(src) => { + let msg = "Constant declaration needs an initialization type or value.".to_string(); + let tip = + "The compiler cannot yet back-propagate the type of a constant declaration." + .to_string(); self.report_with_ref(&src, msg, Some(tip)); } ParseError::CannotParseAnExpression(src) => { - let msg = "An expression was required at this point of the program but couldn't find any.".to_string(); + let msg = "An expression was required at this point of the program but couldn't parse any.".to_string(); self.report_with_ref(&src, msg, None); } ParseError::TooManyFnArgs(src) => { @@ -303,9 +301,12 @@ impl SourceReporter { let tip = "Consider splitting this function into multiple functions that separate the work.".to_string(); self.report_with_ref(&src, msg, Some(tip)); } - ParseError::NoVariableAtTopLevel(src) => { - let msg = "Variable declarations are not allowed at the top level of a module." - .to_string(); + ParseError::NoVariableAtCurrentScope(src) => { + let mut msg = "Variable declarations are not allowed:\n".to_string(); + msg.push_str( + "* at the top level of module (It is allowed at the top level of the file).\n", + ); + msg.push_str("* inside a type extension.\n"); let tip = "Consider if this can be declared as a constant (use let instead of mut)." .into(); @@ -315,10 +316,12 @@ impl SourceReporter { let msg = "Code block was not terminated.".to_string(); self.report_with_ref(&src, msg, tip); } - ParseError::NoCodeBlockAtTopLevel(src) => { - let msg = "Code block found at top level".to_string(); - let tip = - "Code blocks are only allowed within functions and other code blocks.".into(); + ParseError::NoCodeBlockAllowedInCurrentContext(src) => { + let msg = "Code block is not allowed in this context.".to_string(); + let mut tip = "Code blocks are not allowed:".to_string(); + tip.push_str("* Within type extensions\n"); + tip.push_str("* Within modules declarations\n"); + tip.push_str("* At the top level of a file.\n"); self.report_with_ref(&src, msg, Some(tip)); } ParseError::ReturnInstructionOutsideFunction(src) => { @@ -344,46 +347,21 @@ impl SourceReporter { "Errors might be cascading. Try fixing some error and recompiling.".to_string(); self.report_with_ref(&src, msg, Some(tip)); } - ParseError::UnusualTokenInUsePath(src) => { - let msg = "Unexpected token in use path.".to_string(); - let mut tip = "Some valid use paths include:\n".to_string(); - tip.push_str("* use immediate_module::inner::other;\n"); - tip.push_str("* use immediate_module::inner as alias;\n"); - tip.push_str("* use immediate::[use_path1, use_path2, ...];\n"); - tip.push_str("* use immediate_module;\n"); - tip.push_str("* use import_everything::*;\n"); - tip.push_str("* use ^::module_in_parent_dir;\n"); - tip.push_str("* use ^::module_in_parent_dir::inner;\n"); - tip.push_str("* use ^::^::module_in_grandparent_dir::inner;\n"); - tip.push_str("* use !module_in_current_file;\n"); - tip.push_str("* use $module_in_project_root;\n"); - tip.push_str("* use @core_module::sub_module;\n"); - tip.push_str("Please find more information on use paths in documentation."); - self.report_with_ref(&src, msg, Some(tip)); - } - ParseError::UnterminatedUsePath(src) => { - let msg = "Unterminated use path.".to_string(); - let mut tip = "Some terminated use paths include:\n".to_string(); - tip.push_str("* use immediate_module::inner::other;\n"); - tip.push_str("* use immediate_module::inner as alias;\n"); - tip.push_str("* use immediate::[use_path1, use_path2, ...];\n"); - tip.push_str("* use immediate_module;\n"); - tip.push_str("* use import_everything::*;\n"); - tip.push_str("* use ^::module_in_parent_dir;\n"); - tip.push_str("* use ^::module_in_parent_dir::inner;\n"); - tip.push_str("* use ^::^::module_in_grandparent_dir::inner;\n"); - tip.push_str("* use !module_in_current_file;\n"); - tip.push_str("* use $module_in_project_root;\n"); - tip.push_str("* use @core_module::sub_module;\n"); - tip.push_str("Please find more information on use paths in documentation."); - self.report_with_ref(&src, msg, Some(tip)); - } ParseError::UnknownCompilerDirective(src) => { let msg = "Unknown compiler directive.".to_string(); let tip = "Please find more information on compiler directives in documentation." .to_string(); self.report_with_ref(&src, msg, Some(tip)); } + ParseError::CannotParseType(src, some_tip) => { + let msg = "Cannot parse type.".to_string(); + self.report_with_ref(&src, msg, some_tip); + } + ParseError::TooManyTypes(src) => { + let msg = "Too many types referenced.".to_string(); + let tip = "The maximum number of types allowed is 256.".to_string(); + self.report_with_ref(&src, msg, Some(tip)); + } } } @@ -399,7 +377,6 @@ impl SourceReporter { fn report_with_ref(&self, src: &SourceRef, msg: String, tip: Option) { let err_col = "d_red"; - let target_col = "l_magenta"; let tip_col = "l_yellow"; let line_col = "l_green"; let mut output = String::new(); @@ -410,7 +387,7 @@ impl SourceReporter { // add file name let f_name = &self.src.path; output.push_str(&format!( - " *[_, l_white:d_black]File '{f_name}'[/] *[*, {line_col}]{}[/]:*[*, {tip_col}]{}[/]\n", + " *[_, l_white:d_black]File '{f_name}:[/]*[*, {line_col}]{}[/]:*[*, {tip_col}]{}[/]'\n", src.start_line + 1, src.start_col + 1 )); @@ -432,7 +409,7 @@ impl SourceReporter { "" }; output.push_str(&format!( - " *[d_white:d_black]{}[/] | *[d_white:d_black]{pre_slice}[/]*[*, {err_col}:d_black]{target_slice}[/]*[d_white:d_black]{post_slice}[/]", + " *[d_white:l_black]{}[/] | *[d_white:d_black]{pre_slice}[/]*[*, {err_col}:d_black]{target_slice}[/]*[d_white:d_black]{post_slice}[/]", src.start_line + 1, )); } else { @@ -442,7 +419,7 @@ impl SourceReporter { let pre_slice = &f_line[..src.start_col]; let f_target_slice = &f_line[src.start_col..]; output.push_str(&format!( - " *[d_white:d_black]{}[/] | *[d_white:d_black]{pre_slice}[/]*[*, {target_col}:d_black]{f_target_slice}[/]\n", + " *[d_white:l_black]{}[/] | *[d_white:d_black]{pre_slice}[/]*[*, {err_col}:d_black]{f_target_slice}[/]\n", src.start_line + 1, )); @@ -450,17 +427,21 @@ impl SourceReporter { for line_no in src.start_line + 1..src.end_line { let target_line = self.src.lines[line_no].clone(); output.push_str(&format!( - " *[d_white:d_black]{}[/] | *[*, {target_col}:d_black]{target_line}[/]\n", + " *[d_white:l_black]{}[/] | *[*, {err_col}:d_black]{target_line}[/]\n", line_no + 1, )); } // - add last line of target area (if it is not the same as first line) let l_line = &self.src.lines[src.end_line].clone(); - let l_target_slice = &l_line[..src.end_col]; - let post_slice = &l_line[src.end_col..]; + let mut end_col = src.end_col; + if src.end_col >= l_line.len() { + end_col = l_line.len(); + } + let l_target_slice = &l_line[..end_col]; + let post_slice = &l_line[end_col..]; output.push_str(&format!( - " *[d_white:d_black]{}[/] | *[*, {target_col}:d_black]{l_target_slice}[/]*[d_white:d_black]{post_slice}[/]\n", + " *[d_white:l_black]{}[/] | *[*, {err_col}:d_black]{l_target_slice}[/]*[d_white:d_black]{post_slice}[/]\n", src.end_line + 1, )); } diff --git a/src/frontend/token.rs b/src/frontend/token.rs index 9715f05..51bd875 100644 --- a/src/frontend/token.rs +++ b/src/frontend/token.rs @@ -1,4 +1,4 @@ -use super::{source::SourceRef, types::Type}; +use super::source::SourceRef; #[allow(dead_code)] #[derive(serde::Deserialize, serde::Serialize, Debug, Clone)] @@ -13,13 +13,12 @@ pub enum Token { While(SourceRef), Break(SourceRef), Continue(SourceRef), - Void(SourceRef), True(SourceRef), False(SourceRef), - Use(SourceRef), Pub(SourceRef), - Mod(SourceRef), Return(SourceRef), + Comp(SourceRef), + Struct(SourceRef), // operators Plus(SourceRef), @@ -28,13 +27,9 @@ pub enum Token { Slash(SourceRef), Modulo(SourceRef), - // special operators - As(SourceRef), - // special characters - Caret(SourceRef), Exclamation(SourceRef), - Dollar(SourceRef), + QuestionMark(SourceRef), At(SourceRef), // comparison @@ -61,41 +56,33 @@ pub enum Token { LBracket(SourceRef), RBracket(SourceRef), Semicolon(SourceRef), - Colon(SourceRef), - Scope(SourceRef), Comma(SourceRef), Dot(SourceRef), // literals Identifier(String, SourceRef), - I8Literal(i8, SourceRef), - I16Literal(i16, SourceRef), - I32Literal(i32, SourceRef), - I64Literal(i64, SourceRef), - IsizeLiteral(isize, SourceRef), - U8Literal(u8, SourceRef), - U16Literal(u16, SourceRef), - U32Literal(u32, SourceRef), - U64Literal(u64, SourceRef), - UsizeLiteral(usize, SourceRef), + Integer(String, SourceRef), CharLiteral(SourceRef, char), - StringLiteral(SourceRef, String), + SingleLineStringLiteral(SourceRef, String), + MultiLineStringFragment(SourceRef, String), SingleLineComment(SourceRef, String), - // primitive types + // type tags I8(SourceRef), I16(SourceRef), I32(SourceRef), I64(SourceRef), - Isize(SourceRef), + ISize(SourceRef), U8(SourceRef), U16(SourceRef), U32(SourceRef), U64(SourceRef), - Usize(SourceRef), + USize(SourceRef), Bool(SourceRef), Char(SourceRef), Str(SourceRef), + Void(SourceRef), + Type(SourceRef), // misc Eof(SourceRef), @@ -135,7 +122,6 @@ impl Token { Token::LBracket(src) => src.clone(), Token::RBracket(src) => src.clone(), Token::Semicolon(src) => src.clone(), - Token::Colon(src) => src.clone(), Token::Comma(src) => src.clone(), Token::Eof(src) => src.clone(), Token::Void(src) => src.clone(), @@ -143,43 +129,33 @@ impl Token { Token::False(src) => src.clone(), Token::CharLiteral(src, _) => src.clone(), Token::Identifier(_, src) => src.clone(), + Token::Dot(src) => src.clone(), + Token::Break(src) => src.clone(), + Token::Continue(src) => src.clone(), + Token::Pub(src) => src.clone(), + Token::Return(src) => src.clone(), + Token::Exclamation(src) => src.clone(), + Token::At(src) => src.clone(), + Token::SingleLineStringLiteral(src, _) => src.clone(), + Token::MultiLineStringFragment(src, _) => src.clone(), + Token::Integer(_, src) => src.clone(), + Token::Comp(src) => src.clone(), + Token::Struct(src) => src.clone(), + Token::QuestionMark(src) => src.clone(), Token::I8(src) => src.clone(), Token::I16(src) => src.clone(), Token::I32(src) => src.clone(), Token::I64(src) => src.clone(), - Token::Isize(src) => src.clone(), + Token::ISize(src) => src.clone(), Token::U8(src) => src.clone(), Token::U16(src) => src.clone(), Token::U32(src) => src.clone(), Token::U64(src) => src.clone(), - Token::Usize(src) => src.clone(), + Token::USize(src) => src.clone(), Token::Bool(src) => src.clone(), Token::Char(src) => src.clone(), Token::Str(src) => src.clone(), - Token::I8Literal(_, src) => src.clone(), - Token::I16Literal(_, src) => src.clone(), - Token::I32Literal(_, src) => src.clone(), - Token::I64Literal(_, src) => src.clone(), - Token::IsizeLiteral(_, src) => src.clone(), - Token::U8Literal(_, src) => src.clone(), - Token::U16Literal(_, src) => src.clone(), - Token::U32Literal(_, src) => src.clone(), - Token::U64Literal(_, src) => src.clone(), - Token::UsizeLiteral(_, src) => src.clone(), - Token::Dot(src) => src.clone(), - Token::Use(src) => src.clone(), - Token::Break(src) => src.clone(), - Token::Continue(src) => src.clone(), - Token::Pub(src) => src.clone(), - Token::Mod(src) => src.clone(), - Token::Return(src) => src.clone(), - Token::Scope(src) => src.clone(), - Token::Caret(src) => src.clone(), - Token::Exclamation(src) => src.clone(), - Token::Dollar(src) => src.clone(), - Token::At(src) => src.clone(), - Token::As(src) => src.clone(), - Token::StringLiteral(src, _) => src.clone(), + Token::Type(src) => src.clone(), } } @@ -194,54 +170,18 @@ impl Token { | Token::LCurly(_) | Token::Loop(_) | Token::While(_) - | Token::Use(_) - | Token::Mod(_) | Token::Pub(_) + | Token::Return(_) + | Token::Break(_) + | Token::Continue(_) + | Token::If(_) + | Token::Struct(_) | Token::At(_) | Token::SingleLineComment(_, _) + | Token::Fn(_) ) } - pub fn is_type_token(&self) -> bool { - matches!( - self, - Token::I8(_) - | Token::I16(_) - | Token::I32(_) - | Token::I64(_) - | Token::Isize(_) - | Token::U8(_) - | Token::U16(_) - | Token::U32(_) - | Token::U64(_) - | Token::Usize(_) - | Token::Bool(_) - | Token::Char(_) - | Token::Void(_) - | Token::Str(_) - ) - } - - pub fn to_type(&self) -> Type { - match self { - Token::I8(_) => Type::I8, - Token::I16(_) => Type::I16, - Token::I32(_) => Type::I32, - Token::I64(_) => Type::I64, - Token::Isize(_) => Type::ISize, - Token::U8(_) => Type::U8, - Token::U16(_) => Type::U16, - Token::U32(_) => Type::U32, - Token::U64(_) => Type::U64, - Token::Usize(_) => Type::USize, - Token::Bool(_) => Type::Bool, - Token::Char(_) => Type::Char, - Token::Void(_) => Type::Void, - Token::Str(_) => Type::Str, - _ => unreachable!("to_type() called on unexpected Token, {self:?}"), - } - } - pub fn as_str(&self) -> String { match self { Token::Fn(_) => "fn".into(), @@ -257,7 +197,6 @@ impl Token { Token::True(_) => "true".into(), Token::False(_) => "false".into(), Token::CharLiteral(_, c) => format!("'{c}'"), - Token::Use(_) => "use".into(), Token::Plus(_) => "+".into(), Token::Minus(_) => "-".into(), Token::Star(_) => "*".into(), @@ -280,45 +219,35 @@ impl Token { Token::LBracket(_) => "[".into(), Token::RBracket(_) => "]".into(), Token::Semicolon(_) => ";".into(), - Token::Colon(_) => ":".into(), Token::Comma(_) => ",".into(), Token::Dot(_) => ".".into(), Token::Identifier(name, _) => name.clone(), - Token::I8Literal(num, _) => num.to_string(), - Token::I16Literal(num, _) => num.to_string(), - Token::I32Literal(num, _) => num.to_string(), - Token::I64Literal(num, _) => num.to_string(), - Token::IsizeLiteral(num, _) => num.to_string(), - Token::U8Literal(num, _) => num.to_string(), - Token::U16Literal(num, _) => num.to_string(), - Token::U32Literal(num, _) => num.to_string(), - Token::U64Literal(num, _) => num.to_string(), - Token::UsizeLiteral(num, _) => num.to_string(), + Token::Integer(num, _) => num.to_string(), + Token::Eof(_) => "\0".into(), + Token::Pub(_) => "pub".into(), + Token::Return(_) => "return".into(), + Token::Exclamation(_) => "!".into(), + Token::At(_) => "@".into(), + Token::SingleLineComment(_, src) => src.clone(), + Token::SingleLineStringLiteral(_, content) => format!("\"{content}\""), + Token::MultiLineStringFragment(_, content) => format!("||{content}"), + Token::Comp(_) => "comp".into(), + Token::Struct(_) => "struct".into(), + Token::QuestionMark(_) => "?".into(), Token::I8(_) => "i8".into(), Token::I16(_) => "i16".into(), Token::I32(_) => "i32".into(), Token::I64(_) => "i64".into(), - Token::Isize(_) => "isize".into(), + Token::ISize(_) => "isize".into(), Token::U8(_) => "u8".into(), Token::U16(_) => "u16".into(), Token::U32(_) => "u32".into(), Token::U64(_) => "u64".into(), - Token::Usize(_) => "usize".into(), + Token::USize(_) => "usize".into(), Token::Bool(_) => "bool".into(), Token::Char(_) => "char".into(), Token::Str(_) => "str".into(), - Token::Eof(_) => "\0".into(), - Token::Pub(_) => "pub".into(), - Token::Mod(_) => "mod".into(), - Token::Return(_) => "return".into(), - Token::Scope(_) => "::".into(), - Token::Caret(_) => "^".into(), - Token::Exclamation(_) => "!".into(), - Token::Dollar(_) => "$".into(), - Token::At(_) => "@".into(), - Token::As(_) => "as".into(), - Token::StringLiteral(_, src) => format!("\"{src}\""), - Token::SingleLineComment(_, src) => src.clone(), + Token::Type(_) => "type".into(), } } } diff --git a/src/frontend/types.rs b/src/frontend/types.rs deleted file mode 100644 index ae70546..0000000 --- a/src/frontend/types.rs +++ /dev/null @@ -1,39 +0,0 @@ -#[derive(Debug, Clone)] -pub enum Type { - I8, - I16, - I32, - I64, - ISize, - U8, - U16, - U32, - U64, - USize, - Bool, - Char, - Void, - Str, -} - -#[allow(dead_code)] -impl Type { - pub fn as_str(&self) -> String { - match &self { - Type::I8 => "i8".into(), - Type::I16 => "i16".into(), - Type::I32 => "i32".into(), - Type::I64 => "i64".into(), - Type::ISize => "isize".into(), - Type::U8 => "u8".into(), - Type::U16 => "u16".into(), - Type::U32 => "u32".into(), - Type::U64 => "u64".into(), - Type::USize => "usize".into(), - Type::Bool => "bool".into(), - Type::Char => "char".into(), - Type::Void => "void".into(), - Type::Str => "str".into(), - } - } -} diff --git a/src/main.rs b/src/main.rs index cdb1bf3..19bfe5b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,13 +3,10 @@ use std::env; use crate::compilation::pipeline::PipelineConfig; use compilation::pipeline::Workspace; -mod analysis_a; mod compilation; mod frontend; -mod name_resolution; mod pastel; -mod pir; -mod tools; +mod walker; const USAGE: &str = " Usage: proto command [options]? diff --git a/src/name_resolution/mod.rs b/src/name_resolution/mod.rs deleted file mode 100644 index ebbc1e6..0000000 --- a/src/name_resolution/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod name_resolver; -pub mod resolution_table; diff --git a/src/name_resolution/name_resolver.rs b/src/name_resolution/name_resolver.rs deleted file mode 100644 index b2b4732..0000000 --- a/src/name_resolution/name_resolver.rs +++ /dev/null @@ -1,77 +0,0 @@ -use std::rc::Rc; - -use crate::pir::ir::{ - ExprRef, InsRef, KeyValueBindings, PIRExpr, PIRIns, PIRModule, PIRModulePass, -}; - -use super::resolution_table::{ResolutionTable, SymbolKind}; - -pub struct Resolver<'a> { - module: &'a PIRModule, - table: Rc, -} - -impl<'a> Resolver<'a> { - fn add_symbol(&mut self, identifier: String, kind: SymbolKind) -> Result<(), String> { - Rc::get_mut(&mut self.table) - .expect("Could not borrow table as mutable") - .add_symbol(identifier, kind) - } -} - -impl<'a> PIRModulePass<'a, (), (), (), Rc, String> for Resolver<'a> { - fn new(module: &'a PIRModule) -> Self { - Self { - module, - table: Rc::new(ResolutionTable::new()), - } - } - - fn process_ins(&mut self, ins: &InsRef) -> Result<(), String> { - let ins_node = self.module.ins_pool.get(&ins); - - match ins_node { - PIRIns::VariableDecl(var_name, _, init_expr, _) => { - let var_name = var_name.as_str(); - if let Some(init_expr) = init_expr { - self.process_expr(&init_expr)?; - } - - self.add_symbol(var_name, SymbolKind::Binding)?; - } - PIRIns::AssignmentIns(lhs, rhs) => { - self.process_expr(&lhs)?; - self.process_expr(&rhs)?; - } - PIRIns::ExpressionIns(expr, _) => { - self.process_expr(&expr)?; - } - n => todo!("Inst: {n:?}"), - } - - Ok(()) - } - - fn process_expr(&mut self, expr: &ExprRef) -> Result<(), String> { - let expr_node = self.module.expr_pool.get(&expr); - - match expr_node { - PIRExpr::Id(token, _) => {} - n => todo!("Expr: {n:?}"), - } - - Ok(()) - } - - fn process_pairs(&mut self, kv: &KeyValueBindings) -> Result<(), String> { - todo!() - } - - fn process(&mut self) -> Result, String> { - Ok(Rc::clone(&self.table)) - } - - fn get_module(&mut self) -> &'a PIRModule { - self.module - } -} diff --git a/src/name_resolution/resolution_table.rs b/src/name_resolution/resolution_table.rs deleted file mode 100644 index c5f862e..0000000 --- a/src/name_resolution/resolution_table.rs +++ /dev/null @@ -1,49 +0,0 @@ -use std::fmt::format; - -use crate::frontend::errors::NameResolutionError; - -#[derive(Clone, PartialEq, Eq)] -pub enum SymbolKind { - Binding, - Struct { field_names: Vec }, - Function, -} - -pub struct Symbol { - identifier: String, - kind: SymbolKind, -} - -pub struct ResolutionTable { - symbols: Vec, -} - -impl ResolutionTable { - pub fn new() -> Self { - Self { - symbols: Vec::new(), - } - } - - pub fn add_symbol(&mut self, identifier: String, kind: SymbolKind) -> Result<(), String> { - if self.has_symbol(&identifier, &kind) { - return Err(format!( - "Could not add symbol '{identifier}' as it was already defined" - )); - } - - self.symbols.push(Symbol { identifier, kind }); - - Ok(()) - } - - pub fn has_symbol(&self, identifier: &String, kind: &SymbolKind) -> bool { - for symbol in &self.symbols { - if symbol.kind == *kind && symbol.identifier == *identifier { - return true; - } - } - - false - } -} diff --git a/src/pir/ir.rs b/src/pir/ir.rs deleted file mode 100644 index 963a3d2..0000000 --- a/src/pir/ir.rs +++ /dev/null @@ -1,762 +0,0 @@ -use crate::frontend::{ - ast::{ - CompilationModule, DependencyPath, Expr, Instruction, KeyValueBindings as TreeKVBindings, - }, - source::SourceRef, - token::Token, - types::Type, -}; - -#[derive(Debug, Clone)] -#[allow(dead_code)] -pub struct KeyValueBindings { - pub pairs: Vec<(ExprRef, Option)>, - pub span: SourceRef, -} - -#[allow(dead_code)] -impl KeyValueBindings { - pub fn as_str(&self) -> String { - let mut s = String::from("{ "); - for (index, (k, v)) in self.pairs.iter().enumerate() { - s.push_str(&k.as_str()); - if let Some(v) = v { - s.push_str(" = "); - s.push_str(&v.as_str()); - } - - if index < self.pairs.len() - 1 { - s.push_str(", "); - } - } - s.push_str(" }"); - s - } - - pub fn source_ref(&self) -> SourceRef { - self.span.clone() - } -} - -#[derive(Debug, Clone)] -#[allow(dead_code)] -pub enum PIRExpr { - Id(Token, Option), - Number(Token, Option), - StringLiteral(Token, Option), - CharacterLiteral(Token, Option), - Binary(Token, ExprRef, ExprRef, Option), - Comparison(Token, ExprRef, ExprRef, Option), - Boolean(Token, Option), - Unary(Token, ExprRef, Option), - Grouped(ExprRef, Option, SourceRef), - FnCall { - func: ExprRef, - args: Vec, - span: SourceRef, - fn_type: Option, - }, - ScopeInto { - module: ExprRef, - target: ExprRef, - src: SourceRef, - resolved_type: Option, - }, - DirectiveExpr { - directive: ExprRef, - expr: Option, - resolved_type: Option, - src: SourceRef, - }, - NamedStructInit { - name: ExprRef, - fields: KeyValueBindings, - src: SourceRef, - resolved_type: Option, - }, -} - -#[allow(dead_code)] -impl PIRExpr { - pub fn type_info(&self) -> Option { - match &self { - PIRExpr::Id(_, t) => t.clone(), - PIRExpr::Number(_, t) => t.clone(), - PIRExpr::Binary(_, _, _, t) => t.clone(), - PIRExpr::Boolean(_, t) => t.clone(), - PIRExpr::Unary(_, _, t) => t.clone(), - PIRExpr::Comparison(_, _, _, t) => t.clone(), - PIRExpr::FnCall { - func: _, - args: _, - span: _, - fn_type, - } => fn_type.clone(), - PIRExpr::Grouped(_, t, _) => t.clone(), - PIRExpr::ScopeInto { - module: _, - target: _, - src: _, - resolved_type, - } => resolved_type.clone(), - PIRExpr::DirectiveExpr { - directive: _, - expr: _, - resolved_type, - src: _, - } => resolved_type.clone(), - PIRExpr::StringLiteral(_, t) => t.clone(), - PIRExpr::CharacterLiteral(_, t) => t.clone(), - PIRExpr::NamedStructInit { - name: _, - fields: _, - src: _, - resolved_type, - } => resolved_type.clone(), - } - } -} - -#[derive(Debug, Clone)] -#[allow(dead_code)] -pub struct ExprRef { - pub loc: usize, -} - -impl ExprRef { - pub fn as_str(&self) -> String { - format!("ExprRef({})", self.loc) - } -} - -#[derive(Debug, Clone)] -pub struct ExprPool { - pub pool: Vec, -} - -#[allow(dead_code)] -impl ExprPool { - pub fn new() -> Self { - ExprPool { pool: Vec::new() } - } - - fn add(&mut self, expr: PIRExpr) -> ExprRef { - self.pool.push(expr); - ExprRef { - loc: self.pool.len() - 1, - } - } - - pub fn to_pir(&mut self, expr: Expr) -> ExprRef { - match expr { - Expr::Id(id, t) => self.add(PIRExpr::Id(id, t)), - Expr::Number(n, t) => self.add(PIRExpr::Number(n, t)), - Expr::StringLiteral(s, t) => self.add(PIRExpr::StringLiteral(s, t)), - Expr::CharacterLiteral(c, t) => self.add(PIRExpr::CharacterLiteral(c, t)), - Expr::Binary(op, lhs, rhs, t) => { - let lhs = self.to_pir(*lhs); - let rhs = self.to_pir(*rhs); - self.add(PIRExpr::Binary(op, lhs, rhs, t)) - } - Expr::Comparison(op, lhs, rhs, t) => { - let lhs = self.to_pir(*lhs); - let rhs = self.to_pir(*rhs); - self.add(PIRExpr::Comparison(op, lhs, rhs, t)) - } - Expr::Boolean(b, t) => self.add(PIRExpr::Boolean(b, t)), - Expr::Unary(op, expr, t) => { - let expr = self.to_pir(*expr); - self.add(PIRExpr::Unary(op, expr, t)) - } - Expr::Grouped(expr, t, src) => { - let expr = self.to_pir(*expr); - self.add(PIRExpr::Grouped(expr, t, src)) - } - Expr::FnCall { - func, - args, - span, - fn_type, - } => { - let func = self.to_pir(*func); - let args = args - .into_iter() - .map(|arg| self.to_pir(arg)) - .collect::>(); - self.add(PIRExpr::FnCall { - func, - args, - span, - fn_type, - }) - } - Expr::ScopeInto { - module, - target, - src, - resolved_type, - } => { - let module = self.to_pir(*module); - let target = self.to_pir(*target); - self.add(PIRExpr::ScopeInto { - module, - target, - src, - resolved_type, - }) - } - Expr::DirectiveExpr { - directive, - expr, - resolved_type, - src, - } => { - let directive = self.to_pir(*directive); - let expr = expr.map(|expr| self.to_pir(*expr)); - self.add(PIRExpr::DirectiveExpr { - directive, - expr, - resolved_type, - src, - }) - } - Expr::NamedStructInit { - name, - fields, - src, - resolved_type, - } => { - let name = self.to_pir(*name); - let fields = self.pir_bindings(fields); - self.add(PIRExpr::NamedStructInit { - name, - fields, - src, - resolved_type, - }) - } - } - } - - fn pir_bindings(&mut self, bindings: TreeKVBindings) -> KeyValueBindings { - let nbindings = bindings - .pairs - .iter() - .map(|pair| { - let key = self.to_pir(pair.0.clone()); - if let Some(value) = pair.1.clone() { - let value = self.to_pir(value); - (key, Some(value)) - } else { - (key, None) - } - }) - .collect::)>>(); - KeyValueBindings { - pairs: nbindings, - span: bindings.span, - } - } - - pub fn get(&self, expr_ref: &ExprRef) -> PIRExpr { - self.pool[expr_ref.loc].clone() - } -} - -#[derive(Debug, Clone)] -#[allow(dead_code)] -pub enum PIRIns { - SingleLineComment { - comment: String, - src: SourceRef, - }, - NamedStructDecl { - name: ExprRef, - fields: KeyValueBindings, - src: SourceRef, - }, - ConstantDecl { - const_name: Token, - const_type: Option, - init_expr: ExprRef, - src_ref: SourceRef, - is_public: bool, - }, - VariableDecl(Token, Option, Option, SourceRef), - AssignmentIns(ExprRef, ExprRef), - ExpressionIns(ExprRef, Token), - FunctionDef { - name: Token, - params: Vec, - return_type: Type, - body: InsRef, - is_public: bool, - src: SourceRef, - }, - InfiniteLoop { - src: SourceRef, - body: InsRef, - }, - WhileLoop { - src: SourceRef, - condition: ExprRef, - body: InsRef, - }, - CodeBlock { - src: SourceRef, - instructions: Vec, - }, - Module { - name: ExprRef, - body: InsRef, - src: SourceRef, - is_public: bool, - }, - Return { - src: SourceRef, - value: Option, - }, - Break(SourceRef), - Continue(SourceRef), - UseDependency { - paths: Vec, - src: SourceRef, - }, - DirectiveInstruction { - directive: ExprRef, - block: Option, - src: SourceRef, - }, - ConditionalBranchIns { - pairs: Vec<(Option, InsRef)>, - src: SourceRef, - }, -} - -impl PIRIns { - pub fn as_str(&self) -> String { - match self { - PIRIns::SingleLineComment { comment, src: _ } => comment.clone(), - PIRIns::NamedStructDecl { - name, - fields, - src: _, - } => { - format!(":{} {}", name.as_str(), fields.as_str()) - } - PIRIns::ConstantDecl { - const_name, - const_type: t, - init_expr, - src_ref: _, - is_public: _, - } => match t { - Some(c_type) => { - format!( - "let {} {} = {};", - const_name.as_str(), - c_type.as_str(), - init_expr.as_str() - ) - } - None => { - format!("let {} = {};", const_name.as_str(), init_expr.as_str()) - } - }, - PIRIns::VariableDecl(name, t, init, _) => match (t, init) { - (None, None) => format!("mut {};", name.as_str()), - (None, Some(init)) => format!("mut {} = {};", name.as_str(), init.as_str()), - (Some(c_type), None) => { - format!("mut {} {};", name.as_str(), c_type.as_str()) - } - (Some(c_type), Some(init)) => format!( - "mut {} {} = {};", - name.as_str(), - c_type.as_str(), - init.as_str() - ), - }, - PIRIns::AssignmentIns(target, value) => { - format!("{} = {};", target.as_str(), value.as_str()) - } - PIRIns::ExpressionIns(expr, _) => format!("{};", expr.as_str()), - PIRIns::FunctionDef { - name, - params, - return_type, - body, - is_public, - src: _, - } => { - // collect param strings - let mut param_strs = String::new(); - for (i, param) in params.iter().enumerate() { - param_strs.push_str(¶m.as_str()); - if i + 1 < params.len() { - param_strs.push_str(", "); - } - } - let str_rep = format!( - "fn {} ({param_strs}) {} {}", - name.as_str(), - return_type.as_str(), - body.as_str() - ); - if *is_public { - "pub ".to_string() + &str_rep - } else { - str_rep - } - } - PIRIns::CodeBlock { - src: _, - instructions, - } => { - let mut ins_str = "{ ".to_string(); - - for (id, ins) in instructions.iter().enumerate() { - ins_str.push_str(&ins.as_str()); - - if id + 1 < instructions.len() { - ins_str.push(' '); - } - } - ins_str + " }" - } - PIRIns::Module { - name, - body, - src: _, - is_public, - } => { - let mod_str = format!("mod {} {}", name.as_str(), body.as_str()); - if *is_public { - mod_str - } else { - "pub ".to_string() + &mod_str - } - } - PIRIns::Return { src: _, value } => match value { - Some(v) => format!("return {};", v.as_str()), - None => "return;".to_string(), - }, - PIRIns::InfiniteLoop { src: _, body } => { - format!("loop {}", body.as_str()) - } - PIRIns::WhileLoop { - src: _, - condition, - body, - } => { - format!("while {} {}", condition.as_str(), body.as_str()) - } - PIRIns::Break(_) => "break;".to_string(), - PIRIns::Continue(_) => "continue;".to_string(), - PIRIns::UseDependency { paths, src: _ } => { - let mut path_str = String::new(); - for (i, path) in paths.iter().enumerate() { - for (j, part) in path.actions.iter().enumerate() { - path_str.push_str(&part.as_str()); - if j + 1 < path.actions.len() { - path_str.push_str("::"); - } - } - if i + 1 < paths.len() { - path_str.push_str(", "); - } - } - format!("use {};", path_str) - } - PIRIns::DirectiveInstruction { - directive, - block, - src: _, - } => { - if let Some(block) = block { - format!("@{} {}", directive.as_str(), block.as_str()) - } else { - format!("@{}", directive.as_str()) - } - } - PIRIns::ConditionalBranchIns { pairs, src: _ } => { - let mut str_rep = String::new(); - for i in 0..pairs.len() { - let (cond, ins) = &pairs[i]; - if i == 0 { - // for the first pair, we do if - str_rep.push_str(&format!( - "if {} {}", - cond.clone().unwrap().as_str(), - ins.as_str() - )); - } else if i < pairs.len() - 1 { - // for the rest, we do else if - str_rep.push_str(&format!( - " else if {} {}", - cond.clone().unwrap().as_str(), - ins.as_str() - )); - } else { - // for the last, we do else - str_rep.push_str(&format!(" else {}", ins.as_str())); - } - } - str_rep - } - } - } -} - -#[derive(Debug, Clone)] -#[allow(dead_code)] -pub struct InsRef { - pub loc: usize, -} - -impl InsRef { - pub fn as_str(&self) -> String { - format!("InsRef({})", self.loc) - } -} - -#[derive(Debug, Clone)] -#[allow(dead_code)] -pub struct InsPool { - pub pool: Vec, -} - -#[allow(dead_code)] -impl InsPool { - pub fn new() -> InsPool { - InsPool { pool: Vec::new() } - } - - fn exists(&self, ins: &PIRIns) -> Option { - for (i, ins2) in self.pool.iter().enumerate() { - if ins.as_str() == ins2.as_str() { - return Some(InsRef { loc: i }); - } - } - None - } - - fn add(&mut self, ins: PIRIns) -> InsRef { - self.pool.push(ins); - InsRef { - loc: self.pool.len() - 1, - } - } - - pub fn to_pir(&mut self, epool: &mut ExprPool, ins: Instruction) -> InsRef { - match ins { - Instruction::SingleLineComment { comment, src } => { - let ins = PIRIns::SingleLineComment { comment, src }; - self.add(ins) - } - Instruction::NamedStructDecl { name, fields, src } => { - let name_ref = epool.to_pir(name); - let fields = epool.pir_bindings(fields); - let ins = PIRIns::NamedStructDecl { - name: name_ref, - fields, - src, - }; - self.add(ins) - } - Instruction::ConstantDecl { - const_name, - const_type, - init_expr, - src_ref, - is_public, - } => { - let init_expr = epool.to_pir(init_expr); - let ins = PIRIns::ConstantDecl { - const_name, - const_type, - init_expr, - src_ref, - is_public, - }; - self.add(ins) - } - Instruction::VariableDecl(name, var_type, init_expr, span) => { - let init_expr = init_expr.map(|e| epool.to_pir(e)); - let ins = PIRIns::VariableDecl(name, var_type, init_expr, span); - self.add(ins) - } - Instruction::AssignmentIns(dest, target) => { - let dest = epool.to_pir(dest); - let target = epool.to_pir(target); - let ins = PIRIns::AssignmentIns(dest, target); - self.add(ins) - } - Instruction::ExpressionIns(expr, semi) => { - let expr = epool.to_pir(expr); - let ins = PIRIns::ExpressionIns(expr, semi); - self.add(ins) - } - Instruction::FunctionDef { - name, - params, - return_type, - body, - is_public, - src, - } => { - let params = params.into_iter().map(|p| epool.to_pir(p)).collect(); - let body = self.to_pir(epool, *body); - let ins = PIRIns::FunctionDef { - name, - params, - return_type, - body, - is_public, - src, - }; - self.add(ins) - } - Instruction::InfiniteLoop { src, body } => { - let body = self.to_pir(epool, *body); - let ins = PIRIns::InfiniteLoop { src, body }; - self.add(ins) - } - Instruction::WhileLoop { - src, - condition, - body, - } => { - let condition = epool.to_pir(condition); - let body = self.to_pir(epool, *body); - let ins = PIRIns::WhileLoop { - src, - condition, - body, - }; - self.add(ins) - } - Instruction::CodeBlock { src, instructions } => { - let instructions = instructions - .into_iter() - .map(|i| self.to_pir(epool, i)) - .collect(); - let ins = PIRIns::CodeBlock { src, instructions }; - self.add(ins) - } - Instruction::Module { - name, - body, - src, - is_public, - } => { - let name = epool.to_pir(name); - let body = self.to_pir(epool, *body); - let ins = PIRIns::Module { - name, - body, - src, - is_public, - }; - self.add(ins) - } - Instruction::Return { src, value } => { - let value = value.map(|v| epool.to_pir(v)); - let ins = PIRIns::Return { src, value }; - self.add(ins) - } - Instruction::Break(src) => { - let ins = PIRIns::Break(src); - self.add(ins) - } - Instruction::Continue(src) => { - let ins = PIRIns::Continue(src); - self.add(ins) - } - Instruction::UseDependency { paths, src } => { - let ins = PIRIns::UseDependency { paths, src }; - self.add(ins) - } - Instruction::DirectiveInstruction { - directive, - block, - src, - } => { - let directive = epool.to_pir(directive); - let block = block.map(|b| self.to_pir(epool, *b)); - let ins = PIRIns::DirectiveInstruction { - directive, - block, - src, - }; - self.add(ins) - } - Instruction::ConditionalBranchIns { pairs, src } => { - let pairs = pairs - .into_iter() - .map(|(cond, body)| { - if let Some(cond) = cond { - let cond = epool.to_pir(cond); - let body = self.to_pir(epool, *body); - (Some(cond), body) - } else { - let body = self.to_pir(epool, *body); - (None, body) - } - }) - .collect(); - let ins = PIRIns::ConditionalBranchIns { pairs, src }; - self.add(ins) - } - } - } - - pub fn get(&self, ins_ref: &InsRef) -> PIRIns { - self.pool[ins_ref.loc].clone() - } -} - -#[derive(Debug, Clone)] -pub struct PIRModule { - pub ins_pool: InsPool, - pub expr_pool: ExprPool, - pub top_level: Vec, - pub path: String, -} - -#[allow(dead_code)] -impl PIRModule { - pub fn new(cm: CompilationModule, path: String) -> PIRModule { - let mut pirmod = PIRModule { - ins_pool: InsPool::new(), - expr_pool: ExprPool::new(), - top_level: Vec::new(), - path, - }; - for ins in cm.instructions { - let id = pirmod.ins_pool.to_pir(&mut pirmod.expr_pool, ins); - pirmod.top_level.push(id); - } - pirmod - } -} - -#[allow(dead_code)] -pub trait PIRModulePass<'a, InsRes, ExprRes, KVRes, ModRes, Error> { - fn process_ins(&mut self, ins: &InsRef) -> Result; - fn process_expr(&mut self, expr: &ExprRef) -> Result; - fn process_pairs(&mut self, kv: &KeyValueBindings) -> Result; - fn process_module(&mut self) -> Result, Error> { - let mut res = vec![]; - - let module = self.get_module(); - for ins_ref in module.top_level.iter() { - let ins_res = self.process_ins(&ins_ref)?; - res.push(ins_res); - } - - Ok(res) - } - fn process(&mut self) -> Result; - fn new(module: &'a PIRModule) -> Self; - fn get_module(&mut self) -> &'a PIRModule; -} diff --git a/src/pir/mod.rs b/src/pir/mod.rs deleted file mode 100644 index 19d2d13..0000000 --- a/src/pir/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod ir; diff --git a/src/std/primitives.pr b/src/std/primitives.pr new file mode 100644 index 0000000..473a9ab --- /dev/null +++ b/src/std/primitives.pr @@ -0,0 +1,125 @@ +@register pub fn add_i8(a i8, b i8) i8; +@register pub fn sub_i8(a i8, b i8) i8; +@register pub fn mul_i8(a i8, b i8) i8; +@register pub fn div_i8(a i8, b i8) i8; +@register pub fn rem_i8(a i8, b i8) i8; +@register pub fn neg_i8(a i8) i8; +@register pub fn lt_i8(a i8, b i8) bool; +@register pub fn lte_i8(a i8, b i8) bool; +@register pub fn gt_i8(a i8, b i8) bool; +@register pub fn gte_i8(a i8, b i8) bool; +@register pub fn eq_i8(a i8, b i8) bool; +@register pub fn neq_i8(a i8, b i8) bool; + +@register pub fn add_i16(a i16, b i16) i16; +@register pub fn sub_i16(a i16, b i16) i16; +@register pub fn mul_i16(a i16, b i16) i16; +@register pub fn div_i16(a i16, b i16) i16; +@register pub fn rem_i16(a i16, b i16) i16; +@register pub fn neg_i16(a i16) i16; +@register pub fn lt_i16(a i16, b i16) bool; +@register pub fn lte_i16(a i16, b i16) bool; +@register pub fn gt_i16(a i16, b i16) bool; +@register pub fn gte_i16(a i16, b i16) bool; +@register pub fn eq_i16(a i16, b i16) bool; +@register pub fn neq_i16(a i16, b i16) bool; + +@register pub fn add_i32(a i32, b i32) i32; +@register pub fn sub_i32(a i32, b i32) i32; +@register pub fn mul_i32(a i32, b i32) i32; +@register pub fn div_i32(a i32, b i32) i32; +@register pub fn rem_i32(a i32, b i32) i32; +@register pub fn neg_i32(a i32) i32; +@register pub fn lt_i32(a i32, b i32) bool; +@register pub fn lte_i32(a i32, b i32) bool; +@register pub fn gt_i32(a i32, b i32) bool; +@register pub fn gte_i32(a i32, b i32) bool; +@register pub fn eq_i32(a i32, b i32) bool; +@register pub fn neq_i32(a i32, b i32) bool; + +@register pub fn add_i64(a i64, b i64) i64; +@register pub fn sub_i64(a i64, b i64) i64; +@register pub fn mul_i64(a i64, b i64) i64; +@register pub fn div_i64(a i64, b i64) i64; +@register pub fn rem_i64(a i64, b i64) i64; +@register pub fn neg_i64(a i64) i64; +@register pub fn lt_i64(a i64, b i64) bool; +@register pub fn lte_i64(a i64, b i64) bool; +@register pub fn gt_i64(a i64, b i64) bool; +@register pub fn gte_i64(a i64, b i64) bool; +@register pub fn eq_i64(a i64, b i64) bool; +@register pub fn neq_i64(a i64, b i64) bool; + +@register pub fn add_isize(a isize, b isize) isize; +@register pub fn sub_isize(a isize, b isize) isize; +@register pub fn mul_isize(a isize, b isize) isize; +@register pub fn div_isize(a isize, b isize) isize; +@register pub fn rem_isize(a isize, b isize) isize; +@register pub fn neg_isize(a isize) isize; +@register pub fn lt_isize(a isize, b isize) bool; +@register pub fn lte_isize(a isize, b isize) bool; +@register pub fn gt_isize(a isize, b isize) bool; +@register pub fn gte_isize(a isize, b isize) bool; +@register pub fn eq_isize(a isize, b isize) bool; +@register pub fn neq_isize(a isize, b isize) bool; + +@register pub fn add_u8(a u8, b u8) u8; +@register pub fn sub_u8(a u8, b u8) u8; +@register pub fn mul_u8(a u8, b u8) u8; +@register pub fn div_u8(a u8, b u8) u8; +@register pub fn rem_u8(a u8, b u8) u8; +@register pub fn lt_u8(a u8, b u8) bool; +@register pub fn lte_u8(a u8, b u8) bool; +@register pub fn gt_u8(a u8, b u8) bool; +@register pub fn gte_u8(a u8, b u8) bool; +@register pub fn eq_u8(a u8, b u8) bool; +@register pub fn neq_u8(a u8, b u8) bool; + +@register pub fn add_u16(a u16, b u16) u16; +@register pub fn sub_u16(a u16, b u16) u16; +@register pub fn mul_u16(a u16, b u16) u16; +@register pub fn div_u16(a u16, b u16) u16; +@register pub fn rem_u16(a u16, b u16) u16; +@register pub fn lt_u16(a u16, b u16) bool; +@register pub fn lte_u16(a u16, b u16) bool; +@register pub fn gt_u16(a u16, b u16) bool; +@register pub fn gte_u16(a u16, b u16) bool; +@register pub fn eq_u16(a u16, b u16) bool; +@register pub fn neq_u16(a u16, b u16) bool; + +@register pub fn add_u32(a u32, b u32) u32; +@register pub fn sub_u32(a u32, b u32) u32; +@register pub fn mul_u32(a u32, b u32) u32; +@register pub fn div_u32(a u32, b u32) u32; +@register pub fn rem_u32(a u32, b u32) u32; +@register pub fn lt_u32(a u32, b u32) bool; +@register pub fn lte_u32(a u32, b u32) bool; +@register pub fn gt_u32(a u32, b u32) bool; +@register pub fn gte_u32(a u32, b u32) bool; +@register pub fn eq_u32(a u32, b u32) bool; +@register pub fn neq_u32(a u32, b u32) bool; + +@register pub fn add_u64(a u64, b u64) u64; +@register pub fn sub_u64(a u64, b u64) u64; +@register pub fn mul_u64(a u64, b u64) u64; +@register pub fn div_u64(a u64, b u64) u64; +@register pub fn rem_u64(a u64, b u64) u64; +@register pub fn lt_u64(a u64, b u64) bool; +@register pub fn lte_u64(a u64, b u64) bool; +@register pub fn gt_u64(a u64, b u64) bool; +@register pub fn gte_u64(a u64, b u64) bool; +@register pub fn eq_u64(a u64, b u64) bool; +@register pub fn neq_u64(a u64, b u64) bool; + +@register pub fn add_usize(a usize, b usize) usize; +@register pub fn sub_usize(a usize, b usize) usize; +@register pub fn mul_usize(a usize, b usize) usize; +@register pub fn div_usize(a usize, b usize) usize; +@register pub fn rem_usize(a usize, b usize) usize; +@register pub fn neg_usize(a usize) usize; +@register pub fn lt_usize(a usize, b usize) bool; +@register pub fn lte_usize(a usize, b usize) bool; +@register pub fn gt_usize(a usize, b usize) bool; +@register pub fn gte_usize(a usize, b usize) bool; +@register pub fn eq_usize(a usize, b usize) bool; +@register pub fn neq_usize(a usize, b usize) bool; diff --git a/src/std/runtime.h b/src/std/runtime.h new file mode 100644 index 0000000..3e7571b --- /dev/null +++ b/src/std/runtime.h @@ -0,0 +1,267 @@ +#include +#include +#include + +using i8 = std::int8_t; +using i16 = std::int16_t; +using i32 = std::int32_t; +using i64 = std::int64_t; +using isize = std::intptr_t; + +using u8 = std::uint8_t; +using u16 = std::uint16_t; +using u32 = std::uint32_t; +using u64 = std::uint64_t; +using usize = std::uintptr_t; + +constexpr i8 add_i8(i8 a, i8 b) { return a + b; } +constexpr i16 add_i16(i16 a, i16 b) { return a + b; } +constexpr i32 add_i32(i32 a, i32 b) { return a + b; } +constexpr i64 add_i64(i64 a, i64 b) { return a + b; } +constexpr isize add_isize(isize a, isize b) { return a + b; } +constexpr u8 add_u8(u8 a, u8 b) { return a + b; } +constexpr u16 add_u16(u16 a, u16 b) { return a + b; } +constexpr u32 add_u32(u32 a, u32 b) { return a + b; } +constexpr u64 add_u64(u64 a, u64 b) { return a + b; } +constexpr usize add_usize(usize a, usize b) { return a + b; } + +constexpr i8 sub_i8(i8 a, i8 b) { return a - b; } +constexpr i16 sub_i16(i16 a, i16 b) { return a - b; } +constexpr i32 sub_i32(i32 a, i32 b) { return a - b; } +constexpr i64 sub_i64(i64 a, i64 b) { return a - b; } +constexpr isize sub_isize(isize a, isize b) { return a - b; } +constexpr u8 sub_u8(u8 a, u8 b) { return a - b; } +constexpr u16 sub_u16(u16 a, u16 b) { return a - b; } +constexpr u32 sub_u32(u32 a, u32 b) { return a - b; } +constexpr u64 sub_u64(u64 a, u64 b) { return a - b; } +constexpr usize sub_usize(usize a, usize b) { return a - b; } + +constexpr i8 mul_i8(i8 a, i8 b) { return a * b; } +constexpr i16 mul_i16(i16 a, i16 b) { return a * b; } +constexpr i32 mul_i32(i32 a, i32 b) { return a * b; } +constexpr i64 mul_i64(i64 a, i64 b) { return a * b; } +constexpr isize mul_isize(isize a, isize b) { return a * b; } +constexpr u8 mul_u8(u8 a, u8 b) { return a * b; } +constexpr u16 mul_u16(u16 a, u16 b) { return a * b; } +constexpr u32 mul_u32(u32 a, u32 b) { return a * b; } +constexpr u64 mul_u64(u64 a, u64 b) { return a * b; } +constexpr usize mul_usize(usize a, usize b) { return a * b; } + +constexpr i8 div_i8(i8 a, i8 b) { return a / b; } +constexpr i16 div_i16(i16 a, i16 b) { return a / b; } +constexpr i32 div_i32(i32 a, i32 b) { return a / b; } +constexpr i64 div_i64(i64 a, i64 b) { return a / b; } +constexpr isize div_isize(isize a, isize b) { return a / b; } +constexpr u8 div_u8(u8 a, u8 b) { return a / b; } +constexpr u16 div_u16(u16 a, u16 b) { return a / b; } +constexpr u32 div_u32(u32 a, u32 b) { return a / b; } +constexpr u64 div_u64(u64 a, u64 b) { return a / b; } +constexpr usize div_usize(usize a, usize b) { return a / b; } + +constexpr i8 rem_i8(i8 a, i8 b) { return a % b; } +constexpr i16 rem_i16(i16 a, i16 b) { return a % b; } +constexpr i32 rem_i32(i32 a, i32 b) { return a % b; } +constexpr i64 rem_i64(i64 a, i64 b) { return a % b; } +constexpr isize rem_isize(isize a, isize b) { return a % b; } +constexpr u8 rem_u8(u8 a, u8 b) { return a % b; } +constexpr u16 rem_u16(u16 a, u16 b) { return a % b; } +constexpr u32 rem_u32(u32 a, u32 b) { return a % b; } +constexpr u64 rem_u64(u64 a, u64 b) { return a % b; } +constexpr usize rem_usize(usize a, usize b) { return a % b; } + +constexpr i8 neg_i8(i8 a) { return -a; } +constexpr i16 neg_i16(i16 a) { return -a; } +constexpr i32 neg_i32(i32 a) { return -a; } +constexpr i64 neg_i64(i64 a) { return -a; } +constexpr isize neg_isize(isize a) { return -a; } + +constexpr bool lt_i8(i8 a, i8 b) { return a < b; } +constexpr bool lt_i16(i16 a, i16 b) { return a < b; } +constexpr bool lt_i32(i32 a, i32 b) { return a < b; } +constexpr bool lt_i64(i64 a, i64 b) { return a < b; } +constexpr bool lt_isize(isize a, isize b) { return a < b; } +constexpr bool lt_u8(u8 a, u8 b) { return a < b; } +constexpr bool lt_u16(u16 a, u16 b) { return a < b; } +constexpr bool lt_u32(u32 a, u32 b) { return a < b; } +constexpr bool lt_u64(u64 a, u64 b) { return a < b; } +constexpr bool lt_usize(usize a, usize b) { return a < b; } + +constexpr bool gt_i8(i8 a, i8 b) { return a > b; } +constexpr bool gt_i16(i16 a, i16 b) { return a > b; } +constexpr bool gt_i32(i32 a, i32 b) { return a > b; } +constexpr bool gt_i64(i64 a, i64 b) { return a > b; } +constexpr bool gt_isize(isize a, isize b) { return a > b; } +constexpr bool gt_u8(u8 a, u8 b) { return a > b; } +constexpr bool gt_u16(u16 a, u16 b) { return a > b; } +constexpr bool gt_u32(u32 a, u32 b) { return a > b; } +constexpr bool gt_u64(u64 a, u64 b) { return a > b; } +constexpr bool gt_usize(usize a, usize b) { return a > b; } + +constexpr bool lte_i8(i8 a, i8 b) { return a <= b; } +constexpr bool lte_i16(i16 a, i16 b) { return a <= b; } +constexpr bool lte_i32(i32 a, i32 b) { return a <= b; } +constexpr bool lte_i64(i64 a, i64 b) { return a <= b; } +constexpr bool lte_isize(isize a, isize b) { return a <= b; } +constexpr bool lte_u8(u8 a, u8 b) { return a <= b; } +constexpr bool lte_u16(u16 a, u16 b) { return a <= b; } +constexpr bool lte_u32(u32 a, u32 b) { return a <= b; } +constexpr bool lte_u64(u64 a, u64 b) { return a <= b; } +constexpr bool lte_usize(usize a, usize b) { return a <= b; } + +constexpr bool gte_i8(i8 a, i8 b) { return a >= b; } +constexpr bool gte_i16(i16 a, i16 b) { return a >= b; } +constexpr bool gte_i32(i32 a, i32 b) { return a >= b; } +constexpr bool gte_i64(i64 a, i64 b) { return a >= b; } +constexpr bool gte_isize(isize a, isize b) { return a >= b; } +constexpr bool gte_u8(u8 a, u8 b) { return a >= b; } +constexpr bool gte_u16(u16 a, u16 b) { return a >= b; } +constexpr bool gte_u32(u32 a, u32 b) { return a >= b; } +constexpr bool gte_u64(u64 a, u64 b) { return a >= b; } +constexpr bool gte_usize(usize a, usize b) { return a >= b; } + +constexpr bool eq_i8(i8 a, i8 b) { return a == b; } +constexpr bool eq_i16(i16 a, i16 b) { return a == b; } +constexpr bool eq_i32(i32 a, i32 b) { return a == b; } +constexpr bool eq_i64(i64 a, i64 b) { return a == b; } +constexpr bool eq_isize(isize a, isize b) { return a == b; } +constexpr bool eq_u8(u8 a, u8 b) { return a == b; } +constexpr bool eq_u16(u16 a, u16 b) { return a == b; } +constexpr bool eq_u32(u32 a, u32 b) { return a == b; } +constexpr bool eq_u64(u64 a, u64 b) { return a == b; } +constexpr bool eq_usize(usize a, usize b) { return a == b; } + +constexpr bool neq_i8(i8 a, i8 b) { return a != b; } +constexpr bool neq_i16(i16 a, i16 b) { return a != b; } +constexpr bool neq_i32(i32 a, i32 b) { return a != b; } +constexpr bool neq_i64(i64 a, i64 b) { return a != b; } +constexpr bool neq_isize(isize a, isize b) { return a != b; } +constexpr bool neq_u8(u8 a, u8 b) { return a != b; } +constexpr bool neq_u16(u16 a, u16 b) { return a != b; } +constexpr bool neq_u32(u32 a, u32 b) { return a != b; } +constexpr bool neq_u64(u64 a, u64 b) { return a != b; } +constexpr bool neq_usize(usize a, usize b) { return a != b; } + +struct str { + const char *data; + usize len; + + constexpr str(const char *data, usize len) : data(data), len(len) {} + constexpr str(const char *data) : data(data), len(0) { + while (data[len] != '\0') { + len++; + } + } + + constexpr char operator[](usize i) const { return data[i]; } +}; + +template struct Slice { + T *data; + usize len; + usize cap; + + constexpr Slice() : data(nullptr), len(0), cap(0) {} + constexpr Slice(T *data, usize len, usize cap) + : data(data), len(len), cap(cap) {} + constexpr Slice(T *data, usize len) : data(data), len(len), cap(len) {} + constexpr Slice(T *data) : data(data), len(0), cap(0) {} + + constexpr T &operator[](usize i) { return data[i]; } + constexpr const T &operator[](usize i) const { return data[i]; } +}; + +template struct Vec { + T *data; + usize len; + usize cap; + + constexpr Vec() : data(nullptr), len(0), cap(0) {} + constexpr Vec(T *data, usize len, usize cap) + : data(data), len(len), cap(cap) {} + constexpr Vec(T *data, usize len) : data(data), len(len), cap(len) {} + constexpr Vec(T *data) : data(data), len(0), cap(0) {} + + constexpr T &operator[](usize i) { return data[i]; } + constexpr const T &operator[](usize i) const { return data[i]; } + constexpr void push(T t) { + if (len == cap) { + cap = cap * 2 + 1; + T *new_data = new T[cap]; + for (usize i = 0; i < len; i++) { + new_data[i] = data[i]; + } + delete[] data; + data = new_data; + } + data[len++] = t; + } + + constexpr T pop() { return data[--len]; } +}; + +template struct Box { + T *data; + + constexpr Box() : data(nullptr) {} + constexpr Box(T *data) : data(data) {} + + constexpr T &operator*() { return *data; } + constexpr const T &operator*() const { return *data; } + constexpr T *operator->() { return data; } + constexpr const T *operator->() const { return data; } +}; + +constexpr bool operator==(str a, str b) { + if (a.len != b.len) { + return false; + } + for (usize i = 0; i < a.len; i++) { + if (a[i] != b[i]) { + return false; + } + } + return true; +} + +static void panic(const char *msg) { + std::printf("panic: %s\n", msg); + exit(1); +} + +template struct Option { + T some; + bool none = false; + + constexpr Option() : none(true) {} + constexpr Option(T some) : some(some), none(false) {} + + constexpr bool is_some() const { return !none; } + constexpr bool is_none() const { return none; } + constexpr T unwrap() const { + if (is_none()) { + panic("called `Option::unwrap()` on a `None` value"); + } + return some; + } + + constexpr T unwrap_or(T def) const { + if (is_none()) { + return def; + } + return some; + } + + constexpr T unwrap_or_else(T (*f)()) const { + if (is_none()) { + return f(); + } + return some; + } + + constexpr T unwrap_or_else(T (*f)(void *), void *data) const { + if (is_none()) { + return f(data); + } + return some; + } +}; diff --git a/src/tools/mod.rs b/src/tools/mod.rs deleted file mode 100644 index 5ae395a..0000000 --- a/src/tools/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod pcodeview; -pub mod pfmt; diff --git a/src/tools/pcodeview.rs b/src/tools/pcodeview.rs deleted file mode 100644 index 48a075f..0000000 --- a/src/tools/pcodeview.rs +++ /dev/null @@ -1,396 +0,0 @@ -use crate::pir::ir::{ - ExprRef, InsRef, KeyValueBindings, PIRExpr, PIRIns, PIRModule, PIRModulePass, -}; - -#[derive(Clone)] -#[allow(dead_code)] -enum CodeBlockType { - Regular, - InstructionPart, -} - -#[allow(dead_code)] -pub struct PCodeView<'a> { - module: Option<&'a PIRModule>, - left_padding: u16, - block_type: CodeBlockType, -} - -#[allow(dead_code)] -impl<'a> PCodeView<'a> { - pub fn increase_padding(&mut self) { - self.left_padding += 4; - } - - pub fn decrease_padding(&mut self) { - self.left_padding -= 4; - } - - pub fn pad_text(&self, text: String) -> String { - let padding = " ".repeat(self.left_padding as usize); - format!("{}{}", padding, text) - } -} - -impl<'a> PIRModulePass<'a, String, String, String, String, ()> for PCodeView<'a> { - fn process_ins(&mut self, ins: &InsRef) -> Result { - // get instruction from pool - let module = self.module.unwrap(); - let ins_node = module.ins_pool.get(&ins); - - match ins_node { - PIRIns::SingleLineComment { comment, src: _ } => { - let comment = comment.clone(); - Ok(self.pad_text(comment)) - } - PIRIns::NamedStructDecl { - name, - fields, - src: _, - } => { - let name = self.process_expr(&name)?; - let mut view = String::new(); - view.push_str(&self.pad_text(format!(":{} ", name))); - if fields.pairs.len() > 0 { - view.push_str(&self.process_pairs(&fields)?); - } else { - view.push_str("{ }"); - } - Ok(view) - } - PIRIns::ConstantDecl { - const_name, - const_type: _, - init_expr, - src_ref: _, - is_public, - } => { - let const_name = const_name.as_str(); - let init_expr = self.process_expr(&init_expr)?; - let mut view = format!("let {} = {};", const_name, init_expr); - if is_public { - view = format!("pub {}", view); - } - Ok(self.pad_text(view)) - } - PIRIns::VariableDecl(var_name, _, init_expr, _) => { - let var_name = var_name.as_str(); - if let Some(init_expr) = init_expr { - let init_expr = self.process_expr(&init_expr)?; - Ok(self.pad_text(format!("mut {} = {};", var_name, init_expr))) - } else { - Ok(self.pad_text(format!("mut {};", var_name))) - } - } - PIRIns::AssignmentIns(target, val) => { - let target = self.process_expr(&target)?; - let val = self.process_expr(&val)?; - Ok(self.pad_text(format!("{} = {};", target, val))) - } - PIRIns::ExpressionIns(expr, _) => { - let expr = self.process_expr(&expr)?; - Ok(self.pad_text(format!("{};", expr))) - } - PIRIns::FunctionDef { - name, - params, - return_type, - body, - is_public, - src: _, - } => { - let name = name.as_str(); - let mut param_strs = vec![]; - for param in params { - param_strs.push(self.process_expr(¶m)?); - } - let params = param_strs.join(", "); - let return_type = return_type.as_str(); - let block_type = self.block_type.clone(); - self.block_type = CodeBlockType::InstructionPart; - let body = self.process_ins(&body)?; - self.block_type = block_type; - let mut view = format!("fn {name}({params}) {return_type} {body}"); - if is_public { - view = format!("pub {}", view); - } - Ok(self.pad_text(view)) - } - PIRIns::InfiniteLoop { src: _, body } => { - let block_type = self.block_type.clone(); - self.block_type = CodeBlockType::InstructionPart; - let body = self.process_ins(&body)?; - self.block_type = block_type; - Ok(self.pad_text(format!("loop {}", body))) - } - PIRIns::WhileLoop { - src: _, - condition, - body, - } => { - let condition = self.process_expr(&condition)?; - let block_type = self.block_type.clone(); - self.block_type = CodeBlockType::InstructionPart; - let body = self.process_ins(&body)?; - self.block_type = block_type; - Ok(self.pad_text(format!("while {} {}", condition, body))) - } - PIRIns::CodeBlock { - src: _, - instructions, - } => { - let mut view = String::new(); - match self.block_type { - CodeBlockType::InstructionPart => { - view.push_str("{"); - } - CodeBlockType::Regular => { - view.push_str(&self.pad_text("{\n".to_string())); - } - } - - if instructions.len() == 0 { - view.push_str(" }"); - } else { - view.push('\n'); - self.increase_padding(); - let mut ins_strs = vec![]; - for ins in instructions { - ins_strs.push(self.process_ins(&ins)?); - } - self.decrease_padding(); - view.push_str(&ins_strs.join("\n")); - view.push_str(&("\n".to_string() + &self.pad_text("}".to_string()))); - } - Ok(view) - } - PIRIns::Module { - name, - body, - src: _, - is_public, - } => { - let name = self.process_expr(&name)?; - let block_type = self.block_type.clone(); - self.block_type = CodeBlockType::InstructionPart; - let body = self.process_ins(&body)?; - self.block_type = block_type; - let mut view = format!("mod {} {}", name, body); - if is_public { - view = format!("pub {}", view); - } - Ok(self.pad_text(view)) - } - PIRIns::Return { src: _, value } => { - if let Some(value) = value { - let value = self.process_expr(&value)?; - Ok(self.pad_text(format!("return {};", value))) - } else { - Ok(self.pad_text("return;".to_string())) - } - } - PIRIns::Break(_) => Ok(self.pad_text("break;".to_string())), - PIRIns::Continue(_) => Ok(self.pad_text("continue;".to_string())), - PIRIns::UseDependency { paths, src: _ } => { - let mut path_str = String::new(); - for (i, path) in paths.iter().enumerate() { - for (j, part) in path.actions.iter().enumerate() { - path_str.push_str(&part.as_str()); - if j + 1 < path.actions.len() { - path_str.push_str("::"); - } - } - if i + 1 < paths.len() { - path_str.push_str(", "); - } - } - Ok(self.pad_text(format!("use {};", path_str))) - } - PIRIns::DirectiveInstruction { - directive, - block, - src: _, - } => { - let directive = self.process_expr(&directive)?; - if let Some(block) = block { - let block_type = self.block_type.clone(); - self.block_type = CodeBlockType::InstructionPart; - let block = self.process_ins(&block)?; - self.block_type = block_type; - Ok(self.pad_text(format!("@{} {}", directive, block))) - } else { - Ok(self.pad_text(format!("@{};", directive))) - } - } - PIRIns::ConditionalBranchIns { pairs, src: _ } => { - let mut view = String::new(); - let block_type = self.block_type.clone(); - self.block_type = CodeBlockType::InstructionPart; - for i in 0..pairs.len() { - let (cond, ins) = &pairs[i]; - if i == 0 { - let cond = self.process_expr(&cond.clone().unwrap())?; - let ins = self.process_ins(&ins)?; - // self.increase_padding(); - // for the first pair, we do if - view.push_str(&self.pad_text(format!("if {} {}", cond, ins))); - // self.decrease_padding(); - } else if i < pairs.len() - 1 { - let cond = self.process_expr(&cond.clone().unwrap())?; - let ins = self.process_ins(&ins)?; - self.increase_padding(); - // for the rest, we do else if - view.push_str(&format!(" else if {} {}", cond, ins)); - self.decrease_padding(); - } else { - // for the last, we do else - let ins = self.process_ins(&ins)?; - self.increase_padding(); - view.push_str(&format!(" else {}", ins)); - self.decrease_padding(); - } - } - self.block_type = block_type; - Ok(view) - } - } - } - - fn process_expr(&mut self, expr: &ExprRef) -> Result { - // get expr from pool - let module = self.module.unwrap(); - let expr_node = module.expr_pool.get(&expr); - - match expr_node { - PIRExpr::Id(token, id_type) => { - if let Some(id_type) = id_type { - Ok(format!("{} {}", token.as_str(), id_type.as_str())) - } else { - Ok(token.as_str()) - } - } - PIRExpr::Number(num, _) => Ok(num.as_str()), - PIRExpr::StringLiteral(lit, _) => Ok(lit.as_str()), - PIRExpr::CharacterLiteral(lit, _) => Ok(lit.as_str()), - PIRExpr::Binary(operator, lhs, rhs, _) => { - let lhs = self.process_expr(&lhs)?; - let rhs = self.process_expr(&rhs)?; - Ok(format!("{} {} {}", lhs, operator.as_str(), rhs)) - } - PIRExpr::Comparison(operator, lhs, rhs, _) => { - let lhs = self.process_expr(&lhs)?; - let rhs = self.process_expr(&rhs)?; - Ok(format!("{} {} {}", lhs, operator.as_str(), rhs)) - } - PIRExpr::Boolean(lit, _) => Ok(lit.as_str()), - PIRExpr::Unary(operator, expr, _) => { - let expr = self.process_expr(&expr)?; - Ok(format!("{}{}", operator.as_str(), expr)) - } - PIRExpr::Grouped(inner_expr, _, _) => { - let inner_expr = self.process_expr(&inner_expr)?; - Ok(format!("({})", inner_expr)) - } - PIRExpr::FnCall { - func, - args, - span: _, - fn_type: _, - } => { - let func = self.process_expr(&func)?; - let args_str = args - .iter() - .map(|arg| self.process_expr(&arg)) - .collect::, ()>>()?; - let args_str = args_str.join(", "); - Ok(format!("{}({})", func, args_str)) - } - PIRExpr::ScopeInto { - module, - target, - src: _, - resolved_type: _, - } => { - let module = self.process_expr(&module)?; - let target = self.process_expr(&target)?; - Ok(format!("{}::{}", module, target)) - } - PIRExpr::DirectiveExpr { - directive, - expr, - resolved_type: _, - src: _, - } => { - let directive = self.process_expr(&directive)?; - if let Some(expr) = expr { - let expr = self.process_expr(&expr)?; - Ok(format!("@{} {}", directive, expr)) - } else { - Ok(format!("@{}", directive)) - } - } - PIRExpr::NamedStructInit { - name, - fields, - src: _, - resolved_type: _, - } => { - let name = self.process_expr(&name)?; - let block_type = self.block_type.clone(); - self.block_type = CodeBlockType::InstructionPart; - let fields = self.process_pairs(&fields)?; - self.block_type = block_type; - Ok(format!(":{} {}", name, fields)) - } - } - } - - fn process_pairs(&mut self, kv: &KeyValueBindings) -> Result { - let mut view = String::from("{"); - let kv_pair_len = kv.pairs.len(); - if kv_pair_len > 0 { - self.increase_padding(); - } else { - view.push_str(" }"); - return Ok(view); - } - - let mut count = 0; - for (key, value) in &kv.pairs { - let key = self.process_expr(&key)?; - if let Some(value) = value { - let value = self.process_expr(&value)?; - view.push('\n'); - view.push_str(&self.pad_text(format!("{} = {}", key, value))); - } else { - view.push('\n'); - view.push_str(&self.pad_text(format!("{}", key))); - } - count += 1; - if count < kv_pair_len { - view.push(','); - } - } - self.decrease_padding(); - view.push('\n'); - view.push_str(&self.pad_text("}".to_string())); - Ok(view) - } - - fn process(&mut self) -> Result { - let content = self.process_module()?; - Ok(content.join("\n")) - } - - fn new(module: &'a PIRModule) -> Self { - Self { - left_padding: 0, - module: Some(module), - block_type: CodeBlockType::Regular, - } - } - - fn get_module(&mut self) -> &'a PIRModule { - self.module.unwrap() - } -} diff --git a/src/tools/pfmt.rs b/src/tools/pfmt.rs deleted file mode 100644 index 924f750..0000000 --- a/src/tools/pfmt.rs +++ /dev/null @@ -1,50 +0,0 @@ -use std::fs; - -use crate::pir::ir::{ExprRef, InsRef, KeyValueBindings, PIRModule, PIRModulePass}; - -use super::pcodeview::PCodeView; - -pub struct Pfmt<'a> { - module: Option<&'a PIRModule>, -} - -impl<'a> PIRModulePass<'a, (), (), (), String, String> for Pfmt<'a> { - fn new(module: &'a PIRModule) -> Self { - Self { - module: Some(module), - } - } - - fn process_ins(&mut self, _: &InsRef) -> Result<(), String> { - Ok(()) - } - - fn process_expr(&mut self, _: &ExprRef) -> Result<(), String> { - Ok(()) - } - - fn process_pairs(&mut self, _: &KeyValueBindings) -> Result<(), String> { - Ok(()) - } - - fn process(&mut self) -> Result { - let mut module = self.module.unwrap(); - let mut code_view = PCodeView::new(&mut module); - let contents = code_view.process().unwrap(); - - // write out to module path - let write_res = fs::write(&module.path, contents); - if let Err(e) = write_res { - Err(format!( - "Failed to write to file at path `{}`. \n{}", - module.path, e - )) - } else { - Ok("pfmt complete".to_string()) - } - } - - fn get_module(&mut self) -> &'a PIRModule { - self.module.unwrap() - } -} diff --git a/src/walker/mod.rs b/src/walker/mod.rs new file mode 100644 index 0000000..e5edf5b --- /dev/null +++ b/src/walker/mod.rs @@ -0,0 +1 @@ +pub mod walker; diff --git a/src/walker/walker.rs b/src/walker/walker.rs new file mode 100644 index 0000000..3ee1928 --- /dev/null +++ b/src/walker/walker.rs @@ -0,0 +1,47 @@ +#![allow(dead_code, unused_variables)] +use crate::frontend::ast::{CompilationModule, Expr, Instruction, TypeReference}; + +struct Sym { + name: String, + ty_ref: TypeReference, +} + +struct Env { + names: Vec, + types: Vec, + module: CompilationModule, +} + +impl Env { + pub fn new(module: CompilationModule) -> Self { + Self { + names: Vec::new(), + types: Vec::new(), + module, + } + } + + pub fn run(&mut self) { + for ins in &self.module.instructions { + run_ins(ins, self); + } + } +} + +fn run_ins(ins: &Instruction, env: &Env) { + match ins { + Instruction::FunctionDef { + name, + params, + return_type, + body, + is_public, + src, + } => { + // add function to the environment + // run the function + } + _ => {} + } +} +fn run_expr(expr: &Expr, env: &Env) {}