Browse Source

feat: add module builder

modules
Garrit Franke 3 years ago
parent
commit
71a4057f04
  1. 73
      src/builder/mod.rs
  2. 24
      src/command/build.rs
  3. 2
      src/generator/x86.rs
  4. 2
      src/main.rs
  5. 4
      src/parser/mod.rs
  6. 4
      src/parser/node_type.rs
  7. 4
      src/parser/parser.rs
  8. 5
      src/parser/rules.rs
  9. 106
      src/parser/tests.rs
  10. 20
      src/table/mod.rs

73
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<Module>,
}
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<Module, String> {
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"))
}
}

24
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")
}

2
src/generator/x86.rs

@ -61,6 +61,8 @@ impl X86Generator {
func,
globals,
structs: _,
path,
imports,
} = prog;
asm.add(".intel_syntax noprefix");

2
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;

4
src/parser/mod.rs

@ -24,7 +24,7 @@ use node_type::Module;
#[cfg(test)]
mod tests;
pub fn parse(tokens: Vec<Token>, raw: Option<String>) -> Result<Module, String> {
let mut parser = parser::Parser::new(tokens, raw);
pub fn parse(tokens: Vec<Token>, raw: Option<String>, path: String) -> Result<Module, String> {
let mut parser = parser::Parser::new(tokens, raw, path);
parser.parse()
}

4
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<String, Option<Type>>;
#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct Module {
pub path: String,
pub imports: Vec<String>,
pub func: Vec<Function>,
pub structs: Vec<StructDef>,
pub globals: Vec<String>,

4
src/parser/parser.rs

@ -24,6 +24,7 @@ use std::iter::Peekable;
use std::vec::IntoIter;
pub struct Parser {
pub path: String,
tokens: Peekable<IntoIter<Token>>,
peeked: Vec<Token>,
current: Option<Token>,
@ -32,12 +33,13 @@ pub struct Parser {
}
impl Parser {
pub fn new(tokens: Vec<Token>, raw: Option<String>) -> Parser {
pub fn new(tokens: Vec<Token>, raw: Option<String>, file_name: String) -> Parser {
let tokens_without_whitespace: Vec<Token> = 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,

5
src/parser/rules.rs

@ -25,6 +25,7 @@ impl Parser {
pub fn parse_module(&mut self) -> Result<Module, String> {
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
})
}

106
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());
}

20
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<Type>,
functions: HashMap<String, Function>,
modules: Vec<String>,
}
impl Table {
pub(crate) fn new() -> Self {
Self {
types: Vec::new(),
functions: HashMap::new(),
modules: Vec::new()
}
}
}
Loading…
Cancel
Save