Compare commits
4 Commits
916b6377ac
...
c5781114a5
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c5781114a5 | ||
|
|
655a0288d3 | ||
|
|
53ec6a8f4f | ||
|
|
41e798d8a6 |
@ -4,6 +4,7 @@ mod run;
|
|||||||
use crate::repl::repl;
|
use crate::repl::repl;
|
||||||
use crate::run::compile_and_run_script;
|
use crate::run::compile_and_run_script;
|
||||||
use clap::{Parser, Subcommand};
|
use clap::{Parser, Subcommand};
|
||||||
|
use std::io;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
#[derive(Debug, Parser)]
|
#[derive(Debug, Parser)]
|
||||||
@ -23,29 +24,27 @@ enum SubCommand {
|
|||||||
|
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
show_ir: bool,
|
show_ir: bool,
|
||||||
|
|
||||||
#[arg(long, default_value = "8")]
|
|
||||||
register_count: usize,
|
|
||||||
},
|
|
||||||
Repl {
|
|
||||||
#[arg(long, default_value = "8")]
|
|
||||||
register_count: usize,
|
|
||||||
},
|
},
|
||||||
|
Repl,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
let register_count = std::env::var("DVM_REGISTER_COUNT")
|
||||||
|
.map(|v| v.parse::<usize>())
|
||||||
|
.unwrap_or(Ok(8))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let args = Cli::parse();
|
let args = Cli::parse();
|
||||||
match &args.sub_command {
|
match &args.sub_command {
|
||||||
SubCommand::Run {
|
SubCommand::Run {
|
||||||
script,
|
script,
|
||||||
show_asm,
|
show_asm,
|
||||||
show_ir,
|
show_ir,
|
||||||
register_count,
|
|
||||||
} => {
|
} => {
|
||||||
compile_and_run_script(script, *show_asm, *show_ir, *register_count);
|
compile_and_run_script(script, *show_asm, *show_ir, register_count);
|
||||||
}
|
}
|
||||||
SubCommand::Repl { register_count } => {
|
SubCommand::Repl => {
|
||||||
repl(*register_count);
|
repl(&mut io::stdin().lock(), register_count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
206
dm/src/repl.rs
206
dm/src/repl.rs
@ -4,28 +4,44 @@ use dmc_lib::diagnostic::Diagnostic;
|
|||||||
use dmc_lib::ir::ir_function::IrFunction;
|
use dmc_lib::ir::ir_function::IrFunction;
|
||||||
use dmc_lib::ir::ir_return::IrReturn;
|
use dmc_lib::ir::ir_return::IrReturn;
|
||||||
use dmc_lib::ir::ir_statement::IrStatement;
|
use dmc_lib::ir::ir_statement::IrStatement;
|
||||||
|
use dmc_lib::ir::ir_variable::IrVariable;
|
||||||
use dmc_lib::lexer::Lexer;
|
use dmc_lib::lexer::Lexer;
|
||||||
use dmc_lib::parser::parse_expression;
|
use dmc_lib::offset_counter::OffsetCounter;
|
||||||
|
use dmc_lib::parser::{parse_expression, parse_let_statement};
|
||||||
|
use dmc_lib::symbol::variable_symbol::VariableSymbol;
|
||||||
use dmc_lib::symbol_table::SymbolTable;
|
use dmc_lib::symbol_table::SymbolTable;
|
||||||
use dmc_lib::token::TokenKind;
|
use dmc_lib::token::TokenKind;
|
||||||
|
use dmc_lib::type_info::TypeInfo;
|
||||||
use dmc_lib::types_table::TypesTable;
|
use dmc_lib::types_table::TypesTable;
|
||||||
use dvm_lib::vm::constant::{Constant, StringConstant};
|
use dvm_lib::vm::constant::{Constant, StringConstant};
|
||||||
use dvm_lib::vm::function::Function;
|
use dvm_lib::vm::function::Function;
|
||||||
use dvm_lib::vm::operand::Operand;
|
use dvm_lib::vm::operand::Operand;
|
||||||
use dvm_lib::vm::{CallStack, DvmContext, call};
|
use dvm_lib::vm::{CallStack, DvmContext, loop_instructions, prepare_for_instruction_loop};
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::io::Write;
|
use std::io::{BufRead, Write};
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
pub fn repl(register_count: usize) {
|
pub fn repl(read: &mut impl BufRead, register_count: usize) {
|
||||||
let mut buffer = String::new();
|
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 constants_table = ConstantsTable::new();
|
||||||
let mut context = DvmContext::new();
|
let mut context = DvmContext::new();
|
||||||
|
|
||||||
|
let mut repl_fn_stack_locals: Vec<Operand> = vec![];
|
||||||
|
|
||||||
'repl: loop {
|
'repl: loop {
|
||||||
print!("> ");
|
print!("> ");
|
||||||
io::stdout().flush().unwrap();
|
io::stdout().flush().unwrap();
|
||||||
io::stdin().read_line(&mut buffer).unwrap();
|
read.read_line(&mut buffer).unwrap();
|
||||||
let input = buffer.trim();
|
let input = buffer.trim();
|
||||||
if input.is_empty() {
|
if input.is_empty() {
|
||||||
buffer.clear();
|
buffer.clear();
|
||||||
@ -52,9 +68,40 @@ pub fn repl(register_count: usize) {
|
|||||||
todo!("Parse functions in repl")
|
todo!("Parse functions in repl")
|
||||||
}
|
}
|
||||||
TokenKind::Let => {
|
TokenKind::Let => {
|
||||||
todo!("Parse let statements in repl")
|
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 constants_table) {
|
_ => 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) => {
|
Ok(function) => {
|
||||||
context
|
context
|
||||||
.functions_mut()
|
.functions_mut()
|
||||||
@ -63,9 +110,9 @@ pub fn repl(register_count: usize) {
|
|||||||
Err(diagnostics) => {
|
Err(diagnostics) => {
|
||||||
for diagnostic in &diagnostics {
|
for diagnostic in &diagnostics {
|
||||||
eprintln!("{}", diagnostic.message());
|
eprintln!("{}", diagnostic.message());
|
||||||
buffer.clear();
|
|
||||||
continue 'repl;
|
|
||||||
}
|
}
|
||||||
|
buffer.clear();
|
||||||
|
continue 'repl;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -77,10 +124,25 @@ pub fn repl(register_count: usize) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut registers = vec![Operand::Null; register_count];
|
|
||||||
let mut call_stack = CallStack::new();
|
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());
|
||||||
|
|
||||||
let result = call(&context, &mut registers, &mut call_stack, "__repl", &[]);
|
|
||||||
if let Some(value) = result {
|
if let Some(value) = result {
|
||||||
println!("{}", value);
|
println!("{}", value);
|
||||||
}
|
}
|
||||||
@ -89,35 +151,58 @@ pub fn repl(register_count: usize) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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(
|
fn compile_expression(
|
||||||
input: &str,
|
input: &str,
|
||||||
register_count: usize,
|
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,
|
constants_table: &mut ConstantsTable,
|
||||||
) -> Result<Function, Vec<Diagnostic>> {
|
) -> Result<Function, Vec<Diagnostic>> {
|
||||||
let parse_result = parse_expression(input);
|
// parse
|
||||||
let mut expression = parse_result?;
|
let mut expression = parse_expression(input)?;
|
||||||
|
|
||||||
let mut symbol_table = SymbolTable::new();
|
// init scopes, if necessary
|
||||||
let mut types_table = TypesTable::new();
|
let container_scope = prepare_scopes(symbol_table, fn_body_scope_id);
|
||||||
|
|
||||||
// "fake" scopes
|
// inner scopes
|
||||||
symbol_table.push_module_scope("__repl_module");
|
expression.init_scopes(symbol_table, container_scope);
|
||||||
let function_scope_id = symbol_table.push_function_scope("__repl_function");
|
|
||||||
|
|
||||||
expression.init_scopes(&mut symbol_table, function_scope_id);
|
|
||||||
|
|
||||||
symbol_table.pop_scope(); // function
|
|
||||||
symbol_table.pop_scope(); // module
|
|
||||||
|
|
||||||
|
// names
|
||||||
let diagnostics = expression.check_static_fn_local_names(&symbol_table);
|
let diagnostics = expression.check_static_fn_local_names(&symbol_table);
|
||||||
if !diagnostics.is_empty() {
|
if !diagnostics.is_empty() {
|
||||||
return Err(diagnostics);
|
return Err(diagnostics);
|
||||||
}
|
}
|
||||||
|
|
||||||
expression.type_check(&symbol_table, &mut types_table)?;
|
// type check
|
||||||
|
expression.type_check(&symbol_table, types_table)?;
|
||||||
|
|
||||||
// synthesize a function
|
// synthesize a function
|
||||||
|
// init ir_builder
|
||||||
let mut ir_builder = IrBuilder::new();
|
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 entry_block_id = ir_builder.new_block();
|
||||||
|
|
||||||
let maybe_ir_expression =
|
let maybe_ir_expression =
|
||||||
@ -138,6 +223,75 @@ fn compile_expression(
|
|||||||
entry_block.clone(),
|
entry_block.clone(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let (_, stack_size) = ir_function.assign_registers(register_count);
|
// spilled registers are put on the stack, so we need to add it to our stack size
|
||||||
Ok(ir_function.assemble(stack_size, constants_table))
|
ir_function.assign_registers(register_count, offset_counter);
|
||||||
|
|
||||||
|
Ok(ir_function.assemble(offset_counter.get_count(), constants_table))
|
||||||
|
}
|
||||||
|
|
||||||
|
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 mut let_statement = parse_let_statement(input)?;
|
||||||
|
|
||||||
|
// 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))
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,13 +6,13 @@ use dm_std_lib::add_all_std_core;
|
|||||||
use dmc_lib::constants_table::ConstantsTable;
|
use dmc_lib::constants_table::ConstantsTable;
|
||||||
use dmc_lib::diagnostic::Diagnostic;
|
use dmc_lib::diagnostic::Diagnostic;
|
||||||
use dmc_lib::intrinsics::{insert_intrinsic_symbols, insert_intrinsic_types};
|
use dmc_lib::intrinsics::{insert_intrinsic_symbols, insert_intrinsic_types};
|
||||||
|
use dmc_lib::offset_counter::OffsetCounter;
|
||||||
use dmc_lib::parser::parse_compilation_unit;
|
use dmc_lib::parser::parse_compilation_unit;
|
||||||
use dmc_lib::symbol_table::SymbolTable;
|
use dmc_lib::symbol_table::SymbolTable;
|
||||||
use dmc_lib::types_table::TypesTable;
|
use dmc_lib::types_table::TypesTable;
|
||||||
use dvm_lib::vm::constant::{Constant, StringConstant};
|
use dvm_lib::vm::constant::{Constant, StringConstant};
|
||||||
use dvm_lib::vm::function::Function;
|
use dvm_lib::vm::function::Function;
|
||||||
use dvm_lib::vm::operand::Operand;
|
use dvm_lib::vm::{DvmContext, call};
|
||||||
use dvm_lib::vm::{CallStack, DvmContext, call};
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
@ -67,8 +67,9 @@ fn run(
|
|||||||
let mut constants_table = ConstantsTable::new();
|
let mut constants_table = ConstantsTable::new();
|
||||||
|
|
||||||
for ir_function in &mut ir_functions {
|
for ir_function in &mut ir_functions {
|
||||||
let (_, stack_size) = ir_function.assign_registers(register_count);
|
let mut offset_counter = OffsetCounter::new();
|
||||||
let function = ir_function.assemble(stack_size, &mut constants_table);
|
ir_function.assign_registers(register_count, &mut offset_counter);
|
||||||
|
let function = ir_function.assemble(offset_counter.get_count(), &mut constants_table);
|
||||||
functions.push(function);
|
functions.push(function);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -107,16 +108,8 @@ fn run(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut registers: Vec<Operand> = vec![Operand::Null; register_count];
|
let result = call(&dvm_context, "main", &vec![], 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 {
|
if let Some(value) = result {
|
||||||
println!("{}", value);
|
println!("{}", value);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,7 +8,7 @@ use crate::ir::ir_class::IrClass;
|
|||||||
use crate::ir::ir_function::IrFunction;
|
use crate::ir::ir_function::IrFunction;
|
||||||
use crate::symbol_table::SymbolTable;
|
use crate::symbol_table::SymbolTable;
|
||||||
use crate::types_table::TypesTable;
|
use crate::types_table::TypesTable;
|
||||||
use crate::{diagnostics_result, handle_diagnostics, ok_or_err_diagnostics};
|
use crate::{diagnostics_result, handle_diagnostics};
|
||||||
|
|
||||||
pub struct CompilationUnit {
|
pub struct CompilationUnit {
|
||||||
functions: Vec<Function>,
|
functions: Vec<Function>,
|
||||||
|
|||||||
@ -10,6 +10,7 @@ use crate::symbol::Symbol;
|
|||||||
use crate::symbol::class_symbol::ClassSymbol;
|
use crate::symbol::class_symbol::ClassSymbol;
|
||||||
use crate::symbol::variable_symbol::VariableSymbol;
|
use crate::symbol::variable_symbol::VariableSymbol;
|
||||||
use crate::symbol_table::SymbolTable;
|
use crate::symbol_table::SymbolTable;
|
||||||
|
use crate::type_info::TypeInfo;
|
||||||
use crate::types_table::TypesTable;
|
use crate::types_table::TypesTable;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
@ -55,6 +56,10 @@ impl LetStatement {
|
|||||||
self.initializer.init_scopes(symbol_table, container_scope);
|
self.initializer.init_scopes(symbol_table, container_scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn scope_id(&self) -> usize {
|
||||||
|
self.scope_id.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
fn make_and_insert_variable_symbol(
|
fn make_and_insert_variable_symbol(
|
||||||
&self,
|
&self,
|
||||||
symbol_table: &mut SymbolTable,
|
symbol_table: &mut SymbolTable,
|
||||||
@ -131,6 +136,7 @@ impl LetStatement {
|
|||||||
types_table: &mut TypesTable,
|
types_table: &mut TypesTable,
|
||||||
) -> Result<(), Vec<Diagnostic>> {
|
) -> Result<(), Vec<Diagnostic>> {
|
||||||
self.initializer.type_check(symbol_table, types_table)?;
|
self.initializer.type_check(symbol_table, types_table)?;
|
||||||
|
// TODO: this is wrong. We need to check assignability
|
||||||
let initializer_type_info = self
|
let initializer_type_info = self
|
||||||
.initializer
|
.initializer
|
||||||
.type_info(symbol_table, types_table)
|
.type_info(symbol_table, types_table)
|
||||||
@ -144,6 +150,34 @@ impl LetStatement {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn make_vr_variable(&self, builder: &mut IrBuilder, destination_type: &TypeInfo) -> IrVariable {
|
||||||
|
IrVariable::new_vr(
|
||||||
|
self.declared_name().into(),
|
||||||
|
builder.current_block().id(),
|
||||||
|
destination_type,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make_stack_variable(
|
||||||
|
&self,
|
||||||
|
builder: &mut IrBuilder,
|
||||||
|
destination_type: &TypeInfo,
|
||||||
|
offset: isize,
|
||||||
|
) -> IrVariable {
|
||||||
|
IrVariable::new_stack_with_offset(
|
||||||
|
self.declared_name().into(),
|
||||||
|
builder.current_block().id(),
|
||||||
|
destination_type,
|
||||||
|
offset,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_destination_symbol(&self, symbol_table: &SymbolTable) -> Rc<VariableSymbol> {
|
||||||
|
symbol_table
|
||||||
|
.get_variable_symbol_owned(self.scope_id.unwrap(), &self.declared_name)
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn to_ir(
|
pub fn to_ir(
|
||||||
&self,
|
&self,
|
||||||
builder: &mut IrBuilder,
|
builder: &mut IrBuilder,
|
||||||
@ -154,20 +188,14 @@ impl LetStatement {
|
|||||||
.initializer
|
.initializer
|
||||||
.to_ir_operation(builder, symbol_table, types_table);
|
.to_ir_operation(builder, symbol_table, types_table);
|
||||||
|
|
||||||
let destination_symbol = symbol_table
|
let destination_symbol = self.get_destination_symbol(symbol_table);
|
||||||
.get_variable_symbol_owned(self.scope_id.unwrap(), &self.declared_name)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let destination_type = types_table
|
let destination_type = types_table
|
||||||
.variable_types()
|
.variable_types()
|
||||||
.get(&destination_symbol)
|
.get(&destination_symbol)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let destination_vr_variable = IrVariable::new_vr(
|
let destination_vr_variable = self.make_vr_variable(builder, destination_type);
|
||||||
self.declared_name().into(),
|
|
||||||
builder.current_block().id(),
|
|
||||||
destination_type,
|
|
||||||
);
|
|
||||||
|
|
||||||
let as_rc = Rc::new(RefCell::new(destination_vr_variable));
|
let as_rc = Rc::new(RefCell::new(destination_vr_variable));
|
||||||
let ir_assign = IrAssign::new(as_rc.clone(), init_operation);
|
let ir_assign = IrAssign::new(as_rc.clone(), init_operation);
|
||||||
@ -180,4 +208,30 @@ impl LetStatement {
|
|||||||
.current_block_mut()
|
.current_block_mut()
|
||||||
.add_statement(IrStatement::Assign(ir_assign));
|
.add_statement(IrStatement::Assign(ir_assign));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn to_repl_ir(
|
||||||
|
&self,
|
||||||
|
builder: &mut IrBuilder,
|
||||||
|
symbol_table: &SymbolTable,
|
||||||
|
types_table: &TypesTable,
|
||||||
|
destination_stack_offset: isize,
|
||||||
|
) -> Rc<RefCell<IrVariable>> {
|
||||||
|
let init_operation = self
|
||||||
|
.initializer
|
||||||
|
.to_ir_operation(builder, symbol_table, types_table);
|
||||||
|
let destination_symbol = self.get_destination_symbol(symbol_table);
|
||||||
|
let destination_type = types_table
|
||||||
|
.variable_types()
|
||||||
|
.get(&destination_symbol)
|
||||||
|
.unwrap();
|
||||||
|
let destination_stack_variable =
|
||||||
|
self.make_stack_variable(builder, destination_type, destination_stack_offset);
|
||||||
|
let as_rc = Rc::new(RefCell::new(destination_stack_variable));
|
||||||
|
let ir_assign = IrAssign::new(as_rc.clone(), init_operation);
|
||||||
|
// do not need to save variable to builder as a new one is created for each repl function
|
||||||
|
builder
|
||||||
|
.current_block_mut()
|
||||||
|
.add_statement(IrStatement::Assign(ir_assign));
|
||||||
|
as_rc
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
pub type Diagnostics = Vec<Diagnostic>;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Diagnostic {
|
pub struct Diagnostic {
|
||||||
message: String,
|
message: String,
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
pub type ErrorCode = usize;
|
pub type ErrorCode = usize;
|
||||||
|
|
||||||
|
pub const LEXER_ERROR: ErrorCode = 1;
|
||||||
|
pub const PARSE_ERROR: ErrorCode = 2;
|
||||||
pub const SYMBOL_NOT_FOUND: ErrorCode = 13;
|
pub const SYMBOL_NOT_FOUND: ErrorCode = 13;
|
||||||
pub const SYMBOL_ALREADY_DECLARED: ErrorCode = 14;
|
pub const SYMBOL_ALREADY_DECLARED: ErrorCode = 14;
|
||||||
pub const BINARY_INCOMPATIBLE_TYPES: ErrorCode = 15;
|
pub const BINARY_INCOMPATIBLE_TYPES: ErrorCode = 15;
|
||||||
|
|||||||
@ -2,8 +2,9 @@ use crate::constants_table::ConstantsTable;
|
|||||||
use crate::ir::assemble::{Assemble, InstructionsBuilder};
|
use crate::ir::assemble::{Assemble, InstructionsBuilder};
|
||||||
use crate::ir::ir_operation::IrOperation;
|
use crate::ir::ir_operation::IrOperation;
|
||||||
use crate::ir::ir_variable::{IrVariable, IrVariableDescriptor, IrVrVariableDescriptor};
|
use crate::ir::ir_variable::{IrVariable, IrVariableDescriptor, IrVrVariableDescriptor};
|
||||||
use crate::ir::register_allocation::{OffsetCounter, VrUser};
|
use crate::ir::register_allocation::VrUser;
|
||||||
use crate::ir::util::propagate_spills;
|
use crate::ir::util::propagate_spills;
|
||||||
|
use crate::offset_counter::OffsetCounter;
|
||||||
use dvm_lib::instruction::Instruction;
|
use dvm_lib::instruction::Instruction;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
@ -57,7 +58,7 @@ impl VrUser for IrAssign {
|
|||||||
fn propagate_stack_offsets(&mut self, counter: &mut OffsetCounter) {
|
fn propagate_stack_offsets(&mut self, counter: &mut OffsetCounter) {
|
||||||
let mut borrowed_destination = self.destination.borrow_mut();
|
let mut borrowed_destination = self.destination.borrow_mut();
|
||||||
if let IrVariableDescriptor::Stack(stack_variable) = borrowed_destination.descriptor_mut() {
|
if let IrVariableDescriptor::Stack(stack_variable) = borrowed_destination.descriptor_mut() {
|
||||||
stack_variable.set_offset(counter.next());
|
stack_variable.use_next_offset(counter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,7 +2,8 @@ use crate::constants_table::ConstantsTable;
|
|||||||
use crate::ir::assemble::{Assemble, InstructionsBuilder};
|
use crate::ir::assemble::{Assemble, InstructionsBuilder};
|
||||||
use crate::ir::ir_statement::IrStatement;
|
use crate::ir::ir_statement::IrStatement;
|
||||||
use crate::ir::ir_variable::IrVrVariableDescriptor;
|
use crate::ir::ir_variable::IrVrVariableDescriptor;
|
||||||
use crate::ir::register_allocation::{HasVrUsers, OffsetCounter, VrUser};
|
use crate::ir::register_allocation::{HasVrUsers, VrUser};
|
||||||
|
use crate::offset_counter::OffsetCounter;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::fmt::{Display, Formatter};
|
use std::fmt::{Display, Formatter};
|
||||||
@ -122,6 +123,7 @@ impl Display for IrBlock {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::diagnostic::Diagnostic;
|
use crate::diagnostic::Diagnostic;
|
||||||
|
use crate::offset_counter::OffsetCounter;
|
||||||
use crate::parser::parse_compilation_unit;
|
use crate::parser::parse_compilation_unit;
|
||||||
use crate::symbol_table::SymbolTable;
|
use crate::symbol_table::SymbolTable;
|
||||||
use crate::types_table::TypesTable;
|
use crate::types_table::TypesTable;
|
||||||
@ -155,7 +157,7 @@ mod tests {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let mut main_ir = main.to_ir(&symbol_table, &types_table, None);
|
let mut main_ir = main.to_ir(&symbol_table, &types_table, None);
|
||||||
let (register_assignments, _) = main_ir.assign_registers(2);
|
let register_assignments = main_ir.assign_registers(2, &mut OffsetCounter::new());
|
||||||
assert_eq!(register_assignments.len(), 4);
|
assert_eq!(register_assignments.len(), 4);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@ -4,6 +4,7 @@ use crate::ir::ir_block::IrBlock;
|
|||||||
use crate::ir::ir_parameter::IrParameter;
|
use crate::ir::ir_parameter::IrParameter;
|
||||||
use crate::ir::ir_variable::IrVrVariableDescriptor;
|
use crate::ir::ir_variable::IrVrVariableDescriptor;
|
||||||
use crate::ir::register_allocation::HasVrUsers;
|
use crate::ir::register_allocation::HasVrUsers;
|
||||||
|
use crate::offset_counter::OffsetCounter;
|
||||||
use crate::type_info::TypeInfo;
|
use crate::type_info::TypeInfo;
|
||||||
use dvm_lib::vm::function::Function;
|
use dvm_lib::vm::function::Function;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
@ -36,11 +37,14 @@ impl IrFunction {
|
|||||||
pub fn assign_registers(
|
pub fn assign_registers(
|
||||||
&mut self,
|
&mut self,
|
||||||
register_count: usize,
|
register_count: usize,
|
||||||
) -> (HashMap<IrVrVariableDescriptor, usize>, isize) {
|
offset_counter: &mut OffsetCounter,
|
||||||
self.entry.borrow_mut().assign_registers(register_count)
|
) -> HashMap<IrVrVariableDescriptor, usize> {
|
||||||
|
self.entry
|
||||||
|
.borrow_mut()
|
||||||
|
.assign_registers(register_count, offset_counter)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn assemble(&self, stack_size: isize, constants_table: &mut ConstantsTable) -> Function {
|
pub fn assemble(&self, stack_size: usize, constants_table: &mut ConstantsTable) -> Function {
|
||||||
let mut builder = InstructionsBuilder::new();
|
let mut builder = InstructionsBuilder::new();
|
||||||
self.entry.borrow().assemble(&mut builder, constants_table);
|
self.entry.borrow().assemble(&mut builder, constants_table);
|
||||||
let instructions = builder.take_instructions();
|
let instructions = builder.take_instructions();
|
||||||
|
|||||||
@ -5,7 +5,8 @@ use crate::ir::ir_call::IrCall;
|
|||||||
use crate::ir::ir_return::IrReturn;
|
use crate::ir::ir_return::IrReturn;
|
||||||
use crate::ir::ir_set_field::IrSetField;
|
use crate::ir::ir_set_field::IrSetField;
|
||||||
use crate::ir::ir_variable::IrVrVariableDescriptor;
|
use crate::ir::ir_variable::IrVrVariableDescriptor;
|
||||||
use crate::ir::register_allocation::{OffsetCounter, VrUser};
|
use crate::ir::register_allocation::VrUser;
|
||||||
|
use crate::offset_counter::OffsetCounter;
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::fmt::{Display, Formatter};
|
use std::fmt::{Display, Formatter};
|
||||||
|
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
use crate::offset_counter::OffsetCounter;
|
||||||
use crate::type_info::TypeInfo;
|
use crate::type_info::TypeInfo;
|
||||||
use dvm_lib::instruction::Location;
|
use dvm_lib::instruction::Location;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
@ -20,9 +21,16 @@ impl IrVariable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_stack(name: Rc<str>, block_id: usize, type_info: TypeInfo) -> Self {
|
pub fn new_stack_with_offset(
|
||||||
|
name: Rc<str>,
|
||||||
|
block_id: usize,
|
||||||
|
type_info: &TypeInfo,
|
||||||
|
offset: isize,
|
||||||
|
) -> Self {
|
||||||
|
let mut descriptor = IrStackVariableDescriptor::new(name, block_id);
|
||||||
|
descriptor.set_offset(offset);
|
||||||
Self {
|
Self {
|
||||||
descriptor: IrVariableDescriptor::Stack(IrStackVariableDescriptor::new(name, block_id)),
|
descriptor: IrVariableDescriptor::Stack(descriptor),
|
||||||
type_info: type_info.clone(),
|
type_info: type_info.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -177,6 +185,12 @@ impl IrStackVariableDescriptor {
|
|||||||
self.name.clone()
|
self.name.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn use_next_offset(&mut self, offset_counter: &mut OffsetCounter) {
|
||||||
|
if self.offset.is_none() {
|
||||||
|
self.offset = Some(offset_counter.next() as isize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_offset(&mut self, offset: isize) {
|
pub fn set_offset(&mut self, offset: isize) {
|
||||||
self.offset = Some(offset);
|
self.offset = Some(offset);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
use crate::ir::ir_variable::IrVrVariableDescriptor;
|
use crate::ir::ir_variable::IrVrVariableDescriptor;
|
||||||
|
use crate::offset_counter::OffsetCounter;
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
|
|
||||||
pub type InterferenceGraph = HashMap<IrVrVariableDescriptor, HashSet<IrVrVariableDescriptor>>;
|
pub type InterferenceGraph = HashMap<IrVrVariableDescriptor, HashSet<IrVrVariableDescriptor>>;
|
||||||
@ -104,7 +105,8 @@ pub trait HasVrUsers {
|
|||||||
fn assign_registers(
|
fn assign_registers(
|
||||||
&mut self,
|
&mut self,
|
||||||
register_count: usize,
|
register_count: usize,
|
||||||
) -> (HashMap<IrVrVariableDescriptor, usize>, isize) {
|
offset_counter: &mut OffsetCounter,
|
||||||
|
) -> HashMap<IrVrVariableDescriptor, usize> {
|
||||||
let mut spills: HashSet<IrVrVariableDescriptor> = HashSet::new();
|
let mut spills: HashSet<IrVrVariableDescriptor> = HashSet::new();
|
||||||
loop {
|
loop {
|
||||||
let mut interference_graph = self.interference_graph();
|
let mut interference_graph = self.interference_graph();
|
||||||
@ -123,12 +125,11 @@ pub trait HasVrUsers {
|
|||||||
vr_user.propagate_register_assignments(®isters);
|
vr_user.propagate_register_assignments(®isters);
|
||||||
}
|
}
|
||||||
// also set offsets
|
// also set offsets
|
||||||
let mut offset_counter = OffsetCounter::new();
|
|
||||||
for vr_user in self.vr_users_mut() {
|
for vr_user in self.vr_users_mut() {
|
||||||
vr_user.propagate_stack_offsets(&mut offset_counter);
|
vr_user.propagate_stack_offsets(offset_counter);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (registers, offset_counter.get_count());
|
return registers;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -157,26 +158,6 @@ pub trait VrUser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct OffsetCounter {
|
|
||||||
counter: isize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl OffsetCounter {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self { counter: 0 }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn next(&mut self) -> isize {
|
|
||||||
let offset = self.counter;
|
|
||||||
self.counter += 1;
|
|
||||||
offset
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_count(&self) -> isize {
|
|
||||||
self.counter
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct WorkItem {
|
struct WorkItem {
|
||||||
vr: IrVrVariableDescriptor,
|
vr: IrVrVariableDescriptor,
|
||||||
|
|||||||
@ -34,134 +34,133 @@ impl<'a> Lexer<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let token = if chunk.starts_with("->") {
|
let mut chars = chunk.chars();
|
||||||
Token::new(self.position, self.position + 2, TokenKind::RightArrow)
|
let current = chars.next().unwrap(); // safe because we return None if chunk is empty above
|
||||||
} else if chunk.starts_with("-") {
|
let peek = chars.next();
|
||||||
Token::new(self.position, self.position + 1, TokenKind::Minus)
|
|
||||||
} else if chunk.starts_with("(") {
|
|
||||||
Token::new(self.position, self.position + 1, TokenKind::LeftParentheses)
|
|
||||||
} else if chunk.starts_with(")") {
|
|
||||||
Token::new(
|
|
||||||
self.position,
|
|
||||||
self.position + 1,
|
|
||||||
TokenKind::RightParentheses,
|
|
||||||
)
|
|
||||||
} else if chunk.starts_with("*") {
|
|
||||||
Token::new(self.position, self.position + 1, TokenKind::Star)
|
|
||||||
} else if chunk.starts_with("/") {
|
|
||||||
Token::new(self.position, self.position + 1, TokenKind::Slash)
|
|
||||||
} else if chunk.starts_with("%") {
|
|
||||||
Token::new(self.position, self.position + 1, TokenKind::Modulo)
|
|
||||||
} else if chunk.starts_with("+") {
|
|
||||||
Token::new(self.position, self.position + 1, TokenKind::Plus)
|
|
||||||
} else if chunk.starts_with("&") {
|
|
||||||
Token::new(self.position, self.position + 1, TokenKind::Ampersand)
|
|
||||||
} else if chunk.starts_with("^") {
|
|
||||||
Token::new(self.position, self.position + 1, TokenKind::Caret)
|
|
||||||
} else if chunk.starts_with("|") {
|
|
||||||
Token::new(self.position, self.position + 1, TokenKind::Bar)
|
|
||||||
} else if chunk.starts_with("=") {
|
|
||||||
Token::new(self.position, self.position + 1, TokenKind::Equals)
|
|
||||||
} else if chunk.starts_with(",") {
|
|
||||||
Token::new(self.position, self.position + 1, TokenKind::Comma)
|
|
||||||
} else if chunk.starts_with(":") {
|
|
||||||
Token::new(self.position, self.position + 1, TokenKind::Colon)
|
|
||||||
} else if chunk.starts_with(".") {
|
|
||||||
Token::new(self.position, self.position + 1, TokenKind::Dot)
|
|
||||||
} else if chunk.starts_with("[") {
|
|
||||||
Token::new(self.position, self.position + 1, TokenKind::LeftSquare)
|
|
||||||
} else if chunk.starts_with("]") {
|
|
||||||
Token::new(self.position, self.position + 1, TokenKind::RightSquare)
|
|
||||||
} else if chunk.starts_with("<") {
|
|
||||||
Token::new(self.position, self.position + 1, TokenKind::Lt)
|
|
||||||
} else if chunk.starts_with(">") {
|
|
||||||
Token::new(self.position, self.position + 1, TokenKind::Gt)
|
|
||||||
} else {
|
|
||||||
// more than one char token
|
|
||||||
if chunk.starts_with(|c: char| c.is_ascii_digit()) {
|
|
||||||
// number literal
|
|
||||||
let mut end = self.position;
|
|
||||||
let mut whole_chars = chunk.chars();
|
|
||||||
while let Some(c) = whole_chars.next() {
|
|
||||||
if c.is_ascii_digit() {
|
|
||||||
end += 1;
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut fraction_chars = chunk.chars().skip(end - self.position);
|
let (end, kind) = match current {
|
||||||
if fraction_chars.next().map(|c| c == '.').unwrap_or(false) {
|
'-' => {
|
||||||
let mut found_fraction = false;
|
if let Some(peek) = peek {
|
||||||
while let Some(c) = fraction_chars.next() {
|
if peek == '>' {
|
||||||
|
(self.position + 2, TokenKind::RightArrow)
|
||||||
|
} else {
|
||||||
|
(self.position + 1, TokenKind::Minus)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
(self.position + 1, TokenKind::Minus)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'(' => (self.position + 1, TokenKind::LeftParentheses),
|
||||||
|
')' => (self.position + 1, TokenKind::RightParentheses),
|
||||||
|
'[' => (self.position + 1, TokenKind::LeftSquare),
|
||||||
|
']' => (self.position + 1, TokenKind::RightSquare),
|
||||||
|
'<' => (self.position + 1, TokenKind::Lt),
|
||||||
|
'>' => (self.position + 1, TokenKind::Gt),
|
||||||
|
'*' => (self.position + 1, TokenKind::Star),
|
||||||
|
'/' => (self.position + 1, TokenKind::Slash),
|
||||||
|
'%' => (self.position + 1, TokenKind::Modulo),
|
||||||
|
'+' => (self.position + 1, TokenKind::Plus),
|
||||||
|
'&' => (self.position + 1, TokenKind::Ampersand),
|
||||||
|
'^' => (self.position + 1, TokenKind::Caret),
|
||||||
|
'|' => (self.position + 1, TokenKind::Bar),
|
||||||
|
'=' => (self.position + 1, TokenKind::Equals),
|
||||||
|
',' => (self.position + 1, TokenKind::Comma),
|
||||||
|
'.' => (self.position + 1, TokenKind::Dot),
|
||||||
|
':' => (self.position + 1, TokenKind::Colon),
|
||||||
|
_ => {
|
||||||
|
// more than one char token
|
||||||
|
if chunk.starts_with(|c: char| c.is_ascii_digit()) {
|
||||||
|
// number literal
|
||||||
|
let mut end = self.position;
|
||||||
|
let mut whole_chars = chunk.chars();
|
||||||
|
while let Some(c) = whole_chars.next() {
|
||||||
if c.is_ascii_digit() {
|
if c.is_ascii_digit() {
|
||||||
end += 1;
|
end += 1;
|
||||||
if !found_fraction {
|
|
||||||
end += 1; // to account for decimal point
|
|
||||||
found_fraction = true;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if found_fraction {
|
|
||||||
Token::new(self.position, end, TokenKind::DoubleLiteral)
|
let mut fraction_chars = chunk.chars().skip(end - self.position);
|
||||||
|
if fraction_chars.next().map(|c| c == '.').unwrap_or(false) {
|
||||||
|
let mut found_fraction = false;
|
||||||
|
while let Some(c) = fraction_chars.next() {
|
||||||
|
if c.is_ascii_digit() {
|
||||||
|
end += 1;
|
||||||
|
if !found_fraction {
|
||||||
|
end += 1; // to account for decimal point
|
||||||
|
found_fraction = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if found_fraction {
|
||||||
|
(end, TokenKind::DoubleLiteral)
|
||||||
|
} else {
|
||||||
|
(end, TokenKind::IntegerLiteral)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Token::new(self.position, end, TokenKind::IntegerLiteral)
|
(end, TokenKind::IntegerLiteral)
|
||||||
}
|
}
|
||||||
} else {
|
} else if chunk.starts_with("\"") {
|
||||||
Token::new(self.position, end, TokenKind::IntegerLiteral)
|
// string literal
|
||||||
}
|
let mut end = self.position;
|
||||||
} else if chunk.starts_with("\"") {
|
let mut terminated = false;
|
||||||
// string literal
|
let mut chars = chunk.chars();
|
||||||
let mut end = self.position;
|
chars.next(); // skip opening quote
|
||||||
let mut terminated = false;
|
|
||||||
let mut chars = chunk.chars();
|
|
||||||
chars.next(); // skip opening quote
|
|
||||||
end += 1;
|
|
||||||
for char in chars {
|
|
||||||
end += 1;
|
end += 1;
|
||||||
if char == '"' {
|
for char in chars {
|
||||||
terminated = true;
|
end += 1;
|
||||||
break;
|
if char == '"' {
|
||||||
|
terminated = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
if !terminated {
|
||||||
if !terminated {
|
return Some(Err(LexerError::new(
|
||||||
return Some(Err(LexerError::new(LexerErrorKind::UnterminatedString)));
|
self.position,
|
||||||
}
|
end,
|
||||||
Token::new(self.position, end, TokenKind::String)
|
LexerErrorKind::UnterminatedString,
|
||||||
} else {
|
)));
|
||||||
// keyword or identifier
|
}
|
||||||
let mut prefix = String::new();
|
(end, TokenKind::String)
|
||||||
for char in chunk.chars() {
|
} else {
|
||||||
if char.is_alphanumeric() || char == '_' {
|
// keyword or identifier
|
||||||
prefix.push(char);
|
let mut prefix = String::new();
|
||||||
} else {
|
for char in chunk.chars() {
|
||||||
break;
|
if char.is_alphanumeric() || char == '_' {
|
||||||
|
prefix.push(char);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if prefix.len() == 0 {
|
if prefix.len() == 0 {
|
||||||
return Some(Err(LexerError::new(LexerErrorKind::UnrecognizedCharacter(
|
return Some(Err(LexerError::new(
|
||||||
chunk.chars().next().unwrap(),
|
self.position,
|
||||||
))));
|
self.position + 1,
|
||||||
}
|
LexerErrorKind::UnrecognizedCharacter(chunk.chars().next().unwrap()),
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
let token_kind = match prefix.as_str() {
|
let token_kind = match prefix.as_str() {
|
||||||
"fn" => TokenKind::Fn,
|
"fn" => TokenKind::Fn,
|
||||||
"end" => TokenKind::End,
|
"end" => TokenKind::End,
|
||||||
"let" => TokenKind::Let,
|
"let" => TokenKind::Let,
|
||||||
"extern" => TokenKind::Extern,
|
"extern" => TokenKind::Extern,
|
||||||
"class" => TokenKind::Class,
|
"class" => TokenKind::Class,
|
||||||
"self" => TokenKind::SelfKw,
|
"self" => TokenKind::SelfKw,
|
||||||
"pub" => TokenKind::Public,
|
"pub" => TokenKind::Public,
|
||||||
"mut" => TokenKind::Mut,
|
"mut" => TokenKind::Mut,
|
||||||
"ctor" => TokenKind::Ctor,
|
"ctor" => TokenKind::Ctor,
|
||||||
_ => TokenKind::Identifier,
|
_ => TokenKind::Identifier,
|
||||||
};
|
};
|
||||||
Token::new(self.position, self.position + prefix.len(), token_kind)
|
(self.position + prefix.len(), token_kind)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
let token = Token::new(self.position, end, kind);
|
||||||
self.position += token.end() - token.start();
|
self.position += token.end() - token.start();
|
||||||
Some(Ok(token))
|
Some(Ok(token))
|
||||||
}
|
}
|
||||||
@ -169,12 +168,22 @@ impl<'a> Lexer<'a> {
|
|||||||
|
|
||||||
#[derive(Debug, Eq, PartialEq)]
|
#[derive(Debug, Eq, PartialEq)]
|
||||||
pub struct LexerError {
|
pub struct LexerError {
|
||||||
|
start: usize,
|
||||||
|
end: usize,
|
||||||
kind: LexerErrorKind,
|
kind: LexerErrorKind,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LexerError {
|
impl LexerError {
|
||||||
pub fn new(kind: LexerErrorKind) -> Self {
|
pub fn new(start: usize, end: usize, kind: LexerErrorKind) -> Self {
|
||||||
Self { kind }
|
Self { start, end, kind }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn start(&self) -> usize {
|
||||||
|
self.start
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn end(&self) -> usize {
|
||||||
|
self.end
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn kind(&self) -> LexerErrorKind {
|
pub fn kind(&self) -> LexerErrorKind {
|
||||||
|
|||||||
@ -5,6 +5,7 @@ pub mod error_codes;
|
|||||||
pub mod intrinsics;
|
pub mod intrinsics;
|
||||||
pub mod ir;
|
pub mod ir;
|
||||||
pub mod lexer;
|
pub mod lexer;
|
||||||
|
pub mod offset_counter;
|
||||||
pub mod parser;
|
pub mod parser;
|
||||||
pub mod scope;
|
pub mod scope;
|
||||||
pub mod source_range;
|
pub mod source_range;
|
||||||
|
|||||||
23
dmc-lib/src/offset_counter.rs
Normal file
23
dmc-lib/src/offset_counter.rs
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
pub struct OffsetCounter {
|
||||||
|
counter: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl OffsetCounter {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self { counter: 0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_base(base: usize) -> Self {
|
||||||
|
Self { counter: base }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn next(&mut self) -> usize {
|
||||||
|
let offset = self.counter;
|
||||||
|
self.counter += 1;
|
||||||
|
offset
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_count(&self) -> usize {
|
||||||
|
self.counter
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -19,23 +19,34 @@ use crate::ast::parameter::Parameter;
|
|||||||
use crate::ast::statement::Statement;
|
use crate::ast::statement::Statement;
|
||||||
use crate::ast::string_literal::StringLiteral;
|
use crate::ast::string_literal::StringLiteral;
|
||||||
use crate::ast::type_use::TypeUse;
|
use crate::ast::type_use::TypeUse;
|
||||||
use crate::diagnostic::Diagnostic;
|
use crate::diagnostic::{Diagnostic, Diagnostics};
|
||||||
use crate::lexer::Lexer;
|
use crate::error_codes::{LEXER_ERROR, PARSE_ERROR};
|
||||||
|
use crate::lexer::{Lexer, LexerErrorKind};
|
||||||
use crate::source_range::SourceRange;
|
use crate::source_range::SourceRange;
|
||||||
use crate::token::{Token, TokenKind};
|
use crate::token::{Token, TokenKind};
|
||||||
|
use crate::{handle_diagnostics, ok_or_err_diagnostics};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
pub fn parse_compilation_unit(input: &str) -> Result<CompilationUnit, Vec<Diagnostic>> {
|
pub type ParseResult<T> = Result<T, Diagnostics>;
|
||||||
|
|
||||||
|
pub fn parse_compilation_unit(input: &str) -> ParseResult<CompilationUnit> {
|
||||||
let mut parser = Parser::new(input);
|
let mut parser = Parser::new(input);
|
||||||
|
parser.advance()?; // get started
|
||||||
parser.compilation_unit()
|
parser.compilation_unit()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_expression(input: &str) -> Result<Expression, Vec<Diagnostic>> {
|
pub fn parse_expression(input: &str) -> ParseResult<Expression> {
|
||||||
let mut parser = Parser::new(input);
|
let mut parser = Parser::new(input);
|
||||||
parser.advance(); // get started
|
parser.advance()?; // get started
|
||||||
parser.expression()
|
parser.expression()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn parse_let_statement(input: &str) -> ParseResult<LetStatement> {
|
||||||
|
let mut parser = Parser::new(input);
|
||||||
|
parser.advance()?;
|
||||||
|
parser.let_statement()
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! matches_expression_first {
|
macro_rules! matches_expression_first {
|
||||||
( $token_kind : expr ) => {
|
( $token_kind : expr ) => {
|
||||||
matches!(
|
matches!(
|
||||||
@ -96,96 +107,116 @@ impl<'a> Parser<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn advance(&mut self) {
|
fn advance(&mut self) -> Result<(), Diagnostics> {
|
||||||
|
fn fetch(lexer: &mut Lexer) -> Result<Option<Token>, Diagnostics> {
|
||||||
|
let mut diagnostics = vec![];
|
||||||
|
let mut maybe_token: Option<Token> = None;
|
||||||
|
while let Some(lexer_result) = lexer.next() {
|
||||||
|
match lexer_result {
|
||||||
|
Ok(token) => {
|
||||||
|
maybe_token = Some(token);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Err(lexer_error) => {
|
||||||
|
let diagnostic = match lexer_error.kind() {
|
||||||
|
LexerErrorKind::UnterminatedString => Diagnostic::new(
|
||||||
|
"Unterminated string literal.",
|
||||||
|
lexer_error.start(),
|
||||||
|
lexer_error.end(),
|
||||||
|
)
|
||||||
|
.with_error_code(LEXER_ERROR),
|
||||||
|
LexerErrorKind::UnrecognizedCharacter(c) => Diagnostic::new(
|
||||||
|
&format!("Unrecognized character: {}", c),
|
||||||
|
lexer_error.start(),
|
||||||
|
lexer_error.end(),
|
||||||
|
)
|
||||||
|
.with_error_code(LEXER_ERROR),
|
||||||
|
};
|
||||||
|
diagnostics.push(diagnostic);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ok_or_err_diagnostics!(maybe_token, diagnostics)
|
||||||
|
}
|
||||||
|
|
||||||
if self.lookahead.is_some() {
|
if self.lookahead.is_some() {
|
||||||
// we've advanced at least once
|
// we've advanced at least once
|
||||||
self.current = self.lookahead.take();
|
self.current = self.lookahead.take();
|
||||||
self.lookahead = match self.lexer.next() {
|
self.lookahead = fetch(&mut self.lexer)?;
|
||||||
None => None,
|
Ok(())
|
||||||
Some(result) => match result {
|
|
||||||
Ok(token) => Some(token),
|
|
||||||
Err(lexer_error) => {
|
|
||||||
panic!("{:?}", lexer_error);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
} else if self.lookahead.is_none() && self.current.is_some() {
|
} else if self.lookahead.is_none() && self.current.is_some() {
|
||||||
// we're on the last token
|
// we're on the last token
|
||||||
self.current = None;
|
self.current = None;
|
||||||
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
// we've not yet advanced, so fetch both
|
// we've not yet advanced, so fetch both
|
||||||
// current
|
self.current = fetch(&mut self.lexer)?;
|
||||||
match self.lexer.next() {
|
self.lookahead = fetch(&mut self.lexer)?;
|
||||||
None => {}
|
Ok(())
|
||||||
Some(result) => match result {
|
|
||||||
Ok(token) => {
|
|
||||||
self.current = Some(token);
|
|
||||||
}
|
|
||||||
Err(lexer_error) => {
|
|
||||||
panic!("{:?}", lexer_error);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
// lookahead
|
|
||||||
match self.lexer.next() {
|
|
||||||
None => {}
|
|
||||||
Some(result) => match result {
|
|
||||||
Ok(token) => {
|
|
||||||
self.lookahead = Some(token);
|
|
||||||
}
|
|
||||||
Err(lexer_error) => {
|
|
||||||
panic!("{:?}", lexer_error);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expect_advance(&mut self, token_kind: TokenKind) -> Result<Token, Vec<Diagnostic>> {
|
fn join_kinds(kinds: &[TokenKind]) -> String {
|
||||||
|
kinds
|
||||||
|
.iter()
|
||||||
|
.map(|kind| format!("{:?}", kind))
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(", ")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_expected_but_found(kinds: &[TokenKind], found: &Token) -> Diagnostic {
|
||||||
|
Diagnostic::new(
|
||||||
|
&format!("Unexpected token: {:?}.", found.kind()),
|
||||||
|
found.start(),
|
||||||
|
found.end(),
|
||||||
|
)
|
||||||
|
.with_error_code(PARSE_ERROR)
|
||||||
|
.with_primary_label_message(&format!("Expected {}.", Self::join_kinds(kinds)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_expected_but_found_eoi(kinds: &[TokenKind], position: usize) -> Diagnostic {
|
||||||
|
Diagnostic::new("Unexpected end-of-input.", position, position)
|
||||||
|
.with_error_code(PARSE_ERROR)
|
||||||
|
.with_primary_label_message(&format!("Expected {}.", Self::join_kinds(kinds)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn expect_advance(&mut self, token_kind: TokenKind) -> Result<Token, Diagnostics> {
|
||||||
match self.current.take() {
|
match self.current.take() {
|
||||||
None => Err(vec![
|
None => Err(vec![Self::get_expected_but_found_eoi(
|
||||||
Diagnostic::new(
|
&[token_kind],
|
||||||
&format!("Expected {:?} but found end-of-input.", token_kind),
|
self.input.len(),
|
||||||
self.input.len(),
|
)]),
|
||||||
self.input.len(),
|
|
||||||
)
|
|
||||||
.with_reporter(file!(), line!()),
|
|
||||||
]),
|
|
||||||
Some(token) => {
|
Some(token) => {
|
||||||
if token.kind() == token_kind {
|
if token.kind() == token_kind {
|
||||||
self.advance();
|
self.advance()?;
|
||||||
Ok(token)
|
Ok(token)
|
||||||
} else {
|
} else {
|
||||||
self.advance_until(&[token_kind]);
|
self.advance_until(&[token_kind]);
|
||||||
Err(vec![
|
Err(vec![Self::get_expected_but_found(&[token_kind], &token)])
|
||||||
Diagnostic::new(
|
|
||||||
&format!("Expected {:?} but found {:?}", token_kind, token.kind()),
|
|
||||||
token.start(),
|
|
||||||
token.end(),
|
|
||||||
)
|
|
||||||
.with_reporter(file!(), line!()),
|
|
||||||
])
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expect_position_advance(
|
fn expect_immediately_after_advance(
|
||||||
&mut self,
|
&mut self,
|
||||||
token_kind: TokenKind,
|
token_kind: TokenKind,
|
||||||
start_position: usize,
|
previous_token: &Token,
|
||||||
) -> Result<Token, Vec<Diagnostic>> {
|
) -> Result<Token, Diagnostics> {
|
||||||
let matched = self.expect_advance(token_kind)?;
|
let matched = self.expect_advance(token_kind)?;
|
||||||
if matched.start() == start_position {
|
if matched.start() == previous_token.end() {
|
||||||
Ok(matched)
|
Ok(matched)
|
||||||
} else {
|
} else {
|
||||||
Err(vec![
|
Err(vec![
|
||||||
Diagnostic::new(
|
Diagnostic::new(
|
||||||
&format!("Expected {:?} but found {:?}", token_kind, matched.kind()),
|
&format!(
|
||||||
|
"Expected {:?} immediately after previous token.",
|
||||||
|
token_kind
|
||||||
|
),
|
||||||
matched.start(),
|
matched.start(),
|
||||||
matched.end(),
|
matched.end(),
|
||||||
)
|
)
|
||||||
.with_reporter(file!(), line!()),
|
.with_error_code(PARSE_ERROR),
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -206,13 +237,6 @@ impl<'a> Parser<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn peek_lookahead(&self, token_kind: TokenKind) -> bool {
|
|
||||||
match &self.lookahead {
|
|
||||||
None => panic!("Unexpected end of input."),
|
|
||||||
Some(token) => token.kind() == token_kind,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn sample_input(&self, start: usize, end: usize) -> &'a str {
|
fn sample_input(&self, start: usize, end: usize) -> &'a str {
|
||||||
&self.input[start..end]
|
&self.input[start..end]
|
||||||
}
|
}
|
||||||
@ -221,49 +245,40 @@ impl<'a> Parser<'a> {
|
|||||||
self.sample_input(token.start(), token.end())
|
self.sample_input(token.start(), token.end())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn compilation_unit(&mut self) -> Result<CompilationUnit, Vec<Diagnostic>> {
|
fn compilation_unit(&mut self) -> Result<CompilationUnit, Vec<Diagnostic>> {
|
||||||
let mut functions: Vec<Function> = vec![];
|
let mut functions: Vec<Function> = vec![];
|
||||||
let mut extern_functions: Vec<ExternFunction> = vec![];
|
let mut extern_functions: Vec<ExternFunction> = vec![];
|
||||||
let mut classes: Vec<Class> = vec![];
|
let mut classes: Vec<Class> = vec![];
|
||||||
|
|
||||||
let mut diagnostics = vec![];
|
let mut diagnostics = vec![];
|
||||||
|
|
||||||
self.advance(); // get started
|
|
||||||
|
|
||||||
while self.current.is_some() {
|
while self.current.is_some() {
|
||||||
let current = self.get_current();
|
let current = self.get_current();
|
||||||
match current.kind() {
|
match current.kind() {
|
||||||
TokenKind::Fn | TokenKind::Extern | TokenKind::Class => {
|
TokenKind::Fn | TokenKind::Extern | TokenKind::Class => {
|
||||||
match self.module_level_declaration(
|
handle_diagnostics!(
|
||||||
&mut functions,
|
self.module_level_declaration(
|
||||||
&mut extern_functions,
|
&mut functions,
|
||||||
&mut classes,
|
&mut extern_functions,
|
||||||
) {
|
&mut classes
|
||||||
Ok(_) => {}
|
),
|
||||||
Err(mut declaration_diagnostics) => {
|
diagnostics
|
||||||
diagnostics.append(&mut declaration_diagnostics)
|
);
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
diagnostics.push(Diagnostic::new(
|
diagnostics.push(Self::get_expected_but_found(
|
||||||
&format!(
|
&[TokenKind::Fn, TokenKind::Extern, TokenKind::Class],
|
||||||
"Expected any of {:?}; found {:?}",
|
current,
|
||||||
[TokenKind::Fn, TokenKind::Extern, TokenKind::Class],
|
|
||||||
current.kind()
|
|
||||||
),
|
|
||||||
current.start(),
|
|
||||||
current.end(),
|
|
||||||
));
|
));
|
||||||
self.advance_until(&[TokenKind::Fn, TokenKind::Extern]);
|
self.advance_until(&[TokenKind::Fn, TokenKind::Extern, TokenKind::Class]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if diagnostics.is_empty() {
|
|
||||||
Ok(CompilationUnit::new(functions, extern_functions, classes))
|
ok_or_err_diagnostics!(
|
||||||
} else {
|
CompilationUnit::new(functions, extern_functions, classes),
|
||||||
Err(diagnostics)
|
diagnostics
|
||||||
}
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn module_level_declaration(
|
fn module_level_declaration(
|
||||||
@ -307,7 +322,7 @@ impl<'a> Parser<'a> {
|
|||||||
|
|
||||||
fn function(&mut self) -> Result<Function, Vec<Diagnostic>> {
|
fn function(&mut self) -> Result<Function, Vec<Diagnostic>> {
|
||||||
let is_public = if self.current.is_some() && self.peek_current(TokenKind::Public) {
|
let is_public = if self.current.is_some() && self.peek_current(TokenKind::Public) {
|
||||||
self.advance(); // pub
|
self.advance()?; // pub
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
@ -356,18 +371,17 @@ impl<'a> Parser<'a> {
|
|||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
if diagnostics.is_empty() {
|
ok_or_err_diagnostics!(
|
||||||
Ok(Function::new(
|
Function::new(
|
||||||
self.token_text(&identifier_token),
|
self.token_text(&identifier_token),
|
||||||
SourceRange::new(identifier_token.start(), identifier_token.end()),
|
SourceRange::new(identifier_token.start(), identifier_token.end()),
|
||||||
is_public,
|
is_public,
|
||||||
parameters,
|
parameters,
|
||||||
return_type,
|
return_type,
|
||||||
statements,
|
statements,
|
||||||
))
|
),
|
||||||
} else {
|
diagnostics
|
||||||
Err(diagnostics)
|
)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extern_function(&mut self) -> Result<ExternFunction, Vec<Diagnostic>> {
|
fn extern_function(&mut self) -> Result<ExternFunction, Vec<Diagnostic>> {
|
||||||
@ -399,16 +413,15 @@ impl<'a> Parser<'a> {
|
|||||||
|
|
||||||
let return_type = self.return_type()?;
|
let return_type = self.return_type()?;
|
||||||
|
|
||||||
if diagnostics.is_empty() {
|
ok_or_err_diagnostics!(
|
||||||
Ok(ExternFunction::new(
|
ExternFunction::new(
|
||||||
self.token_text(&identifier_token),
|
self.token_text(&identifier_token),
|
||||||
SourceRange::new(identifier_token.start(), identifier_token.end()),
|
SourceRange::new(identifier_token.start(), identifier_token.end()),
|
||||||
maybe_parameters.unwrap(),
|
maybe_parameters.unwrap(),
|
||||||
return_type,
|
return_type,
|
||||||
))
|
),
|
||||||
} else {
|
diagnostics
|
||||||
Err(diagnostics)
|
)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn class(&mut self) -> Result<Class, Vec<Diagnostic>> {
|
fn class(&mut self) -> Result<Class, Vec<Diagnostic>> {
|
||||||
@ -459,18 +472,17 @@ impl<'a> Parser<'a> {
|
|||||||
|
|
||||||
self.expect_advance(TokenKind::End)?;
|
self.expect_advance(TokenKind::End)?;
|
||||||
|
|
||||||
if diagnostics.is_empty() {
|
ok_or_err_diagnostics!(
|
||||||
Ok(Class::new(
|
Class::new(
|
||||||
self.token_text(&identifier_token),
|
self.token_text(&identifier_token),
|
||||||
SourceRange::new(identifier_token.start(), identifier_token.end()),
|
SourceRange::new(identifier_token.start(), identifier_token.end()),
|
||||||
generic_parameters,
|
generic_parameters,
|
||||||
maybe_constructor,
|
maybe_constructor,
|
||||||
fields,
|
fields,
|
||||||
functions,
|
functions,
|
||||||
))
|
),
|
||||||
} else {
|
diagnostics
|
||||||
Err(diagnostics)
|
)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parameter_list(&mut self) -> Result<Vec<Parameter>, Vec<Diagnostic>> {
|
fn parameter_list(&mut self) -> Result<Vec<Parameter>, Vec<Diagnostic>> {
|
||||||
@ -487,14 +499,15 @@ impl<'a> Parser<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if self.current.is_some() && self.peek_current(TokenKind::Comma) {
|
if self.current.is_some() && self.peek_current(TokenKind::Comma) {
|
||||||
self.advance();
|
match self.advance() {
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(mut ds) => {
|
||||||
|
diagnostics.append(&mut ds);
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if diagnostics.is_empty() {
|
ok_or_err_diagnostics!(parameters, diagnostics)
|
||||||
Ok(parameters)
|
|
||||||
} else {
|
|
||||||
Err(diagnostics)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parameter(&mut self) -> Result<Parameter, Vec<Diagnostic>> {
|
fn parameter(&mut self) -> Result<Parameter, Vec<Diagnostic>> {
|
||||||
@ -518,7 +531,7 @@ impl<'a> Parser<'a> {
|
|||||||
let current = self.get_current();
|
let current = self.get_current();
|
||||||
return match current.kind() {
|
return match current.kind() {
|
||||||
TokenKind::LeftSquare => {
|
TokenKind::LeftSquare => {
|
||||||
self.advance(); // [
|
self.advance()?; // [
|
||||||
let inner_type_use = self.type_use()?;
|
let inner_type_use = self.type_use()?;
|
||||||
self.expect_advance(TokenKind::RightSquare)?;
|
self.expect_advance(TokenKind::RightSquare)?;
|
||||||
todo!()
|
todo!()
|
||||||
@ -527,7 +540,7 @@ impl<'a> Parser<'a> {
|
|||||||
let identifier_token = self.expect_advance(TokenKind::Identifier)?;
|
let identifier_token = self.expect_advance(TokenKind::Identifier)?;
|
||||||
let generic_arguments =
|
let generic_arguments =
|
||||||
if self.current.is_some() && self.peek_current(TokenKind::Lt) {
|
if self.current.is_some() && self.peek_current(TokenKind::Lt) {
|
||||||
self.advance(); // <
|
self.advance()?; // <
|
||||||
let generic_arguments = self.generic_arguments_list()?;
|
let generic_arguments = self.generic_arguments_list()?;
|
||||||
self.expect_advance(TokenKind::Gt)?; // >
|
self.expect_advance(TokenKind::Gt)?; // >
|
||||||
generic_arguments
|
generic_arguments
|
||||||
@ -540,19 +553,14 @@ impl<'a> Parser<'a> {
|
|||||||
generic_arguments,
|
generic_arguments,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
_ => Err(vec![Diagnostic::new(
|
_ => Err(vec![Self::get_expected_but_found(
|
||||||
&format!(
|
&[TokenKind::LeftSquare, TokenKind::Identifier],
|
||||||
"Expected LeftSquare or Identifier; found: {:?}",
|
current,
|
||||||
current.kind()
|
|
||||||
),
|
|
||||||
current.start(),
|
|
||||||
current.end(),
|
|
||||||
)]),
|
)]),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
Err(vec![Diagnostic::new(
|
Err(vec![Self::get_expected_but_found_eoi(
|
||||||
"Expected LeftSquare or Identifier; found end of input.",
|
&[TokenKind::LeftSquare, TokenKind::Identifier],
|
||||||
self.input.len(),
|
|
||||||
self.input.len(),
|
self.input.len(),
|
||||||
)])
|
)])
|
||||||
}
|
}
|
||||||
@ -562,7 +570,7 @@ impl<'a> Parser<'a> {
|
|||||||
while self.current.is_some() && matches_type_use_first!(self.get_current().kind()) {
|
while self.current.is_some() && matches_type_use_first!(self.get_current().kind()) {
|
||||||
generic_arguments.push(self.type_use()?);
|
generic_arguments.push(self.type_use()?);
|
||||||
if self.current.is_some() && self.peek_current(TokenKind::Comma) {
|
if self.current.is_some() && self.peek_current(TokenKind::Comma) {
|
||||||
self.advance(); // comma
|
self.advance()?; // comma
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -576,7 +584,7 @@ impl<'a> Parser<'a> {
|
|||||||
while self.current.is_some() && self.peek_current(TokenKind::Identifier) {
|
while self.current.is_some() && self.peek_current(TokenKind::Identifier) {
|
||||||
parameters.push(self.generic_parameter()?);
|
parameters.push(self.generic_parameter()?);
|
||||||
if self.current.is_some() && self.peek_current(TokenKind::Plus) {
|
if self.current.is_some() && self.peek_current(TokenKind::Plus) {
|
||||||
self.advance(); // +
|
self.advance()?; // +
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -589,11 +597,11 @@ impl<'a> Parser<'a> {
|
|||||||
let identifier = self.expect_advance(TokenKind::Identifier)?;
|
let identifier = self.expect_advance(TokenKind::Identifier)?;
|
||||||
let mut extends_list: Vec<TypeUse> = vec![];
|
let mut extends_list: Vec<TypeUse> = vec![];
|
||||||
if self.current.is_some() && self.peek_current(TokenKind::Colon) {
|
if self.current.is_some() && self.peek_current(TokenKind::Colon) {
|
||||||
self.advance(); // :
|
self.advance()?; // :
|
||||||
while self.current.is_some() && matches_type_use_first!(self.get_current().kind()) {
|
while self.current.is_some() && matches_type_use_first!(self.get_current().kind()) {
|
||||||
extends_list.push(self.type_use()?);
|
extends_list.push(self.type_use()?);
|
||||||
if self.current.is_some() && self.peek_current(TokenKind::Comma) {
|
if self.current.is_some() && self.peek_current(TokenKind::Comma) {
|
||||||
self.advance(); // ,
|
self.advance()?; // ,
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -623,34 +631,25 @@ impl<'a> Parser<'a> {
|
|||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let lookahead = self.lookahead.as_ref().unwrap();
|
let lookahead = self.lookahead.as_ref().unwrap();
|
||||||
return Err(vec![Diagnostic::new(
|
return Err(vec![Self::get_expected_but_found(
|
||||||
&format!(
|
&[TokenKind::Mut, TokenKind::Identifier, TokenKind::Fn],
|
||||||
"Expected any of {:?}; found {:?}",
|
lookahead,
|
||||||
[TokenKind::Mut, TokenKind::Identifier, TokenKind::Fn],
|
|
||||||
lookahead.kind()
|
|
||||||
),
|
|
||||||
lookahead.start(),
|
|
||||||
lookahead.end(),
|
|
||||||
)]);
|
)]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
let current = self.current.as_ref().unwrap();
|
let current = self.current.as_ref().unwrap();
|
||||||
Err(vec![Diagnostic::new(
|
Err(vec![Self::get_expected_but_found(
|
||||||
&format!(
|
&[TokenKind::Mut, TokenKind::Identifier, TokenKind::Fn],
|
||||||
"Expected any of {:?}; found end-of-input.",
|
current,
|
||||||
[TokenKind::Mut, TokenKind::Identifier, TokenKind::Fn]
|
|
||||||
),
|
|
||||||
current.end(),
|
|
||||||
current.end(),
|
|
||||||
)])
|
)])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn constructor(&mut self) -> Result<Constructor, Vec<Diagnostic>> {
|
fn constructor(&mut self) -> Result<Constructor, Vec<Diagnostic>> {
|
||||||
let is_public = if self.current.is_some() && self.peek_current(TokenKind::Public) {
|
let is_public = if self.current.is_some() && self.peek_current(TokenKind::Public) {
|
||||||
self.advance();
|
self.advance()?;
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
@ -700,14 +699,14 @@ impl<'a> Parser<'a> {
|
|||||||
|
|
||||||
fn field(&mut self) -> Result<Field, Vec<Diagnostic>> {
|
fn field(&mut self) -> Result<Field, Vec<Diagnostic>> {
|
||||||
let is_public = if self.current.is_some() && self.peek_current(TokenKind::Public) {
|
let is_public = if self.current.is_some() && self.peek_current(TokenKind::Public) {
|
||||||
self.advance();
|
self.advance()?;
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
};
|
};
|
||||||
|
|
||||||
let is_mut = if self.current.is_some() && self.peek_current(TokenKind::Mut) {
|
let is_mut = if self.current.is_some() && self.peek_current(TokenKind::Mut) {
|
||||||
self.advance();
|
self.advance()?;
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
@ -716,14 +715,14 @@ impl<'a> Parser<'a> {
|
|||||||
let identifier = self.expect_advance(TokenKind::Identifier)?;
|
let identifier = self.expect_advance(TokenKind::Identifier)?;
|
||||||
|
|
||||||
let declared_type = if self.current.is_some() && self.peek_current(TokenKind::Colon) {
|
let declared_type = if self.current.is_some() && self.peek_current(TokenKind::Colon) {
|
||||||
self.advance(); // colon
|
self.advance()?; // colon
|
||||||
Some(self.type_use()?)
|
Some(self.type_use()?)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
let initializer = if self.current.is_some() && self.peek_current(TokenKind::Equals) {
|
let initializer = if self.current.is_some() && self.peek_current(TokenKind::Equals) {
|
||||||
self.advance(); // equals
|
self.advance()?; // equals
|
||||||
Some(self.expression()?)
|
Some(self.expression()?)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
@ -751,7 +750,7 @@ impl<'a> Parser<'a> {
|
|||||||
self.expect_advance(TokenKind::Let)?;
|
self.expect_advance(TokenKind::Let)?;
|
||||||
|
|
||||||
let is_mut = if self.current.is_some() && self.peek_current(TokenKind::Mut) {
|
let is_mut = if self.current.is_some() && self.peek_current(TokenKind::Mut) {
|
||||||
self.advance();
|
self.advance()?;
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
@ -790,7 +789,7 @@ impl<'a> Parser<'a> {
|
|||||||
fn bitwise_or_expression(&mut self) -> Result<Expression, Vec<Diagnostic>> {
|
fn bitwise_or_expression(&mut self) -> Result<Expression, Vec<Diagnostic>> {
|
||||||
let mut result = self.bitwise_xor_expression()?;
|
let mut result = self.bitwise_xor_expression()?;
|
||||||
while self.current.is_some() && self.peek_current(TokenKind::Bar) {
|
while self.current.is_some() && self.peek_current(TokenKind::Bar) {
|
||||||
self.advance(); // |
|
self.advance()?; // |
|
||||||
let rhs = self.bitwise_xor_expression()?;
|
let rhs = self.bitwise_xor_expression()?;
|
||||||
let source_range =
|
let source_range =
|
||||||
SourceRange::new(result.source_range().start(), rhs.source_range().end());
|
SourceRange::new(result.source_range().start(), rhs.source_range().end());
|
||||||
@ -807,7 +806,7 @@ impl<'a> Parser<'a> {
|
|||||||
fn bitwise_xor_expression(&mut self) -> Result<Expression, Vec<Diagnostic>> {
|
fn bitwise_xor_expression(&mut self) -> Result<Expression, Vec<Diagnostic>> {
|
||||||
let mut result = self.bitwise_and_expression()?;
|
let mut result = self.bitwise_and_expression()?;
|
||||||
while self.current.is_some() && self.peek_current(TokenKind::Caret) {
|
while self.current.is_some() && self.peek_current(TokenKind::Caret) {
|
||||||
self.advance(); // ^
|
self.advance()?; // ^
|
||||||
let rhs = self.bitwise_and_expression()?;
|
let rhs = self.bitwise_and_expression()?;
|
||||||
let source_range =
|
let source_range =
|
||||||
SourceRange::new(result.source_range().start(), rhs.source_range().end());
|
SourceRange::new(result.source_range().start(), rhs.source_range().end());
|
||||||
@ -824,7 +823,7 @@ impl<'a> Parser<'a> {
|
|||||||
fn bitwise_and_expression(&mut self) -> Result<Expression, Vec<Diagnostic>> {
|
fn bitwise_and_expression(&mut self) -> Result<Expression, Vec<Diagnostic>> {
|
||||||
let mut result = self.shift_expression()?;
|
let mut result = self.shift_expression()?;
|
||||||
while self.current.is_some() && self.peek_current(TokenKind::Ampersand) {
|
while self.current.is_some() && self.peek_current(TokenKind::Ampersand) {
|
||||||
self.advance(); // &
|
self.advance()?; // &
|
||||||
let rhs = self.shift_expression()?;
|
let rhs = self.shift_expression()?;
|
||||||
let source_range =
|
let source_range =
|
||||||
SourceRange::new(result.source_range().start(), rhs.source_range().end());
|
SourceRange::new(result.source_range().start(), rhs.source_range().end());
|
||||||
@ -844,9 +843,9 @@ impl<'a> Parser<'a> {
|
|||||||
let current = self.get_current();
|
let current = self.get_current();
|
||||||
match current.kind() {
|
match current.kind() {
|
||||||
TokenKind::Lt => {
|
TokenKind::Lt => {
|
||||||
let second_lt_start = current.start() + 1;
|
let previous_cloned = current.clone();
|
||||||
self.advance(); // first <
|
self.advance()?; // first <
|
||||||
self.expect_position_advance(TokenKind::Lt, second_lt_start)?; // second <
|
self.expect_immediately_after_advance(TokenKind::Lt, &previous_cloned)?; // second <
|
||||||
let rhs = self.additive_expression()?;
|
let rhs = self.additive_expression()?;
|
||||||
let source_range =
|
let source_range =
|
||||||
SourceRange::new(result.source_range().start(), rhs.source_range().end());
|
SourceRange::new(result.source_range().start(), rhs.source_range().end());
|
||||||
@ -858,9 +857,9 @@ impl<'a> Parser<'a> {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
TokenKind::Gt => {
|
TokenKind::Gt => {
|
||||||
let second_gt_start = current.start() + 1;
|
let previous_cloned = current.clone();
|
||||||
self.advance(); // first >
|
self.advance()?; // first >
|
||||||
self.expect_position_advance(TokenKind::Gt, second_gt_start)?; // second gt
|
self.expect_immediately_after_advance(TokenKind::Gt, &previous_cloned)?; // second gt
|
||||||
let rhs = self.additive_expression()?;
|
let rhs = self.additive_expression()?;
|
||||||
let source_range =
|
let source_range =
|
||||||
SourceRange::new(result.source_range().start(), rhs.source_range().end());
|
SourceRange::new(result.source_range().start(), rhs.source_range().end());
|
||||||
@ -883,7 +882,7 @@ impl<'a> Parser<'a> {
|
|||||||
let current = self.get_current();
|
let current = self.get_current();
|
||||||
match current.kind() {
|
match current.kind() {
|
||||||
TokenKind::Plus => {
|
TokenKind::Plus => {
|
||||||
self.advance(); // plus
|
self.advance()?; // plus
|
||||||
let rhs = self.multiplicative_expression()?;
|
let rhs = self.multiplicative_expression()?;
|
||||||
let source_range =
|
let source_range =
|
||||||
SourceRange::new(result.source_range().start(), rhs.source_range().end());
|
SourceRange::new(result.source_range().start(), rhs.source_range().end());
|
||||||
@ -895,7 +894,7 @@ impl<'a> Parser<'a> {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
TokenKind::Minus => {
|
TokenKind::Minus => {
|
||||||
self.advance(); // minus
|
self.advance()?; // minus
|
||||||
let rhs = self.multiplicative_expression()?;
|
let rhs = self.multiplicative_expression()?;
|
||||||
let source_range =
|
let source_range =
|
||||||
SourceRange::new(result.source_range().start(), rhs.source_range().end());
|
SourceRange::new(result.source_range().start(), rhs.source_range().end());
|
||||||
@ -918,7 +917,7 @@ impl<'a> Parser<'a> {
|
|||||||
let current = self.get_current();
|
let current = self.get_current();
|
||||||
match current.kind() {
|
match current.kind() {
|
||||||
TokenKind::Star => {
|
TokenKind::Star => {
|
||||||
self.advance(); // multiply
|
self.advance()?; // multiply
|
||||||
let rhs = self.prefix_expression()?;
|
let rhs = self.prefix_expression()?;
|
||||||
let source_range =
|
let source_range =
|
||||||
SourceRange::new(result.source_range().start(), rhs.source_range().end());
|
SourceRange::new(result.source_range().start(), rhs.source_range().end());
|
||||||
@ -930,7 +929,7 @@ impl<'a> Parser<'a> {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
TokenKind::Slash => {
|
TokenKind::Slash => {
|
||||||
self.advance(); // slash
|
self.advance()?; // slash
|
||||||
let rhs = self.prefix_expression()?;
|
let rhs = self.prefix_expression()?;
|
||||||
let source_range =
|
let source_range =
|
||||||
SourceRange::new(result.source_range().start(), rhs.source_range().end());
|
SourceRange::new(result.source_range().start(), rhs.source_range().end());
|
||||||
@ -942,7 +941,7 @@ impl<'a> Parser<'a> {
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
TokenKind::Modulo => {
|
TokenKind::Modulo => {
|
||||||
self.advance(); // modulo
|
self.advance()?; // modulo
|
||||||
let rhs = self.prefix_expression()?;
|
let rhs = self.prefix_expression()?;
|
||||||
let source_range =
|
let source_range =
|
||||||
SourceRange::new(result.source_range().start(), rhs.source_range().end());
|
SourceRange::new(result.source_range().start(), rhs.source_range().end());
|
||||||
@ -967,7 +966,7 @@ impl<'a> Parser<'a> {
|
|||||||
match current.kind() {
|
match current.kind() {
|
||||||
TokenKind::Minus => {
|
TokenKind::Minus => {
|
||||||
operator_tokens.push(current.clone()); // unfortunately necessary
|
operator_tokens.push(current.clone()); // unfortunately necessary
|
||||||
self.advance();
|
self.advance()?;
|
||||||
}
|
}
|
||||||
_ => break,
|
_ => break,
|
||||||
}
|
}
|
||||||
@ -1010,7 +1009,7 @@ impl<'a> Parser<'a> {
|
|||||||
TokenKind::IntegerLiteral => {
|
TokenKind::IntegerLiteral => {
|
||||||
let raw = self.token_text(¤t);
|
let raw = self.token_text(¤t);
|
||||||
let source_range = SourceRange::new(current.start(), current.end());
|
let source_range = SourceRange::new(current.start(), current.end());
|
||||||
self.advance();
|
self.advance()?;
|
||||||
Ok(Expression::Integer(IntegerLiteral::new(
|
Ok(Expression::Integer(IntegerLiteral::new(
|
||||||
i32::from_str(raw).unwrap(),
|
i32::from_str(raw).unwrap(),
|
||||||
source_range,
|
source_range,
|
||||||
@ -1019,7 +1018,7 @@ impl<'a> Parser<'a> {
|
|||||||
TokenKind::DoubleLiteral => {
|
TokenKind::DoubleLiteral => {
|
||||||
let raw = self.token_text(¤t);
|
let raw = self.token_text(¤t);
|
||||||
let source_range = SourceRange::new(current.start(), current.end());
|
let source_range = SourceRange::new(current.start(), current.end());
|
||||||
self.advance();
|
self.advance()?;
|
||||||
Ok(Expression::Double(DoubleLiteral::new(
|
Ok(Expression::Double(DoubleLiteral::new(
|
||||||
f64::from_str(raw).unwrap(),
|
f64::from_str(raw).unwrap(),
|
||||||
source_range,
|
source_range,
|
||||||
@ -1028,7 +1027,7 @@ impl<'a> Parser<'a> {
|
|||||||
TokenKind::String => {
|
TokenKind::String => {
|
||||||
let with_quotes = self.token_text(¤t);
|
let with_quotes = self.token_text(¤t);
|
||||||
let source_range = SourceRange::new(current.start(), current.end());
|
let source_range = SourceRange::new(current.start(), current.end());
|
||||||
self.advance();
|
self.advance()?;
|
||||||
Ok(Expression::String(StringLiteral::new(
|
Ok(Expression::String(StringLiteral::new(
|
||||||
&with_quotes[1..with_quotes.len() - 1],
|
&with_quotes[1..with_quotes.len() - 1],
|
||||||
source_range,
|
source_range,
|
||||||
@ -1037,7 +1036,7 @@ impl<'a> Parser<'a> {
|
|||||||
TokenKind::Identifier => {
|
TokenKind::Identifier => {
|
||||||
let declared_name = self.token_text(¤t);
|
let declared_name = self.token_text(¤t);
|
||||||
let source_range = SourceRange::new(current.start(), current.end());
|
let source_range = SourceRange::new(current.start(), current.end());
|
||||||
self.advance();
|
self.advance()?;
|
||||||
Ok(Expression::Identifier(Identifier::new(
|
Ok(Expression::Identifier(Identifier::new(
|
||||||
declared_name,
|
declared_name,
|
||||||
source_range,
|
source_range,
|
||||||
@ -1065,7 +1064,7 @@ impl<'a> Parser<'a> {
|
|||||||
let mut expressions = vec![];
|
let mut expressions = vec![];
|
||||||
expressions.push(self.expression()?);
|
expressions.push(self.expression()?);
|
||||||
while self.current.is_some() && self.peek_current(TokenKind::Comma) {
|
while self.current.is_some() && self.peek_current(TokenKind::Comma) {
|
||||||
self.advance(); // comma
|
self.advance()?; // comma
|
||||||
expressions.push(self.expression()?);
|
expressions.push(self.expression()?);
|
||||||
}
|
}
|
||||||
Ok(expressions)
|
Ok(expressions)
|
||||||
|
|||||||
@ -89,6 +89,10 @@ impl SymbolTable {
|
|||||||
self.current_scope_id.unwrap()
|
self.current_scope_id.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn change_scope(&mut self, scope_id: usize) {
|
||||||
|
self.current_scope_id = Some(scope_id);
|
||||||
|
}
|
||||||
|
|
||||||
fn scope(&self, scope_id: usize) -> &Scope {
|
fn scope(&self, scope_id: usize) -> &Scope {
|
||||||
&self.scopes[scope_id]
|
&self.scopes[scope_id]
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,7 +5,7 @@ use std::rc::Rc;
|
|||||||
pub struct Function {
|
pub struct Function {
|
||||||
name: Rc<str>,
|
name: Rc<str>,
|
||||||
parameter_count: usize,
|
parameter_count: usize,
|
||||||
stack_size: isize,
|
stack_size: usize,
|
||||||
instructions: Vec<Instruction>,
|
instructions: Vec<Instruction>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -13,7 +13,7 @@ impl Function {
|
|||||||
pub fn new(
|
pub fn new(
|
||||||
name: Rc<str>,
|
name: Rc<str>,
|
||||||
parameter_count: usize,
|
parameter_count: usize,
|
||||||
stack_size: isize,
|
stack_size: usize,
|
||||||
instructions: Vec<Instruction>,
|
instructions: Vec<Instruction>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
@ -36,7 +36,7 @@ impl Function {
|
|||||||
self.parameter_count
|
self.parameter_count
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn stack_size(&self) -> isize {
|
pub fn stack_size(&self) -> usize {
|
||||||
self.stack_size
|
self.stack_size
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -115,15 +115,15 @@ impl<'a> CallFrame<'a> {
|
|||||||
self.ip += 1;
|
self.ip += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn stack(&self) -> &[Operand] {
|
pub fn stack(&self) -> &[Operand] {
|
||||||
&self.stack
|
&self.stack
|
||||||
}
|
}
|
||||||
|
|
||||||
fn stack_mut(&mut self) -> &mut Vec<Operand> {
|
pub fn stack_mut(&mut self) -> &mut Vec<Operand> {
|
||||||
&mut self.stack
|
&mut self.stack
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fp(&self) -> usize {
|
pub fn fp(&self) -> usize {
|
||||||
self.fp
|
self.fp
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -163,11 +163,11 @@ impl<'a> CallStack<'a> {
|
|||||||
self.call_frames.pop().unwrap()
|
self.call_frames.pop().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn top(&self) -> &CallFrame<'a> {
|
pub fn top(&self) -> &CallFrame<'a> {
|
||||||
&self.call_frames[self.call_frames.len() - 1]
|
&self.call_frames[self.call_frames.len() - 1]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn top_mut(&mut self) -> &mut CallFrame<'a> {
|
pub fn top_mut(&mut self) -> &mut CallFrame<'a> {
|
||||||
let call_frames_len = self.call_frames.len();
|
let call_frames_len = self.call_frames.len();
|
||||||
&mut self.call_frames[call_frames_len - 1] // dang borrow checker
|
&mut self.call_frames[call_frames_len - 1] // dang borrow checker
|
||||||
}
|
}
|
||||||
@ -190,18 +190,24 @@ impl<'a> CallStack<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn call<'a>(
|
pub fn call(
|
||||||
context: &'a DvmContext,
|
context: &DvmContext,
|
||||||
registers: &mut Vec<Operand>,
|
|
||||||
call_stack: &mut CallStack<'a>,
|
|
||||||
function_name: &str,
|
function_name: &str,
|
||||||
arguments: &[Value],
|
arguments: &[Value],
|
||||||
|
register_count: usize,
|
||||||
) -> Option<Value> {
|
) -> Option<Value> {
|
||||||
// check if DVM_DEBUG is enabled
|
let mut call_stack = CallStack::new();
|
||||||
let debug = std::env::var("DVM_DEBUG")
|
let mut registers = vec![Operand::Null; register_count];
|
||||||
.map(|s| s.eq("1"))
|
prepare_for_instruction_loop(context, function_name, &mut call_stack, arguments);
|
||||||
.unwrap_or(false);
|
loop_instructions(context, &mut registers, &mut call_stack)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn prepare_for_instruction_loop<'a>(
|
||||||
|
context: &'a DvmContext,
|
||||||
|
function_name: &str,
|
||||||
|
call_stack: &mut CallStack<'a>,
|
||||||
|
arguments: &[Value],
|
||||||
|
) {
|
||||||
let function = context
|
let function = context
|
||||||
.functions
|
.functions
|
||||||
.get(function_name)
|
.get(function_name)
|
||||||
@ -222,12 +228,22 @@ pub fn call<'a>(
|
|||||||
call_stack.top_mut().set_fp(arguments.len());
|
call_stack.top_mut().set_fp(arguments.len());
|
||||||
|
|
||||||
// ensure enough stack space
|
// ensure enough stack space
|
||||||
call_stack.top_mut().stack_mut().resize(
|
call_stack
|
||||||
arguments.len() + (function.stack_size() as usize),
|
.top_mut()
|
||||||
Operand::Null,
|
.stack_mut()
|
||||||
);
|
.resize(arguments.len() + function.stack_size(), Operand::Null);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn loop_instructions<'a>(
|
||||||
|
context: &'a DvmContext,
|
||||||
|
registers: &mut Vec<Operand>,
|
||||||
|
call_stack: &mut CallStack<'a>,
|
||||||
|
) -> Option<Value> {
|
||||||
|
// check if DVM_DEBUG is enabled
|
||||||
|
let debug = std::env::var("DVM_DEBUG")
|
||||||
|
.map(|s| s.eq("1"))
|
||||||
|
.unwrap_or(false);
|
||||||
|
|
||||||
// container for final return value
|
|
||||||
let mut return_value: Option<Value> = None;
|
let mut return_value: Option<Value> = None;
|
||||||
|
|
||||||
while call_stack.maybe_top().is_some()
|
while call_stack.maybe_top().is_some()
|
||||||
@ -296,7 +312,7 @@ pub fn call<'a>(
|
|||||||
call_stack
|
call_stack
|
||||||
.top_mut()
|
.top_mut()
|
||||||
.stack_mut()
|
.stack_mut()
|
||||||
.resize(arg_count + (function.stack_size() as usize), Operand::Null);
|
.resize(arg_count + function.stack_size(), Operand::Null);
|
||||||
|
|
||||||
// set fp for callee frame
|
// set fp for callee frame
|
||||||
let callee_frame = call_stack.top_mut();
|
let callee_frame = call_stack.top_mut();
|
||||||
@ -690,6 +706,9 @@ pub fn call<'a>(
|
|||||||
// callee is the bottommost frame ("main" or whatever was called)
|
// callee is the bottommost frame ("main" or whatever was called)
|
||||||
// set the return value
|
// set the return value
|
||||||
return_value = callee.take_return_value();
|
return_value = callee.take_return_value();
|
||||||
|
// push the frame back on the call stack for further inspection by caller
|
||||||
|
call_stack.push(callee);
|
||||||
|
return return_value;
|
||||||
}
|
}
|
||||||
// do not increment ip of the caller; this was done above BEFORE the call
|
// do not increment ip of the caller; this was done above BEFORE the call
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,15 +3,15 @@ mod e2e_tests {
|
|||||||
use dmc_lib::constants_table::ConstantsTable;
|
use dmc_lib::constants_table::ConstantsTable;
|
||||||
use dmc_lib::diagnostic::Diagnostic;
|
use dmc_lib::diagnostic::Diagnostic;
|
||||||
use dmc_lib::intrinsics::{insert_intrinsic_symbols, insert_intrinsic_types};
|
use dmc_lib::intrinsics::{insert_intrinsic_symbols, insert_intrinsic_types};
|
||||||
|
use dmc_lib::offset_counter::OffsetCounter;
|
||||||
use dmc_lib::parser::parse_compilation_unit;
|
use dmc_lib::parser::parse_compilation_unit;
|
||||||
use dmc_lib::symbol_table::SymbolTable;
|
use dmc_lib::symbol_table::SymbolTable;
|
||||||
use dmc_lib::types_table::TypesTable;
|
use dmc_lib::types_table::TypesTable;
|
||||||
use dvm_lib::vm::class::Class;
|
use dvm_lib::vm::class::Class;
|
||||||
use dvm_lib::vm::constant::{Constant, StringConstant};
|
use dvm_lib::vm::constant::{Constant, StringConstant};
|
||||||
use dvm_lib::vm::function::Function;
|
use dvm_lib::vm::function::Function;
|
||||||
use dvm_lib::vm::operand::Operand;
|
|
||||||
use dvm_lib::vm::value::Value;
|
use dvm_lib::vm::value::Value;
|
||||||
use dvm_lib::vm::{CallStack, DvmContext, call};
|
use dvm_lib::vm::{DvmContext, call};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
const REGISTER_COUNT: usize = 8;
|
const REGISTER_COUNT: usize = 8;
|
||||||
@ -56,7 +56,9 @@ mod e2e_tests {
|
|||||||
let mut constants_table = ConstantsTable::new();
|
let mut constants_table = ConstantsTable::new();
|
||||||
|
|
||||||
for ir_function in &mut ir_functions {
|
for ir_function in &mut ir_functions {
|
||||||
let (_, stack_size) = ir_function.assign_registers(REGISTER_COUNT);
|
let mut offset_counter = OffsetCounter::new();
|
||||||
|
ir_function.assign_registers(REGISTER_COUNT, &mut offset_counter);
|
||||||
|
let stack_size = offset_counter.get_count();
|
||||||
let function = ir_function.assemble(stack_size, &mut constants_table);
|
let function = ir_function.assemble(stack_size, &mut constants_table);
|
||||||
functions.push(function);
|
functions.push(function);
|
||||||
}
|
}
|
||||||
@ -95,16 +97,7 @@ mod e2e_tests {
|
|||||||
function_name: &str,
|
function_name: &str,
|
||||||
arguments: &[Value],
|
arguments: &[Value],
|
||||||
) -> Option<Value> {
|
) -> Option<Value> {
|
||||||
let mut registers: Vec<Operand> = vec![Operand::Null; REGISTER_COUNT];
|
call(&dvm_context, function_name, &arguments, REGISTER_COUNT)
|
||||||
let mut call_stack = CallStack::new();
|
|
||||||
|
|
||||||
call(
|
|
||||||
&dvm_context,
|
|
||||||
&mut registers,
|
|
||||||
&mut call_stack,
|
|
||||||
function_name,
|
|
||||||
&arguments,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn assert_result(input: &str, function_name: &str, arguments: &[Value], expected_value: Value) {
|
fn assert_result(input: &str, function_name: &str, arguments: &[Value], expected_value: Value) {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user