The Cows are all working. Moo.

This commit is contained in:
2025-12-09 16:31:24 -07:00
parent c3986ab4d9
commit 0cddb3e8c8
4 changed files with 88 additions and 54 deletions

View File

@@ -43,6 +43,6 @@ parser = { path = "libs/parser" }
compiler = { path = "libs/compiler" } compiler = { path = "libs/compiler" }
helpers = { path = "libs/helpers" } helpers = { path = "libs/helpers" }
safer-ffi = { workspace = true } safer-ffi = { workspace = true }
anyhow = { version = "^1.0", features = ["backtrace"] }
[dev-dependencies] [dev-dependencies]
anyhow = { version = "^1.0", features = ["backtrace"] }

View File

@@ -152,12 +152,12 @@ struct CompilationResult<'a> {
temp_name: Option<Cow<'a, str>>, temp_name: Option<Cow<'a, str>>,
} }
pub struct Compiler<'a, W: std::io::Write> { pub struct Compiler<'a, 'w, W: std::io::Write> {
pub parser: ASTParser<'a>, pub parser: ASTParser<'a>,
function_locations: HashMap<Cow<'a, str>, usize>, function_locations: HashMap<Cow<'a, str>, usize>,
function_metadata: HashMap<Cow<'a, str>, Vec<Cow<'a, str>>>, function_metadata: HashMap<Cow<'a, str>, Vec<Cow<'a, str>>>,
devices: HashMap<Cow<'a, str>, Cow<'a, str>>, devices: HashMap<Cow<'a, str>, Cow<'a, str>>,
output: &'a mut BufWriter<W>, output: &'w mut BufWriter<W>,
current_line: usize, current_line: usize,
declared_main: bool, declared_main: bool,
config: CompilerConfig, config: CompilerConfig,
@@ -167,10 +167,10 @@ pub struct Compiler<'a, W: std::io::Write> {
pub errors: Vec<Error<'a>>, pub errors: Vec<Error<'a>>,
} }
impl<'a, W: std::io::Write> Compiler<'a, W> { impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> {
pub fn new( pub fn new(
parser: ASTParser<'a>, parser: ASTParser<'a>,
writer: &'a mut BufWriter<W>, writer: &'w mut BufWriter<W>,
config: Option<CompilerConfig>, config: Option<CompilerConfig>,
) -> Self { ) -> Self {
Self { Self {
@@ -258,7 +258,7 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
fn expression( fn expression(
&mut self, &mut self,
expr: Spanned<Expression<'a>>, expr: Spanned<Expression<'a>>,
scope: &mut VariableScope<'a>, scope: &mut VariableScope<'a, '_>,
) -> Result<Option<CompilationResult<'a>>, Error<'a>> { ) -> Result<Option<CompilationResult<'a>>, Error<'a>> {
match expr.node { match expr.node {
Expression::Function(expr_func) => { Expression::Function(expr_func) => {
@@ -459,7 +459,7 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
fn resolve_device( fn resolve_device(
&mut self, &mut self,
expr: Spanned<Expression<'a>>, expr: Spanned<Expression<'a>>,
scope: &mut VariableScope<'a>, scope: &mut VariableScope<'a, '_>,
) -> Result<(Cow<'a, str>, Option<Cow<'a, str>>), Error<'a>> { ) -> Result<(Cow<'a, str>, Option<Cow<'a, str>>), Error<'a>> {
// If it's a direct variable reference, check if it's a known device alias first // If it's a direct variable reference, check if it's a known device alias first
if let Expression::Variable(ref name) = expr.node if let Expression::Variable(ref name) = expr.node
@@ -516,7 +516,7 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
&mut self, &mut self,
var_name: Spanned<Cow<'a, str>>, var_name: Spanned<Cow<'a, str>>,
expr: Spanned<Expression<'a>>, expr: Spanned<Expression<'a>>,
scope: &mut VariableScope<'a>, scope: &mut VariableScope<'a, '_>,
) -> Result<Option<CompilationResult<'a>>, Error<'a>> { ) -> Result<Option<CompilationResult<'a>>, Error<'a>> {
let name_str = var_name.node; let name_str = var_name.node;
let name_span = var_name.span; let name_span = var_name.span;
@@ -599,8 +599,11 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
)); ));
}; };
let loc = let loc = scope.add_variable(
scope.add_variable(name_str, LocationRequest::Persist, Some(name_span))?; name_str.clone(),
LocationRequest::Persist,
Some(name_span),
)?;
self.emit_variable_assignment( self.emit_variable_assignment(
name_str, name_str,
&loc, &loc,
@@ -612,8 +615,11 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
// Support assigning binary expressions to variables directly // Support assigning binary expressions to variables directly
Expression::Binary(bin_expr) => { Expression::Binary(bin_expr) => {
let result = self.expression_binary(bin_expr, scope)?; let result = self.expression_binary(bin_expr, scope)?;
let var_loc = let var_loc = scope.add_variable(
scope.add_variable(name_str, LocationRequest::Persist, Some(name_span))?; name_str.clone(),
LocationRequest::Persist,
Some(name_span),
)?;
if let CompilationResult { if let CompilationResult {
location: VariableLocation::Constant(Literal::Number(num)), location: VariableLocation::Constant(Literal::Number(num)),
@@ -636,8 +642,11 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
} }
Expression::Logical(log_expr) => { Expression::Logical(log_expr) => {
let result = self.expression_logical(log_expr, scope)?; let result = self.expression_logical(log_expr, scope)?;
let var_loc = let var_loc = scope.add_variable(
scope.add_variable(name_str, LocationRequest::Persist, Some(name_span))?; name_str.clone(),
LocationRequest::Persist,
Some(name_span),
)?;
// Move result from temp to new persistent variable // Move result from temp to new persistent variable
let result_reg = self.resolve_register(&result.location)?; let result_reg = self.resolve_register(&result.location)?;
@@ -661,8 +670,11 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
} }
}; };
let var_loc = let var_loc = scope.add_variable(
scope.add_variable(name_str, LocationRequest::Persist, Some(name_span))?; name_str.clone(),
LocationRequest::Persist,
Some(name_span),
)?;
// Handle loading from stack if necessary // Handle loading from stack if necessary
let src_str = match src_loc { let src_str = match src_loc {
@@ -713,8 +725,11 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
)); ));
}; };
let var_loc = let var_loc = scope.add_variable(
scope.add_variable(name_str, LocationRequest::Persist, Some(name_span))?; name_str.clone(),
LocationRequest::Persist,
Some(name_span),
)?;
let result_reg = self.resolve_register(&comp_res.location)?; let result_reg = self.resolve_register(&comp_res.location)?;
self.emit_variable_assignment(name_str, &var_loc, result_reg)?; self.emit_variable_assignment(name_str, &var_loc, result_reg)?;
@@ -742,7 +757,7 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
fn expression_const_declaration( fn expression_const_declaration(
&mut self, &mut self,
expr: ConstDeclarationExpression<'a>, expr: ConstDeclarationExpression<'a>,
scope: &mut VariableScope<'a>, scope: &mut VariableScope<'a, '_>,
) -> Result<CompilationResult<'a>, Error<'a>> { ) -> Result<CompilationResult<'a>, Error<'a>> {
let ConstDeclarationExpression { let ConstDeclarationExpression {
name: const_name, name: const_name,
@@ -777,7 +792,7 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
fn expression_assignment( fn expression_assignment(
&mut self, &mut self,
expr: AssignmentExpression<'a>, expr: AssignmentExpression<'a>,
scope: &mut VariableScope<'a>, scope: &mut VariableScope<'a, '_>,
) -> Result<(), Error<'a>> { ) -> Result<(), Error<'a>> {
let AssignmentExpression { let AssignmentExpression {
assignee, assignee,
@@ -865,7 +880,7 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
fn expression_function_invocation( fn expression_function_invocation(
&mut self, &mut self,
invoke_expr: Spanned<InvocationExpression<'a>>, invoke_expr: Spanned<InvocationExpression<'a>>,
stack: &mut VariableScope<'a>, stack: &mut VariableScope<'a, '_>,
) -> Result<(), Error<'a>> { ) -> Result<(), Error<'a>> {
let InvocationExpression { name, arguments } = invoke_expr.node; let InvocationExpression { name, arguments } = invoke_expr.node;
@@ -1062,7 +1077,7 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
fn expression_if( fn expression_if(
&mut self, &mut self,
expr: IfExpression<'a>, expr: IfExpression<'a>,
scope: &mut VariableScope<'a>, scope: &mut VariableScope<'a, '_>,
) -> Result<(), Error<'a>> { ) -> Result<(), Error<'a>> {
let end_label = self.next_label_name(); let end_label = self.next_label_name();
let else_label = if expr.else_branch.is_some() { let else_label = if expr.else_branch.is_some() {
@@ -1109,7 +1124,7 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
fn expression_loop( fn expression_loop(
&mut self, &mut self,
expr: LoopExpression<'a>, expr: LoopExpression<'a>,
scope: &mut VariableScope<'a>, scope: &mut VariableScope<'a, '_>,
) -> Result<(), Error<'a>> { ) -> Result<(), Error<'a>> {
let start_label = self.next_label_name(); let start_label = self.next_label_name();
let end_label = self.next_label_name(); let end_label = self.next_label_name();
@@ -1135,7 +1150,7 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
fn expression_while( fn expression_while(
&mut self, &mut self,
expr: WhileExpression<'a>, expr: WhileExpression<'a>,
scope: &mut VariableScope<'a>, scope: &mut VariableScope<'a, '_>,
) -> Result<(), Error<'a>> { ) -> Result<(), Error<'a>> {
let start_label = self.next_label_name(); let start_label = self.next_label_name();
let end_label = self.next_label_name(); let end_label = self.next_label_name();
@@ -1222,7 +1237,7 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
fn compile_operand( fn compile_operand(
&mut self, &mut self,
expr: Spanned<Expression<'a>>, expr: Spanned<Expression<'a>>,
scope: &mut VariableScope<'a>, scope: &mut VariableScope<'a, '_>,
) -> Result<(Cow<'a, str>, Option<Cow<'a, str>>), Error<'a>> { ) -> Result<(Cow<'a, str>, Option<Cow<'a, str>>), Error<'a>> {
// Optimization for literals // Optimization for literals
if let Expression::Literal(spanned_lit) = &expr.node { if let Expression::Literal(spanned_lit) = &expr.node {
@@ -1293,7 +1308,7 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
fn compile_literal_or_variable( fn compile_literal_or_variable(
&mut self, &mut self,
val: LiteralOrVariable<'a>, val: LiteralOrVariable<'a>,
scope: &mut VariableScope<'a>, scope: &mut VariableScope<'a, '_>,
) -> Result<(Cow<'a, str>, Option<Cow<'a, str>>), Error<'a>> { ) -> Result<(Cow<'a, str>, Option<Cow<'a, str>>), Error<'a>> {
let dummy_span = Span { let dummy_span = Span {
start_line: 0, start_line: 0,
@@ -1321,7 +1336,7 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
fn expression_binary( fn expression_binary(
&mut self, &mut self,
expr: Spanned<BinaryExpression<'a>>, expr: Spanned<BinaryExpression<'a>>,
scope: &mut VariableScope<'a>, scope: &mut VariableScope<'a, '_>,
) -> Result<CompilationResult<'a>, Error<'a>> { ) -> Result<CompilationResult<'a>, Error<'a>> {
fn fold_binary_expression<'a>(expr: &BinaryExpression<'a>) -> Option<Number> { fn fold_binary_expression<'a>(expr: &BinaryExpression<'a>) -> Option<Number> {
let (lhs, rhs) = match &expr { let (lhs, rhs) = match &expr {
@@ -1414,7 +1429,7 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
fn expression_logical( fn expression_logical(
&mut self, &mut self,
expr: Spanned<LogicalExpression<'a>>, expr: Spanned<LogicalExpression<'a>>,
scope: &mut VariableScope<'a>, scope: &mut VariableScope<'a, '_>,
) -> Result<CompilationResult<'a>, Error<'a>> { ) -> Result<CompilationResult<'a>, Error<'a>> {
match expr.node { match expr.node {
LogicalExpression::Not(inner) => { LogicalExpression::Not(inner) => {
@@ -1480,10 +1495,10 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
} }
} }
fn expression_block( fn expression_block<'v>(
&mut self, &mut self,
mut expr: BlockExpression<'a>, mut expr: BlockExpression<'a>,
parent_scope: &mut VariableScope<'a>, parent_scope: &'v mut VariableScope<'a, '_>,
) -> Result<(), Error<'a>> { ) -> Result<(), Error<'a>> {
// First, sort the expressions to ensure functions are hoisted // First, sort the expressions to ensure functions are hoisted
expr.0.sort_by(|a, b| { expr.0.sort_by(|a, b| {
@@ -1549,7 +1564,7 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
fn expression_return( fn expression_return(
&mut self, &mut self,
expr: Spanned<Expression<'a>>, expr: Spanned<Expression<'a>>,
scope: &mut VariableScope<'a>, scope: &mut VariableScope<'a, '_>,
) -> Result<VariableLocation<'a>, Error<'a>> { ) -> Result<VariableLocation<'a>, Error<'a>> {
if let Expression::Negation(neg_expr) = &expr.node if let Expression::Negation(neg_expr) = &expr.node
&& let Expression::Literal(spanned_lit) = &neg_expr.node && let Expression::Literal(spanned_lit) = &neg_expr.node
@@ -1686,7 +1701,7 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
&mut self, &mut self,
expr: System<'a>, expr: System<'a>,
span: Span, span: Span,
scope: &mut VariableScope<'a>, scope: &mut VariableScope<'a, '_>,
) -> Result<Option<CompilationResult<'a>>, Error<'a>> { ) -> Result<Option<CompilationResult<'a>>, Error<'a>> {
macro_rules! cleanup { macro_rules! cleanup {
($($to_clean:expr),*) => { ($($to_clean:expr),*) => {
@@ -1943,7 +1958,7 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
fn expression_syscall_math( fn expression_syscall_math(
&mut self, &mut self,
expr: Math<'a>, expr: Math<'a>,
scope: &mut VariableScope<'a>, scope: &mut VariableScope<'a, '_>,
) -> Result<Option<CompilationResult<'a>>, Error<'a>> { ) -> Result<Option<CompilationResult<'a>>, Error<'a>> {
macro_rules! cleanup { macro_rules! cleanup {
($($to_clean:expr),*) => { ($($to_clean:expr),*) => {
@@ -2139,7 +2154,7 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
fn expression_function( fn expression_function(
&mut self, &mut self,
expr: Spanned<FunctionExpression<'a>>, expr: Spanned<FunctionExpression<'a>>,
scope: &mut VariableScope<'a>, scope: &mut VariableScope<'a, '_>,
) -> Result<(), Error<'a>> { ) -> Result<(), Error<'a>> {
let FunctionExpression { let FunctionExpression {
name, name,
@@ -2222,7 +2237,7 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
self.write_output("push ra")?; self.write_output("push ra")?;
block_scope.add_variable( block_scope.add_variable(
format!("{}_ra", name.node), Cow::from(format!("{}_ra", name.node)),
LocationRequest::Stack, LocationRequest::Stack,
Some(name.span), Some(name.span),
)?; )?;
@@ -2249,7 +2264,8 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
} }
// Get the saved return address and save it back into `ra` // Get the saved return address and save it back into `ra`
let ra_res = block_scope.get_location_of(format!("{}_ra", name.node), Some(name.span)); let ra_res =
block_scope.get_location_of(&Cow::from(format!("{}_ra", name.node)), Some(name.span));
let ra_stack_offset = match ra_res { let ra_stack_offset = match ra_res {
Ok(VariableLocation::Stack(offset)) => offset, Ok(VariableLocation::Stack(offset)) => offset,

View File

@@ -66,15 +66,17 @@ pub enum VariableLocation<'a> {
Device(Cow<'a, str>), Device(Cow<'a, str>),
} }
pub struct VariableScope<'a> { // FIX: Added 'b lifetime for the parent reference
pub struct VariableScope<'a, 'b> {
temporary_vars: VecDeque<u8>, temporary_vars: VecDeque<u8>,
persistant_vars: VecDeque<u8>, persistant_vars: VecDeque<u8>,
var_lookup_table: HashMap<Cow<'a, str>, VariableLocation<'a>>, var_lookup_table: HashMap<Cow<'a, str>, VariableLocation<'a>>,
stack_offset: u16, stack_offset: u16,
parent: Option<&'a VariableScope<'a>>, parent: Option<&'b VariableScope<'a, 'b>>,
} }
impl<'a> Default for VariableScope<'a> { // FIX: Updated Default impl to include 'b
impl<'a, 'b> Default for VariableScope<'a, 'b> {
fn default() -> Self { fn default() -> Self {
Self { Self {
parent: None, parent: None,
@@ -86,7 +88,8 @@ impl<'a> Default for VariableScope<'a> {
} }
} }
impl<'a> VariableScope<'a> { // FIX: Updated impl block to include 'b
impl<'a, 'b> VariableScope<'a, 'b> {
#[allow(dead_code)] #[allow(dead_code)]
pub const TEMP_REGISTER_COUNT: u8 = 7; pub const TEMP_REGISTER_COUNT: u8 = 7;
pub const PERSIST_REGISTER_COUNT: u8 = 7; pub const PERSIST_REGISTER_COUNT: u8 = 7;
@@ -109,7 +112,8 @@ impl<'a> VariableScope<'a> {
}) })
} }
pub fn scoped(parent: &'a VariableScope<'a>) -> Self { // FIX: parent is now &'b VariableScope<'a, 'b>
pub fn scoped(parent: &'b VariableScope<'a, 'b>) -> Self {
Self { Self {
parent: Option::Some(parent), parent: Option::Some(parent),
temporary_vars: parent.temporary_vars.clone(), temporary_vars: parent.temporary_vars.clone(),
@@ -206,7 +210,7 @@ impl<'a> VariableScope<'a> {
return Ok(loc); return Ok(loc);
} }
Err(Error::UnknownVariable(Cow::from(var_name.to_owned()), span)) Err(Error::UnknownVariable(var_name.clone(), span))
} }
pub fn has_parent(&self) -> bool { pub fn has_parent(&self) -> bool {

View File

@@ -12,20 +12,38 @@ use thiserror::Error;
use tokenizer::{self, Tokenizer}; use tokenizer::{self, Tokenizer};
#[derive(Error, Debug)] #[derive(Error, Debug)]
enum StationlangError { enum Error<'a> {
#[error(transparent)] #[error(transparent)]
Tokenizer(#[from] tokenizer::Error), Tokenizer(tokenizer::Error),
#[error(transparent)] #[error(transparent)]
Parser(#[from] parser::Error), Parser(parser::Error<'a>),
#[error(transparent)] #[error(transparent)]
Compile(#[from] compiler::Error), Compile(compiler::Error<'a>),
#[error(transparent)] #[error(transparent)]
IO(#[from] std::io::Error), IO(#[from] std::io::Error),
} }
impl<'a> From<parser::Error<'a>> for Error<'a> {
fn from(value: parser::Error<'a>) -> Self {
Self::Parser(value)
}
}
impl<'a> From<compiler::Error<'a>> for Error<'a> {
fn from(value: compiler::Error<'a>) -> Self {
Self::Compile(value)
}
}
impl<'a> From<tokenizer::Error> for Error<'a> {
fn from(value: tokenizer::Error) -> Self {
Self::Tokenizer(value)
}
}
#[derive(Parser, Debug)] #[derive(Parser, Debug)]
#[command(version, about, long_about = None)] #[command(version, about, long_about = None)]
struct Args { struct Args {
@@ -37,7 +55,7 @@ struct Args {
output_file: Option<PathBuf>, output_file: Option<PathBuf>,
} }
fn run_logic() -> Result<(), StationlangError> { fn run_logic<'a>() -> Result<(), Error<'a>> {
let args = Args::parse(); let args = Args::parse();
let input_file = args.input_file; let input_file = args.input_file;
@@ -63,7 +81,6 @@ fn run_logic() -> Result<(), StationlangError> {
}; };
let tokenizer = Tokenizer::from(input_string.as_str()); let tokenizer = Tokenizer::from(input_string.as_str());
let parser = ASTParser::new(tokenizer); let parser = ASTParser::new(tokenizer);
let mut writer: BufWriter<Box<dyn Write>> = match args.output_file { let mut writer: BufWriter<Box<dyn Write>> = match args.output_file {
@@ -73,20 +90,17 @@ fn run_logic() -> Result<(), StationlangError> {
let compiler = Compiler::new(parser, &mut writer, None); let compiler = Compiler::new(parser, &mut writer, None);
let mut errors = compiler.compile(); let errors = compiler.compile();
if !errors.is_empty() { if !errors.is_empty() {
let mut std_error = stderr(); let mut std_error = stderr();
let last = errors.pop(); let errors = errors.into_iter().map(Error::from);
let errors = errors.into_iter().map(StationlangError::from);
std_error.write_all(b"Compilation error:\n")?; std_error.write_all(b"Compilation error:\n")?;
for err in errors { for err in errors {
std_error.write_all(format!("{}\n", err).as_bytes())?; std_error.write_all(format!("{}\n", err).as_bytes())?;
} }
return Err(StationlangError::from(last.unwrap()));
} }
writer.flush()?; writer.flush()?;
@@ -94,7 +108,7 @@ fn run_logic() -> Result<(), StationlangError> {
Ok(()) Ok(())
} }
fn main() -> Result<(), StationlangError> { fn main() -> anyhow::Result<()> {
run_logic()?; run_logic()?;
Ok(()) Ok(())