473 lines
17 KiB
Rust
473 lines
17 KiB
Rust
use dmc_lib::ast::expression_statement::ExpressionStatement;
|
|
use dmc_lib::ast::statement::Statement;
|
|
use dmc_lib::compile_statement_to_synthetic_function;
|
|
use dmc_lib::constants_table::ConstantsTable;
|
|
use dmc_lib::diagnostic::Diagnostics;
|
|
use dmc_lib::ir::variable_locations::VariableLocations;
|
|
use dmc_lib::lexer::Lexer;
|
|
use dmc_lib::parser::{parse_expression, parse_let_statement};
|
|
use dmc_lib::semantic_analysis::analysis_context::AnalysisContext;
|
|
use dmc_lib::token::TokenKind;
|
|
use dvm_lib::vm::constant::{Constant, StringConstant};
|
|
use dvm_lib::vm::function::Function;
|
|
use dvm_lib::vm::operand::Operand;
|
|
use dvm_lib::vm::{CallStack, DvmContext, loop_instructions, prepare_for_instruction_loop};
|
|
use std::io;
|
|
use std::io::{BufRead, Write};
|
|
use std::rc::Rc;
|
|
//
|
|
// pub fn repl(read: &mut impl BufRead, register_count: usize) {
|
|
// let mut buffer = String::new();
|
|
//
|
|
// let mut symbol_table = SymbolTable::new();
|
|
// let mut types_table = TypesTable::new();
|
|
//
|
|
// let mut repl_fn_body_scope_id: Option<usize> = None;
|
|
// let mut repl_fn_offset_counter = OffsetCounter::new();
|
|
// let mut repl_fn_local_variables = HashMap::new();
|
|
//
|
|
// let mut constants_table = ConstantsTable::new();
|
|
// let mut context = DvmContext::new();
|
|
//
|
|
// let mut repl_fn_stack_locals: Vec<Operand> = vec![];
|
|
//
|
|
// 'repl: loop {
|
|
// print!("> ");
|
|
// io::stdout().flush().unwrap();
|
|
// read.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 => {
|
|
// match compile_let_statement(
|
|
// input,
|
|
// register_count,
|
|
// &mut symbol_table,
|
|
// &mut repl_fn_body_scope_id,
|
|
// &mut repl_fn_offset_counter,
|
|
// &mut repl_fn_local_variables,
|
|
// &mut types_table,
|
|
// &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;
|
|
// }
|
|
// }
|
|
// }
|
|
// _ => match compile_expression(
|
|
// input,
|
|
// register_count,
|
|
// &mut symbol_table,
|
|
// &mut types_table,
|
|
// &mut repl_fn_body_scope_id,
|
|
// &mut repl_fn_local_variables,
|
|
// &mut repl_fn_offset_counter,
|
|
// &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 call_stack = CallStack::new();
|
|
// prepare_for_instruction_loop(&context, "__repl", &mut call_stack, &[]);
|
|
//
|
|
// // copy all old locals to current call frame's stack
|
|
// // this has to be done with indexing because the preparation above creates space for them
|
|
// for (i, operand) in repl_fn_stack_locals.iter().enumerate() {
|
|
// let target_index = call_stack.top().fp() + i;
|
|
// call_stack.top_mut().stack_mut()[target_index] = operand.clone();
|
|
// }
|
|
//
|
|
// let result = loop_instructions(
|
|
// &context,
|
|
// &mut vec![Operand::Null; register_count],
|
|
// &mut call_stack,
|
|
// );
|
|
//
|
|
// // copy the top frame's stack locals back to OUR stack locals for next iteration
|
|
// repl_fn_stack_locals = std::mem::take(call_stack.top_mut().stack_mut());
|
|
//
|
|
// if let Some(value) = result {
|
|
// println!("{}", value);
|
|
// }
|
|
//
|
|
// buffer.clear();
|
|
// }
|
|
// }
|
|
//
|
|
// fn prepare_scopes(symbol_table: &mut SymbolTable, fn_body_scope_id: &mut Option<usize>) -> usize {
|
|
// if let Some(scope_id) = fn_body_scope_id {
|
|
// symbol_table.change_scope(*scope_id);
|
|
// *scope_id
|
|
// } else {
|
|
// symbol_table.push_module_scope("__repl_module");
|
|
// symbol_table.push_function_scope("__repl_fn");
|
|
// let container_scope_id = symbol_table.push_block_scope("__repl_fn_body");
|
|
// fn_body_scope_id.replace(container_scope_id);
|
|
// container_scope_id
|
|
// }
|
|
// }
|
|
//
|
|
// fn compile_expression(
|
|
// input: &str,
|
|
// register_count: usize,
|
|
// symbol_table: &mut SymbolTable,
|
|
// types_table: &mut TypesTable,
|
|
// fn_body_scope_id: &mut Option<usize>,
|
|
// fn_local_variables: &HashMap<Rc<VariableSymbol>, Rc<RefCell<IrVariable>>>,
|
|
// offset_counter: &mut OffsetCounter,
|
|
// constants_table: &mut ConstantsTable,
|
|
// ) -> Result<Function, Vec<Diagnostic>> {
|
|
// // // parse
|
|
// // let (mut expression, parse_diagnostics) = parse_expression(input);
|
|
// // if !parse_diagnostics.is_empty() {
|
|
// // return Err(parse_diagnostics);
|
|
// // }
|
|
// //
|
|
// // // init scopes, if necessary
|
|
// // let container_scope = prepare_scopes(symbol_table, fn_body_scope_id);
|
|
// //
|
|
// // // inner scopes
|
|
// // expression.init_scopes(symbol_table, container_scope);
|
|
// //
|
|
// // // names
|
|
// // let diagnostics = expression.check_static_fn_local_names(&symbol_table);
|
|
// // if !diagnostics.is_empty() {
|
|
// // return Err(diagnostics);
|
|
// // }
|
|
// //
|
|
// // // type check
|
|
// // expression.type_check(&symbol_table, types_table)?;
|
|
// //
|
|
// // // synthesize a function
|
|
// // // init ir_builder
|
|
// // let mut ir_builder = IrBuilder::new();
|
|
// //
|
|
// // // copy all previous declared variables to here so we preserve their stack offsets
|
|
// // for (key, value) in fn_local_variables {
|
|
// // ir_builder
|
|
// // .local_variables_mut()
|
|
// // .insert(key.clone(), value.clone());
|
|
// // }
|
|
// //
|
|
// // let entry_block_id = ir_builder.new_block();
|
|
// //
|
|
// // let maybe_ir_expression =
|
|
// // expression.to_ir_expression(&mut ir_builder, &symbol_table, &types_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);
|
|
// //
|
|
// // let mut ir_function = IrFunction::new(
|
|
// // "__repl".into(),
|
|
// // vec![],
|
|
// // expression.type_info(&symbol_table, &types_table),
|
|
// // entry_block.clone(),
|
|
// // );
|
|
// //
|
|
// // // spilled registers are put on the stack, so we need to add it to our stack size
|
|
// // ir_function.assign_registers(register_count, offset_counter);
|
|
// //
|
|
// // Ok(ir_function.assemble(offset_counter.get_count(), constants_table))
|
|
// todo!()
|
|
// }
|
|
//
|
|
// fn compile_let_statement(
|
|
// input: &str,
|
|
// register_count: usize,
|
|
// symbol_table: &mut SymbolTable,
|
|
// body_scope_id: &mut Option<usize>,
|
|
// offset_counter: &mut OffsetCounter,
|
|
// local_variables: &mut HashMap<Rc<VariableSymbol>, Rc<RefCell<IrVariable>>>,
|
|
// types_table: &mut TypesTable,
|
|
// constants_table: &mut ConstantsTable,
|
|
// ) -> Result<Function, Vec<Diagnostic>> {
|
|
// // // parse
|
|
// // let (maybe_let_statement, parse_diagnostics) = parse_let_statement(input);
|
|
// // if !parse_diagnostics.is_empty() {
|
|
// // return Err(parse_diagnostics);
|
|
// // }
|
|
// // let mut let_statement = maybe_let_statement.unwrap();
|
|
// //
|
|
// // // names
|
|
// // let container_scope_id = prepare_scopes(symbol_table, body_scope_id);
|
|
// //
|
|
// // let_statement.init_scopes(symbol_table, container_scope_id);
|
|
// //
|
|
// // let name_diagnostics = let_statement.analyze_static_fn_local_names(symbol_table);
|
|
// // if !name_diagnostics.is_empty() {
|
|
// // return Err(name_diagnostics);
|
|
// // }
|
|
// //
|
|
// // // types
|
|
// // let_statement.type_check(&symbol_table, types_table)?;
|
|
// //
|
|
// // // init the ir builder
|
|
// // let mut ir_builder = IrBuilder::new();
|
|
// //
|
|
// // // put previous locals in ir_builder so expressions can find them
|
|
// // for (k, v) in local_variables.iter() {
|
|
// // ir_builder
|
|
// // .local_variables_mut()
|
|
// // .insert(k.clone(), v.clone());
|
|
// // }
|
|
// //
|
|
// // // ir function
|
|
// // let entry_block_id = ir_builder.new_block();
|
|
// //
|
|
// // let destination_ir_variable = let_statement.to_repl_ir(
|
|
// // &mut ir_builder,
|
|
// // symbol_table,
|
|
// // types_table,
|
|
// // offset_counter.next() as isize,
|
|
// // ); // put it on top
|
|
// //
|
|
// // // Now that we've translated to ir, we can add the new local variable in the IrBuilder to our
|
|
// // // record of them to be used for next loop iteration.
|
|
// // let variable_symbol = let_statement.get_destination_symbol(symbol_table);
|
|
// // local_variables.insert(variable_symbol, destination_ir_variable);
|
|
// //
|
|
// // ir_builder.finish_block();
|
|
// // let entry_block = ir_builder.get_block(entry_block_id);
|
|
// // let mut ir_function = IrFunction::new(
|
|
// // "__repl".into(),
|
|
// // vec![],
|
|
// // &TypeInfo::Void,
|
|
// // entry_block.clone(),
|
|
// // );
|
|
// //
|
|
// // // By here, the variables should all be assigned to their new or existing stack slots.
|
|
// // // Register allocation should only be required for temp variables.
|
|
// // ir_function.assign_registers(register_count, offset_counter);
|
|
// //
|
|
// // Ok(ir_function.assemble(offset_counter.get_count(), constants_table))
|
|
// todo!()
|
|
// }
|
|
|
|
pub fn repl_2(read: &mut impl BufRead, register_count: usize) {
|
|
let mut buffer = String::new();
|
|
|
|
let mut analysis_context = AnalysisContext::new();
|
|
|
|
analysis_context.push_scope("__repl_root_scope");
|
|
analysis_context.push_scope("__repl_function_scope");
|
|
analysis_context.push_scope("__repl_body_scope");
|
|
|
|
let fqn: Rc<str> = Rc::from("__repl");
|
|
let mut variable_locations = VariableLocations::new();
|
|
let mut constants_table = ConstantsTable::new();
|
|
|
|
let mut dvm_context = DvmContext::new();
|
|
let mut repl_fn_stack_locals: Vec<Operand> = Vec::new();
|
|
|
|
'repl: loop {
|
|
print!("> ");
|
|
io::stdout().flush().unwrap();
|
|
read.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::Let => {
|
|
let compile_result = compile_let_statement_2(
|
|
input,
|
|
&mut analysis_context,
|
|
&fqn,
|
|
&mut variable_locations,
|
|
register_count,
|
|
&mut constants_table,
|
|
);
|
|
match compile_result {
|
|
Ok(function) => {
|
|
dvm_context
|
|
.functions_mut()
|
|
.insert(function.name_owned(), function);
|
|
}
|
|
Err(diagnostics) => {
|
|
for diagnostic in diagnostics {
|
|
eprintln!("{}", diagnostic.message());
|
|
}
|
|
buffer.clear();
|
|
continue 'repl;
|
|
}
|
|
}
|
|
}
|
|
_ => {
|
|
let compile_result = compile_expression_2(
|
|
input,
|
|
&mut analysis_context,
|
|
&fqn,
|
|
&mut variable_locations,
|
|
register_count,
|
|
&mut constants_table,
|
|
);
|
|
match compile_result {
|
|
Ok(function) => {
|
|
dvm_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() {
|
|
dvm_context.constants_mut().insert(
|
|
name.clone(),
|
|
Constant::String(StringConstant::new(name, content)),
|
|
);
|
|
}
|
|
|
|
let mut call_stack = CallStack::new();
|
|
prepare_for_instruction_loop(&dvm_context, "__repl", &mut call_stack, &[]);
|
|
|
|
// copy all old locals to current call frame's stack
|
|
// this has to be done with indexing because the preparation above creates space for them
|
|
for (i, operand) in repl_fn_stack_locals.iter().enumerate() {
|
|
let target_index = call_stack.top().fp() + i;
|
|
call_stack.top_mut().stack_mut()[target_index] = operand.clone();
|
|
}
|
|
|
|
let result = loop_instructions(
|
|
&dvm_context,
|
|
&mut vec![Operand::Null; register_count],
|
|
&mut call_stack,
|
|
);
|
|
|
|
// copy the top frame's stack locals back to OUR stack locals for next iteration
|
|
repl_fn_stack_locals = std::mem::take(call_stack.top_mut().stack_mut());
|
|
|
|
if let Some(value) = result {
|
|
println!("{}", value);
|
|
}
|
|
|
|
buffer.clear();
|
|
}
|
|
}
|
|
|
|
fn compile_expression_2(
|
|
input: &str,
|
|
analysis_context: &mut AnalysisContext,
|
|
fqn: &Rc<str>,
|
|
variable_locations: &mut VariableLocations,
|
|
register_count: usize,
|
|
constants_table: &mut ConstantsTable,
|
|
) -> Result<Function, Diagnostics> {
|
|
let (expression, parse_diagnostics) = parse_expression(input);
|
|
if !parse_diagnostics.is_empty() {
|
|
return Err(parse_diagnostics);
|
|
}
|
|
|
|
let statement = Statement::Expression(ExpressionStatement::new(0, expression));
|
|
|
|
compile_statement_to_synthetic_function(
|
|
&statement,
|
|
analysis_context,
|
|
fqn.clone(),
|
|
variable_locations,
|
|
register_count,
|
|
constants_table,
|
|
)
|
|
}
|
|
|
|
fn compile_let_statement_2(
|
|
input: &str,
|
|
analysis_context: &mut AnalysisContext,
|
|
fqn: &Rc<str>,
|
|
variable_locations: &mut VariableLocations,
|
|
register_count: usize,
|
|
constants_table: &mut ConstantsTable,
|
|
) -> Result<Function, Diagnostics> {
|
|
let (maybe_let_statement, parse_diagnostics) = parse_let_statement(input);
|
|
if !parse_diagnostics.is_empty() {
|
|
return Err(parse_diagnostics);
|
|
}
|
|
compile_statement_to_synthetic_function(
|
|
&Statement::Let(maybe_let_statement.unwrap()),
|
|
analysis_context,
|
|
fqn.clone(),
|
|
variable_locations,
|
|
register_count,
|
|
constants_table,
|
|
)
|
|
}
|