diff --git a/Cargo.lock b/Cargo.lock index 1d50ff1a..bf8427d5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -503,6 +503,7 @@ version = "0.1.0" dependencies = [ "inkwell", "nac3core", + "parking_lot", "rustpython-parser", ] diff --git a/nac3standalone/Cargo.toml b/nac3standalone/Cargo.toml index 600ee138..5ca0a86c 100644 --- a/nac3standalone/Cargo.toml +++ b/nac3standalone/Cargo.toml @@ -5,6 +5,7 @@ authors = ["M-Labs"] edition = "2018" [dependencies] -inkwell = { git = "https://github.com/TheDan64/inkwell", branch = "master", features = ["llvm10-0"] } +inkwell = { git = "https://github.com/TheDan64/inkwell", branch = "master", features = ["llvm11-0"] } rustpython-parser = { git = "https://github.com/RustPython/RustPython", branch = "master" } +parking_lot = "0.11.1" nac3core = { path = "../nac3core" } diff --git a/nac3standalone/mandelbrot.py b/nac3standalone/mandelbrot.py index 63fee33b..6c8de275 100644 --- a/nac3standalone/mandelbrot.py +++ b/nac3standalone/mandelbrot.py @@ -1,18 +1,18 @@ def run() -> int32: minX = -2.0 maxX = 1.0 - width = 78 - height = 36 + width = 78.0 + height = 36.0 aspectRatio = 2.0 - yScale = float64(maxX-minX)*(float64(height)/float64(width))*aspectRatio + yScale = (maxX-minX)*(height/width)*aspectRatio - y = 0 + y = 0.0 while y < height: - x = 0 + x = 0.0 while x < width: - c_r = minX+float64(x)*(maxX-minX)/float64(width) - c_i = float64(y)*yScale/float64(height)-yScale/2.0 + c_r = minX+x*(maxX-minX)/width + c_i = y*yScale/height-yScale/2.0 z_r = c_r z_i = c_i i = 0 @@ -24,7 +24,8 @@ def run() -> int32: z_r = new_z_r i = i + 1 output(i) - x = x + 1 + x = x + 1.0 output(-1) - y = y + 1 + y = y + 1.0 return 0 + diff --git a/nac3standalone/src/basic_symbol_resolver.rs b/nac3standalone/src/basic_symbol_resolver.rs new file mode 100644 index 00000000..8e36afe7 --- /dev/null +++ b/nac3standalone/src/basic_symbol_resolver.rs @@ -0,0 +1,35 @@ +use nac3core::{ + location::Location, + symbol_resolver::{SymbolResolver, SymbolValue}, + top_level::DefinitionId, + typecheck::{ + type_inferencer::PrimitiveStore, + typedef::{Type, Unifier}, + }, +}; +use std::collections::HashMap; + +#[derive(Clone)] +pub struct Resolver { + pub id_to_type: HashMap<String, Type>, + pub id_to_def: HashMap<String, DefinitionId>, + pub class_names: HashMap<String, Type>, +} + +impl SymbolResolver for Resolver { + fn get_symbol_type(&self, _: &mut Unifier, _: &PrimitiveStore, str: &str) -> Option<Type> { + self.id_to_type.get(str).cloned() + } + + fn get_symbol_value(&self, _: &str) -> Option<SymbolValue> { + unimplemented!() + } + + fn get_symbol_location(&self, _: &str) -> Option<Location> { + unimplemented!() + } + + fn get_identifier_def(&self, id: &str) -> Option<DefinitionId> { + self.id_to_def.get(id).cloned() + } +} diff --git a/nac3standalone/src/main.rs b/nac3standalone/src/main.rs index f42a4f32..464d4cf1 100644 --- a/nac3standalone/src/main.rs +++ b/nac3standalone/src/main.rs @@ -1,30 +1,162 @@ use std::fs; -use inkwell::context::Context; -use inkwell::targets::*; -use rustpython_parser::parser; +use inkwell::{targets::*, OptimizationLevel}; +use parking_lot::RwLock; +use rustpython_parser::{ + ast::{fold::Fold, StmtKind}, + parser, +}; +use std::{cell::RefCell, collections::HashMap, path::Path, sync::Arc}; -use nac3core::CodeGen; +use nac3core::{ + codegen::{CodeGenTask, WithCall, WorkerRegistry}, + top_level::{DefinitionId, TopLevelComposer, TopLevelContext, TopLevelDef}, + typecheck::{ + type_inferencer::{FunctionData, Inferencer}, + typedef::{FunSignature, FuncArg, TypeEnum}, + }, +}; +mod basic_symbol_resolver; fn main() { Target::initialize_all(&InitializationConfig::default()); let program = match fs::read_to_string("mandelbrot.py") { Ok(program) => program, - Err(err) => { println!("Cannot open input file: {}", err); return; } - }; - let ast = match parser::parse_program(&program) { - Ok(ast) => ast, - Err(err) => { println!("Parse error: {}", err); return; } + Err(err) => { + println!("Cannot open input file: {}", err); + return; + } }; - let context = Context::create(); - let mut codegen = CodeGen::new(&context); - match codegen.compile_toplevel(&ast.statements[0]) { - Ok(_) => (), - Err(err) => { println!("Compilation error: {}", err); return; } - } - codegen.print_ir(); - codegen.output("mandelbrot.o"); + let statements = match parser::parse_program(&program) { + Ok(mut ast) => { + let first = ast.remove(0); + if let StmtKind::FunctionDef { name, body, .. } = first.node { + if name != "run" { + panic!("Parse error: expected function \"run\" but got {}", name); + } + body + } else { + panic!( + "Parse error: expected function \"run\" but got {:?}", + first.node + ); + } + } + Err(err) => { + panic!("Parse error: {}", err); + } + }; + + let (_, composer) = TopLevelComposer::new(); + let mut unifier = composer.unifier.clone(); + let primitives = composer.primitives.clone(); + let top_level = composer.to_top_level_context(); + let fun = unifier.add_ty(TypeEnum::TFunc(RefCell::new(FunSignature { + args: vec![FuncArg { + name: "c".into(), + ty: primitives.int32, + default_value: None, + }], + ret: primitives.none, + vars: HashMap::new(), + }))); + let def_id = top_level.definitions.read().len(); + top_level + .definitions + .write() + .push(Arc::new(RwLock::new(TopLevelDef::Function { + name: "output".into(), + signature: fun, + instance_to_stmt: HashMap::new(), + instance_to_symbol: [("".to_string(), "output".to_string())] + .iter() + .cloned() + .collect(), + resolver: None, + }))); + let resolver = Arc::new(basic_symbol_resolver::Resolver { + id_to_type: [("output".into(), fun)].iter().cloned().collect(), + id_to_def: [("output".into(), DefinitionId(def_id))] + .iter() + .cloned() + .collect(), + class_names: Default::default(), + }); + + let threads = ["test"]; + let signature = FunSignature { + args: vec![], + ret: primitives.int32, + vars: HashMap::new(), + }; + + let mut function_data = FunctionData { + resolver: resolver.clone(), + bound_variables: Vec::new(), + return_type: Some(primitives.int32), + }; + let mut virtual_checks = Vec::new(); + let mut calls = HashMap::new(); + let mut inferencer = Inferencer { + top_level: &top_level, + function_data: &mut function_data, + unifier: &mut unifier, + variable_mapping: Default::default(), + primitives: &primitives, + virtual_checks: &mut virtual_checks, + calls: &mut calls, + }; + + let statements = statements + .into_iter() + .map(|v| inferencer.fold_stmt(v)) + .collect::<Result<Vec<_>, _>>() + .unwrap(); + let mut identifiers = vec!["output".to_string()]; + inferencer + .check_block(&statements, &mut identifiers) + .unwrap(); + let top_level = Arc::new(TopLevelContext { + definitions: Arc::new(RwLock::new(std::mem::take( + &mut *top_level.definitions.write(), + ))), + unifiers: Arc::new(RwLock::new(vec![( + unifier.get_shared_unifier(), + primitives.clone(), + )])), + }); + let task = CodeGenTask { + subst: Default::default(), + symbol_name: "run".to_string(), + body: statements, + unifier_index: 0, + resolver, + calls, + signature, + }; + let f = Arc::new(WithCall::new(Box::new(|module| { + let triple = TargetMachine::get_default_triple(); + let target = + Target::from_triple(&triple).expect("couldn't create target from target triple"); + let target_machine = target + .create_target_machine( + &triple, + "", + "", + OptimizationLevel::Default, + RelocMode::Default, + CodeModel::Default, + ) + .expect("couldn't create target machine"); + target_machine + .write_to_file(module, FileType::Object, Path::new("mandelbrot.o")) + .expect("couldn't write module to file"); + }))); + let (registry, handles) = WorkerRegistry::create_workers(&threads, top_level, f); + registry.add_task(task); + registry.wait_tasks_complete(handles); + println!("object file is in mandelbrot.o") }