Repl with expressions working, let statements still not working.

This commit is contained in:
Jesse Brault 2026-07-11 14:37:29 -05:00
parent ed6f15a8a9
commit 7b76771843
22 changed files with 163 additions and 9 deletions

View File

@ -1,7 +1,7 @@
mod repl;
mod run;
use crate::repl::repl;
use crate::repl::{repl, repl_2};
use crate::run::compile_and_run_script;
use clap::{Parser, Subcommand};
use std::io;
@ -44,7 +44,7 @@ fn main() {
compile_and_run_script(script, *show_asm, *show_ir, register_count);
}
SubCommand::Repl => {
repl(&mut io::stdin().lock(), register_count);
repl_2(&mut io::stdin().lock(), register_count);
}
}
}

View File

@ -7,9 +7,9 @@ use dmc_lib::ir::ir_variable::IrVariable;
use dmc_lib::ir::variable_locations::VariableLocations;
use dmc_lib::lexer::Lexer;
use dmc_lib::offset_counter::OffsetCounter;
use dmc_lib::parser::parse_expression;
use dmc_lib::parser::{parse_expression, parse_let_statement};
use dmc_lib::semantic_analysis::AnalysisContext;
use dmc_lib::semantic_analysis::scope::ScopeId;
use dmc_lib::semantic_analysis::scope::{Scope, ScopeId};
use dmc_lib::symbol::variable_symbol::VariableSymbol;
use dmc_lib::symbol_table::SymbolTable;
use dmc_lib::token::TokenKind;
@ -310,8 +310,17 @@ pub fn repl_2(read: &mut impl BufRead, register_count: usize) {
let mut buffer = String::new();
let mut analysis_context = AnalysisContext::new();
let mut function_scope_id: Option<ScopeId> = None;
let fqn: Rc<str> = Rc::from("repl");
let root_scope_id = analysis_context.root_scope_id();
analysis_context
.scopes_mut()
.push(Scope::new(Some(root_scope_id))); // function scope
let function_scope_id = analysis_context.scopes().len() - 1;
analysis_context
.scopes_mut()
.push(Scope::new(Some(function_scope_id))); // body scope
let body_scope_id = analysis_context.scopes().len() - 1;
let fqn: Rc<str> = Rc::from("__repl");
let mut variable_locations = VariableLocations::new();
let mut constants_table = ConstantsTable::new();
@ -342,6 +351,91 @@ pub fn repl_2(read: &mut impl BufRead, register_count: usize) {
}
},
};
match first_token.kind() {
TokenKind::Let => {
let compile_result = compile_let_statement_2(
input,
&mut analysis_context,
body_scope_id,
&fqn,
&mut variable_locations,
register_count,
&mut constants_table,
);
match compile_result {
Ok(function) => {
dvm_context
.functions_mut()
.insert(function.name_owned(), function);
}
Err(diagnostics) => {
for diagnostic in diagnostics {
eprintln!("{}", diagnostic.message());
}
buffer.clear();
continue 'repl;
}
}
}
_ => {
let compile_result = compile_expression_2(
input,
&mut analysis_context,
body_scope_id,
&fqn,
&mut variable_locations,
register_count,
&mut constants_table,
);
match compile_result {
Ok(function) => {
dvm_context
.functions_mut()
.insert(function.name_owned(), function);
}
Err(diagnostics) => {
for diagnostic in diagnostics {
eprintln!("{}", diagnostic.message());
}
buffer.clear();
continue 'repl;
}
}
}
}
for (name, content) in constants_table.string_constants() {
dvm_context.constants_mut().insert(
name.clone(),
Constant::String(StringConstant::new(name, content)),
);
}
let mut call_stack = CallStack::new();
prepare_for_instruction_loop(&dvm_context, "__repl", &mut call_stack, &[]);
// copy all old locals to current call frame's stack
// this has to be done with indexing because the preparation above creates space for them
for (i, operand) in repl_fn_stack_locals.iter().enumerate() {
let target_index = call_stack.top().fp() + i;
call_stack.top_mut().stack_mut()[target_index] = operand.clone();
}
let result = loop_instructions(
&dvm_context,
&mut vec![Operand::Null; register_count],
&mut call_stack,
);
// copy the top frame's stack locals back to OUR stack locals for next iteration
repl_fn_stack_locals = std::mem::take(call_stack.top_mut().stack_mut());
if let Some(value) = result {
println!("{}", value);
}
buffer.clear();
}
}
@ -371,3 +465,27 @@ fn compile_expression_2(
constants_table,
)
}
fn compile_let_statement_2(
input: &str,
analysis_context: &mut AnalysisContext,
function_scope_id: ScopeId,
fqn: &Rc<str>,
variable_locations: &mut VariableLocations,
register_count: usize,
constants_table: &mut ConstantsTable,
) -> Result<Function, Diagnostics> {
let (maybe_let_statement, parse_diagnostics) = parse_let_statement(input);
if !parse_diagnostics.is_empty() {
return Err(parse_diagnostics);
}
compile_statement_to_synthetic_function(
&Statement::Let(maybe_let_statement.unwrap()),
analysis_context,
function_scope_id,
fqn.clone(),
variable_locations,
register_count,
constants_table,
)
}

View File

@ -1,6 +1,7 @@
use std::fmt::{Display, Formatter};
use std::rc::Rc;
#[derive(Debug)]
pub struct IrAllocate {
class_fqn: Rc<str>,
}

View File

@ -3,6 +3,7 @@ use crate::ir::ir_variable::IrVariableId;
use crate::ir::register_allocation::VrUser;
use std::collections::HashSet;
#[derive(Debug)]
pub struct IrAssign {
destination: IrVariableId,
initializer: Box<IrOperation>,

View File

@ -4,6 +4,7 @@ use crate::ir::register_allocation::VrUser;
use std::collections::HashSet;
use std::fmt::{Display, Formatter};
#[derive(Debug)]
pub enum IrBinaryOperator {
Multiply,
Divide,
@ -17,6 +18,7 @@ pub enum IrBinaryOperator {
BitwiseOr,
}
#[derive(Debug)]
pub struct IrBinaryOperation {
left: Box<IrExpression>,
right: Box<IrExpression>,

View File

@ -5,6 +5,7 @@ use std::collections::HashSet;
pub type IrBlockId = usize;
#[derive(Debug)]
pub struct IrBlock {
id: IrBlockId,
debug_label: String,

View File

@ -5,6 +5,7 @@ use std::collections::HashSet;
use std::fmt::{Display, Formatter};
use std::rc::Rc;
#[derive(Debug)]
pub struct IrCall {
function_name: Rc<str>,
arguments: Vec<IrExpression>,

View File

@ -5,6 +5,7 @@ use std::collections::HashSet;
use std::fmt::{Display, Formatter};
use std::rc::Rc;
#[derive(Debug)]
pub enum IrExpression {
Parameter(IrParameterId),
Variable(IrVariableId),

View File

@ -9,6 +9,7 @@ use dvm_lib::vm::function::Function;
use std::collections::HashMap;
use std::rc::Rc;
#[derive(Debug)]
pub struct IrFunction {
fqn: Rc<str>,
parameters: Vec<IrParameter>,

View File

@ -4,6 +4,7 @@ use crate::ir::register_allocation::VrUser;
use std::collections::HashSet;
use std::fmt::{Display, Formatter};
#[derive(Debug)]
pub struct IrGetFieldRef {
self_variable_or_parameter: IrParameterOrVariable,
field_index: usize,

View File

@ -4,6 +4,7 @@ use crate::ir::register_allocation::VrUser;
use std::collections::HashSet;
use std::fmt::{Display, Formatter};
#[derive(Debug)]
pub struct IrGetFieldRefMut {
self_variable_or_parameter: IrParameterOrVariable,
field_index: usize,

View File

@ -10,6 +10,7 @@ use crate::ir::register_allocation::VrUser;
use std::collections::HashSet;
use std::fmt::{Display, Formatter};
#[derive(Debug)]
pub enum IrOperation {
GetFieldRef(IrGetFieldRef),
GetFieldRefMut(IrGetFieldRefMut),

View File

@ -5,6 +5,7 @@ use std::rc::Rc;
pub type IrParameterId = usize;
#[derive(Debug)]
pub struct IrParameter {
name: Rc<str>,
type_info: IrTypeInfo,

View File

@ -3,6 +3,7 @@ use crate::ir::register_allocation::VrUser;
use std::collections::HashSet;
use std::fmt::{Display, Formatter};
#[derive(Debug)]
pub struct IrReadField {
field_ref_variable: IrVariableId,
}

View File

@ -4,6 +4,7 @@ use crate::ir::register_allocation::VrUser;
use std::collections::HashSet;
use std::fmt::{Display, Formatter};
#[derive(Debug)]
pub struct IrReturn {
value: Option<IrExpression>,
}

View File

@ -4,6 +4,7 @@ use crate::ir::register_allocation::VrUser;
use std::collections::HashSet;
use std::fmt::{Display, Formatter};
#[derive(Debug)]
pub struct IrSetField {
field_ref_variable: IrVariableId,
initializer: Box<IrExpression>,

View File

@ -6,6 +6,7 @@ use crate::ir::ir_variable::IrVariableId;
use crate::ir::register_allocation::VrUser;
use std::collections::HashSet;
#[derive(Debug)]
pub enum IrStatement {
Assign(IrAssign),
Call(IrCall),

View File

@ -4,6 +4,7 @@ use std::rc::Rc;
pub type IrVariableId = usize;
#[derive(Debug)]
pub struct IrVariable {
name: Rc<str>,
type_info: IrTypeInfo,

View File

@ -34,6 +34,7 @@ pub struct LowerToIrResult {
pub functions: Vec<IrFunction>,
}
#[derive(Debug)]
struct LowerToIrContext<'a> {
symbols: &'a [Symbol],
nodes_to_symbols: &'a HashMap<NodeId, SymbolId>,
@ -104,6 +105,7 @@ pub fn lower_to_ir_synthetic_function(
)
}
#[derive(Debug)]
struct LowerToIrFunctionContext {
blocks: Vec<IrBlock>,
ir_variables: Vec<IrVariable>,
@ -463,6 +465,7 @@ fn lower_expression_to_ir_expression(
{
IrExpression::Parameter(*rhs_ir_parameter_id)
} else {
println!("Dump:\n{:#?}\n{:#?}", ctx, fn_ctx);
panic!(
"Could not find parameter or variable for symbol_id {}",
rhs_symbol_id

View File

@ -44,9 +44,9 @@ pub struct AnalysisContext {
impl AnalysisContext {
pub fn new() -> Self {
Self {
root_scope_id: 0, // pushed in vec! below
scopes: vec![Scope::new(None)],
nodes_to_scopes: HashMap::new(),
root_scope_id: 0, // already pushed in vec! above
symbols: Vec::new(),
nodes_to_symbols: HashMap::new(),
type_infos: Vec::new(),
@ -55,6 +55,18 @@ impl AnalysisContext {
}
}
pub fn root_scope_id(&self) -> ScopeId {
self.root_scope_id
}
pub fn scopes(&self) -> &[Scope] {
&self.scopes
}
pub fn scopes_mut(&mut self) -> &mut Vec<Scope> {
&mut self.scopes
}
pub fn symbols(&self) -> &[Symbol] {
&self.symbols
}

View File

@ -3,6 +3,7 @@ use std::rc::Rc;
pub type SymbolId = usize;
#[derive(Debug)]
pub enum Symbol {
Function(FunctionSymbol),
Parameter(ParameterSymbol),
@ -35,6 +36,7 @@ impl Symbol {
}
}
#[derive(Debug)]
pub struct FunctionSymbol {
declared_name: Rc<str>,
declared_name_source_range: Option<SourceRange>,
@ -82,6 +84,7 @@ impl FunctionSymbol {
}
}
#[derive(Debug)]
pub struct ParameterSymbol {
name: Rc<str>,
source_range: Option<SourceRange>,
@ -105,6 +108,7 @@ impl ParameterSymbol {
}
}
#[derive(Debug)]
pub struct VariableSymbol {
name: Rc<str>,
source_range: Option<SourceRange>,

View File

@ -2,7 +2,7 @@ use std::fmt::{Display, Formatter};
pub type TypeInfoId = usize;
#[derive(Clone)]
#[derive(Clone, Debug)]
pub enum TypeInfo {
Any,
Function(FunctionTypeInfo),
@ -31,7 +31,7 @@ impl Display for TypeInfo {
}
}
#[derive(Clone)]
#[derive(Clone, Debug)]
pub struct FunctionTypeInfo {
parameter_type_info_ids: Vec<TypeInfoId>,
return_type_info_id: TypeInfoId,