diff --git a/src/builder/mod.rs b/src/builder/mod.rs new file mode 100644 index 0000000..c2a22ad --- /dev/null +++ b/src/builder/mod.rs @@ -0,0 +1,73 @@ +use crate::generator; +use crate::lexer; +use crate::parser; +use std::io::Write; +use crate::PathBuf; +use parser::node_type::Module; +/** + * Copyright 2021 Garrit Franke + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +use std::fs::File; +use std::io::Read; + +pub struct Builder { + in_file: PathBuf, + modules: Vec, +} + +impl Builder { + pub fn new(entrypoint: PathBuf) -> Self { + Self { + in_file: entrypoint, + modules: Vec::new(), + } + } + + pub fn build(&mut self) -> Result<(), String> { + self.build_module(self.in_file.clone())?; + + Ok(()) + } + + fn build_module(&mut self, file_path: PathBuf) -> Result { + let mut file = File::open(&file_path) + .map_err(|_| format!("Could not open file: {}", file_path.display()))?; + let mut contents = String::new(); + + file.read_to_string(&mut contents) + .expect("Could not read file"); + let tokens = lexer::tokenize(&contents); + let module = parser::parse(tokens, Some(contents), file_path.display().to_string())?; + for import in &module.imports { + self.build_module(PathBuf::from(import))?; + } + self.modules.push(module.clone()); + Ok(module) + } + + pub(crate) fn generate(&mut self, out_file: PathBuf) -> Result<(), String> { + let mut mod_iter = self.modules.iter(); + + // TODO: We shouldn't clone here + let mut condensed = mod_iter.next().ok_or("No module specified")?.clone(); + while let Some(module) = mod_iter.next() { + condensed.merge_with(module.clone()); + }; + let output = generator::generate(condensed); + let mut file = std::fs::File::create(out_file).expect("create failed"); + file.write_all(output.as_bytes()).expect("write failed"); + Ok(file.flush().expect("Could not flush file")) + } +} diff --git a/src/command/build.rs b/src/command/build.rs index d54d6d1..85b41e6 100644 --- a/src/command/build.rs +++ b/src/command/build.rs @@ -15,32 +15,18 @@ */ use crate::generator; use crate::lexer; +use crate::builder; use crate::parser; use crate::Lib; -use std::fs::File; -use std::io::Read; use std::io::Write; use std::path::Path; pub fn build(in_file: &Path, out_file: &Path) -> Result<(), String> { - let mut file = File::open(in_file).expect("Could not open file"); - let mut contents = String::new(); + let mut b = builder::Builder::new(in_file.to_path_buf()); + b.build(); - file.read_to_string(&mut contents) - .expect("Could not read file"); - let tokens = lexer::tokenize(&contents); - let mut program = parser::parse(tokens, Some(contents))?; + b.generate(out_file.to_path_buf())?; - // C Backend currently does not support stdlib yet, since not all features are implemented - if cfg!(feature = "backend_node") { - let stdlib = build_stdlib(); - program.merge_with(stdlib); - } - - let output = generator::generate(program); - let mut file = std::fs::File::create(out_file).expect("create failed"); - file.write_all(output.as_bytes()).expect("write failed"); - file.flush().expect("Could not flush file"); Ok(()) } @@ -52,5 +38,5 @@ fn build_stdlib() -> parser::node_type::Module { std::str::from_utf8(&stdlib_raw).expect("Could not interpret standard library."); let stdlib_tokens = lexer::tokenize(&stblib_str); - parser::parse(stdlib_tokens, Some(stblib_str.into())).expect("Could not parse stdlib") + parser::parse(stdlib_tokens, Some(stblib_str.into()), "stdio".to_string()).expect("Could not parse stdlib") } diff --git a/src/generator/x86.rs b/src/generator/x86.rs index 89d7e7f..6805456 100644 --- a/src/generator/x86.rs +++ b/src/generator/x86.rs @@ -61,6 +61,8 @@ impl X86Generator { func, globals, structs: _, + path, + imports, } = prog; asm.add(".intel_syntax noprefix"); diff --git a/src/main.rs b/src/main.rs index 13570db..b9d5f78 100644 --- a/src/main.rs +++ b/src/main.rs @@ -22,10 +22,12 @@ extern crate tempfile; use std::path::PathBuf; use structopt::StructOpt; +mod builder; mod command; mod generator; mod lexer; mod parser; +mod table; #[cfg(test)] mod tests; mod util; diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 812411d..99113c9 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -24,7 +24,7 @@ use node_type::Module; #[cfg(test)] mod tests; -pub fn parse(tokens: Vec, raw: Option) -> Result { - let mut parser = parser::Parser::new(tokens, raw); +pub fn parse(tokens: Vec, raw: Option, path: String) -> Result { + let mut parser = parser::Parser::new(tokens, raw, path); parser.parse() } diff --git a/src/parser/node_type.rs b/src/parser/node_type.rs index 8f0a2c0..82d78f1 100644 --- a/src/parser/node_type.rs +++ b/src/parser/node_type.rs @@ -20,8 +20,10 @@ use std::collections::HashMap; /// Table that contains all symbol and its types pub type SymbolTable = HashMap>; -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct Module { + pub path: String, + pub imports: Vec, pub func: Vec, pub structs: Vec, pub globals: Vec, diff --git a/src/parser/parser.rs b/src/parser/parser.rs index 622652b..5467181 100644 --- a/src/parser/parser.rs +++ b/src/parser/parser.rs @@ -24,6 +24,7 @@ use std::iter::Peekable; use std::vec::IntoIter; pub struct Parser { + pub path: String, tokens: Peekable>, peeked: Vec, current: Option, @@ -32,12 +33,13 @@ pub struct Parser { } impl Parser { - pub fn new(tokens: Vec, raw: Option) -> Parser { + pub fn new(tokens: Vec, raw: Option, file_name: String) -> Parser { let tokens_without_whitespace: Vec = tokens .into_iter() .filter(|token| token.kind != TokenKind::Whitespace && token.kind != TokenKind::Comment) .collect(); Parser { + path: file_name, tokens: tokens_without_whitespace.into_iter().peekable(), peeked: vec![], current: None, diff --git a/src/parser/rules.rs b/src/parser/rules.rs index 6f94192..8e19328 100644 --- a/src/parser/rules.rs +++ b/src/parser/rules.rs @@ -25,6 +25,7 @@ impl Parser { pub fn parse_module(&mut self) -> Result { let mut functions = Vec::new(); let mut structs = Vec::new(); + let imports = Vec::new(); let globals = Vec::new(); while self.has_more() { @@ -38,10 +39,14 @@ impl Parser { } } + // TODO: Populate imports + Ok(Module { func: functions, structs, globals, + path: self.path.clone(), + imports }) } diff --git a/src/parser/tests.rs b/src/parser/tests.rs index 614639c..e0291a9 100644 --- a/src/parser/tests.rs +++ b/src/parser/tests.rs @@ -21,7 +21,7 @@ use crate::parser::parse; fn test_parse_empty_function() { let raw = "fn main() {}"; let tokens = tokenize(raw); - let tree = parse(tokens, Some(raw.to_string())); + let tree = parse(tokens, Some(raw.to_string()), "".into()); assert!(tree.is_ok()) } @@ -33,7 +33,7 @@ fn test_parse_function_with_return() { } "; let tokens = tokenize(raw); - let tree = parse(tokens, Some(raw.to_string())); + let tree = parse(tokens, Some(raw.to_string()), "".into()); assert!(tree.is_ok()) } @@ -45,7 +45,7 @@ fn test_parse_redundant_semicolon() { } "; let tokens = tokenize(raw); - let tree = parse(tokens, Some(raw.to_string())); + let tree = parse(tokens, Some(raw.to_string()), "".into()); assert!(tree.is_err()) } @@ -55,7 +55,7 @@ fn test_parse_no_function_context() { let x = 1 "; let tokens = tokenize(raw); - let tree = parse(tokens, Some(raw.to_string())); + let tree = parse(tokens, Some(raw.to_string()), "".into()); assert!(tree.is_err()) } @@ -73,7 +73,7 @@ fn test_parse_multiple_functions() { } "; let tokens = tokenize(raw); - let tree = parse(tokens, Some(raw.to_string())); + let tree = parse(tokens, Some(raw.to_string()), "".into()); assert!(tree.is_ok()) } @@ -86,7 +86,7 @@ fn test_parse_variable_declaration() { } "; let tokens = tokenize(raw); - let tree = parse(tokens, Some(raw.to_string())); + let tree = parse(tokens, Some(raw.to_string()), "".into()); assert!(tree.is_ok()) } @@ -100,7 +100,7 @@ fn test_parse_variable_reassignment() { } "; let tokens = tokenize(raw); - let tree = parse(tokens, Some(raw.to_string())); + let tree = parse(tokens, Some(raw.to_string()), "".into()); assert!(tree.is_ok()) } @@ -114,7 +114,7 @@ fn test_parse_variable_declaration_added() { } "; let tokens = tokenize(raw); - let tree = parse(tokens, Some(raw.to_string())); + let tree = parse(tokens, Some(raw.to_string()), "".into()); assert!(tree.is_ok()) } @@ -126,7 +126,7 @@ fn test_parse_function_with_args() { } "; let tokens = tokenize(raw); - let tree = parse(tokens, Some(raw.to_string())); + let tree = parse(tokens, Some(raw.to_string()), "".into()); assert!(tree.is_ok()) } @@ -142,7 +142,7 @@ fn test_parse_function_call() { } "; let tokens = tokenize(raw); - let tree = parse(tokens, Some(raw.to_string())); + let tree = parse(tokens, Some(raw.to_string()), "".into()); assert!(tree.is_ok()) } @@ -158,7 +158,7 @@ fn test_parse_return_function_call() { } "; let tokens = tokenize(raw); - let tree = parse(tokens, Some(raw.to_string())); + let tree = parse(tokens, Some(raw.to_string()), "".into()); assert!(tree.is_ok()) } @@ -174,7 +174,7 @@ fn test_parse_function_call_multiple_arguments() { } "; let tokens = tokenize(raw); - let tree = parse(tokens, Some(raw.to_string())); + let tree = parse(tokens, Some(raw.to_string()), "".into()); assert!(tree.is_ok()) } @@ -190,7 +190,7 @@ fn test_parse_nexted_function_call() { } "; let tokens = tokenize(raw); - let tree = parse(tokens, Some(raw.to_string())); + let tree = parse(tokens, Some(raw.to_string()), "".into()); assert!(tree.is_ok()) } @@ -202,7 +202,7 @@ fn test_parse_basic_ops() { } "; let tokens = tokenize(raw); - let tree = parse(tokens, Some(raw.to_string())); + let tree = parse(tokens, Some(raw.to_string()), "".into()); assert!(tree.is_ok()) } @@ -214,7 +214,7 @@ fn test_parse_compound_ops() { } "; let tokens = tokenize(raw); - let tree = parse(tokens, Some(raw.to_string())); + let tree = parse(tokens, Some(raw.to_string()), "".into()); assert!(tree.is_ok()) } @@ -226,7 +226,7 @@ fn test_parse_compound_ops_with_function_call() { } "; let tokens = tokenize(raw); - let tree = parse(tokens, Some(raw.to_string())); + let tree = parse(tokens, Some(raw.to_string()), "".into()); assert!(tree.is_ok()) } @@ -238,7 +238,7 @@ fn test_parse_compound_ops_with_strings() { } "; let tokens = tokenize(raw); - let tree = parse(tokens, Some(raw.to_string())); + let tree = parse(tokens, Some(raw.to_string()), "".into()); assert!(tree.is_ok()) } @@ -250,7 +250,7 @@ fn test_parse_compound_ops_with_identifier() { } "; let tokens = tokenize(raw); - let tree = parse(tokens, Some(raw.to_string())); + let tree = parse(tokens, Some(raw.to_string()), "".into()); assert!(tree.is_ok()) } @@ -262,7 +262,7 @@ fn test_parse_compound_ops_with_identifier_first() { } "; let tokens = tokenize(raw); - let tree = parse(tokens, Some(raw.to_string())); + let tree = parse(tokens, Some(raw.to_string()), "".into()); assert!(tree.is_ok()) } @@ -274,7 +274,7 @@ fn test_parse_compound_ops_return() { } "; let tokens = tokenize(raw); - let tree = parse(tokens, Some(raw.to_string())); + let tree = parse(tokens, Some(raw.to_string()), "".into()); assert!(tree.is_ok()) } @@ -288,7 +288,7 @@ fn test_parse_basic_conditional() { } "; let tokens = tokenize(raw); - let tree = parse(tokens, Some(raw.to_string())); + let tree = parse(tokens, Some(raw.to_string()), "".into()); assert!(tree.is_ok()) } @@ -303,7 +303,7 @@ fn test_parse_basic_conditional_with_multiple_statements() { } "; let tokens = tokenize(raw); - let tree = parse(tokens, Some(raw.to_string())); + let tree = parse(tokens, Some(raw.to_string()), "".into()); assert!(tree.is_ok()) } @@ -320,7 +320,7 @@ fn test_parse_conditional_else_if_branch() { } "; let tokens = tokenize(raw); - let tree = parse(tokens, Some(raw.to_string())); + let tree = parse(tokens, Some(raw.to_string()), "".into()); assert!(tree.is_ok()) } @@ -339,7 +339,7 @@ fn test_parse_conditional_multiple_else_if_branch_branches() { } "; let tokens = tokenize(raw); - let tree = parse(tokens, Some(raw.to_string())); + let tree = parse(tokens, Some(raw.to_string()), "".into()); assert!(tree.is_ok()) } @@ -356,7 +356,7 @@ fn test_parse_conditional_else_branch() { } "; let tokens = tokenize(raw); - let tree = parse(tokens, Some(raw.to_string())); + let tree = parse(tokens, Some(raw.to_string()), "".into()); assert!(tree.is_ok()) } @@ -377,7 +377,7 @@ fn test_parse_conditional_elseif_else_branch() { } "; let tokens = tokenize(raw); - let tree = parse(tokens, Some(raw.to_string())); + let tree = parse(tokens, Some(raw.to_string()), "".into()); assert!(tree.is_ok()) } @@ -390,7 +390,7 @@ fn test_int_array() { } "; let tokens = tokenize(raw); - let tree = parse(tokens, Some(raw.to_string())); + let tree = parse(tokens, Some(raw.to_string()), "".into()); assert!(tree.is_ok()) } @@ -402,7 +402,7 @@ fn test_string_array() { } "; let tokens = tokenize(raw); - let tree = parse(tokens, Some(raw.to_string())); + let tree = parse(tokens, Some(raw.to_string()), "".into()); assert!(tree.is_ok()) } @@ -417,7 +417,7 @@ fn test_basic_while_loop() { } "; let tokens = tokenize(raw); - let tree = parse(tokens, Some(raw.to_string())); + let tree = parse(tokens, Some(raw.to_string()), "".into()); assert!(tree.is_ok()) } @@ -432,7 +432,7 @@ fn test_while_loop_boolean_expression() { } "; let tokens = tokenize(raw); - let tree = parse(tokens, Some(raw.to_string())); + let tree = parse(tokens, Some(raw.to_string()), "".into()); assert!(tree.is_ok()) } @@ -449,7 +449,7 @@ fn test_boolean_arithmetic() { } "; let tokens = tokenize(raw); - let tree = parse(tokens, Some(raw.to_string())); + let tree = parse(tokens, Some(raw.to_string()), "".into()); assert!(tree.is_ok()) } @@ -468,7 +468,7 @@ fn test_array_access_in_loop() { } "; let tokens = tokenize(raw); - let tree = parse(tokens, Some(raw.to_string())); + let tree = parse(tokens, Some(raw.to_string()), "".into()); assert!(tree.is_ok()) } @@ -482,7 +482,7 @@ fn test_array_access_standalone() { } "; let tokens = tokenize(raw); - let tree = parse(tokens, Some(raw.to_string())); + let tree = parse(tokens, Some(raw.to_string()), "".into()); assert!(tree.is_ok()) } @@ -497,7 +497,7 @@ fn test_array_access_assignment() { } "; let tokens = tokenize(raw); - let tree = parse(tokens, Some(raw.to_string())); + let tree = parse(tokens, Some(raw.to_string()), "".into()); assert!(tree.is_ok()) } @@ -513,7 +513,7 @@ fn test_array_access_in_if() { } "; let tokens = tokenize(raw); - let tree = parse(tokens, Some(raw.to_string())); + let tree = parse(tokens, Some(raw.to_string()), "".into()); assert!(tree.is_ok()) } @@ -526,7 +526,7 @@ fn test_uninitialized_variables() { } "; let tokens = tokenize(raw); - let tree = parse(tokens, Some(raw.to_string())); + let tree = parse(tokens, Some(raw.to_string()), "".into()); assert!(tree.is_ok()) } @@ -538,7 +538,7 @@ fn test_function_call_math() { } "; let tokens = tokenize(raw); - let tree = parse(tokens, Some(raw.to_string())); + let tree = parse(tokens, Some(raw.to_string()), "".into()); assert!(tree.is_ok()) } @@ -550,7 +550,7 @@ fn test_function_multiple_args() { } "; let tokens = tokenize(raw); - let tree = parse(tokens, Some(raw.to_string())); + let tree = parse(tokens, Some(raw.to_string()), "".into()); assert!(tree.is_ok()) } @@ -562,7 +562,7 @@ fn test_array_position_assignment() { } "; let tokens = tokenize(raw); - let tree = parse(tokens, Some(raw.to_string())); + let tree = parse(tokens, Some(raw.to_string()), "".into()); assert!(tree.is_ok()) } @@ -576,7 +576,7 @@ fn test_typed_declare() { } "; let tokens = tokenize(raw); - let tree = parse(tokens, Some(raw.to_string())); + let tree = parse(tokens, Some(raw.to_string()), "".into()); assert!(tree.is_ok()) } @@ -588,7 +588,7 @@ fn test_no_function_args_without_type() { } "; let tokens = tokenize(raw); - let tree = parse(tokens, Some(raw.to_string())); + let tree = parse(tokens, Some(raw.to_string()), "".into()); assert!(tree.is_err()) } @@ -600,7 +600,7 @@ fn test_function_with_return_type() { } "; let tokens = tokenize(raw); - let tree = parse(tokens, Some(raw.to_string())); + let tree = parse(tokens, Some(raw.to_string()), "".into()); assert!(tree.is_ok()); assert_eq!(tree.unwrap().func[0].ret_type, Some(Type::Int)); } @@ -617,7 +617,7 @@ fn test_booleans_in_function_call() { } "; let tokens = tokenize(raw); - let tree = parse(tokens, Some(raw.to_string())); + let tree = parse(tokens, Some(raw.to_string()), "".into()); assert!(tree.is_ok()); } @@ -637,7 +637,7 @@ fn test_late_initializing_variable() { } "; let tokens = tokenize(raw); - let tree = parse(tokens, Some(raw.to_string())); + let tree = parse(tokens, Some(raw.to_string()), "".into()); assert!(tree.is_ok()); } @@ -653,7 +653,7 @@ fn test_simple_for_loop() { } "; let tokens = tokenize(raw); - let tree = parse(tokens, Some(raw.to_string())); + let tree = parse(tokens, Some(raw.to_string()), "".into()); assert!(tree.is_ok()); } @@ -671,7 +671,7 @@ fn test_nested_for_loop() { } "; let tokens = tokenize(raw); - let tree = parse(tokens, Some(raw.to_string())); + let tree = parse(tokens, Some(raw.to_string()), "".into()); assert!(tree.is_ok()); } @@ -689,7 +689,7 @@ fn test_nested_array() { } "; let tokens = tokenize(raw); - let tree = parse(tokens, Some(raw.to_string())); + let tree = parse(tokens, Some(raw.to_string()), "".into()); assert!(tree.is_ok()); } @@ -702,7 +702,7 @@ fn test_simple_nested_expression() { } "; let tokens = tokenize(raw); - let tree = parse(tokens, Some(raw.to_string())); + let tree = parse(tokens, Some(raw.to_string()), "".into()); assert!(tree.is_ok()); } @@ -722,7 +722,7 @@ fn test_continue() { } "; let tokens = tokenize(raw); - let tree = parse(tokens, Some(raw.to_string())); + let tree = parse(tokens, Some(raw.to_string()), "".into()); assert!(tree.is_ok()); } @@ -742,7 +742,7 @@ fn test_break() { } "; let tokens = tokenize(raw); - let tree = parse(tokens, Some(raw.to_string())); + let tree = parse(tokens, Some(raw.to_string()), "".into()); assert!(tree.is_ok()); } @@ -761,7 +761,7 @@ fn test_complex_nested_expressions() { } "; let tokens = tokenize(raw); - let tree = parse(tokens, Some(raw.to_string())); + let tree = parse(tokens, Some(raw.to_string()), "".into()); assert!(tree.is_ok()); } @@ -773,7 +773,7 @@ fn test_array_as_argument() { } "; let tokens = tokenize(raw); - let tree = parse(tokens, Some(raw.to_string())); + let tree = parse(tokens, Some(raw.to_string()), "".into()); assert!(tree.is_ok()); } @@ -795,6 +795,6 @@ fn test_struct_initialization() { } "; let tokens = tokenize(raw); - let tree = parse(tokens, Some(raw.to_string())); + let tree = parse(tokens, Some(raw.to_string()), "".into()); assert!(tree.is_ok()); } diff --git a/src/table/mod.rs b/src/table/mod.rs new file mode 100644 index 0000000..e12df63 --- /dev/null +++ b/src/table/mod.rs @@ -0,0 +1,20 @@ +use std::collections::HashMap; +use crate::parser::node_type::Function; +use crate::parser::node_type::Type; + +pub struct Table { + types: Vec, + functions: HashMap, + modules: Vec, +} + +impl Table { + pub(crate) fn new() -> Self { + Self { + types: Vec::new(), + functions: HashMap::new(), + modules: Vec::new() + } + } +} +