Some examples/ files working again.
This commit is contained in:
parent
c69098db71
commit
9b2e952bf8
232
dm/src/repl.rs
232
dm/src/repl.rs
@ -174,62 +174,63 @@ fn compile_expression(
|
||||
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))
|
||||
// // 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(
|
||||
@ -242,63 +243,64 @@ fn compile_let_statement(
|
||||
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))
|
||||
// // 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!()
|
||||
}
|
||||
|
||||
@ -3,18 +3,12 @@ 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::compile_compilation_unit;
|
||||
use dmc_lib::constants_table::ConstantsTable;
|
||||
use dmc_lib::diagnostic::Diagnostic;
|
||||
use dmc_lib::intrinsics::{insert_intrinsic_symbols, insert_intrinsic_types};
|
||||
use dmc_lib::offset_counter::OffsetCounter;
|
||||
use dmc_lib::parser::get_compilation_unit;
|
||||
use dmc_lib::symbol_table::SymbolTable;
|
||||
use dmc_lib::types_table::TypesTable;
|
||||
use dmc_lib::diagnostic::{Diagnostic, Diagnostics};
|
||||
use dvm_lib::vm::constant::{Constant, StringConstant};
|
||||
use dvm_lib::vm::function::Function;
|
||||
use dvm_lib::vm::{DvmContext, call};
|
||||
use std::path::PathBuf;
|
||||
use std::rc::Rc;
|
||||
|
||||
pub fn compile_and_run_script(
|
||||
script: &PathBuf,
|
||||
@ -40,65 +34,18 @@ fn run(
|
||||
show_ir: bool,
|
||||
show_asm: bool,
|
||||
register_count: usize,
|
||||
) -> Result<(), Vec<Diagnostic>> {
|
||||
let mut compilation_unit = get_compilation_unit(&input, None)?;
|
||||
|
||||
let mut symbol_table = SymbolTable::new();
|
||||
symbol_table.push_module_scope("global scope");
|
||||
insert_intrinsic_symbols(&mut symbol_table);
|
||||
let mut types_table = TypesTable::new();
|
||||
insert_intrinsic_types(&symbol_table, &mut types_table);
|
||||
|
||||
compilation_unit.init_scopes(&mut symbol_table);
|
||||
compilation_unit.gather_symbols_into(&mut symbol_table)?;
|
||||
compilation_unit.check_names(&mut symbol_table)?;
|
||||
compilation_unit.gather_types_into(&symbol_table, &mut types_table)?;
|
||||
compilation_unit.type_check(&symbol_table, &mut types_table)?;
|
||||
|
||||
let (ir_classes, mut ir_functions) = compilation_unit.to_ir(&symbol_table, &types_table);
|
||||
|
||||
if show_ir {
|
||||
for ir_function in &ir_functions {
|
||||
println!("{}", ir_function);
|
||||
}
|
||||
}
|
||||
|
||||
let mut functions: Vec<Function> = vec![];
|
||||
) -> Result<(), Diagnostics> {
|
||||
let mut constants_table = ConstantsTable::new();
|
||||
|
||||
for ir_function in &mut ir_functions {
|
||||
let mut offset_counter = OffsetCounter::new();
|
||||
ir_function.assign_registers(register_count, &mut offset_counter);
|
||||
let function = ir_function.assemble(offset_counter.get_count(), &mut constants_table);
|
||||
functions.push(function);
|
||||
}
|
||||
|
||||
let classes = ir_classes
|
||||
.iter()
|
||||
.map(|ir_class| ir_class.to_vm_class())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
if show_asm {
|
||||
for function in &functions {
|
||||
println!("{}", function);
|
||||
}
|
||||
}
|
||||
let compile_compilation_unit_result =
|
||||
compile_compilation_unit(input, register_count, &mut constants_table)?;
|
||||
|
||||
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 class in classes {
|
||||
dvm_context
|
||||
.classes_mut()
|
||||
.insert(class.fqn().into(), Rc::new(class));
|
||||
for (name, function) in compile_compilation_unit_result.functions {
|
||||
dvm_context.functions_mut().insert(name, function);
|
||||
}
|
||||
|
||||
for (name, content) in &constants_table.string_constants() {
|
||||
|
||||
@ -243,6 +243,10 @@ fn to_add_operand(ir_expression: &IrExpression, ctx: &mut FunctionAssemblyContex
|
||||
IrTypeInfo::Int | IrTypeInfo::Double | IrTypeInfo::String => {
|
||||
AddOperand::Location(Location::StackFrameOffset(ir_parameter.stack_offset()))
|
||||
}
|
||||
_ => panic!(
|
||||
"Attempt to add with non-integer type (found {})",
|
||||
ir_parameter.type_info()
|
||||
),
|
||||
}
|
||||
}
|
||||
IrExpression::Variable(ir_variable_id) => {
|
||||
@ -251,6 +255,10 @@ fn to_add_operand(ir_expression: &IrExpression, ctx: &mut FunctionAssemblyContex
|
||||
IrTypeInfo::Int | IrTypeInfo::Double | IrTypeInfo::String => AddOperand::Location(
|
||||
to_location(ctx.variable_locations.get_variable_location(ir_variable_id)),
|
||||
),
|
||||
_ => panic!(
|
||||
"Attempt to add with non-integer type (found {})",
|
||||
ir_variable.type_info()
|
||||
),
|
||||
}
|
||||
}
|
||||
IrExpression::Int(i) => AddOperand::Int(*i),
|
||||
|
||||
@ -7,6 +7,7 @@ pub enum IrTypeInfo {
|
||||
String,
|
||||
Int,
|
||||
Double,
|
||||
Void,
|
||||
}
|
||||
|
||||
impl Display for IrTypeInfo {
|
||||
|
||||
@ -145,9 +145,20 @@ fn lower_to_ir_function(function: &Function, ctx: &mut LowerToIrContext) {
|
||||
|
||||
lower_to_ir_parameters(function, ctx, &mut fn_ctx);
|
||||
|
||||
let function_symbol_id = ctx.nodes_to_symbols[&function.node_id()];
|
||||
let function_type_info_id = ctx.symbols_to_type_infos[&function_symbol_id];
|
||||
let function_type_info = match &ctx.type_infos[function_type_info_id] {
|
||||
TypeInfo::Function(function_type_info) => function_type_info,
|
||||
_ => panic!("Expected FunctionTypeInfo"),
|
||||
};
|
||||
let is_void_function = match ctx.type_infos[function_type_info.return_type_id()] {
|
||||
TypeInfo::Void => true,
|
||||
_ => false,
|
||||
};
|
||||
|
||||
let n_statements = function.statements().len();
|
||||
for (i, statement) in function.statements().iter().enumerate() {
|
||||
let can_return_value = i == n_statements - 1;
|
||||
let can_return_value = i == n_statements - 1 && !is_void_function;
|
||||
lower_to_ir_statement(statement, ctx, &mut fn_ctx, can_return_value);
|
||||
}
|
||||
|
||||
@ -265,10 +276,8 @@ fn lower_to_ir_expression_statement(
|
||||
let ir_statement = IrStatement::Return(IrReturn::new(Some(ir_expression)));
|
||||
fn_ctx.current_block_statements.push(ir_statement);
|
||||
} else {
|
||||
// we could try to filter out useless code, but it's not guaranteed that there aren't
|
||||
// intended side effects from the lowering, so, for now, let's throw the result in a t_var.
|
||||
// in the future we may want to somehow enforce with the type system a way that we can't
|
||||
// create useless, dead ir code
|
||||
// This block executes when the expression has side effects. For now, we just throw the
|
||||
// result away in a temporary variable.
|
||||
let ir_operation =
|
||||
lower_expression_to_ir_operation(expression_statement.expression(), ctx, fn_ctx);
|
||||
|
||||
|
||||
@ -6,8 +6,9 @@ pub fn to_ir_type_info(sa_type_info: &TypeInfo) -> IrTypeInfo {
|
||||
TypeInfo::String => IrTypeInfo::String,
|
||||
TypeInfo::Int => IrTypeInfo::Int,
|
||||
TypeInfo::Double => IrTypeInfo::Double,
|
||||
TypeInfo::Void => IrTypeInfo::Void,
|
||||
_ => {
|
||||
panic!()
|
||||
panic!("BUG! Unknown sa_type_info: {}", sa_type_info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,6 +5,7 @@ use crate::ast::call::Call;
|
||||
use crate::ast::compilation_unit::CompilationUnit;
|
||||
use crate::ast::expression::Expression;
|
||||
use crate::ast::expression_statement::ExpressionStatement;
|
||||
use crate::ast::extern_function::ExternFunction;
|
||||
use crate::ast::function::Function;
|
||||
use crate::ast::identifier::Identifier;
|
||||
use crate::ast::let_statement::LetStatement;
|
||||
@ -99,6 +100,10 @@ pub fn resolve_names(
|
||||
resolve_names_function(function, &mut ctx);
|
||||
}
|
||||
|
||||
for extern_function in compilation_unit.extern_functions() {
|
||||
resolve_names_extern_function(extern_function, &mut ctx);
|
||||
}
|
||||
|
||||
NameResolutionResult {
|
||||
nodes_to_symbols: ctx.nodes_to_symbols,
|
||||
diagnostics: ctx.diagnostics,
|
||||
@ -121,6 +126,22 @@ fn resolve_names_function(function: &Function, ctx: &mut NameResolutionContext)
|
||||
ctx.nodes_to_symbols.insert(function.node_id(), symbol_id);
|
||||
}
|
||||
|
||||
fn resolve_names_extern_function(
|
||||
extern_function: &ExternFunction,
|
||||
ctx: &mut NameResolutionContext,
|
||||
) {
|
||||
for parameter in extern_function.parameters() {
|
||||
resolve_names_parameter(parameter, ctx);
|
||||
}
|
||||
|
||||
// point this extern function's node_id to the symbol_id for this function symbol
|
||||
let scope_id = ctx.nodes_to_scopes[&extern_function.node_id()];
|
||||
let scope = &ctx.scopes[scope_id];
|
||||
let symbol_id = scope.symbols()[extern_function.declared_name()];
|
||||
ctx.nodes_to_symbols
|
||||
.insert(extern_function.node_id(), symbol_id);
|
||||
}
|
||||
|
||||
fn resolve_names_parameter(parameter: &Parameter, ctx: &mut NameResolutionContext) {
|
||||
// point this parameter's node_id to the symbol_id for the parameter symbol
|
||||
let scope_id = ctx.nodes_to_scopes[¶meter.node_id()];
|
||||
|
||||
Loading…
Reference in New Issue
Block a user