Compare commits
2 Commits
ebca87ddb9
...
705436ba61
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
705436ba61 | ||
|
|
b88b230495 |
182
dm/src/main.rs
182
dm/src/main.rs
@ -1,163 +1,51 @@
|
||||
use clap::Parser;
|
||||
use codespan_reporting::diagnostic::Label;
|
||||
use codespan_reporting::files::SimpleFiles;
|
||||
use codespan_reporting::term;
|
||||
use codespan_reporting::term::termcolor::{ColorChoice, StandardStream};
|
||||
use dm_std_lib::add_all_std_core;
|
||||
use dmc_lib::constants_table::ConstantsTable;
|
||||
use dmc_lib::diagnostic::Diagnostic;
|
||||
use dmc_lib::parser::parse_compilation_unit;
|
||||
use dmc_lib::symbol_table::SymbolTable;
|
||||
use dvm_lib::vm::constant::{Constant, StringConstant};
|
||||
use dvm_lib::vm::function::Function;
|
||||
use dvm_lib::vm::value::Value;
|
||||
use dvm_lib::vm::{CallStack, DvmContext, call};
|
||||
mod repl;
|
||||
mod run;
|
||||
|
||||
use crate::repl::repl;
|
||||
use crate::run::run;
|
||||
use clap::{Parser, Subcommand};
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
#[command(name = "dm", about = "Deimos", version = "0.1.0", long_about = None)]
|
||||
struct Cli {
|
||||
script: PathBuf,
|
||||
#[command(subcommand)]
|
||||
sub_command: SubCommand,
|
||||
}
|
||||
|
||||
#[arg(long)]
|
||||
show_asm: bool,
|
||||
#[derive(Debug, Subcommand)]
|
||||
enum SubCommand {
|
||||
Run {
|
||||
script: PathBuf,
|
||||
|
||||
#[arg(long)]
|
||||
show_ir: bool,
|
||||
#[arg(long)]
|
||||
show_asm: bool,
|
||||
|
||||
#[arg(long, default_value = "8")]
|
||||
register_count: usize,
|
||||
#[arg(long)]
|
||||
show_ir: bool,
|
||||
|
||||
#[arg(long, default_value = "8")]
|
||||
register_count: usize,
|
||||
},
|
||||
Repl {
|
||||
#[arg(long, default_value = "8")]
|
||||
register_count: usize,
|
||||
},
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let args = Cli::parse();
|
||||
let input = std::fs::read_to_string(&args.script).unwrap();
|
||||
|
||||
let mut files: SimpleFiles<&str, &str> = SimpleFiles::new();
|
||||
let script_file_id = files.add(args.script.to_str().unwrap(), &input);
|
||||
|
||||
let parse_result = parse_compilation_unit(&input);
|
||||
let mut compilation_unit = match parse_result {
|
||||
Ok(compilation_unit) => compilation_unit,
|
||||
Err(diagnostics) => {
|
||||
check_and_report_diagnostics(&files, script_file_id, &diagnostics);
|
||||
unreachable!();
|
||||
match &args.sub_command {
|
||||
SubCommand::Run {
|
||||
script,
|
||||
show_asm,
|
||||
show_ir,
|
||||
register_count,
|
||||
} => {
|
||||
run(script, *show_asm, *show_ir, *register_count);
|
||||
}
|
||||
};
|
||||
|
||||
let mut symbol_table = SymbolTable::new();
|
||||
|
||||
match compilation_unit.gather_declared_names(&mut symbol_table) {
|
||||
Ok(_) => {}
|
||||
Err(diagnostics) => {
|
||||
report_and_exit(&diagnostics, script_file_id, &files);
|
||||
SubCommand::Repl { register_count } => {
|
||||
repl(*register_count);
|
||||
}
|
||||
}
|
||||
|
||||
match compilation_unit.check_name_usages(&symbol_table) {
|
||||
Ok(_) => {}
|
||||
Err(diagnostics) => {
|
||||
report_and_exit(&diagnostics, script_file_id, &files);
|
||||
}
|
||||
}
|
||||
|
||||
match compilation_unit.type_check(&symbol_table) {
|
||||
Ok(_) => {}
|
||||
Err(diagnostics) => {
|
||||
report_and_exit(&diagnostics, script_file_id, &files);
|
||||
}
|
||||
}
|
||||
|
||||
let mut ir_functions = compilation_unit.to_ir(&symbol_table);
|
||||
|
||||
if args.show_ir {
|
||||
for ir_function in &ir_functions {
|
||||
println!("{}", ir_function);
|
||||
}
|
||||
}
|
||||
|
||||
let mut functions: Vec<Function> = vec![];
|
||||
let mut constants_table = ConstantsTable::new();
|
||||
|
||||
for ir_function in &mut ir_functions {
|
||||
let (_, stack_size) = ir_function.assign_registers(args.register_count);
|
||||
let function = ir_function.assemble(stack_size, &mut constants_table);
|
||||
functions.push(function);
|
||||
}
|
||||
|
||||
if args.show_asm {
|
||||
for function in &functions {
|
||||
println!("{}", function);
|
||||
}
|
||||
}
|
||||
|
||||
let mut dvm_context = DvmContext::new();
|
||||
|
||||
// add std::core fns
|
||||
add_all_std_core(&mut dvm_context);
|
||||
|
||||
for function in functions {
|
||||
dvm_context
|
||||
.functions_mut()
|
||||
.insert(function.name_owned(), function);
|
||||
}
|
||||
|
||||
for (name, content) in &constants_table.string_constants() {
|
||||
dvm_context.constants_mut().insert(
|
||||
name.clone(),
|
||||
Constant::String(StringConstant::new(name.clone(), content.clone())),
|
||||
);
|
||||
}
|
||||
|
||||
let mut registers: Vec<Value> = vec![Value::Null; args.register_count];
|
||||
let mut call_stack = CallStack::new();
|
||||
|
||||
let result = call(
|
||||
&dvm_context,
|
||||
&mut registers,
|
||||
&mut call_stack,
|
||||
"main",
|
||||
&vec![],
|
||||
);
|
||||
if let Some(value) = result {
|
||||
println!("{}", value);
|
||||
}
|
||||
}
|
||||
|
||||
fn check_and_report_diagnostics(
|
||||
files: &SimpleFiles<&str, &str>,
|
||||
script_file_id: usize,
|
||||
diagnostics: &[Diagnostic],
|
||||
) {
|
||||
if !diagnostics.is_empty() {
|
||||
report_and_exit(diagnostics, script_file_id, files);
|
||||
}
|
||||
}
|
||||
|
||||
fn report_and_exit(
|
||||
diagnostics: &[Diagnostic],
|
||||
script_file_id: usize,
|
||||
files: &SimpleFiles<&str, &str>,
|
||||
) -> ! {
|
||||
let writer = StandardStream::stderr(ColorChoice::Always);
|
||||
let config = term::Config::default();
|
||||
for diagnostic in diagnostics {
|
||||
let csr_diagnostic = codespan_reporting::diagnostic::Diagnostic::error()
|
||||
.with_message(diagnostic.message())
|
||||
.with_label(Label::primary(
|
||||
script_file_id,
|
||||
diagnostic.start()..diagnostic.end(),
|
||||
));
|
||||
|
||||
term::emit_to_write_style(&mut writer.lock(), &config, files, &csr_diagnostic).unwrap();
|
||||
}
|
||||
if diagnostics.len() == 1 {
|
||||
eprintln!("There was 1 diagnostic. See above for more information.");
|
||||
} else {
|
||||
eprintln!(
|
||||
"There were {} diagnostics. See above for more information.",
|
||||
diagnostics.len()
|
||||
);
|
||||
}
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
140
dm/src/repl.rs
Normal file
140
dm/src/repl.rs
Normal file
@ -0,0 +1,140 @@
|
||||
use dmc_lib::ast::ir_builder::IrBuilder;
|
||||
use dmc_lib::constants_table::ConstantsTable;
|
||||
use dmc_lib::diagnostic::Diagnostic;
|
||||
use dmc_lib::ir::ir_function::IrFunction;
|
||||
use dmc_lib::ir::ir_return::IrReturn;
|
||||
use dmc_lib::ir::ir_statement::IrStatement;
|
||||
use dmc_lib::lexer::Lexer;
|
||||
use dmc_lib::parser::parse_expression;
|
||||
use dmc_lib::symbol::FunctionSymbol;
|
||||
use dmc_lib::symbol_table::SymbolTable;
|
||||
use dmc_lib::token::TokenKind;
|
||||
use dvm_lib::vm::constant::{Constant, StringConstant};
|
||||
use dvm_lib::vm::function::Function;
|
||||
use dvm_lib::vm::value::Value;
|
||||
use dvm_lib::vm::{CallStack, DvmContext, call};
|
||||
use std::cell::RefCell;
|
||||
use std::io;
|
||||
use std::io::Write;
|
||||
use std::rc::Rc;
|
||||
|
||||
pub fn repl(register_count: usize) {
|
||||
let mut buffer = String::new();
|
||||
|
||||
let mut constants_table = ConstantsTable::new();
|
||||
let mut context = DvmContext::new();
|
||||
|
||||
'repl: loop {
|
||||
print!("> ");
|
||||
io::stdout().flush().unwrap();
|
||||
io::stdin().read_line(&mut buffer).unwrap();
|
||||
let input = buffer.trim();
|
||||
if input.is_empty() {
|
||||
buffer.clear();
|
||||
continue;
|
||||
}
|
||||
|
||||
let mut lexer = Lexer::new(input);
|
||||
let first_token = match lexer.next() {
|
||||
None => {
|
||||
continue;
|
||||
}
|
||||
Some(result) => match result {
|
||||
Ok(first_token) => first_token,
|
||||
Err(lexer_error) => {
|
||||
eprintln!("{:?}", lexer_error);
|
||||
buffer.clear();
|
||||
continue;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
match first_token.kind() {
|
||||
TokenKind::Fn => {
|
||||
todo!("Parse functions in repl")
|
||||
}
|
||||
TokenKind::Let => {
|
||||
todo!("Parse let statements in repl")
|
||||
}
|
||||
_ => match compile_expression(input, register_count, &mut constants_table) {
|
||||
Ok(function) => {
|
||||
context
|
||||
.functions_mut()
|
||||
.insert(function.name_owned(), function);
|
||||
}
|
||||
Err(diagnostics) => {
|
||||
for diagnostic in &diagnostics {
|
||||
eprintln!("{}", diagnostic.message());
|
||||
buffer.clear();
|
||||
continue 'repl;
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
for (name, content) in constants_table.string_constants() {
|
||||
context.constants_mut().insert(
|
||||
name.clone(),
|
||||
Constant::String(StringConstant::new(name, content)),
|
||||
);
|
||||
}
|
||||
|
||||
let mut registers = vec![Value::Null; register_count];
|
||||
let mut call_stack = CallStack::new();
|
||||
|
||||
let result = call(&context, &mut registers, &mut call_stack, "__repl", &[]);
|
||||
if let Some(value) = result {
|
||||
println!("{}", value);
|
||||
}
|
||||
|
||||
buffer.clear();
|
||||
}
|
||||
}
|
||||
|
||||
fn compile_expression(
|
||||
input: &str,
|
||||
register_count: usize,
|
||||
constants_table: &mut ConstantsTable,
|
||||
) -> Result<Function, Vec<Diagnostic>> {
|
||||
let parse_result = parse_expression(input);
|
||||
let mut expression = parse_result?;
|
||||
|
||||
let mut symbol_table = SymbolTable::new();
|
||||
// "fake" scope
|
||||
symbol_table.push_scope("__repl_enter");
|
||||
expression.gather_declared_names(&mut symbol_table)?;
|
||||
symbol_table.pop_scope();
|
||||
|
||||
expression.check_name_usages(&symbol_table)?;
|
||||
expression.type_check(&symbol_table)?;
|
||||
|
||||
// synthesize a function
|
||||
let mut ir_builder = IrBuilder::new();
|
||||
let entry_block_id = ir_builder.new_block();
|
||||
|
||||
let maybe_ir_expression = expression.to_ir(&mut ir_builder, &symbol_table);
|
||||
|
||||
// if Some, return the value
|
||||
ir_builder
|
||||
.current_block_mut()
|
||||
.add_statement(IrStatement::Return(IrReturn::new(maybe_ir_expression)));
|
||||
|
||||
ir_builder.finish_block();
|
||||
let entry_block = ir_builder.get_block(entry_block_id);
|
||||
|
||||
// synthesize symbol
|
||||
let fake_function_symbol = Rc::new(RefCell::new(FunctionSymbol::new(
|
||||
"__repl",
|
||||
false,
|
||||
expression.type_info().clone(), // dubious
|
||||
)));
|
||||
let mut ir_function = IrFunction::new(
|
||||
fake_function_symbol,
|
||||
&[],
|
||||
expression.type_info(),
|
||||
entry_block.clone(),
|
||||
);
|
||||
|
||||
let (_, stack_size) = ir_function.assign_registers(register_count);
|
||||
Ok(ir_function.assemble(stack_size, constants_table))
|
||||
}
|
||||
146
dm/src/run.rs
Normal file
146
dm/src/run.rs
Normal file
@ -0,0 +1,146 @@
|
||||
use codespan_reporting::diagnostic::Label;
|
||||
use codespan_reporting::files::SimpleFiles;
|
||||
use codespan_reporting::term;
|
||||
use codespan_reporting::term::termcolor::{ColorChoice, StandardStream};
|
||||
use dm_std_lib::add_all_std_core;
|
||||
use dmc_lib::constants_table::ConstantsTable;
|
||||
use dmc_lib::diagnostic::Diagnostic;
|
||||
use dmc_lib::parser::parse_compilation_unit;
|
||||
use dmc_lib::symbol_table::SymbolTable;
|
||||
use dvm_lib::vm::constant::{Constant, StringConstant};
|
||||
use dvm_lib::vm::function::Function;
|
||||
use dvm_lib::vm::value::Value;
|
||||
use dvm_lib::vm::{CallStack, DvmContext, call};
|
||||
use std::path::PathBuf;
|
||||
|
||||
pub fn run(script: &PathBuf, show_ir: bool, show_asm: bool, register_count: usize) {
|
||||
let input = std::fs::read_to_string(script).unwrap();
|
||||
|
||||
let mut files: SimpleFiles<&str, &str> = SimpleFiles::new();
|
||||
let script_file_id = files.add(script.to_str().unwrap(), &input);
|
||||
|
||||
let parse_result = parse_compilation_unit(&input);
|
||||
let mut compilation_unit = match parse_result {
|
||||
Ok(compilation_unit) => compilation_unit,
|
||||
Err(diagnostics) => {
|
||||
check_and_report_diagnostics(&files, script_file_id, &diagnostics);
|
||||
unreachable!();
|
||||
}
|
||||
};
|
||||
|
||||
let mut symbol_table = SymbolTable::new();
|
||||
|
||||
match compilation_unit.gather_declared_names(&mut symbol_table) {
|
||||
Ok(_) => {}
|
||||
Err(diagnostics) => {
|
||||
report_and_exit(&diagnostics, script_file_id, &files);
|
||||
}
|
||||
}
|
||||
|
||||
match compilation_unit.check_name_usages(&symbol_table) {
|
||||
Ok(_) => {}
|
||||
Err(diagnostics) => {
|
||||
report_and_exit(&diagnostics, script_file_id, &files);
|
||||
}
|
||||
}
|
||||
|
||||
match compilation_unit.type_check(&symbol_table) {
|
||||
Ok(_) => {}
|
||||
Err(diagnostics) => {
|
||||
report_and_exit(&diagnostics, script_file_id, &files);
|
||||
}
|
||||
}
|
||||
|
||||
let mut ir_functions = compilation_unit.to_ir(&symbol_table);
|
||||
|
||||
if show_ir {
|
||||
for ir_function in &ir_functions {
|
||||
println!("{}", ir_function);
|
||||
}
|
||||
}
|
||||
|
||||
let mut functions: Vec<Function> = vec![];
|
||||
let mut constants_table = ConstantsTable::new();
|
||||
|
||||
for ir_function in &mut ir_functions {
|
||||
let (_, stack_size) = ir_function.assign_registers(register_count);
|
||||
let function = ir_function.assemble(stack_size, &mut constants_table);
|
||||
functions.push(function);
|
||||
}
|
||||
|
||||
if show_asm {
|
||||
for function in &functions {
|
||||
println!("{}", function);
|
||||
}
|
||||
}
|
||||
|
||||
let mut dvm_context = DvmContext::new();
|
||||
|
||||
// add std::core fns
|
||||
add_all_std_core(&mut dvm_context);
|
||||
|
||||
for function in functions {
|
||||
dvm_context
|
||||
.functions_mut()
|
||||
.insert(function.name_owned(), function);
|
||||
}
|
||||
|
||||
for (name, content) in &constants_table.string_constants() {
|
||||
dvm_context.constants_mut().insert(
|
||||
name.clone(),
|
||||
Constant::String(StringConstant::new(name.clone(), content.clone())),
|
||||
);
|
||||
}
|
||||
|
||||
let mut registers: Vec<Value> = vec![Value::Null; register_count];
|
||||
let mut call_stack = CallStack::new();
|
||||
|
||||
let result = call(
|
||||
&dvm_context,
|
||||
&mut registers,
|
||||
&mut call_stack,
|
||||
"main",
|
||||
&vec![],
|
||||
);
|
||||
if let Some(value) = result {
|
||||
println!("{}", value);
|
||||
}
|
||||
}
|
||||
|
||||
fn check_and_report_diagnostics(
|
||||
files: &SimpleFiles<&str, &str>,
|
||||
script_file_id: usize,
|
||||
diagnostics: &[Diagnostic],
|
||||
) {
|
||||
if !diagnostics.is_empty() {
|
||||
report_and_exit(diagnostics, script_file_id, files);
|
||||
}
|
||||
}
|
||||
|
||||
fn report_and_exit(
|
||||
diagnostics: &[Diagnostic],
|
||||
script_file_id: usize,
|
||||
files: &SimpleFiles<&str, &str>,
|
||||
) -> ! {
|
||||
let writer = StandardStream::stderr(ColorChoice::Always);
|
||||
let config = term::Config::default();
|
||||
for diagnostic in diagnostics {
|
||||
let csr_diagnostic = codespan_reporting::diagnostic::Diagnostic::error()
|
||||
.with_message(diagnostic.message())
|
||||
.with_label(Label::primary(
|
||||
script_file_id,
|
||||
diagnostic.start()..diagnostic.end(),
|
||||
));
|
||||
|
||||
term::emit_to_write_style(&mut writer.lock(), &config, files, &csr_diagnostic).unwrap();
|
||||
}
|
||||
if diagnostics.len() == 1 {
|
||||
eprintln!("There was 1 diagnostic. See above for more information.");
|
||||
} else {
|
||||
eprintln!(
|
||||
"There were {} diagnostics. See above for more information.",
|
||||
diagnostics.len()
|
||||
);
|
||||
}
|
||||
std::process::exit(1);
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user