diff --git a/src/vstc/compile.rs b/src/vstc/compile.rs index bc415ca..b21402c 100644 --- a/src/vstc/compile.rs +++ b/src/vstc/compile.rs @@ -14,6 +14,7 @@ use swc_common::{ use swc_ecma_ast::EsVersion; use swc_ecma_parser::{Syntax, TsConfig}; +use super::diagnostic::{handle_diagnostics_cli, Diagnostic}; use super::expression_compiler::string_literal; use super::function_compiler::{FunctionCompiler, Functionish}; use super::name_allocator::NameAllocator; @@ -28,11 +29,13 @@ pub fn command(args: &Vec) { } let program = parse(&args[2]); - let assembly = compile(&program); + let compiler_output = compile(&program); + + handle_diagnostics_cli(&compiler_output.diagnostics); let mut file = File::create("out.vsm").expect("Couldn't create out.vsm"); - for line in assembly { + for line in compiler_output.assembly { file .write_all(line.as_bytes()) .expect("Failed to write line"); @@ -82,26 +85,34 @@ pub fn parse(file_path: &String) -> swc_ecma_ast::Program { return result.expect("Parse failed"); } -pub fn compile(program: &swc_ecma_ast::Program) -> Vec { +pub struct CompilerOutput { + pub diagnostics: Vec, + pub assembly: Vec, +} + +pub fn compile(program: &swc_ecma_ast::Program) -> CompilerOutput { let mut compiler = Compiler::default(); compiler.compile_program(&program); - let mut lines = Vec::::new(); + let mut assembly = Vec::::new(); let mut first = true; for def in compiler.definitions { if first { first = false; } else { - lines.push("".to_string()); + assembly.push("".to_string()); } for line in def { - lines.push(line); + assembly.push(line); } } - return lines; + return CompilerOutput { + diagnostics: compiler.diagnostics, + assembly, + }; } pub fn full_compile_raw(source: &str) -> String { @@ -124,13 +135,16 @@ pub fn full_compile_raw(source: &str) -> String { let program = result.expect("Parse failed"); - let lines = compile(&program); + let compiler_output = compile(&program); - return lines.join("\n"); + // TODO: Handle diagnostics + + return compiler_output.assembly.join("\n"); } #[derive(Default)] struct Compiler { + diagnostics: Vec, definition_allocator: Rc>, definitions: Vec>, } @@ -146,7 +160,8 @@ impl Compiler { } fn compile_module(&mut self, module: &swc_ecma_ast::Module) { - let scope_analysis = ScopeAnalysis::run(module); + let mut scope_analysis = ScopeAnalysis::run(module); + self.diagnostics.append(&mut scope_analysis.diagnostics); let scope = init_std_scope(); use swc_ecma_ast::Decl; diff --git a/src/vstc/diagnostic.rs b/src/vstc/diagnostic.rs new file mode 100644 index 0000000..de0d56f --- /dev/null +++ b/src/vstc/diagnostic.rs @@ -0,0 +1,35 @@ +pub enum DiagnosticLevel { + Lint, + Error, + InternalError, +} + +pub struct Diagnostic { + pub level: DiagnosticLevel, + pub message: String, + pub span: swc_common::Span, +} + +pub fn handle_diagnostics_cli(diagnostics: &Vec) { + let mut has_error = false; + + for diagnostic in diagnostics { + match diagnostic.level { + DiagnosticLevel::Lint => { + println!("Lint: {}", diagnostic.message); + } + DiagnosticLevel::Error => { + println!("Error: {}", diagnostic.message); + has_error = true; + } + DiagnosticLevel::InternalError => { + println!("Internal Error: {}", diagnostic.message); + has_error = true; + } + } + } + + if has_error { + std::process::exit(1); + } +} diff --git a/src/vstc/main.rs b/src/vstc/main.rs index ca981e2..4c03caf 100644 --- a/src/vstc/main.rs +++ b/src/vstc/main.rs @@ -1,82 +1,79 @@ mod assemble; -mod run; -mod virtual_machine; -mod compile; -mod scope; -mod name_allocator; -mod expression_compiler; -mod scope_analysis; -mod function_compiler; mod capture_finder; +mod compile; +mod diagnostic; +mod expression_compiler; +mod function_compiler; +mod name_allocator; +mod run; +mod scope; +mod scope_analysis; +mod virtual_machine; use std::env; use std::process::exit; fn main() { - let args: Vec = env::args().collect(); + let args: Vec = env::args().collect(); - if args.len() < 2 { - std::panic!("Not implemented: ValueScript repl"); - } + if args.len() < 2 { + std::panic!("Not implemented: ValueScript repl"); + } - if args.len() == 2 && ( - args[1] == "-h" || - args[1] == "--help" || - args[1] == "help" - ) { - show_help(); - return; - } - - if args.len() >= 2 && args[1] == "assemble" { - assemble::command(&args); - return; - } - - if args.len() >= 2 && args[1] == "run" { - run::command(&args); - return; - } - - if args.len() >= 2 && args[1] == "compile" { - compile::command(&args); - return; - } - - println!("ERROR: Unrecognized command\n"); + if args.len() == 2 && (args[1] == "-h" || args[1] == "--help" || args[1] == "help") { show_help(); - exit(1); + return; + } + + if args.len() >= 2 && args[1] == "assemble" { + assemble::command(&args); + return; + } + + if args.len() >= 2 && args[1] == "run" { + run::command(&args); + return; + } + + if args.len() >= 2 && args[1] == "compile" { + compile::command(&args); + return; + } + + println!("ERROR: Unrecognized command\n"); + show_help(); + exit(1); } fn show_help() { - println!("ValueScript toolchain 0.1.0"); - println!(""); - println!("USAGE:"); - println!(" vstc [OPTIONS] [SUBCOMMAND]"); - println!(""); - println!("OPTIONS:"); - println!(" -h, --help"); - println!(" Print help information"); - println!(""); - println!(" -V, --version"); - println!(" Print version information"); - println!(""); - println!("SUBCOMMANDS:"); - println!(" compile"); - println!(" Compile an entry point"); - println!(""); - println!(" assemble"); - println!(" Convert assembly to bytecode"); - println!(""); - println!(" disassemble"); - println!(" Convert bytecode to assembly"); - println!(""); - println!(" run"); - println!(" Run a program"); - println!(""); - println!(" repl"); - println!(" Read Eval Print Loop"); - println!(""); - println!(" host"); - println!(" Start database server"); + println!("ValueScript toolchain 0.1.0"); + println!(""); + println!("USAGE:"); + println!(" vstc [OPTIONS] [SUBCOMMAND]"); + println!(""); + println!("OPTIONS:"); + println!(" -h, --help"); + println!(" Print help information"); + println!(""); + println!(" -V, --version"); + println!(" Print version information"); + println!(""); + println!("SUBCOMMANDS:"); + println!(" compile"); + println!(" Compile an entry point"); + println!(""); + println!(" assemble"); + println!(" Convert assembly to bytecode"); + println!(""); + println!(" disassemble"); + println!(" Convert bytecode to assembly"); + println!(""); + println!(" run"); + println!(" Run a program"); + println!(""); + println!(" repl"); + println!(" Read Eval Print Loop"); + println!(""); + println!(" host"); + println!(" Start database server"); } diff --git a/src/vstc/mod.rs b/src/vstc/mod.rs index f6a336e..e19f7a2 100644 --- a/src/vstc/mod.rs +++ b/src/vstc/mod.rs @@ -1,10 +1,11 @@ -pub mod virtual_machine; -pub mod compile; -pub mod run; -pub mod scope_analysis; -mod scope; -mod name_allocator; -mod function_compiler; -mod expression_compiler; -mod capture_finder; mod assemble; +mod capture_finder; +pub mod compile; +pub mod diagnostic; +mod expression_compiler; +mod function_compiler; +mod name_allocator; +pub mod run; +mod scope; +pub mod scope_analysis; +pub mod virtual_machine; diff --git a/src/vstc/run.rs b/src/vstc/run.rs index caa29bb..9879b1a 100644 --- a/src/vstc/run.rs +++ b/src/vstc/run.rs @@ -1,14 +1,15 @@ -use std::rc::Rc; -use std::process::exit; -use std::path::Path; use std::ffi::OsStr; +use std::path::Path; +use std::process::exit; +use std::rc::Rc; use super::assemble::assemble; +use super::compile::compile; use super::compile::full_compile_raw; use super::compile::parse; -use super::compile::compile; -use super::virtual_machine::VirtualMachine; +use super::diagnostic::handle_diagnostics_cli; use super::virtual_machine::ValTrait; +use super::virtual_machine::VirtualMachine; pub fn command(args: &Vec) { if args.len() < 3 { @@ -29,7 +30,7 @@ pub fn command(args: &Vec) { let res = format_from_option(&args[argpos]); argpos += 1; res - }, + } _ => format_from_path(&args[argpos]), }; @@ -66,7 +67,7 @@ fn format_from_option(option: &String) -> RunFormat { "--assembly" => RunFormat::Assembly, "--bytecode" => RunFormat::Bytecode, _ => std::panic!("Unrecognized option {}", option), - } + }; } fn format_from_path(file_path: &String) -> RunFormat { @@ -74,7 +75,7 @@ fn format_from_path(file_path: &String) -> RunFormat { .extension() .and_then(OsStr::to_str) .unwrap_or(""); - + return match ext { "ts" => RunFormat::TypeScript, "mts" => RunFormat::TypeScript, @@ -90,29 +91,29 @@ fn to_bytecode(format: RunFormat, file_path: &String) -> Rc> { return match format { RunFormat::TypeScript => { let ast = parse(file_path); - let assembly_lines = compile(&ast); + let compiler_output = compile(&ast); + handle_diagnostics_cli(&compiler_output.diagnostics); let mut assembly = String::new(); - for line in assembly_lines { + for line in compiler_output.assembly { assembly.push_str(&line); assembly.push('\n'); } return assemble(&assembly); - }, + } RunFormat::Assembly => { let file_content = std::fs::read_to_string(&file_path) .expect(&std::format!("Failed to read file {}", file_path)); assemble(&file_content) - }, + } - RunFormat::Bytecode => Rc::new( - std::fs::read(&file_path) - .expect(&std::format!("Failed to read file {}", file_path)) - ), + RunFormat::Bytecode => { + Rc::new(std::fs::read(&file_path).expect(&std::format!("Failed to read file {}", file_path))) + } }; } diff --git a/src/vstc/scope_analysis.rs b/src/vstc/scope_analysis.rs index c55eaeb..153aa20 100644 --- a/src/vstc/scope_analysis.rs +++ b/src/vstc/scope_analysis.rs @@ -1,5 +1,6 @@ use std::{cell::RefCell, collections::HashMap, collections::HashSet, rc::Rc}; +use super::diagnostic::{Diagnostic, DiagnosticLevel}; use super::scope::Builtin; #[derive(Hash, PartialEq, Eq, Clone, Debug)] @@ -36,18 +37,6 @@ pub struct Name { captures: Vec, } -enum DiagnosticLevel { - Lint, - Error, - InternalError, -} - -pub struct Diagnostic { - level: DiagnosticLevel, - message: String, - span: swc_common::Span, -} - #[derive(Default)] pub struct ScopeAnalysis { pub names: HashMap,