Fix identifier type info being called too early bug.
This commit is contained in:
parent
d39e9afee2
commit
7d8df883e6
@ -31,7 +31,7 @@ mod smoke_tests {
|
|||||||
fn multiple_statements() {
|
fn multiple_statements() {
|
||||||
let asm_functions = assemble(
|
let asm_functions = assemble(
|
||||||
"
|
"
|
||||||
extern fn println()
|
extern fn println() -> Void
|
||||||
fn main()
|
fn main()
|
||||||
let x = 42
|
let x = 42
|
||||||
println(x)
|
println(x)
|
||||||
|
|||||||
@ -3,8 +3,11 @@ use crate::ast::assemble_context::AssembleContext;
|
|||||||
use crate::ast::expression::Expression;
|
use crate::ast::expression::Expression;
|
||||||
use crate::constants_table::ConstantsTable;
|
use crate::constants_table::ConstantsTable;
|
||||||
use crate::diagnostic::Diagnostic;
|
use crate::diagnostic::Diagnostic;
|
||||||
|
use crate::symbol::FunctionSymbol;
|
||||||
use crate::symbol_table::SymbolTable;
|
use crate::symbol_table::SymbolTable;
|
||||||
use crate::type_info::TypeInfo;
|
use crate::type_info::TypeInfo;
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
pub struct ExpressionStatement {
|
pub struct ExpressionStatement {
|
||||||
expression: Box<Expression>,
|
expression: Box<Expression>,
|
||||||
@ -38,6 +41,7 @@ impl ExpressionStatement {
|
|||||||
context: &mut AssembleContext,
|
context: &mut AssembleContext,
|
||||||
symbol_table: &SymbolTable,
|
symbol_table: &SymbolTable,
|
||||||
constants_table: &mut ConstantsTable,
|
constants_table: &mut ConstantsTable,
|
||||||
|
outer_function_symbol: &Rc<RefCell<FunctionSymbol>>,
|
||||||
is_last: bool,
|
is_last: bool,
|
||||||
) {
|
) {
|
||||||
match self.expression.as_ref() {
|
match self.expression.as_ref() {
|
||||||
@ -57,7 +61,15 @@ impl ExpressionStatement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expression::Additive(additive) => {
|
Expression::Additive(additive) => {
|
||||||
additive.assemble(context, symbol_table, constants_table);
|
let result_register = additive.assemble(context, symbol_table, constants_table);
|
||||||
|
if is_last
|
||||||
|
&& !matches!(outer_function_symbol.borrow().return_type(), TypeInfo::Void)
|
||||||
|
{
|
||||||
|
// set return value
|
||||||
|
context.instruction(AsmInstruction::SetReturnValue(SetReturnValue::new(
|
||||||
|
result_register,
|
||||||
|
)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,7 +9,9 @@ use crate::source_range::SourceRange;
|
|||||||
use crate::symbol::FunctionSymbol;
|
use crate::symbol::FunctionSymbol;
|
||||||
use crate::symbol_table::{SymbolInsertError, SymbolTable};
|
use crate::symbol_table::{SymbolInsertError, SymbolTable};
|
||||||
use crate::type_info::TypeInfo;
|
use crate::type_info::TypeInfo;
|
||||||
|
use std::cell::RefCell;
|
||||||
use std::ops::Neg;
|
use std::ops::Neg;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
pub struct Function {
|
pub struct Function {
|
||||||
declared_name: String,
|
declared_name: String,
|
||||||
@ -17,6 +19,7 @@ pub struct Function {
|
|||||||
parameters: Vec<Parameter>,
|
parameters: Vec<Parameter>,
|
||||||
return_type: Option<TypeUse>,
|
return_type: Option<TypeUse>,
|
||||||
statements: Vec<Statement>,
|
statements: Vec<Statement>,
|
||||||
|
function_symbol: Option<Rc<RefCell<FunctionSymbol>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Function {
|
impl Function {
|
||||||
@ -33,6 +36,7 @@ impl Function {
|
|||||||
parameters,
|
parameters,
|
||||||
return_type,
|
return_type,
|
||||||
statements,
|
statements,
|
||||||
|
function_symbol: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,6 +81,9 @@ impl Function {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// save function symbol for later
|
||||||
|
self.function_symbol = Some(function_symbol.clone());
|
||||||
|
|
||||||
// handle parameters
|
// handle parameters
|
||||||
symbol_table.push_scope(&format!("parameter_scope({})", self.declared_name));
|
symbol_table.push_scope(&format!("parameter_scope({})", self.declared_name));
|
||||||
let mut parameter_symbols = vec![];
|
let mut parameter_symbols = vec![];
|
||||||
@ -159,9 +166,19 @@ impl Function {
|
|||||||
) {
|
) {
|
||||||
context.new_function(&self.declared_name, &self.declared_name_source_range);
|
context.new_function(&self.declared_name, &self.declared_name_source_range);
|
||||||
context.new_block(&format!("{}_enter", self.declared_name));
|
context.new_block(&format!("{}_enter", self.declared_name));
|
||||||
|
let function_symbol = self
|
||||||
|
.function_symbol
|
||||||
|
.as_ref()
|
||||||
|
.expect("function_symbol not initialized; did you type check yet?");
|
||||||
for (i, statement) in self.statements.iter().enumerate() {
|
for (i, statement) in self.statements.iter().enumerate() {
|
||||||
let is_last = i == self.statements.len() - 1;
|
let is_last = i == self.statements.len() - 1;
|
||||||
statement.assemble(context, symbol_table, constants_table, is_last);
|
statement.assemble(
|
||||||
|
context,
|
||||||
|
symbol_table,
|
||||||
|
constants_table,
|
||||||
|
function_symbol,
|
||||||
|
is_last,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
// return
|
// return
|
||||||
context.instruction(AsmInstruction::Return(Return::new(self.parameters.len())));
|
context.instruction(AsmInstruction::Return(Return::new(self.parameters.len())));
|
||||||
|
|||||||
@ -43,10 +43,8 @@ impl LetStatement {
|
|||||||
pub fn gather_declared_names(&mut self, symbol_table: &mut SymbolTable) -> Vec<Diagnostic> {
|
pub fn gather_declared_names(&mut self, symbol_table: &mut SymbolTable) -> Vec<Diagnostic> {
|
||||||
let mut diagnostics = vec![];
|
let mut diagnostics = vec![];
|
||||||
self.initializer_mut().gather_declared_names(symbol_table);
|
self.initializer_mut().gather_declared_names(symbol_table);
|
||||||
let insert_result = symbol_table.insert_variable_symbol(VariableSymbol::new(
|
let insert_result =
|
||||||
self.declared_name(),
|
symbol_table.insert_variable_symbol(VariableSymbol::new(self.declared_name()));
|
||||||
self.initializer().type_info().clone(),
|
|
||||||
));
|
|
||||||
if let Err(symbol_insert_error) = insert_result {
|
if let Err(symbol_insert_error) = insert_result {
|
||||||
match symbol_insert_error {
|
match symbol_insert_error {
|
||||||
SymbolInsertError::AlreadyDeclared(already_declared) => {
|
SymbolInsertError::AlreadyDeclared(already_declared) => {
|
||||||
@ -70,9 +68,17 @@ impl LetStatement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Vec<Diagnostic> {
|
pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Vec<Diagnostic> {
|
||||||
let mut diagnostics = vec![];
|
let initializer_diagnostics = self.initializer.type_check(symbol_table);
|
||||||
diagnostics.append(&mut self.initializer.type_check(symbol_table));
|
if !initializer_diagnostics.is_empty() {
|
||||||
diagnostics
|
return initializer_diagnostics;
|
||||||
|
}
|
||||||
|
let initializer_type_info = self.initializer.type_info();
|
||||||
|
let variable_symbol =
|
||||||
|
symbol_table.get_variable_symbol(self.scope_id.unwrap(), &self.declared_name);
|
||||||
|
variable_symbol
|
||||||
|
.borrow_mut()
|
||||||
|
.set_type_info(initializer_type_info);
|
||||||
|
vec![]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn assemble(
|
pub fn assemble(
|
||||||
|
|||||||
@ -3,7 +3,10 @@ use crate::ast::expression_statement::ExpressionStatement;
|
|||||||
use crate::ast::let_statement::LetStatement;
|
use crate::ast::let_statement::LetStatement;
|
||||||
use crate::constants_table::ConstantsTable;
|
use crate::constants_table::ConstantsTable;
|
||||||
use crate::diagnostic::Diagnostic;
|
use crate::diagnostic::Diagnostic;
|
||||||
|
use crate::symbol::FunctionSymbol;
|
||||||
use crate::symbol_table::SymbolTable;
|
use crate::symbol_table::SymbolTable;
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
pub enum Statement {
|
pub enum Statement {
|
||||||
Let(LetStatement),
|
Let(LetStatement),
|
||||||
@ -43,6 +46,7 @@ impl Statement {
|
|||||||
context: &mut AssembleContext,
|
context: &mut AssembleContext,
|
||||||
symbol_table: &SymbolTable,
|
symbol_table: &SymbolTable,
|
||||||
constants_table: &mut ConstantsTable,
|
constants_table: &mut ConstantsTable,
|
||||||
|
outer_function_symbol: &Rc<RefCell<FunctionSymbol>>,
|
||||||
is_last: bool,
|
is_last: bool,
|
||||||
) {
|
) {
|
||||||
match self {
|
match self {
|
||||||
@ -50,7 +54,13 @@ impl Statement {
|
|||||||
let_statement.assemble(context, symbol_table, constants_table);
|
let_statement.assemble(context, symbol_table, constants_table);
|
||||||
}
|
}
|
||||||
Statement::Expression(expression_statement) => {
|
Statement::Expression(expression_statement) => {
|
||||||
expression_statement.assemble(context, symbol_table, constants_table, is_last);
|
expression_statement.assemble(
|
||||||
|
context,
|
||||||
|
symbol_table,
|
||||||
|
constants_table,
|
||||||
|
outer_function_symbol,
|
||||||
|
is_last,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -82,15 +82,15 @@ impl ParameterSymbol {
|
|||||||
|
|
||||||
pub struct VariableSymbol {
|
pub struct VariableSymbol {
|
||||||
name: Rc<str>,
|
name: Rc<str>,
|
||||||
type_info: TypeInfo,
|
type_info: Option<TypeInfo>,
|
||||||
register: Option<usize>,
|
register: Option<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VariableSymbol {
|
impl VariableSymbol {
|
||||||
pub fn new(name: &str, type_info: TypeInfo) -> Self {
|
pub fn new(name: &str) -> Self {
|
||||||
Self {
|
Self {
|
||||||
name: name.into(),
|
name: name.into(),
|
||||||
type_info,
|
type_info: None,
|
||||||
register: None,
|
register: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -103,8 +103,14 @@ impl VariableSymbol {
|
|||||||
self.name.clone()
|
self.name.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_type_info(&mut self, type_info: TypeInfo) {
|
||||||
|
self.type_info = Some(type_info);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn type_info(&self) -> &TypeInfo {
|
pub fn type_info(&self) -> &TypeInfo {
|
||||||
&self.type_info
|
self.type_info
|
||||||
|
.as_ref()
|
||||||
|
.expect("TypeInfo not initialized. Did you type check?")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_register(&mut self, register: usize) {
|
pub fn set_register(&mut self, register: usize) {
|
||||||
|
|||||||
@ -180,6 +180,11 @@ pub fn call<'a>(
|
|||||||
function_name: &str,
|
function_name: &str,
|
||||||
arguments: Vec<Value>,
|
arguments: Vec<Value>,
|
||||||
) -> Option<Value> {
|
) -> Option<Value> {
|
||||||
|
// check if DVM_DEBUG is enabled
|
||||||
|
let debug = std::env::var("DVM_DEBUG")
|
||||||
|
.map(|s| s.eq("1"))
|
||||||
|
.unwrap_or(false);
|
||||||
|
|
||||||
let function = context
|
let function = context
|
||||||
.functions
|
.functions
|
||||||
.get(function_name)
|
.get(function_name)
|
||||||
@ -203,7 +208,9 @@ pub fn call<'a>(
|
|||||||
&& call_stack.top().ip() < call_stack.top().instructions().len()
|
&& call_stack.top().ip() < call_stack.top().instructions().len()
|
||||||
{
|
{
|
||||||
let instruction = &call_stack.top().instructions()[call_stack.top().ip()];
|
let instruction = &call_stack.top().instructions()[call_stack.top().ip()];
|
||||||
// println!("{}", instruction);
|
if debug {
|
||||||
|
println!("{}", instruction);
|
||||||
|
}
|
||||||
|
|
||||||
match instruction {
|
match instruction {
|
||||||
/* Move instructions */
|
/* Move instructions */
|
||||||
@ -361,13 +368,14 @@ pub fn call<'a>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
Instruction::Return(caller_pop_count) => {
|
Instruction::Return(caller_pop_count) => {
|
||||||
call_stack.pop(); // pop this frame
|
let mut callee = call_stack.pop(); // pop this frame
|
||||||
let maybe_caller = call_stack.maybe_top_mut();
|
let maybe_caller = call_stack.maybe_top_mut();
|
||||||
if let Some(caller) = maybe_caller {
|
if let Some(caller) = maybe_caller {
|
||||||
for _ in 0..*caller_pop_count {
|
for _ in 0..*caller_pop_count {
|
||||||
caller.stack_mut().pop();
|
caller.stack_mut().pop();
|
||||||
}
|
}
|
||||||
if let Some(return_value) = caller.take_return_value() {
|
if let Some(return_value) = callee.take_return_value() {
|
||||||
|
// n.b. callee
|
||||||
caller.stack_mut().push(return_value);
|
caller.stack_mut().push(return_value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -375,11 +383,13 @@ pub fn call<'a>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if let Some(top) = call_stack.maybe_top() {
|
if debug {
|
||||||
// println!(" stack: {:?}", top.stack());
|
if let Some(top) = call_stack.maybe_top() {
|
||||||
// println!(" registers: {:?}", registers);
|
println!(" stack: {:?}", top.stack());
|
||||||
// println!(" rv: {:?}", top.return_value());
|
println!(" registers: {:?}", registers);
|
||||||
// }
|
println!(" rv: {:?}", top.return_value());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
None // todo: returning results from main functions
|
None // todo: returning results from main functions
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,12 +1,11 @@
|
|||||||
extern fn println(message: Any) -> Void
|
extern fn println(message: Any) -> Void
|
||||||
|
|
||||||
fn add(a: Int, b: Int) -> Void
|
fn add(a: Int, b: Int) -> Int
|
||||||
println(a + b)
|
a + b
|
||||||
end
|
end
|
||||||
|
|
||||||
fn main()
|
fn main()
|
||||||
let x = 1 + 2 + 3
|
let y = add(1, 2)
|
||||||
add(x, 1)
|
println(y)
|
||||||
add(x, 2)
|
println(add(3, add(4, 5)))
|
||||||
add(21, 21)
|
|
||||||
end
|
end
|
||||||
Loading…
Reference in New Issue
Block a user