Start printing diagnostics

This commit is contained in:
Andrew Morris
2023-02-20 11:21:48 +11:00
parent fa5ed34894
commit b03102227c
6 changed files with 153 additions and 115 deletions

View File

@@ -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<String>) {
}
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<String> {
pub struct CompilerOutput {
pub diagnostics: Vec<Diagnostic>,
pub assembly: Vec<String>,
}
pub fn compile(program: &swc_ecma_ast::Program) -> CompilerOutput {
let mut compiler = Compiler::default();
compiler.compile_program(&program);
let mut lines = Vec::<String>::new();
let mut assembly = Vec::<String>::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<Diagnostic>,
definition_allocator: Rc<RefCell<NameAllocator>>,
definitions: Vec<Vec<String>>,
}
@@ -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;

35
src/vstc/diagnostic.rs Normal file
View File

@@ -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<Diagnostic>) {
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);
}
}

View File

@@ -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<String> = env::args().collect();
let args: Vec<String> = 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");
}

View File

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

View File

@@ -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<String>) {
if args.len() < 3 {
@@ -29,7 +30,7 @@ pub fn command(args: &Vec<String>) {
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<Vec<u8>> {
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)))
}
};
}

View File

@@ -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<Capture>,
}
enum DiagnosticLevel {
Lint,
Error,
InternalError,
}
pub struct Diagnostic {
level: DiagnosticLevel,
message: String,
span: swc_common::Span,
}
#[derive(Default)]
pub struct ScopeAnalysis {
pub names: HashMap<NameId, Name>,