Compare commits

..

No commits in common. "c5781114a5cf427744bdd415603428a5c0c8aaa2" and "916b6377ac6cce2706e27e732a5d1edc2a760d03" have entirely different histories.

21 changed files with 424 additions and 679 deletions

View File

@ -4,7 +4,6 @@ mod run;
use crate::repl::repl;
use crate::run::compile_and_run_script;
use clap::{Parser, Subcommand};
use std::io;
use std::path::PathBuf;
#[derive(Debug, Parser)]
@ -24,27 +23,29 @@ enum SubCommand {
#[arg(long)]
show_ir: bool,
#[arg(long, default_value = "8")]
register_count: usize,
},
Repl {
#[arg(long, default_value = "8")]
register_count: usize,
},
Repl,
}
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();
match &args.sub_command {
SubCommand::Run {
script,
show_asm,
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 => {
repl(&mut io::stdin().lock(), register_count);
SubCommand::Repl { register_count } => {
repl(*register_count);
}
}
}

View File

@ -4,44 +4,28 @@ use dmc_lib::diagnostic::Diagnostic;
use dmc_lib::ir::ir_function::IrFunction;
use dmc_lib::ir::ir_return::IrReturn;
use dmc_lib::ir::ir_statement::IrStatement;
use dmc_lib::ir::ir_variable::IrVariable;
use dmc_lib::lexer::Lexer;
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::parser::parse_expression;
use dmc_lib::symbol_table::SymbolTable;
use dmc_lib::token::TokenKind;
use dmc_lib::type_info::TypeInfo;
use dmc_lib::types_table::TypesTable;
use dvm_lib::vm::constant::{Constant, StringConstant};
use dvm_lib::vm::function::Function;
use dvm_lib::vm::operand::Operand;
use dvm_lib::vm::{CallStack, DvmContext, loop_instructions, prepare_for_instruction_loop};
use std::cell::RefCell;
use std::collections::HashMap;
use dvm_lib::vm::{CallStack, DvmContext, call};
use std::io;
use std::io::{BufRead, Write};
use std::rc::Rc;
use std::io::Write;
pub fn repl(read: &mut impl BufRead, register_count: usize) {
pub fn repl(register_count: usize) {
let mut buffer = String::new();
let mut symbol_table = SymbolTable::new();
let mut types_table = TypesTable::new();
let mut repl_fn_body_scope_id: Option<usize> = None;
let mut repl_fn_offset_counter = OffsetCounter::new();
let mut repl_fn_local_variables = HashMap::new();
let mut constants_table = ConstantsTable::new();
let mut context = DvmContext::new();
let mut repl_fn_stack_locals: Vec<Operand> = vec![];
'repl: loop {
print!("> ");
io::stdout().flush().unwrap();
read.read_line(&mut buffer).unwrap();
io::stdin().read_line(&mut buffer).unwrap();
let input = buffer.trim();
if input.is_empty() {
buffer.clear();
@ -68,40 +52,9 @@ pub fn repl(read: &mut impl BufRead, register_count: usize) {
todo!("Parse functions in repl")
}
TokenKind::Let => {
match compile_let_statement(
input,
register_count,
&mut symbol_table,
&mut repl_fn_body_scope_id,
&mut repl_fn_offset_counter,
&mut repl_fn_local_variables,
&mut types_table,
&mut constants_table,
) {
Ok(function) => {
context
.functions_mut()
.insert(function.name_owned(), function);
}
Err(diagnostics) => {
for diagnostic in diagnostics {
eprintln!("{}", diagnostic.message());
}
buffer.clear();
continue 'repl;
}
}
todo!("Parse let statements in repl")
}
_ => match compile_expression(
input,
register_count,
&mut symbol_table,
&mut types_table,
&mut repl_fn_body_scope_id,
&mut repl_fn_local_variables,
&mut repl_fn_offset_counter,
&mut constants_table,
) {
_ => match compile_expression(input, register_count, &mut constants_table) {
Ok(function) => {
context
.functions_mut()
@ -110,9 +63,9 @@ pub fn repl(read: &mut impl BufRead, register_count: usize) {
Err(diagnostics) => {
for diagnostic in &diagnostics {
eprintln!("{}", diagnostic.message());
buffer.clear();
continue 'repl;
}
buffer.clear();
continue 'repl;
}
},
}
@ -124,25 +77,10 @@ pub fn repl(read: &mut impl BufRead, register_count: usize) {
);
}
let mut registers = vec![Operand::Null; register_count];
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 {
println!("{}", value);
}
@ -151,58 +89,35 @@ pub fn repl(read: &mut impl BufRead, 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(
input: &str,
register_count: usize,
symbol_table: &mut SymbolTable,
types_table: &mut TypesTable,
fn_body_scope_id: &mut Option<usize>,
fn_local_variables: &HashMap<Rc<VariableSymbol>, Rc<RefCell<IrVariable>>>,
offset_counter: &mut OffsetCounter,
constants_table: &mut ConstantsTable,
) -> Result<Function, Vec<Diagnostic>> {
// parse
let mut expression = parse_expression(input)?;
let parse_result = parse_expression(input);
let mut expression = parse_result?;
// init scopes, if necessary
let container_scope = prepare_scopes(symbol_table, fn_body_scope_id);
let mut symbol_table = SymbolTable::new();
let mut types_table = TypesTable::new();
// inner scopes
expression.init_scopes(symbol_table, container_scope);
// "fake" scopes
symbol_table.push_module_scope("__repl_module");
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);
if !diagnostics.is_empty() {
return Err(diagnostics);
}
// type check
expression.type_check(&symbol_table, types_table)?;
expression.type_check(&symbol_table, &mut types_table)?;
// synthesize a function
// init ir_builder
let mut ir_builder = IrBuilder::new();
// copy all previous declared variables to here so we preserve their stack offsets
for (key, value) in fn_local_variables {
ir_builder
.local_variables_mut()
.insert(key.clone(), value.clone());
}
let entry_block_id = ir_builder.new_block();
let maybe_ir_expression =
@ -223,75 +138,6 @@ fn compile_expression(
entry_block.clone(),
);
// spilled registers are put on the stack, so we need to add it to our stack size
ir_function.assign_registers(register_count, offset_counter);
Ok(ir_function.assemble(offset_counter.get_count(), constants_table))
}
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))
let (_, stack_size) = ir_function.assign_registers(register_count);
Ok(ir_function.assemble(stack_size, constants_table))
}

View File

@ -6,13 +6,13 @@ use dm_std_lib::add_all_std_core;
use dmc_lib::constants_table::ConstantsTable;
use dmc_lib::diagnostic::Diagnostic;
use dmc_lib::intrinsics::{insert_intrinsic_symbols, insert_intrinsic_types};
use dmc_lib::offset_counter::OffsetCounter;
use dmc_lib::parser::parse_compilation_unit;
use dmc_lib::symbol_table::SymbolTable;
use dmc_lib::types_table::TypesTable;
use dvm_lib::vm::constant::{Constant, StringConstant};
use dvm_lib::vm::function::Function;
use dvm_lib::vm::{DvmContext, call};
use dvm_lib::vm::operand::Operand;
use dvm_lib::vm::{CallStack, DvmContext, call};
use std::path::PathBuf;
use std::rc::Rc;
@ -67,9 +67,8 @@ fn run(
let mut constants_table = ConstantsTable::new();
for ir_function in &mut ir_functions {
let mut offset_counter = OffsetCounter::new();
ir_function.assign_registers(register_count, &mut offset_counter);
let function = ir_function.assemble(offset_counter.get_count(), &mut constants_table);
let (_, stack_size) = ir_function.assign_registers(register_count);
let function = ir_function.assemble(stack_size, &mut constants_table);
functions.push(function);
}
@ -108,8 +107,16 @@ fn run(
);
}
let result = call(&dvm_context, "main", &vec![], register_count);
let mut registers: Vec<Operand> = vec![Operand::Null; register_count];
let mut call_stack = CallStack::new();
let result = call(
&dvm_context,
&mut registers,
&mut call_stack,
"main",
&vec![],
);
if let Some(value) = result {
println!("{}", value);
}

View File

@ -8,7 +8,7 @@ use crate::ir::ir_class::IrClass;
use crate::ir::ir_function::IrFunction;
use crate::symbol_table::SymbolTable;
use crate::types_table::TypesTable;
use crate::{diagnostics_result, handle_diagnostics};
use crate::{diagnostics_result, handle_diagnostics, ok_or_err_diagnostics};
pub struct CompilationUnit {
functions: Vec<Function>,

View File

@ -10,7 +10,6 @@ use crate::symbol::Symbol;
use crate::symbol::class_symbol::ClassSymbol;
use crate::symbol::variable_symbol::VariableSymbol;
use crate::symbol_table::SymbolTable;
use crate::type_info::TypeInfo;
use crate::types_table::TypesTable;
use std::cell::RefCell;
use std::rc::Rc;
@ -56,10 +55,6 @@ impl LetStatement {
self.initializer.init_scopes(symbol_table, container_scope);
}
pub fn scope_id(&self) -> usize {
self.scope_id.unwrap()
}
fn make_and_insert_variable_symbol(
&self,
symbol_table: &mut SymbolTable,
@ -136,7 +131,6 @@ impl LetStatement {
types_table: &mut TypesTable,
) -> Result<(), Vec<Diagnostic>> {
self.initializer.type_check(symbol_table, types_table)?;
// TODO: this is wrong. We need to check assignability
let initializer_type_info = self
.initializer
.type_info(symbol_table, types_table)
@ -150,34 +144,6 @@ impl LetStatement {
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(
&self,
builder: &mut IrBuilder,
@ -188,14 +154,20 @@ impl LetStatement {
.initializer
.to_ir_operation(builder, symbol_table, types_table);
let destination_symbol = self.get_destination_symbol(symbol_table);
let destination_symbol = symbol_table
.get_variable_symbol_owned(self.scope_id.unwrap(), &self.declared_name)
.unwrap();
let destination_type = types_table
.variable_types()
.get(&destination_symbol)
.unwrap();
let destination_vr_variable = self.make_vr_variable(builder, destination_type);
let destination_vr_variable = IrVariable::new_vr(
self.declared_name().into(),
builder.current_block().id(),
destination_type,
);
let as_rc = Rc::new(RefCell::new(destination_vr_variable));
let ir_assign = IrAssign::new(as_rc.clone(), init_operation);
@ -208,30 +180,4 @@ impl LetStatement {
.current_block_mut()
.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
}
}

View File

@ -1,5 +1,3 @@
pub type Diagnostics = Vec<Diagnostic>;
#[derive(Debug)]
pub struct Diagnostic {
message: String,

View File

@ -1,7 +1,5 @@
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_ALREADY_DECLARED: ErrorCode = 14;
pub const BINARY_INCOMPATIBLE_TYPES: ErrorCode = 15;

View File

@ -2,9 +2,8 @@ use crate::constants_table::ConstantsTable;
use crate::ir::assemble::{Assemble, InstructionsBuilder};
use crate::ir::ir_operation::IrOperation;
use crate::ir::ir_variable::{IrVariable, IrVariableDescriptor, IrVrVariableDescriptor};
use crate::ir::register_allocation::VrUser;
use crate::ir::register_allocation::{OffsetCounter, VrUser};
use crate::ir::util::propagate_spills;
use crate::offset_counter::OffsetCounter;
use dvm_lib::instruction::Instruction;
use std::cell::RefCell;
use std::collections::{HashMap, HashSet};
@ -58,7 +57,7 @@ impl VrUser for IrAssign {
fn propagate_stack_offsets(&mut self, counter: &mut OffsetCounter) {
let mut borrowed_destination = self.destination.borrow_mut();
if let IrVariableDescriptor::Stack(stack_variable) = borrowed_destination.descriptor_mut() {
stack_variable.use_next_offset(counter);
stack_variable.set_offset(counter.next());
}
}
}

View File

@ -2,8 +2,7 @@ use crate::constants_table::ConstantsTable;
use crate::ir::assemble::{Assemble, InstructionsBuilder};
use crate::ir::ir_statement::IrStatement;
use crate::ir::ir_variable::IrVrVariableDescriptor;
use crate::ir::register_allocation::{HasVrUsers, VrUser};
use crate::offset_counter::OffsetCounter;
use crate::ir::register_allocation::{HasVrUsers, OffsetCounter, VrUser};
use std::cell::RefCell;
use std::collections::{HashMap, HashSet};
use std::fmt::{Display, Formatter};
@ -123,7 +122,6 @@ impl Display for IrBlock {
#[cfg(test)]
mod tests {
use crate::diagnostic::Diagnostic;
use crate::offset_counter::OffsetCounter;
use crate::parser::parse_compilation_unit;
use crate::symbol_table::SymbolTable;
use crate::types_table::TypesTable;
@ -157,7 +155,7 @@ mod tests {
.unwrap();
let mut main_ir = main.to_ir(&symbol_table, &types_table, None);
let register_assignments = main_ir.assign_registers(2, &mut OffsetCounter::new());
let (register_assignments, _) = main_ir.assign_registers(2);
assert_eq!(register_assignments.len(), 4);
Ok(())

View File

@ -4,7 +4,6 @@ use crate::ir::ir_block::IrBlock;
use crate::ir::ir_parameter::IrParameter;
use crate::ir::ir_variable::IrVrVariableDescriptor;
use crate::ir::register_allocation::HasVrUsers;
use crate::offset_counter::OffsetCounter;
use crate::type_info::TypeInfo;
use dvm_lib::vm::function::Function;
use std::cell::RefCell;
@ -37,14 +36,11 @@ impl IrFunction {
pub fn assign_registers(
&mut self,
register_count: usize,
offset_counter: &mut OffsetCounter,
) -> HashMap<IrVrVariableDescriptor, usize> {
self.entry
.borrow_mut()
.assign_registers(register_count, offset_counter)
) -> (HashMap<IrVrVariableDescriptor, usize>, isize) {
self.entry.borrow_mut().assign_registers(register_count)
}
pub fn assemble(&self, stack_size: usize, constants_table: &mut ConstantsTable) -> Function {
pub fn assemble(&self, stack_size: isize, constants_table: &mut ConstantsTable) -> Function {
let mut builder = InstructionsBuilder::new();
self.entry.borrow().assemble(&mut builder, constants_table);
let instructions = builder.take_instructions();

View File

@ -5,8 +5,7 @@ use crate::ir::ir_call::IrCall;
use crate::ir::ir_return::IrReturn;
use crate::ir::ir_set_field::IrSetField;
use crate::ir::ir_variable::IrVrVariableDescriptor;
use crate::ir::register_allocation::VrUser;
use crate::offset_counter::OffsetCounter;
use crate::ir::register_allocation::{OffsetCounter, VrUser};
use std::collections::{HashMap, HashSet};
use std::fmt::{Display, Formatter};

View File

@ -1,4 +1,3 @@
use crate::offset_counter::OffsetCounter;
use crate::type_info::TypeInfo;
use dvm_lib::instruction::Location;
use std::collections::HashSet;
@ -21,16 +20,9 @@ impl IrVariable {
}
}
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);
pub fn new_stack(name: Rc<str>, block_id: usize, type_info: TypeInfo) -> Self {
Self {
descriptor: IrVariableDescriptor::Stack(descriptor),
descriptor: IrVariableDescriptor::Stack(IrStackVariableDescriptor::new(name, block_id)),
type_info: type_info.clone(),
}
}
@ -185,12 +177,6 @@ impl IrStackVariableDescriptor {
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) {
self.offset = Some(offset);
}

View File

@ -1,5 +1,4 @@
use crate::ir::ir_variable::IrVrVariableDescriptor;
use crate::offset_counter::OffsetCounter;
use std::collections::{HashMap, HashSet};
pub type InterferenceGraph = HashMap<IrVrVariableDescriptor, HashSet<IrVrVariableDescriptor>>;
@ -105,8 +104,7 @@ pub trait HasVrUsers {
fn assign_registers(
&mut self,
register_count: usize,
offset_counter: &mut OffsetCounter,
) -> HashMap<IrVrVariableDescriptor, usize> {
) -> (HashMap<IrVrVariableDescriptor, usize>, isize) {
let mut spills: HashSet<IrVrVariableDescriptor> = HashSet::new();
loop {
let mut interference_graph = self.interference_graph();
@ -125,11 +123,12 @@ pub trait HasVrUsers {
vr_user.propagate_register_assignments(&registers);
}
// also set offsets
let mut offset_counter = OffsetCounter::new();
for vr_user in self.vr_users_mut() {
vr_user.propagate_stack_offsets(offset_counter);
vr_user.propagate_stack_offsets(&mut offset_counter);
}
return registers;
return (registers, offset_counter.get_count());
}
}
}
@ -158,6 +157,26 @@ 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)]
struct WorkItem {
vr: IrVrVariableDescriptor,

View File

@ -34,133 +34,134 @@ impl<'a> Lexer<'a> {
}
}
let mut chars = chunk.chars();
let current = chars.next().unwrap(); // safe because we return None if chunk is empty above
let peek = chars.next();
let (end, kind) = match current {
'-' => {
if let Some(peek) = peek {
if peek == '>' {
(self.position + 2, TokenKind::RightArrow)
let token = if chunk.starts_with("->") {
Token::new(self.position, self.position + 2, TokenKind::RightArrow)
} else if chunk.starts_with("-") {
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 {
(self.position + 1, TokenKind::Minus)
break;
}
} 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() {
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;
} else {
break;
}
}
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 += 1; // to account for decimal point
found_fraction = true;
}
}
if found_fraction {
(end, TokenKind::DoubleLiteral)
} else {
(end, TokenKind::IntegerLiteral)
break;
}
}
if found_fraction {
Token::new(self.position, end, TokenKind::DoubleLiteral)
} else {
(end, TokenKind::IntegerLiteral)
Token::new(self.position, end, TokenKind::IntegerLiteral)
}
} else if chunk.starts_with("\"") {
// string literal
let mut end = self.position;
let mut terminated = false;
let mut chars = chunk.chars();
chars.next(); // skip opening quote
end += 1;
for char in chars {
end += 1;
if char == '"' {
terminated = true;
break;
}
}
if !terminated {
return Some(Err(LexerError::new(
self.position,
end,
LexerErrorKind::UnterminatedString,
)));
}
(end, TokenKind::String)
} else {
// keyword or identifier
let mut prefix = String::new();
for char in chunk.chars() {
if char.is_alphanumeric() || char == '_' {
prefix.push(char);
} else {
break;
}
}
if prefix.len() == 0 {
return Some(Err(LexerError::new(
self.position,
self.position + 1,
LexerErrorKind::UnrecognizedCharacter(chunk.chars().next().unwrap()),
)));
}
let token_kind = match prefix.as_str() {
"fn" => TokenKind::Fn,
"end" => TokenKind::End,
"let" => TokenKind::Let,
"extern" => TokenKind::Extern,
"class" => TokenKind::Class,
"self" => TokenKind::SelfKw,
"pub" => TokenKind::Public,
"mut" => TokenKind::Mut,
"ctor" => TokenKind::Ctor,
_ => TokenKind::Identifier,
};
(self.position + prefix.len(), token_kind)
Token::new(self.position, end, TokenKind::IntegerLiteral)
}
} else if chunk.starts_with("\"") {
// string literal
let mut end = self.position;
let mut terminated = false;
let mut chars = chunk.chars();
chars.next(); // skip opening quote
end += 1;
for char in chars {
end += 1;
if char == '"' {
terminated = true;
break;
}
}
if !terminated {
return Some(Err(LexerError::new(LexerErrorKind::UnterminatedString)));
}
Token::new(self.position, end, TokenKind::String)
} else {
// keyword or identifier
let mut prefix = String::new();
for char in chunk.chars() {
if char.is_alphanumeric() || char == '_' {
prefix.push(char);
} else {
break;
}
}
if prefix.len() == 0 {
return Some(Err(LexerError::new(LexerErrorKind::UnrecognizedCharacter(
chunk.chars().next().unwrap(),
))));
}
let token_kind = match prefix.as_str() {
"fn" => TokenKind::Fn,
"end" => TokenKind::End,
"let" => TokenKind::Let,
"extern" => TokenKind::Extern,
"class" => TokenKind::Class,
"self" => TokenKind::SelfKw,
"pub" => TokenKind::Public,
"mut" => TokenKind::Mut,
"ctor" => TokenKind::Ctor,
_ => TokenKind::Identifier,
};
Token::new(self.position, self.position + prefix.len(), token_kind)
}
};
let token = Token::new(self.position, end, kind);
self.position += token.end() - token.start();
Some(Ok(token))
}
@ -168,22 +169,12 @@ impl<'a> Lexer<'a> {
#[derive(Debug, Eq, PartialEq)]
pub struct LexerError {
start: usize,
end: usize,
kind: LexerErrorKind,
}
impl LexerError {
pub fn new(start: usize, end: usize, kind: LexerErrorKind) -> Self {
Self { start, end, kind }
}
pub fn start(&self) -> usize {
self.start
}
pub fn end(&self) -> usize {
self.end
pub fn new(kind: LexerErrorKind) -> Self {
Self { kind }
}
pub fn kind(&self) -> LexerErrorKind {

View File

@ -5,7 +5,6 @@ pub mod error_codes;
pub mod intrinsics;
pub mod ir;
pub mod lexer;
pub mod offset_counter;
pub mod parser;
pub mod scope;
pub mod source_range;

View File

@ -1,23 +0,0 @@
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
}
}

View File

@ -19,34 +19,23 @@ use crate::ast::parameter::Parameter;
use crate::ast::statement::Statement;
use crate::ast::string_literal::StringLiteral;
use crate::ast::type_use::TypeUse;
use crate::diagnostic::{Diagnostic, Diagnostics};
use crate::error_codes::{LEXER_ERROR, PARSE_ERROR};
use crate::lexer::{Lexer, LexerErrorKind};
use crate::diagnostic::Diagnostic;
use crate::lexer::Lexer;
use crate::source_range::SourceRange;
use crate::token::{Token, TokenKind};
use crate::{handle_diagnostics, ok_or_err_diagnostics};
use std::str::FromStr;
pub type ParseResult<T> = Result<T, Diagnostics>;
pub fn parse_compilation_unit(input: &str) -> ParseResult<CompilationUnit> {
pub fn parse_compilation_unit(input: &str) -> Result<CompilationUnit, Vec<Diagnostic>> {
let mut parser = Parser::new(input);
parser.advance()?; // get started
parser.compilation_unit()
}
pub fn parse_expression(input: &str) -> ParseResult<Expression> {
pub fn parse_expression(input: &str) -> Result<Expression, Vec<Diagnostic>> {
let mut parser = Parser::new(input);
parser.advance()?; // get started
parser.advance(); // get started
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 {
( $token_kind : expr ) => {
matches!(
@ -107,116 +96,96 @@ impl<'a> Parser<'a> {
}
}
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)
}
fn advance(&mut self) {
if self.lookahead.is_some() {
// we've advanced at least once
self.current = self.lookahead.take();
self.lookahead = fetch(&mut self.lexer)?;
Ok(())
self.lookahead = match self.lexer.next() {
None => None,
Some(result) => match result {
Ok(token) => Some(token),
Err(lexer_error) => {
panic!("{:?}", lexer_error);
}
},
}
} else if self.lookahead.is_none() && self.current.is_some() {
// we're on the last token
self.current = None;
Ok(())
} else {
// we've not yet advanced, so fetch both
self.current = fetch(&mut self.lexer)?;
self.lookahead = fetch(&mut self.lexer)?;
Ok(())
// current
match self.lexer.next() {
None => {}
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 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> {
fn expect_advance(&mut self, token_kind: TokenKind) -> Result<Token, Vec<Diagnostic>> {
match self.current.take() {
None => Err(vec![Self::get_expected_but_found_eoi(
&[token_kind],
self.input.len(),
)]),
None => Err(vec![
Diagnostic::new(
&format!("Expected {:?} but found end-of-input.", token_kind),
self.input.len(),
self.input.len(),
)
.with_reporter(file!(), line!()),
]),
Some(token) => {
if token.kind() == token_kind {
self.advance()?;
self.advance();
Ok(token)
} else {
self.advance_until(&[token_kind]);
Err(vec![Self::get_expected_but_found(&[token_kind], &token)])
Err(vec![
Diagnostic::new(
&format!("Expected {:?} but found {:?}", token_kind, token.kind()),
token.start(),
token.end(),
)
.with_reporter(file!(), line!()),
])
}
}
}
}
fn expect_immediately_after_advance(
fn expect_position_advance(
&mut self,
token_kind: TokenKind,
previous_token: &Token,
) -> Result<Token, Diagnostics> {
start_position: usize,
) -> Result<Token, Vec<Diagnostic>> {
let matched = self.expect_advance(token_kind)?;
if matched.start() == previous_token.end() {
if matched.start() == start_position {
Ok(matched)
} else {
Err(vec![
Diagnostic::new(
&format!(
"Expected {:?} immediately after previous token.",
token_kind
),
&format!("Expected {:?} but found {:?}", token_kind, matched.kind()),
matched.start(),
matched.end(),
)
.with_error_code(PARSE_ERROR),
.with_reporter(file!(), line!()),
])
}
}
@ -237,6 +206,13 @@ 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 {
&self.input[start..end]
}
@ -245,40 +221,49 @@ impl<'a> Parser<'a> {
self.sample_input(token.start(), token.end())
}
fn compilation_unit(&mut self) -> Result<CompilationUnit, Vec<Diagnostic>> {
pub fn compilation_unit(&mut self) -> Result<CompilationUnit, Vec<Diagnostic>> {
let mut functions: Vec<Function> = vec![];
let mut extern_functions: Vec<ExternFunction> = vec![];
let mut classes: Vec<Class> = vec![];
let mut diagnostics = vec![];
self.advance(); // get started
while self.current.is_some() {
let current = self.get_current();
match current.kind() {
TokenKind::Fn | TokenKind::Extern | TokenKind::Class => {
handle_diagnostics!(
self.module_level_declaration(
&mut functions,
&mut extern_functions,
&mut classes
),
diagnostics
);
match self.module_level_declaration(
&mut functions,
&mut extern_functions,
&mut classes,
) {
Ok(_) => {}
Err(mut declaration_diagnostics) => {
diagnostics.append(&mut declaration_diagnostics)
}
}
}
_ => {
diagnostics.push(Self::get_expected_but_found(
&[TokenKind::Fn, TokenKind::Extern, TokenKind::Class],
current,
diagnostics.push(Diagnostic::new(
&format!(
"Expected any of {:?}; found {:?}",
[TokenKind::Fn, TokenKind::Extern, TokenKind::Class],
current.kind()
),
current.start(),
current.end(),
));
self.advance_until(&[TokenKind::Fn, TokenKind::Extern, TokenKind::Class]);
self.advance_until(&[TokenKind::Fn, TokenKind::Extern]);
}
}
}
ok_or_err_diagnostics!(
CompilationUnit::new(functions, extern_functions, classes),
diagnostics
)
if diagnostics.is_empty() {
Ok(CompilationUnit::new(functions, extern_functions, classes))
} else {
Err(diagnostics)
}
}
fn module_level_declaration(
@ -322,7 +307,7 @@ impl<'a> Parser<'a> {
fn function(&mut self) -> Result<Function, Vec<Diagnostic>> {
let is_public = if self.current.is_some() && self.peek_current(TokenKind::Public) {
self.advance()?; // pub
self.advance(); // pub
true
} else {
false
@ -371,17 +356,18 @@ impl<'a> Parser<'a> {
_ => {}
}
ok_or_err_diagnostics!(
Function::new(
if diagnostics.is_empty() {
Ok(Function::new(
self.token_text(&identifier_token),
SourceRange::new(identifier_token.start(), identifier_token.end()),
is_public,
parameters,
return_type,
statements,
),
diagnostics
)
))
} else {
Err(diagnostics)
}
}
fn extern_function(&mut self) -> Result<ExternFunction, Vec<Diagnostic>> {
@ -413,15 +399,16 @@ impl<'a> Parser<'a> {
let return_type = self.return_type()?;
ok_or_err_diagnostics!(
ExternFunction::new(
if diagnostics.is_empty() {
Ok(ExternFunction::new(
self.token_text(&identifier_token),
SourceRange::new(identifier_token.start(), identifier_token.end()),
maybe_parameters.unwrap(),
return_type,
),
diagnostics
)
))
} else {
Err(diagnostics)
}
}
fn class(&mut self) -> Result<Class, Vec<Diagnostic>> {
@ -472,17 +459,18 @@ impl<'a> Parser<'a> {
self.expect_advance(TokenKind::End)?;
ok_or_err_diagnostics!(
Class::new(
if diagnostics.is_empty() {
Ok(Class::new(
self.token_text(&identifier_token),
SourceRange::new(identifier_token.start(), identifier_token.end()),
generic_parameters,
maybe_constructor,
fields,
functions,
),
diagnostics
)
))
} else {
Err(diagnostics)
}
}
fn parameter_list(&mut self) -> Result<Vec<Parameter>, Vec<Diagnostic>> {
@ -499,15 +487,14 @@ impl<'a> Parser<'a> {
}
}
if self.current.is_some() && self.peek_current(TokenKind::Comma) {
match self.advance() {
Ok(_) => {}
Err(mut ds) => {
diagnostics.append(&mut ds);
}
};
self.advance();
}
}
ok_or_err_diagnostics!(parameters, diagnostics)
if diagnostics.is_empty() {
Ok(parameters)
} else {
Err(diagnostics)
}
}
fn parameter(&mut self) -> Result<Parameter, Vec<Diagnostic>> {
@ -531,7 +518,7 @@ impl<'a> Parser<'a> {
let current = self.get_current();
return match current.kind() {
TokenKind::LeftSquare => {
self.advance()?; // [
self.advance(); // [
let inner_type_use = self.type_use()?;
self.expect_advance(TokenKind::RightSquare)?;
todo!()
@ -540,7 +527,7 @@ impl<'a> Parser<'a> {
let identifier_token = self.expect_advance(TokenKind::Identifier)?;
let generic_arguments =
if self.current.is_some() && self.peek_current(TokenKind::Lt) {
self.advance()?; // <
self.advance(); // <
let generic_arguments = self.generic_arguments_list()?;
self.expect_advance(TokenKind::Gt)?; // >
generic_arguments
@ -553,14 +540,19 @@ impl<'a> Parser<'a> {
generic_arguments,
))
}
_ => Err(vec![Self::get_expected_but_found(
&[TokenKind::LeftSquare, TokenKind::Identifier],
current,
_ => Err(vec![Diagnostic::new(
&format!(
"Expected LeftSquare or Identifier; found: {:?}",
current.kind()
),
current.start(),
current.end(),
)]),
};
}
Err(vec![Self::get_expected_but_found_eoi(
&[TokenKind::LeftSquare, TokenKind::Identifier],
Err(vec![Diagnostic::new(
"Expected LeftSquare or Identifier; found end of input.",
self.input.len(),
self.input.len(),
)])
}
@ -570,7 +562,7 @@ impl<'a> Parser<'a> {
while self.current.is_some() && matches_type_use_first!(self.get_current().kind()) {
generic_arguments.push(self.type_use()?);
if self.current.is_some() && self.peek_current(TokenKind::Comma) {
self.advance()?; // comma
self.advance(); // comma
} else {
break;
}
@ -584,7 +576,7 @@ impl<'a> Parser<'a> {
while self.current.is_some() && self.peek_current(TokenKind::Identifier) {
parameters.push(self.generic_parameter()?);
if self.current.is_some() && self.peek_current(TokenKind::Plus) {
self.advance()?; // +
self.advance(); // +
} else {
break;
}
@ -597,11 +589,11 @@ impl<'a> Parser<'a> {
let identifier = self.expect_advance(TokenKind::Identifier)?;
let mut extends_list: Vec<TypeUse> = vec![];
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()) {
extends_list.push(self.type_use()?);
if self.current.is_some() && self.peek_current(TokenKind::Comma) {
self.advance()?; // ,
self.advance(); // ,
} else {
break;
}
@ -631,25 +623,34 @@ impl<'a> Parser<'a> {
}
_ => {
let lookahead = self.lookahead.as_ref().unwrap();
return Err(vec![Self::get_expected_but_found(
&[TokenKind::Mut, TokenKind::Identifier, TokenKind::Fn],
lookahead,
return Err(vec![Diagnostic::new(
&format!(
"Expected any of {:?}; found {:?}",
[TokenKind::Mut, TokenKind::Identifier, TokenKind::Fn],
lookahead.kind()
),
lookahead.start(),
lookahead.end(),
)]);
}
}
Ok(())
} else {
let current = self.current.as_ref().unwrap();
Err(vec![Self::get_expected_but_found(
&[TokenKind::Mut, TokenKind::Identifier, TokenKind::Fn],
current,
Err(vec![Diagnostic::new(
&format!(
"Expected any of {:?}; found end-of-input.",
[TokenKind::Mut, TokenKind::Identifier, TokenKind::Fn]
),
current.end(),
current.end(),
)])
}
}
fn constructor(&mut self) -> Result<Constructor, Vec<Diagnostic>> {
let is_public = if self.current.is_some() && self.peek_current(TokenKind::Public) {
self.advance()?;
self.advance();
true
} else {
false
@ -699,14 +700,14 @@ impl<'a> Parser<'a> {
fn field(&mut self) -> Result<Field, Vec<Diagnostic>> {
let is_public = if self.current.is_some() && self.peek_current(TokenKind::Public) {
self.advance()?;
self.advance();
true
} else {
false
};
let is_mut = if self.current.is_some() && self.peek_current(TokenKind::Mut) {
self.advance()?;
self.advance();
true
} else {
false
@ -715,14 +716,14 @@ impl<'a> Parser<'a> {
let identifier = self.expect_advance(TokenKind::Identifier)?;
let declared_type = if self.current.is_some() && self.peek_current(TokenKind::Colon) {
self.advance()?; // colon
self.advance(); // colon
Some(self.type_use()?)
} else {
None
};
let initializer = if self.current.is_some() && self.peek_current(TokenKind::Equals) {
self.advance()?; // equals
self.advance(); // equals
Some(self.expression()?)
} else {
None
@ -750,7 +751,7 @@ impl<'a> Parser<'a> {
self.expect_advance(TokenKind::Let)?;
let is_mut = if self.current.is_some() && self.peek_current(TokenKind::Mut) {
self.advance()?;
self.advance();
true
} else {
false
@ -789,7 +790,7 @@ impl<'a> Parser<'a> {
fn bitwise_or_expression(&mut self) -> Result<Expression, Vec<Diagnostic>> {
let mut result = self.bitwise_xor_expression()?;
while self.current.is_some() && self.peek_current(TokenKind::Bar) {
self.advance()?; // |
self.advance(); // |
let rhs = self.bitwise_xor_expression()?;
let source_range =
SourceRange::new(result.source_range().start(), rhs.source_range().end());
@ -806,7 +807,7 @@ impl<'a> Parser<'a> {
fn bitwise_xor_expression(&mut self) -> Result<Expression, Vec<Diagnostic>> {
let mut result = self.bitwise_and_expression()?;
while self.current.is_some() && self.peek_current(TokenKind::Caret) {
self.advance()?; // ^
self.advance(); // ^
let rhs = self.bitwise_and_expression()?;
let source_range =
SourceRange::new(result.source_range().start(), rhs.source_range().end());
@ -823,7 +824,7 @@ impl<'a> Parser<'a> {
fn bitwise_and_expression(&mut self) -> Result<Expression, Vec<Diagnostic>> {
let mut result = self.shift_expression()?;
while self.current.is_some() && self.peek_current(TokenKind::Ampersand) {
self.advance()?; // &
self.advance(); // &
let rhs = self.shift_expression()?;
let source_range =
SourceRange::new(result.source_range().start(), rhs.source_range().end());
@ -843,9 +844,9 @@ impl<'a> Parser<'a> {
let current = self.get_current();
match current.kind() {
TokenKind::Lt => {
let previous_cloned = current.clone();
self.advance()?; // first <
self.expect_immediately_after_advance(TokenKind::Lt, &previous_cloned)?; // second <
let second_lt_start = current.start() + 1;
self.advance(); // first <
self.expect_position_advance(TokenKind::Lt, second_lt_start)?; // second <
let rhs = self.additive_expression()?;
let source_range =
SourceRange::new(result.source_range().start(), rhs.source_range().end());
@ -857,9 +858,9 @@ impl<'a> Parser<'a> {
));
}
TokenKind::Gt => {
let previous_cloned = current.clone();
self.advance()?; // first >
self.expect_immediately_after_advance(TokenKind::Gt, &previous_cloned)?; // second gt
let second_gt_start = current.start() + 1;
self.advance(); // first >
self.expect_position_advance(TokenKind::Gt, second_gt_start)?; // second gt
let rhs = self.additive_expression()?;
let source_range =
SourceRange::new(result.source_range().start(), rhs.source_range().end());
@ -882,7 +883,7 @@ impl<'a> Parser<'a> {
let current = self.get_current();
match current.kind() {
TokenKind::Plus => {
self.advance()?; // plus
self.advance(); // plus
let rhs = self.multiplicative_expression()?;
let source_range =
SourceRange::new(result.source_range().start(), rhs.source_range().end());
@ -894,7 +895,7 @@ impl<'a> Parser<'a> {
));
}
TokenKind::Minus => {
self.advance()?; // minus
self.advance(); // minus
let rhs = self.multiplicative_expression()?;
let source_range =
SourceRange::new(result.source_range().start(), rhs.source_range().end());
@ -917,7 +918,7 @@ impl<'a> Parser<'a> {
let current = self.get_current();
match current.kind() {
TokenKind::Star => {
self.advance()?; // multiply
self.advance(); // multiply
let rhs = self.prefix_expression()?;
let source_range =
SourceRange::new(result.source_range().start(), rhs.source_range().end());
@ -929,7 +930,7 @@ impl<'a> Parser<'a> {
));
}
TokenKind::Slash => {
self.advance()?; // slash
self.advance(); // slash
let rhs = self.prefix_expression()?;
let source_range =
SourceRange::new(result.source_range().start(), rhs.source_range().end());
@ -941,7 +942,7 @@ impl<'a> Parser<'a> {
))
}
TokenKind::Modulo => {
self.advance()?; // modulo
self.advance(); // modulo
let rhs = self.prefix_expression()?;
let source_range =
SourceRange::new(result.source_range().start(), rhs.source_range().end());
@ -966,7 +967,7 @@ impl<'a> Parser<'a> {
match current.kind() {
TokenKind::Minus => {
operator_tokens.push(current.clone()); // unfortunately necessary
self.advance()?;
self.advance();
}
_ => break,
}
@ -1009,7 +1010,7 @@ impl<'a> Parser<'a> {
TokenKind::IntegerLiteral => {
let raw = self.token_text(&current);
let source_range = SourceRange::new(current.start(), current.end());
self.advance()?;
self.advance();
Ok(Expression::Integer(IntegerLiteral::new(
i32::from_str(raw).unwrap(),
source_range,
@ -1018,7 +1019,7 @@ impl<'a> Parser<'a> {
TokenKind::DoubleLiteral => {
let raw = self.token_text(&current);
let source_range = SourceRange::new(current.start(), current.end());
self.advance()?;
self.advance();
Ok(Expression::Double(DoubleLiteral::new(
f64::from_str(raw).unwrap(),
source_range,
@ -1027,7 +1028,7 @@ impl<'a> Parser<'a> {
TokenKind::String => {
let with_quotes = self.token_text(&current);
let source_range = SourceRange::new(current.start(), current.end());
self.advance()?;
self.advance();
Ok(Expression::String(StringLiteral::new(
&with_quotes[1..with_quotes.len() - 1],
source_range,
@ -1036,7 +1037,7 @@ impl<'a> Parser<'a> {
TokenKind::Identifier => {
let declared_name = self.token_text(&current);
let source_range = SourceRange::new(current.start(), current.end());
self.advance()?;
self.advance();
Ok(Expression::Identifier(Identifier::new(
declared_name,
source_range,
@ -1064,7 +1065,7 @@ impl<'a> Parser<'a> {
let mut expressions = vec![];
expressions.push(self.expression()?);
while self.current.is_some() && self.peek_current(TokenKind::Comma) {
self.advance()?; // comma
self.advance(); // comma
expressions.push(self.expression()?);
}
Ok(expressions)

View File

@ -89,10 +89,6 @@ impl SymbolTable {
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 {
&self.scopes[scope_id]
}

View File

@ -5,7 +5,7 @@ use std::rc::Rc;
pub struct Function {
name: Rc<str>,
parameter_count: usize,
stack_size: usize,
stack_size: isize,
instructions: Vec<Instruction>,
}
@ -13,7 +13,7 @@ impl Function {
pub fn new(
name: Rc<str>,
parameter_count: usize,
stack_size: usize,
stack_size: isize,
instructions: Vec<Instruction>,
) -> Self {
Self {
@ -36,7 +36,7 @@ impl Function {
self.parameter_count
}
pub fn stack_size(&self) -> usize {
pub fn stack_size(&self) -> isize {
self.stack_size
}

View File

@ -115,15 +115,15 @@ impl<'a> CallFrame<'a> {
self.ip += 1;
}
pub fn stack(&self) -> &[Operand] {
fn stack(&self) -> &[Operand] {
&self.stack
}
pub fn stack_mut(&mut self) -> &mut Vec<Operand> {
fn stack_mut(&mut self) -> &mut Vec<Operand> {
&mut self.stack
}
pub fn fp(&self) -> usize {
fn fp(&self) -> usize {
self.fp
}
@ -163,11 +163,11 @@ impl<'a> CallStack<'a> {
self.call_frames.pop().unwrap()
}
pub fn top(&self) -> &CallFrame<'a> {
fn top(&self) -> &CallFrame<'a> {
&self.call_frames[self.call_frames.len() - 1]
}
pub fn top_mut(&mut self) -> &mut CallFrame<'a> {
fn top_mut(&mut self) -> &mut CallFrame<'a> {
let call_frames_len = self.call_frames.len();
&mut self.call_frames[call_frames_len - 1] // dang borrow checker
}
@ -190,24 +190,18 @@ impl<'a> CallStack<'a> {
}
}
pub fn call(
context: &DvmContext,
function_name: &str,
arguments: &[Value],
register_count: usize,
) -> Option<Value> {
let mut call_stack = CallStack::new();
let mut registers = vec![Operand::Null; register_count];
prepare_for_instruction_loop(context, function_name, &mut call_stack, arguments);
loop_instructions(context, &mut registers, &mut call_stack)
}
pub fn prepare_for_instruction_loop<'a>(
pub fn call<'a>(
context: &'a DvmContext,
function_name: &str,
registers: &mut Vec<Operand>,
call_stack: &mut CallStack<'a>,
function_name: &str,
arguments: &[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
.functions
.get(function_name)
@ -228,22 +222,12 @@ pub fn prepare_for_instruction_loop<'a>(
call_stack.top_mut().set_fp(arguments.len());
// ensure enough stack space
call_stack
.top_mut()
.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);
call_stack.top_mut().stack_mut().resize(
arguments.len() + (function.stack_size() as usize),
Operand::Null,
);
// container for final return value
let mut return_value: Option<Value> = None;
while call_stack.maybe_top().is_some()
@ -312,7 +296,7 @@ pub fn loop_instructions<'a>(
call_stack
.top_mut()
.stack_mut()
.resize(arg_count + function.stack_size(), Operand::Null);
.resize(arg_count + (function.stack_size() as usize), Operand::Null);
// set fp for callee frame
let callee_frame = call_stack.top_mut();
@ -706,9 +690,6 @@ pub fn loop_instructions<'a>(
// callee is the bottommost frame ("main" or whatever was called)
// set the 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
}

View File

@ -3,15 +3,15 @@ mod e2e_tests {
use dmc_lib::constants_table::ConstantsTable;
use dmc_lib::diagnostic::Diagnostic;
use dmc_lib::intrinsics::{insert_intrinsic_symbols, insert_intrinsic_types};
use dmc_lib::offset_counter::OffsetCounter;
use dmc_lib::parser::parse_compilation_unit;
use dmc_lib::symbol_table::SymbolTable;
use dmc_lib::types_table::TypesTable;
use dvm_lib::vm::class::Class;
use dvm_lib::vm::constant::{Constant, StringConstant};
use dvm_lib::vm::function::Function;
use dvm_lib::vm::operand::Operand;
use dvm_lib::vm::value::Value;
use dvm_lib::vm::{DvmContext, call};
use dvm_lib::vm::{CallStack, DvmContext, call};
use std::rc::Rc;
const REGISTER_COUNT: usize = 8;
@ -56,9 +56,7 @@ mod e2e_tests {
let mut constants_table = ConstantsTable::new();
for ir_function in &mut ir_functions {
let mut offset_counter = OffsetCounter::new();
ir_function.assign_registers(REGISTER_COUNT, &mut offset_counter);
let stack_size = offset_counter.get_count();
let (_, stack_size) = ir_function.assign_registers(REGISTER_COUNT);
let function = ir_function.assemble(stack_size, &mut constants_table);
functions.push(function);
}
@ -97,7 +95,16 @@ mod e2e_tests {
function_name: &str,
arguments: &[Value],
) -> Option<Value> {
call(&dvm_context, function_name, &arguments, REGISTER_COUNT)
let mut registers: Vec<Operand> = vec![Operand::Null; 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) {