diff --git a/.github/templates/README.md b/.github/templates/README.md index d42293bf..44c77e48 100644 --- a/.github/templates/README.md +++ b/.github/templates/README.md @@ -9,7 +9,7 @@ Rock is highly inspired from Livescript and Rust, and will also borrow (pun inte No to be taken seriously (yet) -# VTable +# Index - [Features]( #features ) - [Install]( #install ) - [Using released binary]( #using-released-binary ) @@ -74,14 +74,12 @@ cargo run -- -V ## Quickstart -Lets create a new project folder to compute some factorials +- Lets create a new project folder to compute some factorials ``` sh -mkdir -P factorial/src && cd factorial +mkdir -p factorial/src && cd factorial ``` -Add some files like this: - - Create a `factorial/src/main.rk` file: ```haskell @@ -135,6 +133,22 @@ Prints Test ``` +The `id` function here is polymorphic by default, as we don't make any constraint on the type that we should take or return. +If we did something like this +`id a = a + a` +We would have constrained `a` to types that implement [`Num`](https://github.com/Champii/Rock/blob/master/std/src/num.rk) + +Note that this example would still be valid, as `Int64`, `Float64` and `String` are all implementors of `Num`(*). +The output would be + +``` sh +2 +4.4 +TestTest +``` + +(*) `String` is nowhere at its place here, and only implements `+` for string concatenation. This should change in the future with more traits like `Add` in rust + ### Custom infix operator ``` haskell @@ -152,9 +166,14 @@ rock run Prints `6` +You can create any operator that is made of any combination of one or more of `'+', '-', '/', '*', '|', '<', '>', '=', '!', '$', '@', '&'` + +Most of the commonly defined operators like `+`, `<=`, etc are already implemented by the [stdlib](https://github.com/Champii/Rock/tree/master/std) that is automaticaly compiled with every package. +There is a `--nostd` option to allow you to use your own custom implementation. + ### Trait definition -This `trait ToString` is redondant with the `trait Show` implemented in the lib, and serves as a demonstration only +This `trait ToString` is redondant with the `trait Show` implemented in the stdlib, and serves as a demonstration only ``` haskell trait ToString a @@ -176,7 +195,7 @@ main = rock run ``` -Prints +Prints ``` 33 @@ -208,6 +227,31 @@ rock run Prints `MyName` +### Modules and code separation + +- `./myproj/src/foo.rk` + +```haskell +bar a = a + 1 +``` + +- `./myproj/src/main.rk` + +```haskell +mod foo + +use foo::bar + +main = print bar 1 +``` + +Prints `2` + +Note that we could have skiped the +`use foo::bar` +if we wrote +`main = print foo::bar 1` + ## REPL Only supports basic expressions for now. diff --git a/.github/version b/.github/version index 22c08f72..f0cfd3bb 100644 --- a/.github/version +++ b/.github/version @@ -1 +1 @@ -v0.2.1 +v0.2.2 diff --git a/Cargo.lock b/Cargo.lock index 3ddf7734..ae05cff0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -464,7 +464,7 @@ checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" [[package]] name = "rock" -version = "0.2.1" +version = "0.2.2" dependencies = [ "bincode", "bitflags", diff --git a/Cargo.toml b/Cargo.toml index 7d289441..c32f74ea 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rock" -version = "0.2.1" +version = "0.2.2" authors = ["champii "] edition = "2018" diff --git a/README.md b/README.md index 2003521f..eda59ece 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# Rock v0.2.1 +# Rock v0.2.2 -[![Rust](https://github.com/Champii/Rock/actions/workflows/rust.yml/badge.svg?branch=master)](https://github.com/Champii/Rock/actions/workflows/rust.yml) +[![Rust](https://github.com/Champii/Rock/actions/workflows/rust.yml/badge.svg?branch=-)](https://github.com/Champii/Rock/actions/workflows/rust.yml) Little language made with Rust and LLVM. @@ -9,7 +9,7 @@ Rock is highly inspired from Livescript and Rust, and will also borrow (pun inte No to be taken seriously (yet) -# VTable +# Index - [Features]( #features ) - [Install]( #install ) - [Using released binary]( #using-released-binary ) @@ -45,10 +45,10 @@ You will need `clang` somewhere in your $PATH Linux x86_64 only -[Rock v0.2.1](https://github.com/Champii/Rock/releases/download/v0.2.1/rock) (Tested on arch, btw) +[Rock v0.2.2](https://github.com/Champii/Rock/releases/download/v0.2.2/rock) (Tested on arch, btw) ``` sh -wget https://github.com/Champii/Rock/releases/download/v0.2.1/rock +wget https://github.com/Champii/Rock/releases/download/v0.2.2/rock chmod +x rock ./rock -V ``` @@ -74,14 +74,12 @@ cargo run -- -V ## Quickstart -Lets create a new project folder to compute some factorials +- Lets create a new project folder to compute some factorials ``` sh -mkdir -P factorial/src && cd factorial +mkdir -p factorial/src && cd factorial ``` -Add some files like this: - - Create a `factorial/src/main.rk` file: ```haskell @@ -135,6 +133,22 @@ Prints Test ``` +The `id` function here is polymorphic by default, as we don't make any constraint on the type that we should take or return. +If we did something like this +`id a = a + a` +We would have constrained `a` to types that implement [`Num`](https://github.com/Champii/Rock/blob/master/std/src/num.rk) + +Note that this example would still be valid, as `Int64`, `Float64` and `String` are all implementors of `Num`(*). +The output would be + +``` sh +2 +4.4 +TestTest +``` + +(*) `String` is nowhere at its place here, and only implements `+` for string concatenation. This should change in the future with more traits like `Add` in rust + ### Custom infix operator ``` haskell @@ -152,9 +166,14 @@ rock run Prints `6` +You can create any operator that is made of any combination of one or more of `'+', '-', '/', '*', '|', '<', '>', '=', '!', '$', '@', '&'` + +Most of the commonly defined operators like `+`, `<=`, etc are already implemented by the [stdlib](https://github.com/Champii/Rock/tree/master/std) that is automaticaly compiled with every package. +There is a `--nostd` option to allow you to use your own custom implementation. + ### Trait definition -This `trait ToString` is redondant with the `trait Show` implemented in the lib, and serves as a demonstration only +This `trait ToString` is redondant with the `trait Show` implemented in the stdlib, and serves as a demonstration only ``` haskell trait ToString a @@ -176,7 +195,7 @@ main = rock run ``` -Prints +Prints ``` 33 @@ -208,6 +227,31 @@ rock run Prints `MyName` +### Modules and code separation + +- `./myproj/src/foo.rk` + +```haskell +bar a = a + 1 +``` + +- `./myproj/src/main.rk` + +```haskell +mod foo + +use foo::bar + +main = print bar 1 +``` + +Prints `2` + +Note that we could have skiped the +`use foo::bar` +if we wrote +`main = print foo::bar 1` + ## REPL Only supports basic expressions for now. @@ -228,7 +272,7 @@ rock --repl ``` ``` sh -Rock: v0.2.1 +Rock: v0.2.2 ---- Type ':?' for help diff --git a/build.rs b/build.rs index 11ca5d93..ca828481 100644 --- a/build.rs +++ b/build.rs @@ -87,7 +87,7 @@ fn write_header(output_file: &mut File) { let expected_ret = expected_ret.parse::().unwrap(); - let (ret_code, stdout) = super::test::run(path, input.to_string(), config); + let (ret_code, stdout) = super::helpers::test_utils::run(path, input.to_string(), config); assert_eq!(expected_ret, ret_code); assert_eq!(expected_output, stdout); diff --git a/src/lib/ast/mod.rs b/src/lib/ast/mod.rs index f040355b..76097a4d 100644 --- a/src/lib/ast/mod.rs +++ b/src/lib/ast/mod.rs @@ -1,7 +1,6 @@ #[macro_use] pub mod ast_print; -pub mod return_placement; pub mod tree; pub mod visit; diff --git a/src/lib/ast/return_placement.rs b/src/lib/ast/return_placement.rs deleted file mode 100644 index b5c2fec7..00000000 --- a/src/lib/ast/return_placement.rs +++ /dev/null @@ -1,64 +0,0 @@ -use crate::ast::tree::*; - -pub struct ReturnInserter<'a> { - pub body: &'a Body, -} - -// TODO: Implement `Visitor` trait for `ReturnInserter` -impl<'a> ReturnInserter<'a> { - pub fn run(&mut self) -> Body { - let mut body = self.body.clone(); - - self.visit_body(&mut body); - - body - } - - fn visit_body(&mut self, body: &mut Body) { - if let Some(stmt) = body.stmts.iter_mut().last() { - self.visit_statement(stmt); - } - } - - fn visit_statement(&mut self, stmt: &mut Statement) { - let mut is_assign = None; - - match *stmt { - Statement::Expression(ref mut e) => { - *e = Box::new(Expression::Return(e.clone())); - } - Statement::If(ref mut i) => { - self.visit_if(i); - } - Statement::Assign(ref mut a) => { - is_assign = Some(a.value.clone()); - } - Statement::For(ref mut _fa) => { - unimplemented!("Cannot have loop in return position"); - } - } - - // FIXME: do this only if a.name is Identifier - // or else return the ident - if let Some(value) = is_assign { - *stmt = Statement::Expression(Box::new(Expression::Return(Box::new(value)))); - } - } - - fn visit_if(&mut self, r#if: &mut If) { - self.visit_body(&mut r#if.body); - - if let Some(ref mut r#else) = r#if.else_.as_mut() { - self.visit_else(r#else); - } else { - unimplemented!("Else is not found"); - } - } - - fn visit_else(&mut self, r#else: &mut Else) { - match r#else { - Else::If(i) => self.visit_if(i), - Else::Body(b) => self.visit_body(b), - } - } -} diff --git a/src/lib/ast/tree.rs b/src/lib/ast/tree.rs index cf26e85e..2b2c91fe 100644 --- a/src/lib/ast/tree.rs +++ b/src/lib/ast/tree.rs @@ -198,11 +198,15 @@ impl IdentifierPath { Self { path: vec![Identifier { name: "root".to_string(), - node_id: 42, // FIXME: should have a valid node_id ? + node_id: 0, // FIXME: should have a valid node_id ? }], } } + pub fn has_root(&self) -> bool { + self.path.len() > 0 && self.path[0].name == "root" + } + pub fn parent(&self) -> Self { let mut parent = self.clone(); diff --git a/src/lib/ast_lowering/ast_lowering_context.rs b/src/lib/ast_lowering/ast_lowering_context.rs index f68726ec..a9ec5d61 100644 --- a/src/lib/ast_lowering/ast_lowering_context.rs +++ b/src/lib/ast_lowering/ast_lowering_context.rs @@ -1,7 +1,7 @@ use std::collections::{BTreeMap, HashMap}; use crate::{ - ast::{return_placement::ReturnInserter, tree::*, NodeId}, + ast::{tree::*, NodeId}, hir::{self, Arena, FnBodyId, HirId}, infer::Envs, ty::*, @@ -210,9 +210,7 @@ impl AstLoweringContext { body_id: FnBodyId, fn_id: HirId, ) -> hir::FnBody { - let body = ReturnInserter { body: fn_body }.run(); - - let body = self.lower_body(&body); + let body = self.lower_body(&fn_body); hir::FnBody { id: body_id, diff --git a/src/lib/codegen/codegen_context.rs b/src/lib/codegen/codegen_context.rs index c829dc25..bcee76ec 100644 --- a/src/lib/codegen/codegen_context.rs +++ b/src/lib/codegen/codegen_context.rs @@ -8,7 +8,7 @@ use inkwell::{ passes::{PassManager, PassManagerBuilder}, targets::{InitializationConfig, Target}, types::{BasicType, BasicTypeEnum}, - values::{AnyValue, AnyValueEnum, BasicValue, BasicValueEnum, CallableValue, FunctionValue}, + values::{BasicValue, BasicValueEnum, CallableValue, FunctionValue}, AddressSpace, FloatPredicate, IntPredicate, OptimizationLevel::Aggressive, }; @@ -300,7 +300,9 @@ impl<'a> CodegenContext<'a> { self.scopes.add(arg.name.hir_id.clone(), param); } - self.lower_body(&fn_body.body, "entry", builder)?; + let (last, _) = self.lower_body(&fn_body.body, "entry", builder)?; + + builder.build_return(Some(&last)); } else { panic!("Cannot find function {:?}", top_f.get_name()); } @@ -313,7 +315,7 @@ impl<'a> CodegenContext<'a> { body: &'a Body, name: &str, builder: &'a Builder, - ) -> Result<(AnyValueEnum<'a>, BasicBlock<'a>), ()> { + ) -> Result<(BasicValueEnum<'a>, BasicBlock<'a>), ()> { let basic_block = self .context .append_basic_block(self.cur_func.unwrap(), name); @@ -334,9 +336,9 @@ impl<'a> CodegenContext<'a> { &mut self, stmt: &'a Statement, builder: &'a Builder, - ) -> Result, ()> { + ) -> Result, ()> { Ok(match &*stmt.kind { - StatementKind::Expression(e) => self.lower_expression(e, builder)?.as_any_value_enum(), + StatementKind::Expression(e) => self.lower_expression(e, builder)?, StatementKind::If(e) => self.lower_if(e, builder)?.0, StatementKind::Assign(a) => self.lower_assign(a, builder)?, StatementKind::For(f) => self.lower_for(f, builder)?, @@ -347,7 +349,7 @@ impl<'a> CodegenContext<'a> { &mut self, for_loop: &'a For, builder: &'a Builder, - ) -> Result, ()> { + ) -> Result, ()> { match &for_loop { For::In(i) => self.lower_for_in(i, builder), For::While(w) => self.lower_while(w, builder), @@ -358,7 +360,7 @@ impl<'a> CodegenContext<'a> { &mut self, for_in: &'a ForIn, builder: &'a Builder, - ) -> Result, ()> { + ) -> Result, ()> { let block = builder.get_insert_block().unwrap(); let cur_f = block.get_parent().unwrap(); @@ -383,7 +385,7 @@ impl<'a> CodegenContext<'a> { &mut self, while_loop: &'a While, builder: &'a Builder, - ) -> Result, ()> { + ) -> Result, ()> { let block = builder.get_insert_block().unwrap(); let cur_f = block.get_parent().unwrap(); @@ -408,7 +410,7 @@ impl<'a> CodegenContext<'a> { &mut self, assign: &'a Assign, builder: &'a Builder, - ) -> Result, ()> { + ) -> Result, ()> { Ok(match &assign.name { AssignLeftSide::Identifier(id) => { let value = self.lower_expression(&assign.value, builder)?; @@ -441,7 +443,7 @@ impl<'a> CodegenContext<'a> { self.scopes.add(id.get_hir_id(), val); - val.as_any_value_enum() + val } AssignLeftSide::Indice(indice) => { let ptr = self.lower_indice_ptr(indice, builder)?.into_pointer_value(); @@ -450,7 +452,7 @@ impl<'a> CodegenContext<'a> { builder.build_store(ptr, value); - ptr.as_any_value_enum() + ptr.as_basic_value_enum() } AssignLeftSide::Dot(dot) => { let ptr = self.lower_dot_ptr(dot, builder)?.into_pointer_value(); @@ -459,7 +461,7 @@ impl<'a> CodegenContext<'a> { builder.build_store(ptr, value); - ptr.as_any_value_enum() + ptr.as_basic_value_enum() } }) } @@ -468,54 +470,49 @@ impl<'a> CodegenContext<'a> { &mut self, r#if: &'a If, builder: &'a Builder, - ) -> Result<(AnyValueEnum<'a>, BasicBlock<'a>), ()> { + ) -> Result<(BasicValueEnum<'a>, BasicBlock<'a>), ()> { let block = builder.get_insert_block().unwrap(); builder.position_at_end(block); let predicat = self.lower_expression(&r#if.predicat, builder)?; - let (_, then_block) = self.lower_body(&r#if.body, "then", builder)?; - - let else_block = if let Some(e) = &r#if.else_ { - let else_block = self.lower_else(e, builder)?; + let (then_value, then_block) = self.lower_body(&r#if.body, "then", builder)?; - else_block + let (else_value, else_block) = if let Some(e) = &r#if.else_ { + self.lower_else(e, builder)? } else { - //new empty block - let f = self.module.get_last_function().unwrap(); - - self.context.append_basic_block(f, "else") + (then_value, then_block) }; - // FIXME: Need a last block if the 'if' is not the last statement in the fn body - // Investigate PHI values - // - // let rest_block = self - // .context - // .append_basic_block(self.module.get_last_function().unwrap(), "rest"); - - // builder.build_unconditional_branch(rest_block); + let rest_block = self.context.insert_basic_block_after(else_block, "rest"); - // builder.position_at_end(then_block); + builder.position_at_end(then_block); + builder.build_unconditional_branch(rest_block); - // builder.build_unconditional_branch(rest_block); + if r#if.else_.is_some() { + builder.position_at_end(else_block); + builder.build_unconditional_branch(rest_block); + } builder.position_at_end(block); - let if_value = - builder.build_conditional_branch(predicat.into_int_value(), then_block, else_block); + builder.build_conditional_branch(predicat.into_int_value(), then_block, else_block); + + builder.position_at_end(rest_block); + + let phi = builder.build_phi(then_value.get_type(), "phi"); - builder.position_at_end(else_block); + phi.add_incoming(&[(&then_value, then_block), (&else_value, else_block)]); - Ok((if_value.as_any_value_enum(), block)) + Ok((phi.as_basic_value(), block)) } pub fn lower_else( &mut self, r#else: &'a Else, builder: &'a Builder, - ) -> Result, ()> { + ) -> Result<(BasicValueEnum<'a>, BasicBlock<'a>), ()> { Ok(match &r#else { Else::If(i) => { let block = self @@ -524,9 +521,9 @@ impl<'a> CodegenContext<'a> { builder.position_at_end(block); - self.lower_if(i, builder)?.1 + self.lower_if(i, builder)? } - Else::Body(b) => self.lower_body(b, "else", builder)?.1, + Else::Body(b) => self.lower_body(b, "else", builder)?, }) } diff --git a/src/lib/diagnostics/diagnostic.rs b/src/lib/diagnostics/diagnostic.rs index a7bc2b12..69182d5a 100644 --- a/src/lib/diagnostics/diagnostic.rs +++ b/src/lib/diagnostics/diagnostic.rs @@ -8,7 +8,7 @@ use crate::{ ty::{FuncType, Type}, }; use colored::*; -use nom::error::VerboseError; +use nom::error::{VerboseError, VerboseErrorKind}; #[derive(Clone, Debug)] pub struct Diagnostic { @@ -128,12 +128,15 @@ impl Diagnostic { arrow.push('^'); - let mut i = 0; + // FIXME: some span don't have txt + if self.span.end - self.span.start > 0 { + let mut i = 0; - while i < self.span.end - self.span.start { - arrow.push('~'); + while i < self.span.end - self.span.start - 1 { + arrow.push('~'); - i += 1; + i += 1; + } } let diag_type_str = match diag_type { @@ -297,3 +300,17 @@ impl<'a> From>> for Diagnostic { Diagnostic::new_syntax_error(span, msg) } } + +impl From<(I, VerboseErrorKind)> for Diagnostic +where + Span2: From, +{ + fn from((input, _kind): (I, VerboseErrorKind)) -> Self { + let span2 = Span2::from(input); + let span = Span::from(span2); + + let msg = "Syntax error".to_string(); + + Diagnostic::new_syntax_error(span, msg) + } +} diff --git a/src/lib/diagnostics/diagnostics_list.rs b/src/lib/diagnostics/diagnostics_list.rs index 838ad1fb..fc656292 100644 --- a/src/lib/diagnostics/diagnostics_list.rs +++ b/src/lib/diagnostics/diagnostics_list.rs @@ -1,6 +1,8 @@ use std::{collections::HashMap, path::PathBuf}; -use crate::parser::SourceFile; +use nom::error::VerboseError; + +use crate::parser::{Parser, SourceFile}; use super::Diagnostic; @@ -40,6 +42,7 @@ impl Diagnostics { let input = match files.get(&diag.span.file_path) { Some(input) => input, None => { + println!("DIAG FILE {:#?}", diag.span.file_path); warn!("Diagnostic has been silenced because the file is not found"); continue; @@ -56,3 +59,33 @@ impl Diagnostics { self.must_stop = self.must_stop || other.must_stop; } } + +impl<'a> From>> for Diagnostics { + fn from(err: VerboseError>) -> Self { + let mut diags = err + .errors + .clone() + .into_iter() + .take(1) + .map(Diagnostic::from) + .collect::>(); + + let diags2 = err + .errors + .into_iter() + .take(1) + .map(|(input, _kind)| input.extra.diagnostics().list) + .flatten() + .collect::>(); + + diags.extend(diags2); + + let mut list = Diagnostics::default(); + + for diag in diags { + list.push_error(diag); + } + + list + } +} diff --git a/src/lib/helpers/mod.rs b/src/lib/helpers/mod.rs index ee3cca0a..146ef602 100644 --- a/src/lib/helpers/mod.rs +++ b/src/lib/helpers/mod.rs @@ -5,5 +5,7 @@ pub mod class_name; pub mod config; pub mod scopes; +pub mod test_utils; + pub use class_name::*; pub use walk_helpers::*; diff --git a/src/lib/helpers/scopes.rs b/src/lib/helpers/scopes.rs index b7fbd119..fab4d2bb 100644 --- a/src/lib/helpers/scopes.rs +++ b/src/lib/helpers/scopes.rs @@ -1,6 +1,8 @@ use std::collections::HashMap; use std::hash::Hash; +pub type Scope = HashMap; + #[derive(Clone, Debug)] pub struct Scopes where @@ -32,12 +34,8 @@ where } pub fn get(&self, s: K) -> Option { - let mut test = self.scopes.clone(); - test.reverse(); - // Here need reverse scopes - - for scope in test { - if let Some(res) = scope.items.get(&s) { + for scope in self.scopes.iter().rev() { + if let Some(res) = scope.get(&s) { return Some(res.clone()); } } @@ -46,10 +44,7 @@ where } pub fn add(&mut self, s: K, val: T) { - // Here need reverse scopes - let scope = self.scopes.last_mut().unwrap(); - - scope.insert(s, val); + self.scopes.last_mut().unwrap().insert(s, val); } pub fn push(&mut self) { @@ -61,44 +56,6 @@ where } } -#[derive(Clone, Debug)] -pub struct Scope -where - K: Default + Hash + Eq + Clone, - T: Clone, -{ - pub ordering: Vec, - pub items: HashMap, -} - -impl Default for Scope -where - K: Default + Hash + Eq + Clone, - T: Clone, -{ - fn default() -> Self { - Self { - ordering: Default::default(), - items: Default::default(), - } - } -} - -impl Scope -where - K: Default + Hash + Eq + Clone, - T: Clone, -{ - pub fn new() -> Scope { - Default::default() - } - - pub fn insert(&mut self, s: K, v: T) { - self.items.insert(s.clone(), v); - self.ordering.push(s); - } -} - #[cfg(test)] mod tests { use super::*; @@ -115,9 +72,13 @@ mod tests { scopes.push(); - scopes.add("a", 3); scopes.add("b", 4); + assert_eq!(scopes.get("a").unwrap(), 1); + assert_eq!(scopes.get("b").unwrap(), 4); + + scopes.add("a", 3); + assert_eq!(scopes.get("a").unwrap(), 3); assert_eq!(scopes.get("b").unwrap(), 4); diff --git a/src/lib/helpers/test_utils.rs b/src/lib/helpers/test_utils.rs new file mode 100644 index 00000000..64c17db6 --- /dev/null +++ b/src/lib/helpers/test_utils.rs @@ -0,0 +1,74 @@ +use crate::{parser::SourceFile, Config}; +use std::{ + fs, + path::{Path, PathBuf}, + process::Command, +}; + +fn build(input: String, config: Config) -> bool { + let file = SourceFile { + file_path: PathBuf::from("src/lib").join(&config.project_config.entry_point), + mod_path: PathBuf::from("main"), + content: input, + }; + + if let Err(_e) = crate::compile_str(&file, &config) { + return false; + } + + let clang_cmd = Command::new("clang") + .args(&[ + config.build_folder.join("out.bc").to_str().unwrap(), + "-o", + config.build_folder.join("a.out").to_str().unwrap(), + ]) + .output() + .expect("failed to compile to ir"); + + match clang_cmd.status.code() { + Some(code) => { + if code != 0 { + println!( + "BUG: Cannot compile: \n{}", + String::from_utf8(clang_cmd.stderr).unwrap() + ); + + return false; + } + } + None => println!( + "\nError running: \n{}", + String::from_utf8(clang_cmd.stderr).unwrap() + ), + } + + true +} + +pub fn run(path: &str, input: String, config: Config) -> (i64, String) { + let path = Path::new("src/lib/").join(path); + + let build_path = path.parent().unwrap().join("build"); + + let mut config = config; + config.build_folder = build_path; + + fs::create_dir_all(config.build_folder.clone()).unwrap(); + + if !build(input, config.clone()) { + return (-1, String::new()); + } + + let cmd = Command::new(config.build_folder.join("a.out").to_str().unwrap()) + .output() + .expect("failed to execute BINARY"); + + let stdout = String::from_utf8(cmd.stderr).unwrap(); + + fs::remove_dir_all(config.build_folder).unwrap(); + + match cmd.status.code() { + Some(code) => (code.into(), stdout), + None => (-1, stdout), + } +} diff --git a/src/lib/parser/mod.rs b/src/lib/parser/mod.rs index 78bcaab1..58c0d76a 100644 --- a/src/lib/parser/mod.rs +++ b/src/lib/parser/mod.rs @@ -8,7 +8,7 @@ use nom::{ bytes::complete::{tag, take_while}, character::complete::{alphanumeric0, char, line_ending, one_of, satisfy, space0, space1}, combinator::{eof, map, opt, peek, recognize}, - error::{make_error, ErrorKind, ParseError, VerboseError}, + error::{make_error, ErrorKind, FromExternalError, ParseError, VerboseError}, error_position, multi::{many0, many1, separated_list0, separated_list1}, sequence::{delimited, preceded, terminated, tuple}, @@ -22,8 +22,9 @@ use crate::{ tree::{self, *}, NodeId, }, - diagnostics::Diagnostic, + diagnostics::{Diagnostic, Diagnostics}, ty::{FuncType, PrimitiveType, StructType, Type}, + Config, }; pub type Parser<'a> = LocatedSpan<&'a str, ParserCtx>; @@ -110,6 +111,7 @@ lazy_static! { #[derive(Debug, Clone)] pub struct ParserCtx { files: HashMap, + diagnostics: Diagnostics, cur_file_path: PathBuf, identities: BTreeMap, operators_list: HashMap, @@ -117,10 +119,11 @@ pub struct ParserCtx { first_indent: Option, next_node_id: NodeId, structs: HashMap, + pub config: Config, } impl ParserCtx { - pub fn new(file_path: PathBuf) -> Self { + pub fn new(file_path: PathBuf, config: Config) -> Self { Self { files: HashMap::new(), cur_file_path: file_path, @@ -130,11 +133,17 @@ impl ParserCtx { first_indent: None, next_node_id: 0, structs: HashMap::new(), + diagnostics: Diagnostics::default(), + config, } } #[cfg(test)] - pub fn new_with_operators(file_path: PathBuf, operators: HashMap) -> Self { + pub fn new_with_operators( + file_path: PathBuf, + operators: HashMap, + config: Config, + ) -> Self { Self { files: HashMap::new(), cur_file_path: file_path, @@ -144,10 +153,12 @@ impl ParserCtx { first_indent: None, next_node_id: 0, structs: HashMap::new(), + diagnostics: Diagnostics::default(), + config, } } - pub fn new_from(&self, name: &str) -> Self { + pub fn new_from(&self, name: &str, config: Config) -> Self { Self { files: HashMap::new(), cur_file_path: self @@ -161,10 +172,12 @@ impl ParserCtx { first_indent: None, next_node_id: self.next_node_id, structs: HashMap::new(), + diagnostics: Diagnostics::default(), // FIXME + config, } } - pub fn new_std(&self) -> Self { + pub fn new_std(&self, config: Config) -> Self { Self { files: HashMap::new(), cur_file_path: PathBuf::from("/std/src/lib.rk"), @@ -174,6 +187,8 @@ impl ParserCtx { first_indent: None, next_node_id: self.next_node_id, structs: HashMap::new(), + diagnostics: Diagnostics::default(), + config, } } @@ -210,6 +225,10 @@ impl ParserCtx { pub fn files(&self) -> HashMap { self.files.clone() } + + pub fn diagnostics(&self) -> Diagnostics { + self.diagnostics.clone() + } } pub fn parse_root(input: Parser) -> Res { @@ -256,29 +275,54 @@ pub fn parse_eol(input: Parser) -> Res { } pub fn parse_mod_decl(input: Parser) -> Res { + let config = input.extra.config.clone(); + let (mut input, mod_name) = preceded(terminated(tag("mod"), space1), parse_identifier)(input)?; let mut new_ctx = if mod_name.name == "std" { - input.extra.new_std() + input.extra.new_std(config.clone()) } else { - input.extra.new_from(&mod_name.name) + input.extra.new_from(&mod_name.name, config.clone()) }; let file_path = new_ctx.current_file_path().to_str().unwrap().to_string(); - let file = SourceFile::from_file(file_path).unwrap(); // FIXME: ERRORS ARE swallowed HERE - // + let mut file = SourceFile::from_file(file_path.clone()).unwrap(); // FIXME: ERRORS ARE swallowed HERE + // + + if config.std { + if STDLIB_FILES.get(&file_path).is_none() { + file.content = "use root::std::prelude::(*)\n".to_owned() + &file.content; + } + } + new_ctx .files .insert(new_ctx.current_file_path().clone(), file.clone()); - let content = &file.content; - - let new_parser = Parser::new_extra(content, new_ctx); + let new_parser = Parser::new_extra(&file.content, new_ctx); use nom::Finish; - // FIXME: Errors are swallowed here - let (input2, mod_) = parse_mod(new_parser).finish().unwrap(); + + let parsed_mod_opt = parse_mod(new_parser.clone()).finish(); + + let (input2, mod_) = match parsed_mod_opt { + Ok((input2, mod_)) => (input2, mod_), + Err(err) => { + input + .extra + .diagnostics + .append(Diagnostics::from(err.clone())); + input.extra.identities.extend(new_parser.extra.identities); + input.extra.files.extend(new_parser.extra.files); + + return Err(nom::Err::Error(VerboseError::from_external_error( + input, + ErrorKind::Fail, + err.to_owned(), + ))); + } + }; // hydrate `input` with the new parser's operators // TODO: handle duplicate operators @@ -287,9 +331,11 @@ pub fn parse_mod_decl(input: Parser) -> Res { .operators_list .extend(input2.extra.operators_list); + input.extra.diagnostics.append(input2.extra.diagnostics); + // extend identities - input.extra.identities.extend(input2.extra.identities); input.extra.next_node_id = input2.extra.next_node_id; + input.extra.identities.extend(input2.extra.identities); input.extra.files.extend(input2.extra.files); Ok((input, (mod_name, mod_))) @@ -1035,21 +1081,22 @@ pub fn allowed_operator_chars(input: Parser) -> Res { Ok((input, c.to_string())) } -// FIXME: put std bool into config pub fn parse(parsing_ctx: &mut ParsingCtx) -> Result { use nom::Finish; let content = &parsing_ctx.get_current_file().content; - let content = if parsing_ctx.config.std { - "mod std\nuse std::prelude::(*)\n".to_owned() + content - } else { - content.clone() - }; - - let parser = LocatedSpan::new_extra( + let mut parser = LocatedSpan::new_extra( content.as_str(), - ParserCtx::new(parsing_ctx.get_current_file().file_path.clone()), + ParserCtx::new( + parsing_ctx.get_current_file().file_path.clone(), + parsing_ctx.config.clone(), + ), + ); + + parser.extra.files.insert( + parsing_ctx.get_current_file().file_path.clone(), + parsing_ctx.get_current_file().clone(), ); let ast = parse_root(parser).finish(); @@ -1057,7 +1104,7 @@ pub fn parse(parsing_ctx: &mut ParsingCtx) -> Result { let ast = match ast { Ok((ctx, mut ast)) => { parsing_ctx.identities = ctx.extra.identities(); - parsing_ctx.files = ctx.extra.files(); + parsing_ctx.files.extend(ctx.extra.files()); ast.operators_list = ctx.extra.operators_list(); ast.spans = ctx.extra.identities().into_iter().collect(); @@ -1070,11 +1117,19 @@ pub fn parse(parsing_ctx: &mut ParsingCtx) -> Result { Ok(ast) } Err(e) => { - let diagnostic = Diagnostic::from(e); + parsing_ctx + .files + .extend(e.errors.get(0).unwrap().clone().0.extra.files()); + + let diagnostics = Diagnostics::from(e); + + parsing_ctx.diagnostics.append(diagnostics); + + // parsing_ctx.identities = ast.extra.identities(); - parsing_ctx.diagnostics.push_error(diagnostic.clone()); + parsing_ctx.return_if_error()?; - Err(diagnostic) + Err(parsing_ctx.diagnostics.list.get(0).unwrap().clone()) } }?; diff --git a/src/lib/parser/tests.rs b/src/lib/parser/tests.rs index 9406086e..3e6f7159 100644 --- a/src/lib/parser/tests.rs +++ b/src/lib/parser/tests.rs @@ -8,7 +8,7 @@ mod parse_literal { #[test] fn bool() { - let input = Parser::new_extra("true", ParserCtx::new(PathBuf::new())); + let input = Parser::new_extra("true", ParserCtx::new(PathBuf::new(), Config::default())); let (_rest, num_parsed) = parse_literal(input).finish().unwrap(); @@ -17,7 +17,7 @@ mod parse_literal { #[test] fn number() { - let input = Parser::new_extra("42", ParserCtx::new(PathBuf::new())); + let input = Parser::new_extra("42", ParserCtx::new(PathBuf::new(), Config::default())); let (_rest, num_parsed) = parse_literal(input).finish().unwrap(); @@ -26,7 +26,7 @@ mod parse_literal { #[test] fn float() { - let input = Parser::new_extra("42.42", ParserCtx::new(PathBuf::new())); + let input = Parser::new_extra("42.42", ParserCtx::new(PathBuf::new(), Config::default())); let (_rest, num_parsed) = parse_literal(input).finish().unwrap(); @@ -40,7 +40,7 @@ mod parse_bool { #[test] fn r#true() { - let input = Parser::new_extra("true", ParserCtx::new(PathBuf::new())); + let input = Parser::new_extra("true", ParserCtx::new(PathBuf::new(), Config::default())); let (_rest, parsed) = parse_bool(input).finish().unwrap(); @@ -49,7 +49,7 @@ mod parse_bool { #[test] fn r#false() { - let input = Parser::new_extra("false", ParserCtx::new(PathBuf::new())); + let input = Parser::new_extra("false", ParserCtx::new(PathBuf::new(), Config::default())); let (_rest, parsed) = parse_bool(input).finish().unwrap(); @@ -58,7 +58,7 @@ mod parse_bool { #[test] fn invalid() { - let input = Parser::new_extra("atrue", ParserCtx::new(PathBuf::new())); + let input = Parser::new_extra("atrue", ParserCtx::new(PathBuf::new(), Config::default())); assert!(parse_bool(input).finish().is_err()); } @@ -70,7 +70,7 @@ mod parse_float { #[test] fn valid_with_last_part() { - let input = Parser::new_extra("42.42", ParserCtx::new(PathBuf::new())); + let input = Parser::new_extra("42.42", ParserCtx::new(PathBuf::new(), Config::default())); let (_rest, parsed) = parse_float(input).finish().unwrap(); @@ -79,7 +79,7 @@ mod parse_float { #[test] fn valid_no_last_part() { - let input = Parser::new_extra("42.", ParserCtx::new(PathBuf::new())); + let input = Parser::new_extra("42.", ParserCtx::new(PathBuf::new(), Config::default())); let (_rest, parsed) = parse_float(input).finish().unwrap(); @@ -88,7 +88,7 @@ mod parse_float { #[test] fn invalid() { - let input = Parser::new_extra("a42.", ParserCtx::new(PathBuf::new())); + let input = Parser::new_extra("a42.", ParserCtx::new(PathBuf::new(), Config::default())); assert!(parse_float(input).finish().is_err()); } @@ -100,7 +100,7 @@ mod parse_number { #[test] fn valid() { - let input = Parser::new_extra("42", ParserCtx::new(PathBuf::new())); + let input = Parser::new_extra("42", ParserCtx::new(PathBuf::new(), Config::default())); let (_rest, parsed) = parse_number(input).finish().unwrap(); @@ -109,7 +109,7 @@ mod parse_number { #[test] fn invalid() { - let input = Parser::new_extra("a42", ParserCtx::new(PathBuf::new())); + let input = Parser::new_extra("a42", ParserCtx::new(PathBuf::new(), Config::default())); assert!(parse_number(input).finish().is_err()); } @@ -121,7 +121,7 @@ mod parse_signature { #[test] fn valid_1_arg() { - let input = Parser::new_extra("Int64", ParserCtx::new(PathBuf::new())); + let input = Parser::new_extra("Int64", ParserCtx::new(PathBuf::new(), Config::default())); let (_rest, parsed) = parse_signature(input).finish().unwrap(); @@ -131,7 +131,10 @@ mod parse_signature { #[test] fn valid_2_arg() { - let input = Parser::new_extra("Int64 -> Int64", ParserCtx::new(PathBuf::new())); + let input = Parser::new_extra( + "Int64 -> Int64", + ParserCtx::new(PathBuf::new(), Config::default()), + ); let (_rest, parsed) = parse_signature(input).finish().unwrap(); @@ -146,7 +149,7 @@ mod parse_type { #[test] fn valid() { - let input = Parser::new_extra("Int64", ParserCtx::new(PathBuf::new())); + let input = Parser::new_extra("Int64", ParserCtx::new(PathBuf::new(), Config::default())); let (_rest, parsed) = parse_type(input).finish().unwrap(); @@ -155,7 +158,7 @@ mod parse_type { #[test] fn valid_for_all() { - let input = Parser::new_extra("a", ParserCtx::new(PathBuf::new())); + let input = Parser::new_extra("a", ParserCtx::new(PathBuf::new(), Config::default())); let (_rest, parsed) = parse_type(input).finish().unwrap(); @@ -164,7 +167,7 @@ mod parse_type { #[test] fn invalid() { - let input = Parser::new_extra("int64", ParserCtx::new(PathBuf::new())); + let input = Parser::new_extra("int64", ParserCtx::new(PathBuf::new(), Config::default())); assert!(parse_type(input).finish().is_err()); } @@ -176,7 +179,10 @@ mod parse_infix_op { #[test] fn valid() { - let input = Parser::new_extra("infix + 5", ParserCtx::new(PathBuf::new())); + let input = Parser::new_extra( + "infix + 5", + ParserCtx::new(PathBuf::new(), Config::default()), + ); let (rest, parsed) = parse_infix(input).finish().unwrap(); @@ -197,7 +203,7 @@ mod parse_operator { let input = Parser::new_extra( "+", - ParserCtx::new_with_operators(PathBuf::new(), operators), + ParserCtx::new_with_operators(PathBuf::new(), operators, Config::default()), ); let (_rest, parsed) = parse_operator(input).finish().unwrap(); @@ -218,7 +224,7 @@ mod parse_identifier { #[test] fn valid() { - let input = Parser::new_extra("foo", ParserCtx::new(PathBuf::new())); + let input = Parser::new_extra("foo", ParserCtx::new(PathBuf::new(), Config::default())); let (_rest, parsed) = parse_identifier(input).finish().unwrap(); @@ -238,7 +244,10 @@ mod parse_identifier_path { #[test] fn valid() { - let input = Parser::new_extra("foo::bar", ParserCtx::new(PathBuf::new())); + let input = Parser::new_extra( + "foo::bar", + ParserCtx::new(PathBuf::new(), Config::default()), + ); let (_rest, parsed) = parse_identifier_path(input).finish().unwrap(); @@ -266,7 +275,7 @@ mod parse_operand { #[test] fn valid_literal() { - let input = Parser::new_extra("42", ParserCtx::new(PathBuf::new())); + let input = Parser::new_extra("42", ParserCtx::new(PathBuf::new(), Config::default())); let (_rest, parsed) = parse_operand(input).finish().unwrap(); @@ -281,7 +290,10 @@ mod parse_operand { #[test] fn valid_identifier_path() { - let input = Parser::new_extra("foo::bar", ParserCtx::new(PathBuf::new())); + let input = Parser::new_extra( + "foo::bar", + ParserCtx::new(PathBuf::new(), Config::default()), + ); let (_rest, parsed) = parse_operand(input).finish().unwrap(); @@ -293,7 +305,7 @@ mod parse_operand { #[test] fn valid_expression() { - let input = Parser::new_extra("(3)", ParserCtx::new(PathBuf::new())); + let input = Parser::new_extra("(3)", ParserCtx::new(PathBuf::new(), Config::default())); let (_rest, parsed) = parse_operand(input).finish().unwrap(); @@ -307,7 +319,7 @@ mod parse_expression { #[test] fn valid_unary() { - let input = Parser::new_extra("3", ParserCtx::new(PathBuf::new())); + let input = Parser::new_extra("3", ParserCtx::new(PathBuf::new(), Config::default())); let (_rest, parsed) = parse_expression(input).finish().unwrap(); @@ -320,7 +332,7 @@ mod parse_expression { let input = Parser::new_extra( "3 + 4", - ParserCtx::new_with_operators(PathBuf::new(), operators), + ParserCtx::new_with_operators(PathBuf::new(), operators, Config::default()), ); let (_rest, parsed) = parse_expression(input).finish().unwrap(); @@ -340,7 +352,8 @@ mod parse_primary { #[test] fn valid_no_args() { - let input = Parser::new_extra("foo()", ParserCtx::new(PathBuf::new())); + let input = + Parser::new_extra("foo()", ParserCtx::new(PathBuf::new(), Config::default())); let (_rest, parsed) = parse_primary(input).finish().unwrap(); @@ -357,7 +370,8 @@ mod parse_primary { #[test] fn valid_one_arg() { - let input = Parser::new_extra("foo(2)", ParserCtx::new(PathBuf::new())); + let input = + Parser::new_extra("foo(2)", ParserCtx::new(PathBuf::new(), Config::default())); let (_rest, parsed) = parse_primary(input).finish().unwrap(); @@ -374,7 +388,10 @@ mod parse_primary { #[test] fn valid_two_args() { - let input = Parser::new_extra("foo(2, 3)", ParserCtx::new(PathBuf::new())); + let input = Parser::new_extra( + "foo(2, 3)", + ParserCtx::new(PathBuf::new(), Config::default()), + ); let (_rest, parsed) = parse_primary(input).finish().unwrap(); @@ -395,7 +412,8 @@ mod parse_primary { #[test] fn valid_one_arg() { - let input = Parser::new_extra("foo 2", ParserCtx::new(PathBuf::new())); + let input = + Parser::new_extra("foo 2", ParserCtx::new(PathBuf::new(), Config::default())); let (_rest, parsed) = parse_primary(input).finish().unwrap(); @@ -412,7 +430,10 @@ mod parse_primary { #[test] fn valid_two_args() { - let input = Parser::new_extra("foo 2, 3", ParserCtx::new(PathBuf::new())); + let input = Parser::new_extra( + "foo 2, 3", + ParserCtx::new(PathBuf::new(), Config::default()), + ); let (_rest, parsed) = parse_primary(input).finish().unwrap(); @@ -431,7 +452,7 @@ mod parse_primary { #[test] fn valid_indice() { - let input = Parser::new_extra("foo[3]", ParserCtx::new(PathBuf::new())); + let input = Parser::new_extra("foo[3]", ParserCtx::new(PathBuf::new(), Config::default())); let (_rest, parsed) = parse_primary(input).finish().unwrap(); @@ -448,7 +469,10 @@ mod parse_primary { #[test] fn valid_dot() { - let input = Parser::new_extra("foo.toto", ParserCtx::new(PathBuf::new())); + let input = Parser::new_extra( + "foo.toto", + ParserCtx::new(PathBuf::new(), Config::default()), + ); let (_rest, parsed) = parse_primary(input).finish().unwrap(); @@ -465,7 +489,10 @@ mod parse_primary { #[test] fn valid_mixed() { - let input = Parser::new_extra("foo.toto()[a]", ParserCtx::new(PathBuf::new())); + let input = Parser::new_extra( + "foo.toto()[a]", + ParserCtx::new(PathBuf::new(), Config::default()), + ); let (_rest, parsed) = parse_primary(input).finish().unwrap(); @@ -481,7 +508,10 @@ mod parse_fn_decl { #[test] fn valid_no_args() { - let input = Parser::new_extra("toto =\n 2\n", ParserCtx::new(PathBuf::new())); + let input = Parser::new_extra( + "toto =\n 2\n", + ParserCtx::new(PathBuf::new(), Config::default()), + ); let (_rest, parsed) = parse_fn(input).finish().unwrap(); @@ -519,7 +549,7 @@ mod parse_fn_decl { let input = Parser::new_extra( "toto a b =\n a + b", - ParserCtx::new_with_operators(PathBuf::new(), operators), + ParserCtx::new_with_operators(PathBuf::new(), operators, Config::default()), ); let (_rest, parsed) = parse_fn(input).finish().unwrap(); @@ -586,7 +616,7 @@ mod parse_fn_decl { let input = Parser::new_extra( "toto a b =\n a + b\n a + b", - ParserCtx::new_with_operators(PathBuf::new(), operators), + ParserCtx::new_with_operators(PathBuf::new(), operators, Config::default()), ); let (rest, _parsed) = parse_fn(input).finish().unwrap(); @@ -600,7 +630,7 @@ mod parse_fn_decl { let input = Parser::new_extra( "toto a b = a + b", - ParserCtx::new_with_operators(PathBuf::new(), operators), + ParserCtx::new_with_operators(PathBuf::new(), operators, Config::default()), ); let (rest, _parsed) = parse_fn(input).finish().unwrap(); @@ -615,7 +645,10 @@ mod parse_prototype { #[test] fn valid() { - let input = Parser::new_extra("toto :: Int64 -> Int64", ParserCtx::new(PathBuf::new())); + let input = Parser::new_extra( + "toto :: Int64 -> Int64", + ParserCtx::new(PathBuf::new(), Config::default()), + ); let (_rest, parsed) = parse_prototype(input).finish().unwrap(); @@ -641,7 +674,7 @@ mod parse_use { #[test] fn valid() { - let input = Parser::new_extra("use foo", ParserCtx::new(PathBuf::new())); + let input = Parser::new_extra("use foo", ParserCtx::new(PathBuf::new(), Config::default())); let (_rest, parsed) = parse_use(input).finish().unwrap(); @@ -663,7 +696,10 @@ mod parse_if { #[test] fn valid_if() { - let input = Parser::new_extra("if a\nthen b", ParserCtx::new(PathBuf::new())); + let input = Parser::new_extra( + "if a\nthen b", + ParserCtx::new(PathBuf::new(), Config::default()), + ); let (rest, _parsed) = parse_if(input).finish().unwrap(); @@ -672,7 +708,10 @@ mod parse_if { #[test] fn valid_if_else() { - let input = Parser::new_extra("if a\nthen b\nelse c", ParserCtx::new(PathBuf::new())); + let input = Parser::new_extra( + "if a\nthen b\nelse c", + ParserCtx::new(PathBuf::new(), Config::default()), + ); let (rest, _parsed) = parse_if(input).finish().unwrap(); @@ -683,7 +722,7 @@ mod parse_if { fn valid_if_else_if() { let input = Parser::new_extra( "if a\nthen b\nelse if false\nthen c", - ParserCtx::new(PathBuf::new()), + ParserCtx::new(PathBuf::new(), Config::default()), ); let (rest, _parsed) = parse_if(input).finish().unwrap(); @@ -695,7 +734,7 @@ mod parse_if { fn valid_if_else_if_else() { let input = Parser::new_extra( "if a\nthen b\nelse if true\nthen c\nelse d", - ParserCtx::new(PathBuf::new()), + ParserCtx::new(PathBuf::new(), Config::default()), ); let (rest, _parsed) = parse_if(input).finish().unwrap(); @@ -705,7 +744,10 @@ mod parse_if { #[test] fn valid_multiline_if_else() { - let input = Parser::new_extra("if a\nthen\n b\nelse\n d", ParserCtx::new(PathBuf::new())); + let input = Parser::new_extra( + "if a\nthen\n b\nelse\n d", + ParserCtx::new(PathBuf::new(), Config::default()), + ); let (rest, _parsed) = parse_if(input).finish().unwrap(); @@ -719,7 +761,10 @@ mod parse_for { #[test] fn valid_for_in() { - let input = Parser::new_extra("for x in a\n b", ParserCtx::new(PathBuf::new())); + let input = Parser::new_extra( + "for x in a\n b", + ParserCtx::new(PathBuf::new(), Config::default()), + ); let (rest, _parsed) = parse_for(input).finish().unwrap(); @@ -728,7 +773,10 @@ mod parse_for { #[test] fn valid_while() { - let input = Parser::new_extra("while a\n b = 2", ParserCtx::new(PathBuf::new())); + let input = Parser::new_extra( + "while a\n b = 2", + ParserCtx::new(PathBuf::new(), Config::default()), + ); let (rest, _parsed) = parse_for(input).finish().unwrap(); @@ -742,7 +790,10 @@ mod parse_assign { #[test] fn valid_assign() { - let input = Parser::new_extra("let a = 2", ParserCtx::new(PathBuf::new())); + let input = Parser::new_extra( + "let a = 2", + ParserCtx::new(PathBuf::new(), Config::default()), + ); let (rest, _parsed) = parse_assign(input).finish().unwrap(); @@ -751,7 +802,7 @@ mod parse_assign { #[test] fn valid_reassign_ident() { - let input = Parser::new_extra("a = 2", ParserCtx::new(PathBuf::new())); + let input = Parser::new_extra("a = 2", ParserCtx::new(PathBuf::new(), Config::default())); let (rest, _parsed) = parse_assign(input).finish().unwrap(); @@ -760,7 +811,7 @@ mod parse_assign { #[test] fn valid_reassign_dot() { - let input = Parser::new_extra("a.b = 2", ParserCtx::new(PathBuf::new())); + let input = Parser::new_extra("a.b = 2", ParserCtx::new(PathBuf::new(), Config::default())); let (rest, _parsed) = parse_assign(input).finish().unwrap(); @@ -769,7 +820,10 @@ mod parse_assign { #[test] fn valid_reassign_indice() { - let input = Parser::new_extra("a[2] = 2", ParserCtx::new(PathBuf::new())); + let input = Parser::new_extra( + "a[2] = 2", + ParserCtx::new(PathBuf::new(), Config::default()), + ); let (rest, _parsed) = parse_assign(input).finish().unwrap(); @@ -783,7 +837,10 @@ mod parse_struct_decl { #[test] fn valid_struct_decl() { - let input = Parser::new_extra("struct Foo", ParserCtx::new(PathBuf::new())); + let input = Parser::new_extra( + "struct Foo", + ParserCtx::new(PathBuf::new(), Config::default()), + ); let (rest, _parsed) = parse_struct_decl(input).finish().unwrap(); @@ -794,7 +851,7 @@ mod parse_struct_decl { fn valid_struct_decl_with_fields() { let input = Parser::new_extra( "struct Foo\n a :: Int64\n b :: Float64", - ParserCtx::new(PathBuf::new()), + ParserCtx::new(PathBuf::new(), Config::default()), ); let (rest, _parsed) = parse_struct_decl(input).finish().unwrap(); @@ -809,7 +866,7 @@ mod parse_struct_ctor { #[test] fn valid_struct_ctor() { - let input = Parser::new_extra("Foo\n", ParserCtx::new(PathBuf::new())); + let input = Parser::new_extra("Foo\n", ParserCtx::new(PathBuf::new(), Config::default())); let (rest, _parsed) = parse_struct_ctor(input).finish().unwrap(); @@ -818,7 +875,10 @@ mod parse_struct_ctor { #[test] fn valid_struct_ctor_with_fields() { - let input = Parser::new_extra("Foo\n a: 2\n b: 3.0", ParserCtx::new(PathBuf::new())); + let input = Parser::new_extra( + "Foo\n a: 2\n b: 3.0", + ParserCtx::new(PathBuf::new(), Config::default()), + ); let (rest, _parsed) = parse_struct_ctor(input).finish().unwrap(); @@ -834,7 +894,7 @@ mod parse_trait { fn valid_trait() { let input = Parser::new_extra( "trait Foo\n a :: Int64 -> Int64\n b :: Float64 -> String", - ParserCtx::new(PathBuf::new()), + ParserCtx::new(PathBuf::new(), Config::default()), ); let (rest, _parsed) = parse_trait(input).finish().unwrap(); @@ -851,7 +911,7 @@ mod parse_impl { fn valid_impl() { let input = Parser::new_extra( "impl Foo\n a =\n 2\n b a =\n a", - ParserCtx::new(PathBuf::new()), + ParserCtx::new(PathBuf::new(), Config::default()), ); let (rest, _parsed) = parse_impl(input).finish().unwrap(); @@ -866,7 +926,10 @@ mod parse_native_operator { #[test] fn valid_native_operator() { - let input = Parser::new_extra("~IAdd a b", ParserCtx::new(PathBuf::new())); + let input = Parser::new_extra( + "~IAdd a b", + ParserCtx::new(PathBuf::new(), Config::default()), + ); let (_rest, (parsed, _, _)) = parse_native_operator(input).finish().unwrap(); @@ -880,7 +943,10 @@ mod parse_array { #[test] fn valid_array() { - let input = Parser::new_extra("[1, 2, 3]", ParserCtx::new(PathBuf::new())); + let input = Parser::new_extra( + "[1, 2, 3]", + ParserCtx::new(PathBuf::new(), Config::default()), + ); let (rest, _parsed) = parse_array(input).finish().unwrap(); @@ -894,7 +960,7 @@ mod parse_string { #[test] fn valid_string() { - let input = Parser::new_extra("\"foo\"", ParserCtx::new(PathBuf::new())); + let input = Parser::new_extra("\"foo\"", ParserCtx::new(PathBuf::new(), Config::default())); let (rest, _parsed) = parse_string(input).finish().unwrap(); diff --git a/src/lib/resolver/resolve_ctx.rs b/src/lib/resolver/resolve_ctx.rs index 550a2792..140df1dc 100644 --- a/src/lib/resolver/resolve_ctx.rs +++ b/src/lib/resolver/resolve_ctx.rs @@ -194,7 +194,11 @@ impl<'a> Visitor<'a> for ResolveCtx<'a> { panic!("Unimplemented"); } - let mut mod_path = r#use.path.parent().prepend_mod(self.cur_scope.clone()); + let mut mod_path = if r#use.path.has_root() { + r#use.path.parent() + } else { + r#use.path.parent().prepend_mod(self.cur_scope.clone()) + }; mod_path.resolve_supers(); @@ -203,7 +207,7 @@ impl<'a> Visitor<'a> for ResolveCtx<'a> { if ident.name == "(*)" { let scope = scopes.scopes.get(0).unwrap(); - for (k, v) in &scope.items.clone() { + for (k, v) in &scope.clone() { self.add_to_current_scope(k.clone(), v.clone()); } } else { diff --git a/src/lib/rock.rs b/src/lib/rock.rs index 49da7bce..e5d84b36 100644 --- a/src/lib/rock.rs +++ b/src/lib/rock.rs @@ -41,6 +41,10 @@ use parser::{ParsingCtx, SourceFile}; pub fn compile_file(in_name: String, config: &Config) -> Result<(), Diagnostic> { let mut source_file = SourceFile::from_file(in_name)?; + if config.std { + source_file.content = "mod std\nuse std::prelude::(*)\n".to_owned() + &source_file.content; + } + source_file.mod_path = PathBuf::from("root"); compile_str(&source_file, config) @@ -91,81 +95,3 @@ pub fn generate_ir(hir: hir::Root, config: &Config) -> Result<(), Diagnostic> { Ok(()) } - -mod test { - use super::*; - use crate::{parser::SourceFile, Config}; - use std::{ - fs, - path::{Path, PathBuf}, - process::Command, - }; - - fn build(input: String, config: Config) -> bool { - let file = SourceFile { - file_path: PathBuf::from("src/lib").join(&config.project_config.entry_point), - mod_path: PathBuf::from("main"), - content: input, - }; - - if let Err(_e) = compile_str(&file, &config) { - return false; - } - - let clang_cmd = Command::new("clang") - .args(&[ - config.build_folder.join("out.bc").to_str().unwrap(), - "-o", - config.build_folder.join("a.out").to_str().unwrap(), - ]) - .output() - .expect("failed to compile to ir"); - - match clang_cmd.status.code() { - Some(code) => { - if code != 0 { - println!( - "BUG: Cannot compile: \n{}", - String::from_utf8(clang_cmd.stderr).unwrap() - ); - - return false; - } - } - None => println!( - "\nError running: \n{}", - String::from_utf8(clang_cmd.stderr).unwrap() - ), - } - - true - } - - pub fn run(path: &str, input: String, config: Config) -> (i64, String) { - let path = Path::new("src/lib/").join(path); - - let build_path = path.parent().unwrap().join("build"); - - let mut config = config; - config.build_folder = build_path; - - fs::create_dir_all(config.build_folder.clone()).unwrap(); - - if !build(input, config.clone()) { - return (-1, String::new()); - } - - let cmd = Command::new(config.build_folder.join("a.out").to_str().unwrap()) - .output() - .expect("failed to execute BINARY"); - - let stdout = String::from_utf8(cmd.stderr).unwrap(); - - fs::remove_dir_all(config.build_folder).unwrap(); - - match cmd.status.code() { - Some(code) => (code.into(), stdout), - None => (-1, stdout), - } - } -} diff --git a/src/lib/tests.rs b/src/lib/tests.rs index e581e18d..33e5afc8 100644 --- a/src/lib/tests.rs +++ b/src/lib/tests.rs @@ -8,7 +8,7 @@ use std::path::PathBuf; let expected_ret = expected_ret.parse::().unwrap(); - let (ret_code, stdout) = super::test::run(path, input.to_string(), config); + let (ret_code, stdout) = super::helpers::test_utils::run(path, input.to_string(), config); assert_eq!(expected_ret, ret_code); assert_eq!(expected_output, stdout); diff --git a/std/src/eq.rk b/std/src/eq.rk index 097cd64f..48b79eb9 100644 --- a/std/src/eq.rk +++ b/std/src/eq.rk @@ -31,3 +31,9 @@ impl Eq Bool >= i j = ~BEq i j < i j = ~BEq i j > i j = ~BEq i j + +use super::externs::(*) + +impl Eq String + == k l = c_strcmp k, l == 0 + diff --git a/std/src/externs.rk b/std/src/externs.rk index 08832bbe..318ca397 100644 --- a/std/src/externs.rk +++ b/std/src/externs.rk @@ -10,9 +10,15 @@ c_strcat dest src = strcat dest, src extern strcpy :: String -> String -> String c_strcpy dest src = strcpy dest, src +#extern strncpy :: String -> String -> Int64 -> String +#c_strncpy dest src len = strncpy dest, src, len + extern sprintf :: String -> String -> Int64 -> Int64 c_sprintf dest format i = sprintf dest, format, i +extern strcmp :: String -> String -> Int64 +c_strcmp src dest = strcmp src, dest + extern gcvt :: Float64 -> Int64 -> String -> String -> String c_gcvt float digits unused1 unused2 = gcvt float, digits, unused1, unused2 @@ -35,3 +41,6 @@ c_strtol octal_str unused base = strtol octal_str, unused, base extern read :: Int64 -> String -> Int64 -> Int64 c_read fd buf len = read fd, buf, len + +extern write :: Int64 -> String -> Int64 -> Int64 +c_write fd buf len = write fd, buf, len diff --git a/std/src/prelude.rk b/std/src/prelude.rk index 9135268e..29b57598 100644 --- a/std/src/prelude.rk +++ b/std/src/prelude.rk @@ -1,6 +1,7 @@ use super::show::show -use super::print::print +use super::print::(*) use super::num::(*) use super::eq::(*) use super::functor::(*) use super::clone::(*) +use super::externs::(*) diff --git a/std/src/print.rk b/std/src/print.rk index 785eac65..67f16930 100644 --- a/std/src/print.rk +++ b/std/src/print.rk @@ -1,8 +1,16 @@ use super::externs::(*) use super::show::show +use super::eq::(*) +use super::num::(*) + print a = c_puts show a +printl a = c_write 1, a, c_strlen a + _shut_up_warnings = print 0 + printl 0 _shut_up_warnings() + + diff --git a/std/src/show.rk b/std/src/show.rk index 740fe3ee..5f4a22c3 100644 --- a/std/src/show.rk +++ b/std/src/show.rk @@ -4,9 +4,7 @@ use super::eq::(*) itoa a = let s = c_malloc 10 - c_sprintf s, "%d", a - s ftoa c = @@ -30,29 +28,19 @@ impl Show Bool impl Show String show c = let s = c_malloc c_strlen c - c_strcpy s, c - s - show_arr a = let s = c_malloc 100 - c_strcpy s, "[" - let i = 0 - let len = ~Len a a - while i < len c_strcat s, show a[i] c_strcat s, ", " - i = i + 1 - c_strcat s, "]" - s impl Show [Int64] diff --git a/std/src/vec.rk b/std/src/vec.rk index 4157e4a9..3a04f2e0 100644 --- a/std/src/vec.rk +++ b/std/src/vec.rk @@ -15,27 +15,20 @@ new_vec = cap: 1 len: 0 - use super::num::(*) use super::eq::(*) realloc_vec v = let orig_data = v.data - v.cap = v.cap * 2 - v.data = c_malloc (v.cap * 4) - c_memcpy v.data, orig_data - 0 push_vec v item = let d = v.data d[v.len] = item - v.len = v.len + 1 - if v.len == v.cap then realloc_vec v else 0 @@ -46,3 +39,4 @@ _shut_up_warnings = push_vec 0, 0 realloc_vec 0 _shut_up_warnings() +