From 3fb04aef3b235baa4b27543f821fe798e348eeea Mon Sep 17 00:00:00 2001 From: Devin Bidwell Date: Fri, 12 Dec 2025 15:51:36 -0700 Subject: [PATCH] Emit IL alongside raw IC10 for use in future optimization passes --- rust_compiler/Cargo.lock | 14 + rust_compiler/libs/compiler/Cargo.toml | 1 + .../compiler/src/test/binary_expression.rs | 22 +- .../libs/compiler/src/test/branching.rs | 46 +- .../test/declaration_function_invocation.rs | 38 +- .../compiler/src/test/declaration_literal.rs | 32 +- .../compiler/src/test/function_declaration.rs | 24 +- .../compiler/src/test/logic_expression.rs | 30 +- rust_compiler/libs/compiler/src/test/loops.rs | 22 +- .../libs/compiler/src/test/math_syscall.rs | 36 +- .../libs/compiler/src/test/syscall.rs | 8 +- rust_compiler/libs/compiler/src/v1.rs | 834 ++++++++++-------- .../libs/compiler/src/variable_manager.rs | 3 +- rust_compiler/libs/helpers/Cargo.toml | 1 + rust_compiler/libs/helpers/src/lib.rs | 38 + rust_compiler/libs/il/Cargo.toml | 8 + rust_compiler/libs/il/src/lib.rs | 286 ++++++ rust_compiler/libs/optimizer/Cargo.toml | 6 + rust_compiler/libs/optimizer/src/lib.rs | 14 + rust_compiler/libs/parser/src/lib.rs | 1 + rust_compiler/libs/parser/src/tree_node.rs | 39 +- rust_compiler/libs/tokenizer/src/token.rs | 6 + rust_compiler/src/ffi/mod.rs | 4 +- 23 files changed, 990 insertions(+), 523 deletions(-) create mode 100644 rust_compiler/libs/il/Cargo.toml create mode 100644 rust_compiler/libs/il/src/lib.rs create mode 100644 rust_compiler/libs/optimizer/Cargo.toml create mode 100644 rust_compiler/libs/optimizer/src/lib.rs diff --git a/rust_compiler/Cargo.lock b/rust_compiler/Cargo.lock index ca53d0a..30b4270 100644 --- a/rust_compiler/Cargo.lock +++ b/rust_compiler/Cargo.lock @@ -268,6 +268,7 @@ version = "0.1.0" dependencies = [ "anyhow", "helpers", + "il", "indoc", "lsp-types", "parser", @@ -397,6 +398,15 @@ name = "helpers" version = "0.1.0" dependencies = [ "crc32fast", + "lsp-types", +] + +[[package]] +name = "il" +version = "0.1.0" +dependencies = [ + "helpers", + "rust_decimal", ] [[package]] @@ -563,6 +573,10 @@ version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" +[[package]] +name = "optimizer" +version = "0.1.0" + [[package]] name = "parser" version = "0.1.0" diff --git a/rust_compiler/libs/compiler/Cargo.toml b/rust_compiler/libs/compiler/Cargo.toml index 829e4f9..721bfcf 100644 --- a/rust_compiler/libs/compiler/Cargo.toml +++ b/rust_compiler/libs/compiler/Cargo.toml @@ -8,6 +8,7 @@ thiserror = { workspace = true } parser = { path = "../parser" } tokenizer = { path = "../tokenizer" } helpers = { path = "../helpers" } +il = { path = "../il" } lsp-types = { workspace = true } rust_decimal = { workspace = true } diff --git a/rust_compiler/libs/compiler/src/test/binary_expression.rs b/rust_compiler/libs/compiler/src/test/binary_expression.rs index 558b04f..4ac0754 100644 --- a/rust_compiler/libs/compiler/src/test/binary_expression.rs +++ b/rust_compiler/libs/compiler/src/test/binary_expression.rs @@ -18,7 +18,7 @@ fn simple_binary_expression() -> Result<()> { " j main main: - move r8 3 #i + move r8 3 " } ); @@ -45,9 +45,9 @@ fn nested_binary_expressions() -> Result<()> { " j main calculateArgs: - pop r8 #arg3 - pop r9 #arg2 - pop r10 #arg1 + pop r8 + pop r9 + pop r10 push ra add r1 r10 r9 mul r2 r1 r8 @@ -63,9 +63,9 @@ fn nested_binary_expressions() -> Result<()> { push 20 push 30 jal calculateArgs - move r1 r15 #__binary_temp_3 + move r1 r15 add r2 r1 100 - move r8 r2 #returned + move r8 r2 " } ); @@ -88,7 +88,7 @@ fn stress_test_constant_folding() -> Result<()> { " j main main: - move r8 -123 #negationHell + move r8 -123 " } ); @@ -116,7 +116,7 @@ fn test_constant_folding_with_variables_mixed_in() -> Result<()> { mul r2 373.2 r1 sub r3 1 r2 add r4 r3 518.15 - move r8 r4 #i + move r8 r4 " } ); @@ -141,7 +141,7 @@ fn test_ternary_expression() -> Result<()> { main: sgt r1 1 2 select r2 r1 15 20 - move r8 r2 #i + move r8 r2 " } ); @@ -165,10 +165,10 @@ fn test_ternary_expression_assignment() -> Result<()> { " j main main: - move r8 0 #i + move r8 0 sgt r1 1 2 select r2 r1 15 20 - move r8 r2 #i + move r8 r2 " } ); diff --git a/rust_compiler/libs/compiler/src/test/branching.rs b/rust_compiler/libs/compiler/src/test/branching.rs index 1a852da..155c535 100644 --- a/rust_compiler/libs/compiler/src/test/branching.rs +++ b/rust_compiler/libs/compiler/src/test/branching.rs @@ -20,10 +20,10 @@ fn test_if_statement() -> anyhow::Result<()> { " j main main: - move r8 10 #a + move r8 10 sgt r1 r8 5 - beq r1 0 L1 - move r8 20 #a + beqz r1 L1 + move r8 20 L1: " } @@ -52,13 +52,13 @@ fn test_if_else_statement() -> anyhow::Result<()> { " j main main: - move r8 0 #a + move r8 0 sgt r1 10 5 - beq r1 0 L2 - move r8 1 #a + beqz r1 L2 + move r8 1 j L1 L2: - move r8 2 #a + move r8 2 L1: " } @@ -89,18 +89,18 @@ fn test_if_else_if_statement() -> anyhow::Result<()> { " j main main: - move r8 0 #a + move r8 0 seq r1 r8 1 - beq r1 0 L2 - move r8 10 #a + beqz r1 L2 + move r8 10 j L1 L2: seq r2 r8 2 - beq r2 0 L4 - move r8 20 #a + beqz r2 L4 + move r8 20 j L3 L4: - move r8 30 #a + move r8 30 L3: L1: " @@ -136,18 +136,18 @@ fn test_spilled_variable_update_in_branch() -> anyhow::Result<()> { " j main main: - move r8 1 #a - move r9 2 #b - move r10 3 #c - move r11 4 #d - move r12 5 #e - move r13 6 #f - move r14 7 #g - push 8 #h + move r8 1 + move r9 2 + move r10 3 + move r11 4 + move r12 5 + move r13 6 + move r14 7 + push 8 seq r1 r8 1 - beq r1 0 L1 + beqz r1 L1 sub r0 sp 1 - put db r0 99 #h + put db r0 99 L1: sub sp sp 1 " diff --git a/rust_compiler/libs/compiler/src/test/declaration_function_invocation.rs b/rust_compiler/libs/compiler/src/test/declaration_function_invocation.rs index 5f3f499..dbdfaca 100644 --- a/rust_compiler/libs/compiler/src/test/declaration_function_invocation.rs +++ b/rust_compiler/libs/compiler/src/test/declaration_function_invocation.rs @@ -24,7 +24,7 @@ fn no_arguments() -> anyhow::Result<()> { j ra main: jal doSomething - move r8 r15 #i + move r8 r15 " }; @@ -55,7 +55,7 @@ fn let_var_args() -> anyhow::Result<()> { " j main mul2: - pop r8 #arg1 + pop r8 push ra mul r1 r8 2 move r15 r1 @@ -67,16 +67,16 @@ fn let_var_args() -> anyhow::Result<()> { j ra main: L2: - move r8 123 #arg1 + move r8 123 push r8 push r8 jal mul2 sub r0 sp 1 get r8 db r0 sub sp sp 1 - move r9 r15 #i + move r9 r15 pow r1 r9 2 - move r9 r1 #i + move r9 r1 j L2 L3: " @@ -123,10 +123,10 @@ fn inline_literal_args() -> anyhow::Result<()> { " j main doSomething: - pop r8 #arg2 - pop r9 #arg1 + pop r8 + pop r9 push ra - move r15 5 #returnValue + move r15 5 j L1 L1: sub r0 sp 1 @@ -134,7 +134,7 @@ fn inline_literal_args() -> anyhow::Result<()> { sub sp sp 1 j ra main: - move r8 123 #thisVariableShouldStayInPlace + move r8 123 push r8 push 12 push 34 @@ -142,7 +142,7 @@ fn inline_literal_args() -> anyhow::Result<()> { sub r0 sp 1 get r8 db r0 sub sp sp 1 - move r9 r15 #returnedValue + move r9 r15 " } ); @@ -167,8 +167,8 @@ fn mixed_args() -> anyhow::Result<()> { " j main doSomething: - pop r8 #arg2 - pop r9 #arg1 + pop r8 + pop r9 push ra L1: sub r0 sp 1 @@ -176,7 +176,7 @@ fn mixed_args() -> anyhow::Result<()> { sub sp sp 1 j ra main: - move r8 123 #arg1 + move r8 123 push r8 push r8 push 456 @@ -184,7 +184,7 @@ fn mixed_args() -> anyhow::Result<()> { sub r0 sp 1 get r8 db r0 sub sp sp 1 - move r9 r15 #returnValue + move r9 r15 " } ); @@ -211,9 +211,9 @@ fn with_return_statement() -> anyhow::Result<()> { " j main doSomething: - pop r8 #arg1 + pop r8 push ra - move r15 456 #returnValue + move r15 456 j L1 L1: sub r0 sp 1 @@ -223,7 +223,7 @@ fn with_return_statement() -> anyhow::Result<()> { main: push 123 jal doSomething - move r8 r15 #returned + move r8 r15 " } ); @@ -250,7 +250,7 @@ fn with_negative_return_literal() -> anyhow::Result<()> { j main doSomething: push ra - move r15 -1 #returnValue + move r15 -1 L1: sub r0 sp 1 get ra db r0 @@ -258,7 +258,7 @@ fn with_negative_return_literal() -> anyhow::Result<()> { j ra main: jal doSomething - move r8 r15 #i + move r8 r15 " } ); diff --git a/rust_compiler/libs/compiler/src/test/declaration_literal.rs b/rust_compiler/libs/compiler/src/test/declaration_literal.rs index 171f83e..550e332 100644 --- a/rust_compiler/libs/compiler/src/test/declaration_literal.rs +++ b/rust_compiler/libs/compiler/src/test/declaration_literal.rs @@ -15,7 +15,7 @@ fn variable_declaration_numeric_literal() -> anyhow::Result<()> { " j main main: - move r8 293.15 #i + move r8 293.15 " } ); @@ -46,16 +46,16 @@ fn variable_declaration_numeric_literal_stack_spillover() -> anyhow::Result<()> " j main main: - move r8 0 #a - move r9 1 #b - move r10 2 #c - move r11 3 #d - move r12 4 #e - move r13 5 #f - move r14 6 #g - push 7 #h - push 8 #i - push 9 #j + move r8 0 + move r9 1 + move r10 2 + move r11 3 + move r12 4 + move r13 5 + move r14 6 + push 7 + push 8 + push 9 sub sp sp 3 " } @@ -79,7 +79,7 @@ fn variable_declaration_negative() -> anyhow::Result<()> { " j main main: - move r8 -1 #i + move r8 -1 " } ); @@ -103,8 +103,8 @@ fn test_boolean_declaration() -> anyhow::Result<()> { " j main main: - move r8 1 #t - move r9 0 #f + move r8 1 + move r9 0 " } ); @@ -132,7 +132,7 @@ fn test_boolean_return() -> anyhow::Result<()> { j main getTrue: push ra - move r15 1 #returnValue + move r15 1 j L1 L1: sub r0 sp 1 @@ -141,7 +141,7 @@ fn test_boolean_return() -> anyhow::Result<()> { j ra main: jal getTrue - move r8 r15 #val + move r8 r15 " } ); diff --git a/rust_compiler/libs/compiler/src/test/function_declaration.rs b/rust_compiler/libs/compiler/src/test/function_declaration.rs index 374902e..18f5b84 100644 --- a/rust_compiler/libs/compiler/src/test/function_declaration.rs +++ b/rust_compiler/libs/compiler/src/test/function_declaration.rs @@ -13,13 +13,13 @@ fn test_function_declaration_with_spillover_params() -> anyhow::Result<()> { indoc! {" j main doSomething: - pop r8 #arg9 - pop r9 #arg8 - pop r10 #arg7 - pop r11 #arg6 - pop r12 #arg5 - pop r13 #arg4 - pop r14 #arg3 + pop r8 + pop r9 + pop r10 + pop r11 + pop r12 + pop r13 + pop r14 push ra L1: sub r0 sp 1 @@ -54,10 +54,10 @@ fn test_early_return() -> anyhow::Result<()> { doSomething: push ra seq r1 1 1 - beq r1 0 L2 + beqz r1 L2 j L1 L2: - move r8 3 #i + move r8 3 j L1 L1: sub r0 sp 1 @@ -66,7 +66,7 @@ fn test_early_return() -> anyhow::Result<()> { j ra main: jal doSomething - move r1 r15 #__binary_temp_2 + move r1 r15 " } ); @@ -87,8 +87,8 @@ fn test_function_declaration_with_register_params() -> anyhow::Result<()> { indoc! {" j main doSomething: - pop r8 #arg2 - pop r9 #arg1 + pop r8 + pop r9 push ra L1: sub r0 sp 1 diff --git a/rust_compiler/libs/compiler/src/test/logic_expression.rs b/rust_compiler/libs/compiler/src/test/logic_expression.rs index 1f65d4b..df77bd5 100644 --- a/rust_compiler/libs/compiler/src/test/logic_expression.rs +++ b/rust_compiler/libs/compiler/src/test/logic_expression.rs @@ -23,17 +23,17 @@ fn test_comparison_expressions() -> anyhow::Result<()> { j main main: sgt r1 10 5 - move r8 r1 #isGreater + move r8 r1 slt r2 5 10 - move r9 r2 #isLess + move r9 r2 seq r3 5 5 - move r10 r3 #isEqual + move r10 r3 sne r4 5 10 - move r11 r4 #isNotEqual + move r11 r4 sge r5 10 10 - move r12 r5 #isGreaterOrEqual + move r12 r5 sle r6 5 5 - move r13 r6 #isLessOrEqual + move r13 r6 " } ); @@ -59,11 +59,11 @@ fn test_logical_and_or_not() -> anyhow::Result<()> { j main main: and r1 1 1 - move r8 r1 #logic1 + move r8 r1 or r2 1 0 - move r9 r2 #logic2 + move r9 r2 seq r3 1 0 - move r10 r3 #logic3 + move r10 r3 " } ); @@ -89,7 +89,7 @@ fn test_complex_logic() -> anyhow::Result<()> { sgt r1 10 5 slt r2 5 10 and r3 r1 r2 - move r8 r3 #logic + move r8 r3 " } ); @@ -113,7 +113,7 @@ fn test_math_with_logic() -> anyhow::Result<()> { j main main: sgt r1 3 1 - move r8 r1 #logic + move r8 r1 " } ); @@ -137,7 +137,7 @@ fn test_boolean_in_logic() -> anyhow::Result<()> { j main main: and r1 1 0 - move r8 r1 #res + move r8 r1 " } ); @@ -163,11 +163,11 @@ fn test_invert_a_boolean() -> anyhow::Result<()> { " j main main: - move r8 1 #i + move r8 1 seq r1 r8 0 - move r9 r1 #y + move r9 r1 seq r2 r9 0 - move r10 r2 #result + move r10 r2 " } ); diff --git a/rust_compiler/libs/compiler/src/test/loops.rs b/rust_compiler/libs/compiler/src/test/loops.rs index b9c38e3..83745f0 100644 --- a/rust_compiler/libs/compiler/src/test/loops.rs +++ b/rust_compiler/libs/compiler/src/test/loops.rs @@ -21,10 +21,10 @@ fn test_infinite_loop() -> anyhow::Result<()> { " j main main: - move r8 0 #a + move r8 0 L1: add r1 r8 1 - move r8 r1 #a + move r8 r1 j L1 L2: " @@ -56,12 +56,12 @@ fn test_loop_break() -> anyhow::Result<()> { " j main main: - move r8 0 #a + move r8 0 L1: add r1 r8 1 - move r8 r1 #a + move r8 r1 sgt r2 r8 10 - beq r2 0 L3 + beqz r2 L3 j L2 L3: j L1 @@ -92,12 +92,12 @@ fn test_while_loop() -> anyhow::Result<()> { " j main main: - move r8 0 #a + move r8 0 L1: slt r1 r8 10 - beq r1 0 L2 + beqz r1 L2 add r2 r8 1 - move r8 r2 #a + move r8 r2 j L1 L2: " @@ -130,12 +130,12 @@ fn test_loop_continue() -> anyhow::Result<()> { " j main main: - move r8 0 #a + move r8 0 L1: add r1 r8 1 - move r8 r1 #a + move r8 r1 slt r2 r8 5 - beq r2 0 L3 + beqz r2 L3 j L1 L3: j L2 diff --git a/rust_compiler/libs/compiler/src/test/math_syscall.rs b/rust_compiler/libs/compiler/src/test/math_syscall.rs index f102135..cf3b3e0 100644 --- a/rust_compiler/libs/compiler/src/test/math_syscall.rs +++ b/rust_compiler/libs/compiler/src/test/math_syscall.rs @@ -19,7 +19,7 @@ fn test_acos() -> Result<()> { j main main: acos r15 123 - move r8 r15 #i + move r8 r15 " } ); @@ -43,7 +43,7 @@ fn test_asin() -> Result<()> { j main main: asin r15 123 - move r8 r15 #i + move r8 r15 " } ); @@ -67,7 +67,7 @@ fn test_atan() -> Result<()> { j main main: atan r15 123 - move r8 r15 #i + move r8 r15 " } ); @@ -91,7 +91,7 @@ fn test_atan2() -> Result<()> { j main main: atan2 r15 123 456 - move r8 r15 #i + move r8 r15 " } ); @@ -115,7 +115,7 @@ fn test_abs() -> Result<()> { j main main: abs r15 -123 - move r8 r15 #i + move r8 r15 " } ); @@ -139,7 +139,7 @@ fn test_ceil() -> Result<()> { j main main: ceil r15 123.90 - move r8 r15 #i + move r8 r15 " } ); @@ -163,7 +163,7 @@ fn test_cos() -> Result<()> { j main main: cos r15 123 - move r8 r15 #i + move r8 r15 " } ); @@ -187,7 +187,7 @@ fn test_floor() -> Result<()> { j main main: floor r15 123 - move r8 r15 #i + move r8 r15 " } ); @@ -211,7 +211,7 @@ fn test_log() -> Result<()> { j main main: log r15 123 - move r8 r15 #i + move r8 r15 " } ); @@ -235,7 +235,7 @@ fn test_max() -> Result<()> { j main main: max r15 123 456 - move r8 r15 #i + move r8 r15 " } ); @@ -259,9 +259,9 @@ fn test_max_from_game() -> Result<()> { " j main main: - move r8 0 #item + move r8 0 max r15 3 2 - move r8 r15 #item + move r8 r15 " } ); @@ -285,7 +285,7 @@ fn test_min() -> Result<()> { j main main: min r15 123 456 - move r8 r15 #i + move r8 r15 " } ); @@ -309,7 +309,7 @@ fn test_rand() -> Result<()> { j main main: rand r15 - move r8 r15 #i + move r8 r15 " } ); @@ -333,7 +333,7 @@ fn test_sin() -> Result<()> { j main main: sin r15 3 - move r8 r15 #i + move r8 r15 " } ); @@ -357,7 +357,7 @@ fn test_sqrt() -> Result<()> { j main main: sqrt r15 3 - move r8 r15 #i + move r8 r15 " } ); @@ -381,7 +381,7 @@ fn test_tan() -> Result<()> { j main main: tan r15 3 - move r8 r15 #i + move r8 r15 " } ); @@ -405,7 +405,7 @@ fn test_trunc() -> Result<()> { j main main: trunc r15 3.234 - move r8 r15 #i + move r8 r15 " } ); diff --git a/rust_compiler/libs/compiler/src/test/syscall.rs b/rust_compiler/libs/compiler/src/test/syscall.rs index a8e5b9e..8456448 100644 --- a/rust_compiler/libs/compiler/src/test/syscall.rs +++ b/rust_compiler/libs/compiler/src/test/syscall.rs @@ -44,7 +44,7 @@ fn test_sleep() -> anyhow::Result<()> { j main main: sleep 3 - move r8 15 #sleepAmount + move r8 15 sleep r8 mul r1 r8 2 sleep r1 @@ -73,7 +73,7 @@ fn test_set_on_device() -> anyhow::Result<()> { " j main main: - move r8 293.15 #internalTemp + move r8 293.15 sgt r1 r8 298.15 s d0 On r1 " @@ -150,7 +150,7 @@ fn test_load_from_device() -> anyhow::Result<()> { j main main: l r15 d0 On - move r8 r15 #setting + move r8 r15 " } ); @@ -176,7 +176,7 @@ fn test_load_from_slot() -> anyhow::Result<()> { j main main: ls r15 d0 0 Occupied - move r8 r15 #setting + move r8 r15 " } ); diff --git a/rust_compiler/libs/compiler/src/v1.rs b/rust_compiler/libs/compiler/src/v1.rs index 911c29a..5ed8986 100644 --- a/rust_compiler/libs/compiler/src/v1.rs +++ b/rust_compiler/libs/compiler/src/v1.rs @@ -1,6 +1,7 @@ #![allow(clippy::result_large_err)] use crate::variable_manager::{self, LocationRequest, VariableLocation, VariableScope}; -use helpers::prelude::*; +use helpers::{Span, prelude::*}; +use il::{Instruction, InstructionNode, Operand}; use parser::{ Parser as ASTParser, sys_call::{Math, SysCall, System}, @@ -8,9 +9,10 @@ use parser::{ AssignmentExpression, BinaryExpression, BlockExpression, ConstDeclarationExpression, DeviceDeclarationExpression, Expression, FunctionExpression, IfExpression, InvocationExpression, Literal, LiteralOr, LiteralOrVariable, LogicalExpression, - LoopExpression, MemberAccessExpression, Span, Spanned, TernaryExpression, WhileExpression, + LoopExpression, MemberAccessExpression, Spanned, TernaryExpression, WhileExpression, }, }; +use rust_decimal::Decimal; use std::{ borrow::Cow, collections::HashMap, @@ -19,28 +21,10 @@ use std::{ use thiserror::Error; use tokenizer::token::Number; -macro_rules! debug { - ($self: expr, $debug_value: expr) => { - if $self.config.debug { - format!($debug_value) - } else { - "".into() - } - }; - - ($self: expr, $debug_value: expr, $args: expr) => { - if $self.config.debug { - format!($debug_value, $args) - } else { - "".into() - } - }; -} - fn extract_literal<'a>( literal: Literal<'a>, allow_strings: bool, -) -> Result, Error<'a>> { +) -> Result, Error<'a>> { if !allow_strings && matches!(literal, Literal::String(_)) { return Err(Error::Unknown( "Literal strings are not allowed in this context".to_string(), @@ -48,9 +32,9 @@ fn extract_literal<'a>( )); } Ok(match literal { - Literal::String(s) => s, - Literal::Number(n) => Cow::from(n.to_string()), - Literal::Boolean(b) => Cow::from(if b { "1" } else { "0" }), + Literal::String(s) => Operand::LogicType(s), + Literal::Number(n) => Operand::Number(n.into()), + Literal::Boolean(b) => Operand::Number(Number::from(b).into()), }) } @@ -164,6 +148,11 @@ pub struct Compiler<'a, 'w, W: std::io::Write> { function_metadata: HashMap, Vec>>, devices: HashMap, Cow<'a, str>>, output: &'w mut BufWriter, + + // This holds the IL code which will be used in the + // optimizer + pub instructions: Vec>, + current_line: usize, declared_main: bool, config: CompilerConfig, @@ -189,6 +178,7 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { function_metadata: HashMap::new(), devices: HashMap::new(), output: writer, + instructions: Vec::new(), current_line: 1, declared_main: false, config: config.unwrap_or_default(), @@ -241,8 +231,10 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { }; let spanned_root = Spanned { node: expr, span }; - - if let Err(e) = self.write_output("j main", Some(span)) { + if let Err(e) = self.write_instruction( + Instruction::Jump(Operand::Label(Cow::from("main"))), + Some(span), + ) { self.errors.push(e); return CompilationResult { errors: self.errors, @@ -263,23 +255,17 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { } } - fn write_output( + /// Performs a write to the output buffer as well as a push to the IL instructions vec + fn write_instruction( &mut self, - output: impl Into, + instr: Instruction<'a>, span: Option, ) -> Result<(), Error<'a>> { - self.output.write_all(output.into().as_bytes())?; + self.output.write_all(format!("{}", instr).as_bytes())?; self.output.write_all(b"\n")?; - - if let Some(span) = span { - self.source_map - .entry(self.current_line) - .or_default() - .push(span); - } - self.current_line += 1; + self.instructions.push(InstructionNode::new(instr, span)); Ok(()) } @@ -360,9 +346,8 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { let temp_loc = scope.add_variable(temp_name.clone(), LocationRequest::Temp, None)?; self.emit_variable_assignment( - temp_name.clone(), &temp_loc, - Cow::from(format!("r{}", VariableScope::RETURN_REGISTER)), + Operand::Register(VariableScope::RETURN_REGISTER), )?; Ok(Some(CompileLocation { location: temp_loc, @@ -381,21 +366,16 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { Literal::Number(num) => { let temp_name = self.next_temp_name(); let loc = scope.add_variable(temp_name.clone(), LocationRequest::Temp, None)?; - self.emit_variable_assignment( - temp_name.clone(), - &loc, - Cow::from(num.to_string()), - )?; + self.emit_variable_assignment(&loc, Operand::Number(num.into()))?; Ok(Some(CompileLocation { location: loc, temp_name: Some(temp_name), })) } Literal::Boolean(b) => { - let val = if b { "1" } else { "0" }; let temp_name = self.next_temp_name(); let loc = scope.add_variable(temp_name.clone(), LocationRequest::Temp, None)?; - self.emit_variable_assignment(temp_name.clone(), &loc, Cow::from(val))?; + self.emit_variable_assignment(&loc, Operand::Number(Number::from(b).into()))?; Ok(Some(CompileLocation { location: loc, temp_name: Some(temp_name), @@ -432,7 +412,7 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { let MemberAccessExpression { object, member } = access.node; // 1. Resolve the object to a device string (e.g., "d0" or "rX") - let (device_str, cleanup) = self.resolve_device(*object, scope)?; + let (device, cleanup) = self.resolve_device(*object, scope)?; // 2. Allocate a temp register for the result let result_name = self.next_temp_name(); @@ -440,8 +420,12 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { let reg = self.resolve_register(&loc)?; // 3. Emit load instruction: l rX device member - self.write_output( - format!("l {} {} {}", reg, device_str, member.node), + self.write_instruction( + Instruction::Load( + Operand::Register(reg), + device, + Operand::LogicType(member.node), + ), Some(expr.span), )?; @@ -475,7 +459,14 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { scope.add_variable(result_name.clone(), LocationRequest::Temp, None)?; let result_reg = self.resolve_register(&result_loc)?; - self.write_output(format!("sub {result_reg} 0 {inner_str}"), Some(expr.span))?; + self.write_instruction( + Instruction::Sub( + Operand::Register(result_reg), + Operand::Number(0.into()), + inner_str, + ), + Some(expr.span), + )?; if let Some(name) = cleanup { scope.free_temp(name, None)?; @@ -502,12 +493,12 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { &mut self, expr: Spanned>, scope: &mut VariableScope<'a, '_>, - ) -> Result<(Cow<'a, str>, Option>), Error<'a>> { + ) -> Result<(Operand<'a>, Option>), Error<'a>> { // If it's a direct variable reference, check if it's a known device alias first if let Expression::Variable(ref name) = expr.node && let Some(device_id) = self.devices.get(&name.node) { - return Ok((device_id.clone(), None)); + return Ok((Operand::Device(device_id.clone()), None)); } // Otherwise, compile it as an operand (e.g. it might be a register holding a device hash/id) @@ -516,22 +507,18 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { fn emit_variable_assignment( &mut self, - var_name: Cow<'a, str>, location: &VariableLocation<'a>, - source_value: Cow<'a, str>, + source_value: Operand<'a>, ) -> Result<(), Error<'a>> { - let debug_tag = if self.config.debug { - format!(" #{var_name}") - } else { - String::new() - }; - match location { VariableLocation::Temporary(reg) | VariableLocation::Persistant(reg) => { - self.write_output(format!("move r{reg} {}{debug_tag}", source_value), None)?; + self.write_instruction( + Instruction::Move(Operand::Register(*reg), source_value), + None, + )?; } VariableLocation::Stack(_) => { - self.write_output(format!("push {}{debug_tag}", source_value), None)?; + self.write_instruction(Instruction::Push(source_value), None)?; } VariableLocation::Constant(_) => { return Err(Error::Unknown( @@ -570,11 +557,8 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { { let loc = scope.add_variable(name_str.clone(), LocationRequest::Persist, Some(name_span))?; - self.emit_variable_assignment( - name_str.clone(), - &loc, - Cow::from(format!("-{neg_num}")), - )?; + + self.emit_variable_assignment(&loc, Operand::Number((-*neg_num).into()))?; return Ok(Some(CompileLocation { location: loc, temp_name: None, @@ -590,22 +574,20 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { Some(name_span), )?; - self.emit_variable_assignment( - name_str.clone(), - &var_location, - Cow::from(num.to_string()), - )?; + self.emit_variable_assignment(&var_location, Operand::Number(num.into()))?; (var_location, None) } Literal::Boolean(b) => { - let val = if b { "1" } else { "0" }; let var_location = scope.add_variable( name_str.clone(), LocationRequest::Persist, Some(name_span), )?; - self.emit_variable_assignment(name_str, &var_location, Cow::from(val))?; + self.emit_variable_assignment( + &var_location, + Operand::Number(Number::from(b).into()), + )?; (var_location, None) } _ => return Ok(None), @@ -619,9 +601,8 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { Some(name_span), )?; self.emit_variable_assignment( - name_str, &loc, - Cow::from(format!("r{}", VariableScope::RETURN_REGISTER)), + Operand::Register(VariableScope::RETURN_REGISTER), )?; (loc, None) } @@ -649,9 +630,8 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { Some(name_span), )?; self.emit_variable_assignment( - name_str, &loc, - Cow::from(format!("r{}", VariableScope::RETURN_REGISTER)), + Operand::Register(VariableScope::RETURN_REGISTER), )?; (loc, None) @@ -670,12 +650,12 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { .. } = result { - self.emit_variable_assignment(name_str, &var_loc, Cow::from(num.to_string()))?; + self.emit_variable_assignment(&var_loc, Operand::Number(num.into()))?; (var_loc, None) } else { // Move result from temp to new persistent variable let result_reg = self.resolve_register(&result.location)?; - self.emit_variable_assignment(name_str, &var_loc, result_reg)?; + self.emit_variable_assignment(&var_loc, Operand::Register(result_reg))?; // Free the temp result if let Some(name) = result.temp_name { @@ -694,7 +674,7 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { // Move result from temp to new persistent variable let result_reg = self.resolve_register(&result.location)?; - self.emit_variable_assignment(name_str, &var_loc, result_reg)?; + self.emit_variable_assignment(&var_loc, Operand::Register(result_reg))?; // Free the temp result if let Some(name) = result.temp_name { @@ -721,24 +701,34 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { )?; // Handle loading from stack if necessary - let src_str = match src_loc { + let src = match src_loc { VariableLocation::Temporary(r) | VariableLocation::Persistant(r) => { - format!("r{r}") + Operand::Register(r) } VariableLocation::Stack(offset) => { - self.write_output( - format!("sub r{0} sp {offset}", VariableScope::TEMP_STACK_REGISTER), + self.write_instruction( + Instruction::Sub( + Operand::Register(VariableScope::TEMP_STACK_REGISTER), + Operand::StackPointer, + Operand::Number(offset.into()), + ), Some(expr.span), )?; - self.write_output( - format!("get r{0} db r{0}", VariableScope::TEMP_STACK_REGISTER), + + self.write_instruction( + Instruction::Get( + Operand::Register(VariableScope::TEMP_STACK_REGISTER), + Operand::Device(Cow::from("db")), + Operand::Register(VariableScope::TEMP_STACK_REGISTER), + ), Some(expr.span), )?; - format!("r{}", VariableScope::TEMP_STACK_REGISTER) + + Operand::Register(VariableScope::TEMP_STACK_REGISTER) } VariableLocation::Constant(_) | VariableLocation::Device(_) => unreachable!(), }; - self.emit_variable_assignment(name_str, &var_loc, Cow::from(src_str))?; + self.emit_variable_assignment(&var_loc, src)?; (var_loc, None) } Expression::Priority(inner) => { @@ -776,7 +766,7 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { )?; let result_reg = self.resolve_register(&comp_res.location)?; - self.emit_variable_assignment(name_str, &var_loc, result_reg)?; + self.emit_variable_assignment(&var_loc, Operand::Register(result_reg))?; if let Some(temp) = comp_res.temp_name { scope.free_temp(temp, None)?; @@ -794,7 +784,7 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { )?; let res_register = self.resolve_register(&res.location)?; - self.emit_variable_assignment(name_str, &var_loc, res_register)?; + self.emit_variable_assignment(&var_loc, Operand::Register(res_register))?; if let Some(name) = res.temp_name { scope.free_temp(name, None)?; @@ -876,32 +866,32 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { } }; - let (val_str, cleanup) = self.compile_operand(*expression, scope)?; - - let debug_tag = if self.config.debug { - format!(" #{}", identifier.node) - } else { - String::new() - }; + let (val, cleanup) = self.compile_operand(*expression, scope)?; match location { VariableLocation::Temporary(reg) | VariableLocation::Persistant(reg) => { - self.write_output( - format!("move r{reg} {val_str}{debug_tag}"), + self.write_instruction( + Instruction::Move(Operand::Register(reg), val), Some(expr_span), )?; } VariableLocation::Stack(offset) => { // Calculate address: sp - offset - self.write_output( - format!("sub r{0} sp {offset}", VariableScope::TEMP_STACK_REGISTER), + self.write_instruction( + Instruction::Sub( + Operand::Register(VariableScope::TEMP_STACK_REGISTER), + Operand::StackPointer, + Operand::Number(offset.into()), + ), Some(expr_span), )?; + // Store value to stack/db at address - self.write_output( - format!( - "put db r{0} {val_str}{debug_tag}", - VariableScope::TEMP_STACK_REGISTER + self.write_instruction( + Instruction::Put( + Operand::Device(Cow::from("db")), + Operand::Register(VariableScope::TEMP_STACK_REGISTER), + val, ), Some(expr_span), )?; @@ -922,11 +912,11 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { // Set instruction: s device member value let MemberAccessExpression { object, member } = access.node; - let (device_str, dev_cleanup) = self.resolve_device(*object, scope)?; - let (val_str, val_cleanup) = self.compile_operand(*expression, scope)?; + let (device, dev_cleanup) = self.resolve_device(*object, scope)?; + let (val, val_cleanup) = self.compile_operand(*expression, scope)?; - self.write_output( - format!("s {} {} {}", device_str, member.node, val_str,), + self.write_instruction( + Instruction::Store(device, Operand::LogicType(member.node), val), Some(member.span), )?; @@ -989,18 +979,25 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { LocationRequest::Stack, None, )?; - self.write_output(format!("push r{register}"), Some(name.span))?; + self.write_instruction( + Instruction::Push(Operand::Register(*register)), + Some(name.span), + )?; } for arg in arguments { match arg.node { Expression::Literal(spanned_lit) => match spanned_lit.node { Literal::Number(num) => { - let num_str = num.to_string(); - self.write_output(format!("push {num_str}"), Some(spanned_lit.span))?; + self.write_instruction( + Instruction::Push(Operand::Number(num.into())), + Some(spanned_lit.span), + )?; } Literal::Boolean(b) => { - let val = if b { "1" } else { "0" }; - self.write_output(format!("push {val}"), Some(spanned_lit.span))?; + self.write_instruction( + Instruction::Push(Operand::Number(Number::from(b).into())), + Some(spanned_lit.span), + )?; } _ => {} }, @@ -1016,28 +1013,40 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { match loc { VariableLocation::Persistant(reg) | VariableLocation::Temporary(reg) => { - self.write_output(format!("push r{reg}"), Some(var_name.span))?; + self.write_instruction( + Instruction::Push(Operand::Register(reg)), + Some(var_name.span), + )?; } VariableLocation::Constant(lit) => { - self.write_output( - format!("push {}", extract_literal(lit, false)?), + self.write_instruction( + Instruction::Push(extract_literal(lit, false)?), Some(var_name.span), )?; } VariableLocation::Stack(stack_offset) => { - self.write_output( - format!( - "sub r{0} sp {stack_offset}", - VariableScope::TEMP_STACK_REGISTER + self.write_instruction( + Instruction::Sub( + Operand::Register(VariableScope::TEMP_STACK_REGISTER), + Operand::StackPointer, + Operand::Number(stack_offset.into()), ), Some(var_name.span), )?; - self.write_output( - format!("get r{0} db r{0}", VariableScope::TEMP_STACK_REGISTER), + + self.write_instruction( + Instruction::Get( + Operand::Register(VariableScope::TEMP_STACK_REGISTER), + Operand::Device(Cow::from("db")), + Operand::Register(VariableScope::TEMP_STACK_REGISTER), + ), Some(var_name.span), )?; - self.write_output( - format!("push r{0}", VariableScope::TEMP_STACK_REGISTER), + + self.write_instruction( + Instruction::Push(Operand::Register( + VariableScope::TEMP_STACK_REGISTER, + )), Some(var_name.span), )?; } @@ -1053,8 +1062,8 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { let span = bin_expr.span; // Compile the binary expression to a temp register let result = self.expression_binary(bin_expr, &mut stack)?; - let reg_str = self.resolve_register(&result.location)?; - self.write_output(format!("push {reg_str}"), Some(span))?; + let reg = self.resolve_register(&result.location)?; + self.write_instruction(Instruction::Push(Operand::Register(reg)), Some(span))?; if let Some(name) = result.temp_name { stack.free_temp(name, None)?; } @@ -1063,8 +1072,8 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { let span = log_expr.span; // Compile the logical expression to a temp register let result = self.expression_logical(log_expr, &mut stack)?; - let reg_str = self.resolve_register(&result.location)?; - self.write_output(format!("push {reg_str}"), Some(span))?; + let reg = self.resolve_register(&result.location)?; + self.write_instruction(Instruction::Push(Operand::Register(reg)), Some(span))?; if let Some(name) = result.temp_name { stack.free_temp(name, None)?; } @@ -1087,12 +1096,18 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { if let Some(result) = result_opt { let reg_str = self.resolve_register(&result.location)?; - self.write_output(format!("push {reg_str}"), Some(span))?; + self.write_instruction( + Instruction::Push(Operand::Register(reg_str)), + Some(span), + )?; if let Some(name) = result.temp_name { stack.free_temp(name, None)?; } } else { - self.write_output("push 0", Some(span))?; // Should fail ideally + self.write_instruction( + Instruction::Push(Operand::Number(Decimal::from(0))), + Some(span), + )?; } } _ => { @@ -1108,7 +1123,10 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { } // jump to the function and store current line in ra - self.write_output(format!("jal {}", name.node), Some(name.span))?; + self.write_instruction( + Instruction::JumpAndLink(Operand::Label(name.node)), + Some(name.span), + )?; for register in active_registers { let VariableLocation::Stack(stack_offset) = stack @@ -1121,25 +1139,32 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { Some(name.span), )); }; - self.write_output( - format!( - "sub r{0} sp {stack_offset}", - VariableScope::TEMP_STACK_REGISTER + self.write_instruction( + Instruction::Sub( + Operand::Register(VariableScope::TEMP_STACK_REGISTER), + Operand::StackPointer, + Operand::Number(stack_offset.into()), ), Some(name.span), )?; - self.write_output( - format!( - "get r{register} db r{0}", - VariableScope::TEMP_STACK_REGISTER + + self.write_instruction( + Instruction::Get( + Operand::Register(register), + Operand::Device(Cow::from("db")), + Operand::Register(VariableScope::TEMP_STACK_REGISTER), ), Some(name.span), )?; } if stack.stack_offset() > 0 { - self.write_output( - format!("sub sp sp {}", stack.stack_offset()), + self.write_instruction( + Instruction::Sub( + Operand::StackPointer, + Operand::StackPointer, + Operand::Number(Decimal::from(stack.stack_offset())), + ), Some(name.span), )?; } @@ -1181,10 +1206,13 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { let cond_span = expr.condition.span; // Compile Condition - let (cond_str, cleanup) = self.compile_operand(*expr.condition, scope)?; + let (cond, cleanup) = self.compile_operand(*expr.condition, scope)?; // If condition is FALSE (0), jump to else_label - self.write_output(format!("beq {cond_str} 0 {else_label}"), Some(cond_span))?; + self.write_instruction( + Instruction::BranchEqZero(cond, Operand::Label(else_label.clone())), + Some(cond_span), + )?; if let Some(name) = cleanup { scope.free_temp(name, None)?; @@ -1196,8 +1224,11 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { // If we have an else branch, we need to jump over it after the 'if' body if let Some(else_branch) = expr.else_branch { - self.write_output(format!("j {end_label}"), Some(else_branch.span))?; - self.write_output(format!("{else_label}:"), Some(else_branch.span))?; + self.write_instruction( + Instruction::Jump(Operand::Label(end_label.clone())), + Some(else_branch.span), + )?; + self.write_instruction(Instruction::LabelDef(else_label), Some(else_branch.span))?; match else_branch.node { Expression::Block(block) => self.expression_block(block.node, scope)?, @@ -1206,7 +1237,7 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { } } - self.write_output(format!("{end_label}:"), Some(expr.body.span))?; + self.write_instruction(Instruction::LabelDef(end_label), Some(expr.body.span))?; Ok(()) } @@ -1223,14 +1254,20 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { self.loop_stack .push((start_label.clone(), end_label.clone())); - self.write_output(format!("{start_label}:"), Some(expr.body.span))?; + self.write_instruction( + Instruction::LabelDef(start_label.clone()), + Some(expr.body.span), + )?; // Compile Body self.expression_block(expr.body.node, scope)?; // Jump back to start - self.write_output(format!("j {start_label}"), Some(expr.body.span))?; - self.write_output(format!("{end_label}:"), Some(expr.body.span))?; + self.write_instruction( + Instruction::Jump(Operand::Label(start_label)), + Some(expr.body.span), + )?; + self.write_instruction(Instruction::LabelDef(end_label), Some(expr.body.span))?; self.loop_stack.pop(); @@ -1250,13 +1287,16 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { .push((start_label.clone(), end_label.clone())); let span = expr.condition.span; - self.write_output(format!("{start_label}:"), Some(span))?; + self.write_instruction(Instruction::LabelDef(start_label.clone()), Some(span))?; // Compile Condition - let (cond_str, cleanup) = self.compile_operand(*expr.condition, scope)?; + let (cond, cleanup) = self.compile_operand(*expr.condition, scope)?; // If condition is FALSE, jump to end - self.write_output(format!("beq {cond_str} 0 {end_label}"), Some(span))?; + self.write_instruction( + Instruction::BranchEqZero(cond, Operand::Label(end_label.clone())), + Some(span), + )?; if let Some(name) = cleanup { scope.free_temp(name, None)?; @@ -1266,8 +1306,8 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { self.expression_block(expr.body, scope)?; // Jump back to start - self.write_output(format!("j {start_label}"), Some(span))?; - self.write_output(format!("{end_label}:"), Some(span))?; + self.write_instruction(Instruction::Jump(Operand::Label(start_label)), Some(span))?; + self.write_instruction(Instruction::LabelDef(end_label), Some(span))?; self.loop_stack.pop(); @@ -1276,7 +1316,10 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { fn expression_break(&mut self, span: Span) -> Result<(), Error<'a>> { if let Some((_, end_label)) = self.loop_stack.last() { - self.write_output(format!("j {end_label}"), Some(span))?; + self.write_instruction( + Instruction::Jump(Operand::Label(end_label.clone())), + Some(span), + )?; Ok(()) } else { Err(Error::Unknown( @@ -1288,7 +1331,10 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { fn expression_continue(&mut self, span: Span) -> Result<(), Error<'a>> { if let Some((start_label, _)) = self.loop_stack.last() { - self.write_output(format!("j {start_label}"), Some(span))?; + self.write_instruction( + Instruction::Jump(Operand::Label(start_label.clone())), + Some(span), + )?; Ok(()) } else { Err(Error::Unknown( @@ -1324,8 +1370,8 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { let result_loc = scope.add_variable(result_name.clone(), LocationRequest::Temp, None)?; let result_reg = self.resolve_register(&result_loc)?; - self.write_output( - format!("select {} {} {} {}", result_reg, cond, true_val, false_val), + self.write_instruction( + Instruction::Select(Operand::Register(result_reg), cond, true_val, false_val), Some(span), )?; @@ -1347,11 +1393,9 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { /// Helper to resolve a location to a register string (e.g., "r0"). /// Note: This does not handle Stack locations automatically, as they require /// instruction emission to load. Use `compile_operand` for general handling. - fn resolve_register(&self, loc: &VariableLocation) -> Result, Error<'a>> { + fn resolve_register(&self, loc: &VariableLocation) -> Result> { match loc { - VariableLocation::Temporary(r) | VariableLocation::Persistant(r) => { - Ok(Cow::from(format!("r{r}"))) - } + VariableLocation::Temporary(r) | VariableLocation::Persistant(r) => Ok(*r), VariableLocation::Constant(_) => Err(Error::Unknown( "Cannot resolve a constant value to register".into(), None, @@ -1375,17 +1419,17 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { &mut self, expr: Spanned>, scope: &mut VariableScope<'a, '_>, - ) -> Result<(Cow<'a, str>, Option>), Error<'a>> { + ) -> Result<(Operand<'a>, Option>), Error<'a>> { // Optimization for literals if let Expression::Literal(spanned_lit) = &expr.node { if let Literal::Number(n) = spanned_lit.node { - return Ok((Cow::from(n.to_string()), None)); + return Ok((Operand::Number(n.into()), None)); } if let Literal::Boolean(b) = spanned_lit.node { - return Ok((Cow::from(if b { "1" } else { "0" }), None)); + return Ok((Operand::Number(Decimal::from(if b { 1 } else { 0 })), None)); } if let Literal::String(ref s) = spanned_lit.node { - return Ok((s.clone(), None)); + return Ok((Operand::LogicType(s.clone()), None)); } } @@ -1395,7 +1439,7 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { && let Expression::Literal(spanned_lit) = &inner.node && let Literal::Number(n) = spanned_lit.node { - return Ok((Cow::from(format!("-{}", n)), None)); + return Ok((Operand::Number((-n).into()), None)); } let result_opt = self.expression(expr, scope)?; @@ -1404,18 +1448,18 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { Some(r) => r, None => { // Expression failed or returned void. Recover with dummy. - return Ok((Cow::from("r0"), None)); + return Ok((Operand::Register(0), None)); } }; match result.location { VariableLocation::Temporary(r) | VariableLocation::Persistant(r) => { - Ok((Cow::from(format!("r{r}")), result.temp_name)) + Ok((Operand::Register(r), result.temp_name)) } VariableLocation::Constant(lit) => match lit { - Literal::Number(n) => Ok((Cow::from(n.to_string()), None)), - Literal::Boolean(b) => Ok((Cow::from(if b { "1" } else { "0" }), None)), - Literal::String(s) => Ok((s, None)), + Literal::Number(n) => Ok((Operand::Number(n.into()), None)), + Literal::Boolean(b) => Ok((Operand::Number(Number::from(b).into()), None)), + Literal::String(s) => Ok((Operand::LogicType(s), None)), }, VariableLocation::Stack(offset) => { // If it's on the stack, we must load it into a temp to use it as an operand @@ -1424,21 +1468,29 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { scope.add_variable(temp_name.clone(), LocationRequest::Temp, None)?; let temp_reg = self.resolve_register(&temp_loc)?; - self.write_output( - format!("sub r{0} sp {offset}", VariableScope::TEMP_STACK_REGISTER), + self.write_instruction( + Instruction::Sub( + Operand::Register(VariableScope::TEMP_STACK_REGISTER), + Operand::StackPointer, + Operand::Number(Decimal::from(offset)), + ), None, )?; - self.write_output( - format!("get {temp_reg} db r{0}", VariableScope::TEMP_STACK_REGISTER), + self.write_instruction( + Instruction::Get( + Operand::Register(temp_reg), + Operand::Device(Cow::from("db")), + Operand::Register(VariableScope::TEMP_STACK_REGISTER), + ), None, )?; // If the original result had a temp name (unlikely for Stack, but possible logic), // we technically should free it if it's not needed, but Stack usually implies it's safe there. // We return the NEW temp name to be freed. - Ok((temp_reg, Some(temp_name))) + Ok((Operand::Register(temp_reg), Some(temp_name))) } - VariableLocation::Device(d) => Ok((d, None)), + VariableLocation::Device(d) => Ok((Operand::Device(d), None)), } } @@ -1446,7 +1498,7 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { &mut self, val: LiteralOrVariable<'a>, scope: &mut VariableScope<'a, '_>, - ) -> Result<(Cow<'a, str>, Option>), Error<'a>> { + ) -> Result<(Operand<'a>, Option>), Error<'a>> { let dummy_span = Span { start_line: 0, start_col: 0, @@ -1527,13 +1579,30 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { }); }; - let (op_str, left_expr, right_expr) = match expr.node { - BinaryExpression::Add(l, r) => ("add", l, r), - BinaryExpression::Multiply(l, r) => ("mul", l, r), - BinaryExpression::Divide(l, r) => ("div", l, r), - BinaryExpression::Subtract(l, r) => ("sub", l, r), - BinaryExpression::Exponent(l, r) => ("pow", l, r), - BinaryExpression::Modulo(l, r) => ("mod", l, r), + #[allow(clippy::type_complexity)] + let (op_instr, left_expr, right_expr): ( + fn(Operand<'a>, Operand<'a>, Operand<'a>) -> Instruction<'a>, + Box>>, + Box>>, + ) = match expr.node { + BinaryExpression::Add(l, r) => { + (|into, lhs, rhs| Instruction::Add(into, lhs, rhs), l, r) + } + BinaryExpression::Multiply(l, r) => { + (|into, lhs, rhs| Instruction::Mul(into, lhs, rhs), l, r) + } + BinaryExpression::Divide(l, r) => { + (|into, lhs, rhs| Instruction::Div(into, lhs, rhs), l, r) + } + BinaryExpression::Subtract(l, r) => { + (|into, lhs, rhs| Instruction::Sub(into, lhs, rhs), l, r) + } + BinaryExpression::Exponent(l, r) => { + (|into, lhs, rhs| Instruction::Pow(into, lhs, rhs), l, r) + } + BinaryExpression::Modulo(l, r) => { + (|into, lhs, rhs| Instruction::Mod(into, lhs, rhs), l, r) + } }; let span = Span { @@ -1544,9 +1613,9 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { }; // Compile LHS - let (lhs_str, lhs_cleanup) = self.compile_operand(*left_expr, scope)?; + let (lhs, lhs_cleanup) = self.compile_operand(*left_expr, scope)?; // Compile RHS - let (rhs_str, rhs_cleanup) = self.compile_operand(*right_expr, scope)?; + let (rhs, rhs_cleanup) = self.compile_operand(*right_expr, scope)?; // Allocate result register let result_name = self.next_temp_name(); @@ -1554,8 +1623,8 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { let result_reg = self.resolve_register(&result_loc)?; // Emit instruction: op result lhs rhs - self.write_output( - format!("{op_str} {result_reg} {lhs_str} {rhs_str}"), + self.write_instruction( + op_instr(Operand::Register(result_reg), lhs, rhs), Some(span), )?; @@ -1589,7 +1658,14 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { let result_reg = self.resolve_register(&result_loc)?; // seq rX rY 0 => if rY == 0 set rX = 1 else rX = 0 - self.write_output(format!("seq {result_reg} {inner_str} 0"), Some(span))?; + self.write_instruction( + Instruction::SetEq( + Operand::Register(result_reg), + inner_str, + Operand::Number(0.into()), + ), + Some(span), + )?; if let Some(name) = cleanup { scope.free_temp(name, None)?; @@ -1601,15 +1677,36 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { }) } _ => { - let (op_str, left_expr, right_expr) = match expr.node { - LogicalExpression::And(l, r) => ("and", l, r), - LogicalExpression::Or(l, r) => ("or", l, r), - LogicalExpression::Equal(l, r) => ("seq", l, r), - LogicalExpression::NotEqual(l, r) => ("sne", l, r), - LogicalExpression::GreaterThan(l, r) => ("sgt", l, r), - LogicalExpression::GreaterThanOrEqual(l, r) => ("sge", l, r), - LogicalExpression::LessThan(l, r) => ("slt", l, r), - LogicalExpression::LessThanOrEqual(l, r) => ("sle", l, r), + #[allow(clippy::type_complexity)] + let (op_instr, left_expr, right_expr): ( + fn(Operand<'a>, Operand<'a>, Operand<'a>) -> Instruction<'a>, + Box>>, + Box>>, + ) = match expr.node { + LogicalExpression::And(l, r) => { + (|into, lhs, rhs| Instruction::And(into, lhs, rhs), l, r) + } + LogicalExpression::Or(l, r) => { + (|into, lhs, rhs| Instruction::Or(into, lhs, rhs), l, r) + } + LogicalExpression::Equal(l, r) => { + (|into, lhs, rhs| Instruction::SetEq(into, lhs, rhs), l, r) + } + LogicalExpression::NotEqual(l, r) => { + (|into, lhs, rhs| Instruction::SetNe(into, lhs, rhs), l, r) + } + LogicalExpression::GreaterThan(l, r) => { + (|into, lhs, rhs| Instruction::SetGt(into, lhs, rhs), l, r) + } + LogicalExpression::GreaterThanOrEqual(l, r) => { + (|into, lhs, rhs| Instruction::SetGe(into, lhs, rhs), l, r) + } + LogicalExpression::LessThan(l, r) => { + (|into, lhs, rhs| Instruction::SetLt(into, lhs, rhs), l, r) + } + LogicalExpression::LessThanOrEqual(l, r) => { + (|into, lhs, rhs| Instruction::SetLe(into, lhs, rhs), l, r) + } LogicalExpression::Not(_) => unreachable!(), }; @@ -1621,9 +1718,9 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { }; // Compile LHS - let (lhs_str, lhs_cleanup) = self.compile_operand(*left_expr, scope)?; + let (lhs, lhs_cleanup) = self.compile_operand(*left_expr, scope)?; // Compile RHS - let (rhs_str, rhs_cleanup) = self.compile_operand(*right_expr, scope)?; + let (rhs, rhs_cleanup) = self.compile_operand(*right_expr, scope)?; // Allocate result register let result_name = self.next_temp_name(); @@ -1632,8 +1729,8 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { let result_reg = self.resolve_register(&result_loc)?; // Emit instruction: op result lhs rhs - self.write_output( - format!("{op_str} {result_reg} {lhs_str} {rhs_str}"), + self.write_instruction( + op_instr(Operand::Register(result_reg), lhs, rhs), Some(span), )?; @@ -1687,7 +1784,7 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { ) && !parent_scope.has_parent() { - self.write_output("main:", Some(expr.span))?; + self.write_instruction(Instruction::LabelDef(Cow::from("main")), Some(expr.span))?; self.declared_main = true; } @@ -1714,7 +1811,14 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { } if scope.stack_offset() > 0 { - self.write_output(format!("sub sp sp {}", scope.stack_offset()), None)?; + self.write_instruction( + Instruction::Sub( + Operand::StackPointer, + Operand::StackPointer, + Operand::Number(scope.stack_offset().into()), + ), + None, + )?; } Ok(()) @@ -1733,11 +1837,7 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { && let Literal::Number(neg_num) = &spanned_lit.node { let loc = VariableLocation::Persistant(VariableScope::RETURN_REGISTER); - self.emit_variable_assignment( - Cow::from("returnValue"), - &loc, - Cow::from(format!("-{neg_num}")), - )?; + self.emit_variable_assignment(&loc, Operand::Number((-*neg_num).into()))?; return Ok(loc); }; @@ -1747,39 +1847,38 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { Ok(loc) => match loc { VariableLocation::Temporary(reg) | VariableLocation::Persistant(reg) => { - self.write_output( - format!( - "move r{} r{reg} {}", - VariableScope::RETURN_REGISTER, - debug!(self, "#returnValue") + self.write_instruction( + Instruction::Move( + Operand::Register(VariableScope::RETURN_REGISTER), + Operand::Register(reg), ), Some(span), )?; } VariableLocation::Constant(lit) => { - let str = extract_literal(lit, false)?; - self.write_output( - format!( - "move r{} {str} {}", - VariableScope::RETURN_REGISTER, - debug!(self, "#returnValue") - ), - Some(span), - )? - } - VariableLocation::Stack(offset) => { - self.write_output( - format!( - "sub r{} sp {offset}", - VariableScope::TEMP_STACK_REGISTER + let op = extract_literal(lit, false)?; + self.write_instruction( + Instruction::Move( + Operand::Register(VariableScope::RETURN_REGISTER), + op, ), Some(span), )?; - self.write_output( - format!( - "get r{} db r{}", - VariableScope::RETURN_REGISTER, - VariableScope::TEMP_STACK_REGISTER + } + VariableLocation::Stack(offset) => { + self.write_instruction( + Instruction::Sub( + Operand::Register(VariableScope::TEMP_STACK_REGISTER), + Operand::StackPointer, + Operand::Number(offset.into()), + ), + Some(span), + )?; + self.write_instruction( + Instruction::Get( + Operand::Register(VariableScope::RETURN_REGISTER), + Operand::Device(Cow::from("db")), + Operand::Register(VariableScope::TEMP_STACK_REGISTER), ), Some(span), )?; @@ -1803,17 +1902,14 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { Expression::Literal(spanned_lit) => match spanned_lit.node { Literal::Number(num) => { self.emit_variable_assignment( - Cow::from("returnValue"), &VariableLocation::Persistant(VariableScope::RETURN_REGISTER), - Cow::from(num.to_string()), + Operand::Number(num.into()), )?; } Literal::Boolean(b) => { - let val = if b { "1" } else { "0" }; self.emit_variable_assignment( - Cow::from("returnValue"), &VariableLocation::Persistant(VariableScope::RETURN_REGISTER), - Cow::from(val.to_string()), + Operand::Number(Number::from(b).into()), )?; } _ => {} @@ -1822,10 +1918,14 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { let span = bin_expr.span; let result = self.expression_binary(bin_expr, scope)?; let result_reg = self.resolve_register(&result.location)?; - self.write_output( - format!("move r{} {}", VariableScope::RETURN_REGISTER, result_reg), + self.write_instruction( + Instruction::Move( + Operand::Register(VariableScope::RETURN_REGISTER), + Operand::Register(result_reg), + ), Some(span), )?; + if let Some(name) = result.temp_name { scope.free_temp(name, None)?; } @@ -1834,10 +1934,14 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { let span = log_expr.span; let result = self.expression_logical(log_expr, scope)?; let result_reg = self.resolve_register(&result.location)?; - self.write_output( - format!("move r{} {}", VariableScope::RETURN_REGISTER, result_reg), + self.write_instruction( + Instruction::Move( + Operand::Register(VariableScope::RETURN_REGISTER), + Operand::Register(result_reg), + ), Some(span), )?; + if let Some(name) = result.temp_name { scope.free_temp(name, None)?; } @@ -1854,10 +1958,14 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { )?; if let Some(res) = res_opt { let reg = self.resolve_register(&res.location)?; - self.write_output( - format!("move r{} {}", VariableScope::RETURN_REGISTER, reg), + self.write_instruction( + Instruction::Move( + Operand::Register(VariableScope::RETURN_REGISTER), + Operand::Register(reg), + ), Some(span), )?; + if let Some(temp) = res.temp_name { scope.free_temp(temp, Some(span))?; } @@ -1873,7 +1981,7 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { } if let Some(label) = &self.current_return_label { - self.write_output(format!("j {}", label), None)?; + self.write_instruction(Instruction::Jump(Operand::Label(label.clone())), None)?; } else { return Err(Error::Unknown( "Return statement used outside of function context.".into(), @@ -1903,15 +2011,14 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { } match expr { System::Yield => { - self.write_output("yield", Some(span))?; + self.write_instruction(Instruction::Yield, Some(span))?; Ok(None) } System::Sleep(amt) => { - let (var, var_cleanup) = self.compile_operand(*amt, scope)?; - self.write_output(format!("sleep {var}"), Some(span))?; + let (op, var_cleanup) = self.compile_operand(*amt, scope)?; + self.write_instruction(Instruction::Sleep(op), Some(span))?; cleanup!(var_cleanup); - Ok(None) } System::Hash(hash_arg) => { @@ -1975,11 +2082,14 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { )); }; - self.write_output( - format!("s {} {} {}", device_val, logic_type, variable), + self.write_instruction( + Instruction::Store( + Operand::Device(device_val), + Operand::LogicType(logic_type), + variable, + ), Some(span), )?; - cleanup!(var_cleanup); Ok(None) @@ -1999,11 +2109,10 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { )); }; - self.write_output( - format!("sb {} {} {}", device_hash_val, logic_type, var), + self.write_instruction( + Instruction::StoreBatch(device_hash_val, Operand::LogicType(logic_type), var), Some(span), )?; - cleanup!(var_cleanup, device_hash_cleanup); Ok(None) @@ -2021,11 +2130,10 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { scope, )?; - self.write_output( - format!("sbn {} {} {} {}", device_hash, name_hash, logic_type, value), + self.write_instruction( + Instruction::StoreBatchNamed(device_hash, name_hash, logic_type, value), Some(span), )?; - cleanup!( value_cleanup, device_hash_cleanup, @@ -2073,12 +2181,11 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { )); }; - self.write_output( - format!( - "l r{} {} {}", - VariableScope::RETURN_REGISTER, - device_val, - logic_type + self.write_instruction( + Instruction::Load( + Operand::Register(VariableScope::RETURN_REGISTER), + Operand::Device(device_val), + Operand::LogicType(logic_type), ), Some(span), )?; @@ -2100,17 +2207,15 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { scope, )?; - self.write_output( - format!( - "lb r{} {} {} {}", - VariableScope::RETURN_REGISTER, + self.write_instruction( + Instruction::LoadBatch( + Operand::Register(VariableScope::RETURN_REGISTER), device_hash, logic_type, - batch_mode + batch_mode, ), Some(span), )?; - cleanup!(device_hash_cleanup, logic_type_cleanup, batch_mode_cleanup); Ok(Some(CompileLocation { @@ -2132,18 +2237,16 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { scope, )?; - self.write_output( - format!( - "lbn r{} {} {} {} {}", - VariableScope::RETURN_REGISTER, + self.write_instruction( + Instruction::LoadBatchNamed( + Operand::Register(VariableScope::RETURN_REGISTER), device_hash, name_hash, logic_type, - batch_mode + batch_mode, ), Some(span), )?; - cleanup!( device_hash_cleanup, name_hash_cleanup, @@ -2168,17 +2271,15 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { scope, )?; - self.write_output( - format!( - "ls r{} {} {} {}", - VariableScope::RETURN_REGISTER, + self.write_instruction( + Instruction::LoadSlot( + Operand::Register(VariableScope::RETURN_REGISTER), dev_hash, slot_index, - logic_type + logic_type, ), Some(span), )?; - cleanup!(hash_cleanup, slot_cleanup, logic_cleanup); Ok(Some(CompileLocation { @@ -2199,11 +2300,10 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { )?; let (var, var_cleanup) = self.compile_operand(*var, scope)?; - self.write_output( - format!("ss {} {} {} {}", dev_name, slot_index, logic_type, var), + self.write_instruction( + Instruction::StoreSlot(dev_name, slot_index, logic_type, var), Some(span), )?; - cleanup!(name_cleanup, index_cleanup, type_cleanup, var_cleanup); Ok(None) @@ -2229,12 +2329,12 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { match expr { Math::Acos(expr) => { let (var, cleanup) = self.compile_operand(*expr, scope)?; - self.write_output( - format!("acos r{} {}", VariableScope::RETURN_REGISTER, var), + self.write_instruction( + Instruction::Acos(Operand::Register(VariableScope::RETURN_REGISTER), var), Some(span), )?; - cleanup!(cleanup); + Ok(Some(CompileLocation { location: VariableLocation::Persistant(VariableScope::RETURN_REGISTER), temp_name: None, @@ -2242,12 +2342,13 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { } Math::Asin(expr) => { let (var, cleanup) = self.compile_operand(*expr, scope)?; - self.write_output( - format!("asin r{} {}", VariableScope::RETURN_REGISTER, var), + + self.write_instruction( + Instruction::Asin(Operand::Register(VariableScope::RETURN_REGISTER), var), Some(span), )?; - cleanup!(cleanup); + Ok(Some(CompileLocation { location: VariableLocation::Persistant(VariableScope::RETURN_REGISTER), temp_name: None, @@ -2255,12 +2356,13 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { } Math::Atan(expr) => { let (var, cleanup) = self.compile_operand(*expr, scope)?; - self.write_output( - format!("atan r{} {}", VariableScope::RETURN_REGISTER, var), + + self.write_instruction( + Instruction::Atan(Operand::Register(VariableScope::RETURN_REGISTER), var), Some(span), )?; - cleanup!(cleanup); + Ok(Some(CompileLocation { location: VariableLocation::Persistant(VariableScope::RETURN_REGISTER), temp_name: None, @@ -2270,16 +2372,16 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { let (var1, var1_cleanup) = self.compile_operand(*expr1, scope)?; let (var2, var2_cleanup) = self.compile_operand(*expr2, scope)?; - self.write_output( - format!( - "atan2 r{} {} {}", - VariableScope::RETURN_REGISTER, + self.write_instruction( + Instruction::Atan2( + Operand::Register(VariableScope::RETURN_REGISTER), var1, - var2 + var2, ), Some(span), )?; cleanup!(var1_cleanup, var2_cleanup); + Ok(Some(CompileLocation { location: VariableLocation::Persistant(VariableScope::RETURN_REGISTER), temp_name: None, @@ -2287,12 +2389,13 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { } Math::Abs(expr) => { let (var, cleanup) = self.compile_operand(*expr, scope)?; - self.write_output( - format!("abs r{} {}", VariableScope::RETURN_REGISTER, var), + + self.write_instruction( + Instruction::Abs(Operand::Register(VariableScope::RETURN_REGISTER), var), Some(span), )?; - cleanup!(cleanup); + Ok(Some(CompileLocation { location: VariableLocation::Persistant(VariableScope::RETURN_REGISTER), temp_name: None, @@ -2300,12 +2403,13 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { } Math::Ceil(expr) => { let (var, cleanup) = self.compile_operand(*expr, scope)?; - self.write_output( - format!("ceil r{} {}", VariableScope::RETURN_REGISTER, var), + + self.write_instruction( + Instruction::Ceil(Operand::Register(VariableScope::RETURN_REGISTER), var), Some(span), )?; - cleanup!(cleanup); + Ok(Some(CompileLocation { location: VariableLocation::Persistant(VariableScope::RETURN_REGISTER), temp_name: None, @@ -2313,12 +2417,12 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { } Math::Cos(expr) => { let (var, cleanup) = self.compile_operand(*expr, scope)?; - self.write_output( - format!("cos r{} {}", VariableScope::RETURN_REGISTER, var), + self.write_instruction( + Instruction::Cos(Operand::Register(VariableScope::RETURN_REGISTER), var), Some(span), )?; - cleanup!(cleanup); + Ok(Some(CompileLocation { location: VariableLocation::Persistant(VariableScope::RETURN_REGISTER), temp_name: None, @@ -2326,12 +2430,13 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { } Math::Floor(expr) => { let (var, cleanup) = self.compile_operand(*expr, scope)?; - self.write_output( - format!("floor r{} {}", VariableScope::RETURN_REGISTER, var), + + self.write_instruction( + Instruction::Floor(Operand::Register(VariableScope::RETURN_REGISTER), var), Some(span), )?; - cleanup!(cleanup); + Ok(Some(CompileLocation { location: VariableLocation::Persistant(VariableScope::RETURN_REGISTER), temp_name: None, @@ -2339,12 +2444,13 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { } Math::Log(expr) => { let (var, cleanup) = self.compile_operand(*expr, scope)?; - self.write_output( - format!("log r{} {}", VariableScope::RETURN_REGISTER, var), + + self.write_instruction( + Instruction::Log(Operand::Register(VariableScope::RETURN_REGISTER), var), Some(span), )?; - cleanup!(cleanup); + Ok(Some(CompileLocation { location: VariableLocation::Persistant(VariableScope::RETURN_REGISTER), temp_name: None, @@ -2353,12 +2459,17 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { Math::Max(expr1, expr2) => { let (var1, clean1) = self.compile_operand(*expr1, scope)?; let (var2, clean2) = self.compile_operand(*expr2, scope)?; - self.write_output( - format!("max r{} {} {}", VariableScope::RETURN_REGISTER, var1, var2), + + self.write_instruction( + Instruction::Max( + Operand::Register(VariableScope::RETURN_REGISTER), + var1, + var2, + ), Some(span), )?; - cleanup!(clean1, clean2); + Ok(Some(CompileLocation { location: VariableLocation::Persistant(VariableScope::RETURN_REGISTER), temp_name: None, @@ -2367,20 +2478,25 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { Math::Min(expr1, expr2) => { let (var1, clean1) = self.compile_operand(*expr1, scope)?; let (var2, clean2) = self.compile_operand(*expr2, scope)?; - self.write_output( - format!("min r{} {} {}", VariableScope::RETURN_REGISTER, var1, var2), + + self.write_instruction( + Instruction::Min( + Operand::Register(VariableScope::RETURN_REGISTER), + var1, + var2, + ), Some(span), )?; - cleanup!(clean1, clean2); + Ok(Some(CompileLocation { location: VariableLocation::Persistant(VariableScope::RETURN_REGISTER), temp_name: None, })) } Math::Rand => { - self.write_output( - format!("rand r{}", VariableScope::RETURN_REGISTER), + self.write_instruction( + Instruction::Rand(Operand::Register(VariableScope::RETURN_REGISTER)), Some(span), )?; @@ -2391,12 +2507,13 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { } Math::Sin(expr) => { let (var, clean) = self.compile_operand(*expr, scope)?; - self.write_output( - format!("sin r{} {}", VariableScope::RETURN_REGISTER, var), + + self.write_instruction( + Instruction::Sin(Operand::Register(VariableScope::RETURN_REGISTER), var), Some(span), )?; - cleanup!(clean); + Ok(Some(CompileLocation { location: VariableLocation::Persistant(VariableScope::RETURN_REGISTER), temp_name: None, @@ -2404,12 +2521,13 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { } Math::Sqrt(expr) => { let (var, clean) = self.compile_operand(*expr, scope)?; - self.write_output( - format!("sqrt r{} {}", VariableScope::RETURN_REGISTER, var), + + self.write_instruction( + Instruction::Sqrt(Operand::Register(VariableScope::RETURN_REGISTER), var), Some(span), )?; - cleanup!(clean); + Ok(Some(CompileLocation { location: VariableLocation::Persistant(VariableScope::RETURN_REGISTER), temp_name: None, @@ -2417,12 +2535,12 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { } Math::Tan(expr) => { let (var, clean) = self.compile_operand(*expr, scope)?; - self.write_output( - format!("tan r{} {}", VariableScope::RETURN_REGISTER, var), + self.write_instruction( + Instruction::Tan(Operand::Register(VariableScope::RETURN_REGISTER), var), Some(span), )?; - cleanup!(clean); + Ok(Some(CompileLocation { location: VariableLocation::Persistant(VariableScope::RETURN_REGISTER), temp_name: None, @@ -2430,12 +2548,12 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { } Math::Trunc(expr) => { let (var, clean) = self.compile_operand(*expr, scope)?; - self.write_output( - format!("trunc r{} {}", VariableScope::RETURN_REGISTER, var), + self.write_instruction( + Instruction::Trunc(Operand::Register(VariableScope::RETURN_REGISTER), var), Some(span), )?; - cleanup!(clean); + Ok(Some(CompileLocation { location: VariableLocation::Persistant(VariableScope::RETURN_REGISTER), temp_name: None, @@ -2472,7 +2590,7 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { ); // Declare the function as a line identifier - self.write_output(format!("{}:", name.node), Some(name.span))?; + self.write_instruction(Instruction::LabelDef(name.node.clone()), Some(span))?; self.function_locations .insert(name.node.clone(), self.current_line); @@ -2498,8 +2616,8 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { match loc { VariableLocation::Persistant(loc) => { - self.write_output( - format!("pop r{loc} {}", debug!(self, "#{}", var_name.node)), + self.write_instruction( + Instruction::Pop(Operand::Register(loc)), Some(var_name.span), )?; } @@ -2532,7 +2650,7 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { )?; } - self.write_output("push ra", Some(span))?; + self.write_instruction(Instruction::Push(Operand::ReturnAddress), Some(span))?; let return_label = self.next_label_name(); @@ -2585,28 +2703,38 @@ impl<'a, 'w, W: std::io::Write> Compiler<'a, 'w, W> { self.current_return_label = prev_return_label; - self.write_output(format!("{}:", return_label), Some(span))?; + self.write_instruction(Instruction::LabelDef(return_label.clone()), Some(span))?; - self.write_output( - format!( - "sub r{0} sp {ra_stack_offset}", - VariableScope::TEMP_STACK_REGISTER + self.write_instruction( + Instruction::Sub( + Operand::Register(VariableScope::TEMP_STACK_REGISTER), + Operand::StackPointer, + Operand::Number(ra_stack_offset.into()), ), Some(span), )?; - self.write_output( - format!("get ra db r{0}", VariableScope::TEMP_STACK_REGISTER), + + self.write_instruction( + Instruction::Get( + Operand::ReturnAddress, + Operand::Device(Cow::from("db")), + Operand::Register(VariableScope::TEMP_STACK_REGISTER), + ), Some(span), )?; if block_scope.stack_offset() > 0 { - self.write_output( - format!("sub sp sp {}", block_scope.stack_offset()), + self.write_instruction( + Instruction::Sub( + Operand::StackPointer, + Operand::StackPointer, + Operand::Number(block_scope.stack_offset().into()), + ), Some(span), )?; } - self.write_output("j ra", Some(span))?; + self.write_instruction(Instruction::Jump(Operand::ReturnAddress), Some(span))?; Ok(()) } } diff --git a/rust_compiler/libs/compiler/src/variable_manager.rs b/rust_compiler/libs/compiler/src/variable_manager.rs index 96b2271..95e482c 100644 --- a/rust_compiler/libs/compiler/src/variable_manager.rs +++ b/rust_compiler/libs/compiler/src/variable_manager.rs @@ -3,8 +3,9 @@ // r1 - r7 : Temporary Variables // r8 - r14 : Persistant Variables +use helpers::Span; use lsp_types::{Diagnostic, DiagnosticSeverity}; -use parser::tree_node::{Literal, Span}; +use parser::tree_node::Literal; use std::{ borrow::Cow, collections::{HashMap, VecDeque}, diff --git a/rust_compiler/libs/helpers/Cargo.toml b/rust_compiler/libs/helpers/Cargo.toml index 97e7548..6b5bb3e 100644 --- a/rust_compiler/libs/helpers/Cargo.toml +++ b/rust_compiler/libs/helpers/Cargo.toml @@ -5,3 +5,4 @@ edition = "2024" [dependencies] crc32fast = { workspace = true } +lsp-types = { workspace = true } diff --git a/rust_compiler/libs/helpers/src/lib.rs b/rust_compiler/libs/helpers/src/lib.rs index 680897e..aea7024 100644 --- a/rust_compiler/libs/helpers/src/lib.rs +++ b/rust_compiler/libs/helpers/src/lib.rs @@ -2,6 +2,44 @@ mod helper_funcs; mod macros; mod syscall; +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct Span { + pub start_line: usize, + pub end_line: usize, + pub start_col: usize, + pub end_col: usize, +} + +impl From for lsp_types::Range { + fn from(value: Span) -> Self { + Self { + start: lsp_types::Position { + line: value.start_line as u32, + character: value.start_col as u32, + }, + end: lsp_types::Position { + line: value.end_line as u32, + character: value.end_col as u32, + }, + } + } +} + +impl From<&Span> for lsp_types::Range { + fn from(value: &Span) -> Self { + Self { + start: lsp_types::Position { + line: value.start_line as u32, + character: value.start_col as u32, + }, + end: lsp_types::Position { + line: value.end_line as u32, + character: value.end_col as u32, + }, + } + } +} + /// This trait will allow the LSP to emit documentation for various tokens and expressions. /// You can easily create documentation for large enums with the `documented!` macro. pub trait Documentation { diff --git a/rust_compiler/libs/il/Cargo.toml b/rust_compiler/libs/il/Cargo.toml new file mode 100644 index 0000000..8eb8461 --- /dev/null +++ b/rust_compiler/libs/il/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "il" +version = "0.1.0" +edition = "2024" + +[dependencies] +helpers = { path = "../helpers" } +rust_decimal = { workspace = true } diff --git a/rust_compiler/libs/il/src/lib.rs b/rust_compiler/libs/il/src/lib.rs new file mode 100644 index 0000000..e8a33f9 --- /dev/null +++ b/rust_compiler/libs/il/src/lib.rs @@ -0,0 +1,286 @@ +use helpers::Span; +use rust_decimal::Decimal; +use std::borrow::Cow; +use std::fmt; + +pub struct InstructionNode<'a> { + pub instruction: Instruction<'a>, + pub span: Option, +} + +impl<'a> InstructionNode<'a> { + pub fn new(instr: Instruction<'a>, span: Option) -> Self { + Self { + span, + instruction: instr, + } + } +} + +/// Represents the different types of operands available in IC10. +#[derive(Debug, Clone, PartialEq)] +pub enum Operand<'a> { + /// A hardware register (r0-r15) + Register(u8), + /// A device alias or direct connection (d0-d5, db) + Device(Cow<'a, str>), + /// A numeric literal (integer or float) + Number(Decimal), + /// A label used for jumping + Label(Cow<'a, str>), + /// A logic type string (e.g., "Temperature", "Open") + LogicType(Cow<'a, str>), + /// Special register: Stack Pointer + StackPointer, + /// Special register: Return Address + ReturnAddress, +} + +impl<'a> fmt::Display for Operand<'a> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Operand::Register(r) => write!(f, "r{}", r), + Operand::Device(d) => write!(f, "{}", d), + Operand::Number(n) => write!(f, "{}", n), + Operand::Label(l) => write!(f, "{}", l), + Operand::LogicType(t) => write!(f, "{}", t), + Operand::StackPointer => write!(f, "sp"), + Operand::ReturnAddress => write!(f, "ra"), + } + } +} + +/// Represents a single IC10 MIPS instruction. +#[derive(Debug, Clone, PartialEq)] +pub enum Instruction<'a> { + /// `move dst val` - Copy value to register + Move(Operand<'a>, Operand<'a>), + + /// `add dst a b` - Addition + Add(Operand<'a>, Operand<'a>, Operand<'a>), + /// `sub dst a b` - Subtraction + Sub(Operand<'a>, Operand<'a>, Operand<'a>), + /// `mul dst a b` - Multiplication + Mul(Operand<'a>, Operand<'a>, Operand<'a>), + /// `div dst a b` - Division + Div(Operand<'a>, Operand<'a>, Operand<'a>), + /// `mod dst a b` - Modulo + Mod(Operand<'a>, Operand<'a>, Operand<'a>), + /// `pow dst a b` - Power + Pow(Operand<'a>, Operand<'a>, Operand<'a>), + /// `acos dst a` + Acos(Operand<'a>, Operand<'a>), + /// `asin dst a` + Asin(Operand<'a>, Operand<'a>), + /// `atan dst a` + Atan(Operand<'a>, Operand<'a>), + /// `atan2 dst a b` + Atan2(Operand<'a>, Operand<'a>, Operand<'a>), + /// `abs dst a` + Abs(Operand<'a>, Operand<'a>), + /// `ceil dst a` + Ceil(Operand<'a>, Operand<'a>), + /// `cos dst a` + Cos(Operand<'a>, Operand<'a>), + /// `floor dst a` + Floor(Operand<'a>, Operand<'a>), + /// `log dst a` + Log(Operand<'a>, Operand<'a>), + /// `max dst a b` + Max(Operand<'a>, Operand<'a>, Operand<'a>), + /// `min dst a b` + Min(Operand<'a>, Operand<'a>, Operand<'a>), + /// `rand dst` + Rand(Operand<'a>), + /// `sin dst a` + Sin(Operand<'a>, Operand<'a>), + /// `sqrt dst a` + Sqrt(Operand<'a>, Operand<'a>), + /// `tan dst a` + Tan(Operand<'a>, Operand<'a>), + /// `trunc dst a` + Trunc(Operand<'a>, Operand<'a>), + + /// `l register device type` - Load from device + Load(Operand<'a>, Operand<'a>, Operand<'a>), + /// `s device type value` - Set on device + Store(Operand<'a>, Operand<'a>, Operand<'a>), + + /// `ls register device slot type` - Load Slot + LoadSlot(Operand<'a>, Operand<'a>, Operand<'a>, Operand<'a>), + /// `ss device slot type value` - Set Slot + StoreSlot(Operand<'a>, Operand<'a>, Operand<'a>, Operand<'a>), + + /// `lb register deviceHash type batchMode` - Load Batch + LoadBatch(Operand<'a>, Operand<'a>, Operand<'a>, Operand<'a>), + /// `sb deviceHash type value` - Set Batch + StoreBatch(Operand<'a>, Operand<'a>, Operand<'a>), + + /// `lbn register deviceHash nameHash type batchMode` - Load Batch Named + LoadBatchNamed( + Operand<'a>, + Operand<'a>, + Operand<'a>, + Operand<'a>, + Operand<'a>, + ), + /// `sbn deviceHash nameHash type value` - Set Batch Named + StoreBatchNamed(Operand<'a>, Operand<'a>, Operand<'a>, Operand<'a>), + + /// `j label` - Unconditional Jump + Jump(Operand<'a>), + /// `jal label` - Jump and Link (Function Call) + JumpAndLink(Operand<'a>), + /// `jr offset` - Jump Relative + JumpRelative(Operand<'a>), + + /// `beq a b label` - Branch if Equal + BranchEq(Operand<'a>, Operand<'a>, Operand<'a>), + /// `bne a b label` - Branch if Not Equal + BranchNe(Operand<'a>, Operand<'a>, Operand<'a>), + /// `bgt a b label` - Branch if Greater Than + BranchGt(Operand<'a>, Operand<'a>, Operand<'a>), + /// `blt a b label` - Branch if Less Than + BranchLt(Operand<'a>, Operand<'a>, Operand<'a>), + /// `bge a b label` - Branch if Greater or Equal + BranchGe(Operand<'a>, Operand<'a>, Operand<'a>), + /// `ble a b label` - Branch if Less or Equal + BranchLe(Operand<'a>, Operand<'a>, Operand<'a>), + /// `beqz a label` - Branch if Equal Zero + BranchEqZero(Operand<'a>, Operand<'a>), + /// `bnez a label` - Branch if Not Equal Zero + BranchNeZero(Operand<'a>, Operand<'a>), + + /// `seq dst a b` - Set if Equal + SetEq(Operand<'a>, Operand<'a>, Operand<'a>), + /// `sne dst a b` - Set if Not Equal + SetNe(Operand<'a>, Operand<'a>, Operand<'a>), + /// `sgt dst a b` - Set if Greater Than + SetGt(Operand<'a>, Operand<'a>, Operand<'a>), + /// `slt dst a b` - Set if Less Than + SetLt(Operand<'a>, Operand<'a>, Operand<'a>), + /// `sge dst a b` - Set if Greater or Equal + SetGe(Operand<'a>, Operand<'a>, Operand<'a>), + /// `sle dst a b` - Set if Less or Equal + SetLe(Operand<'a>, Operand<'a>, Operand<'a>), + + /// `and dst a b` - Logical AND + And(Operand<'a>, Operand<'a>, Operand<'a>), + /// `or dst a b` - Logical OR + Or(Operand<'a>, Operand<'a>, Operand<'a>), + /// `xor dst a b` - Logical XOR + Xor(Operand<'a>, Operand<'a>, Operand<'a>), + + /// `push val` - Push to Stack + Push(Operand<'a>), + /// `pop dst` - Pop from Stack + Pop(Operand<'a>), + /// `peek dst` - Peek from Stack (Usually sp - 1) + Peek(Operand<'a>), + /// `get dst dev num` + Get(Operand<'a>, Operand<'a>, Operand<'a>), + /// put dev addr val + Put(Operand<'a>, Operand<'a>, Operand<'a>), + + /// `select dst cond a b` - Ternary Select + Select(Operand<'a>, Operand<'a>, Operand<'a>, Operand<'a>), + + /// `yield` - Pause execution + Yield, + /// `sleep val` - Sleep for seconds + Sleep(Operand<'a>), + + /// `alias name target` - Define Alias (Usually handled by compiler, but good for IR) + Alias(Cow<'a, str>, Operand<'a>), + /// `define name val` - Define Constant (Usually handled by compiler) + Define(Cow<'a, str>, f64), + + /// A label definition `Label:` + LabelDef(Cow<'a, str>), + + /// A comment `# text` + Comment(Cow<'a, str>), +} + +impl<'a> fmt::Display for Instruction<'a> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Instruction::Move(dst, val) => write!(f, "move {} {}", dst, val), + Instruction::Add(dst, a, b) => write!(f, "add {} {} {}", dst, a, b), + Instruction::Sub(dst, a, b) => write!(f, "sub {} {} {}", dst, a, b), + Instruction::Mul(dst, a, b) => write!(f, "mul {} {} {}", dst, a, b), + Instruction::Div(dst, a, b) => write!(f, "div {} {} {}", dst, a, b), + Instruction::Mod(dst, a, b) => write!(f, "mod {} {} {}", dst, a, b), + Instruction::Pow(dst, a, b) => write!(f, "pow {} {} {}", dst, a, b), + Instruction::Acos(dst, a) => write!(f, "acos {} {}", dst, a), + Instruction::Asin(dst, a) => write!(f, "asin {} {}", dst, a), + Instruction::Atan(dst, a) => write!(f, "atan {} {}", dst, a), + Instruction::Atan2(dst, a, b) => write!(f, "atan2 {} {} {}", dst, a, b), + Instruction::Abs(dst, a) => write!(f, "abs {} {}", dst, a), + Instruction::Ceil(dst, a) => write!(f, "ceil {} {}", dst, a), + Instruction::Cos(dst, a) => write!(f, "cos {} {}", dst, a), + Instruction::Floor(dst, a) => write!(f, "floor {} {}", dst, a), + Instruction::Log(dst, a) => write!(f, "log {} {}", dst, a), + Instruction::Max(dst, a, b) => write!(f, "max {} {} {}", dst, a, b), + Instruction::Min(dst, a, b) => write!(f, "min {} {} {}", dst, a, b), + Instruction::Rand(dst) => write!(f, "rand {}", dst), + Instruction::Sin(dst, a) => write!(f, "sin {} {}", dst, a), + Instruction::Sqrt(dst, a) => write!(f, "sqrt {} {}", dst, a), + Instruction::Tan(dst, a) => write!(f, "tan {} {}", dst, a), + Instruction::Trunc(dst, a) => write!(f, "trunc {} {}", dst, a), + + Instruction::Load(reg, dev, typ) => write!(f, "l {} {} {}", reg, dev, typ), + Instruction::Store(dev, typ, val) => write!(f, "s {} {} {}", dev, typ, val), + Instruction::LoadSlot(reg, dev, slot, typ) => { + write!(f, "ls {} {} {} {}", reg, dev, slot, typ) + } + Instruction::StoreSlot(dev, slot, typ, val) => { + write!(f, "ss {} {} {} {}", dev, slot, typ, val) + } + Instruction::LoadBatch(reg, hash, typ, mode) => { + write!(f, "lb {} {} {} {}", reg, hash, typ, mode) + } + Instruction::StoreBatch(hash, typ, val) => write!(f, "sb {} {} {}", hash, typ, val), + Instruction::LoadBatchNamed(reg, d_hash, n_hash, typ, mode) => { + write!(f, "lbn {} {} {} {} {}", reg, d_hash, n_hash, typ, mode) + } + Instruction::StoreBatchNamed(d_hash, n_hash, typ, val) => { + write!(f, "sbn {} {} {} {}", d_hash, n_hash, typ, val) + } + Instruction::Jump(lbl) => write!(f, "j {}", lbl), + Instruction::JumpAndLink(lbl) => write!(f, "jal {}", lbl), + Instruction::JumpRelative(off) => write!(f, "jr {}", off), + Instruction::BranchEq(a, b, lbl) => write!(f, "beq {} {} {}", a, b, lbl), + Instruction::BranchNe(a, b, lbl) => write!(f, "bne {} {} {}", a, b, lbl), + Instruction::BranchGt(a, b, lbl) => write!(f, "bgt {} {} {}", a, b, lbl), + Instruction::BranchLt(a, b, lbl) => write!(f, "blt {} {} {}", a, b, lbl), + Instruction::BranchGe(a, b, lbl) => write!(f, "bge {} {} {}", a, b, lbl), + Instruction::BranchLe(a, b, lbl) => write!(f, "ble {} {} {}", a, b, lbl), + Instruction::BranchEqZero(a, lbl) => write!(f, "beqz {} {}", a, lbl), + Instruction::BranchNeZero(a, lbl) => write!(f, "bnez {} {}", a, lbl), + Instruction::SetEq(dst, a, b) => write!(f, "seq {} {} {}", dst, a, b), + Instruction::SetNe(dst, a, b) => write!(f, "sne {} {} {}", dst, a, b), + Instruction::SetGt(dst, a, b) => write!(f, "sgt {} {} {}", dst, a, b), + Instruction::SetLt(dst, a, b) => write!(f, "slt {} {} {}", dst, a, b), + Instruction::SetGe(dst, a, b) => write!(f, "sge {} {} {}", dst, a, b), + Instruction::SetLe(dst, a, b) => write!(f, "sle {} {} {}", dst, a, b), + Instruction::And(dst, a, b) => write!(f, "and {} {} {}", dst, a, b), + Instruction::Or(dst, a, b) => write!(f, "or {} {} {}", dst, a, b), + Instruction::Xor(dst, a, b) => write!(f, "xor {} {} {}", dst, a, b), + Instruction::Push(val) => write!(f, "push {}", val), + Instruction::Pop(dst) => write!(f, "pop {}", dst), + Instruction::Peek(dst) => write!(f, "peek {}", dst), + Instruction::Get(dst, dev, val) => write!(f, "get {} {} {}", dst, dev, val), + Instruction::Put(dev, addr, val) => write!(f, "put {} {} {}", dev, addr, val), + Instruction::Select(dst, cond, a, b) => { + write!(f, "select {} {} {} {}", dst, cond, a, b) + } + Instruction::Yield => write!(f, "yield"), + Instruction::Sleep(val) => write!(f, "sleep {}", val), + Instruction::Alias(name, target) => write!(f, "alias {} {}", name, target), + Instruction::Define(name, val) => write!(f, "define {} {}", name, val), + Instruction::LabelDef(lbl) => write!(f, "{}:", lbl), + Instruction::Comment(c) => write!(f, "# {}", c), + } + } +} diff --git a/rust_compiler/libs/optimizer/Cargo.toml b/rust_compiler/libs/optimizer/Cargo.toml new file mode 100644 index 0000000..29f308d --- /dev/null +++ b/rust_compiler/libs/optimizer/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "optimizer" +version = "0.1.0" +edition = "2024" + +[dependencies] diff --git a/rust_compiler/libs/optimizer/src/lib.rs b/rust_compiler/libs/optimizer/src/lib.rs new file mode 100644 index 0000000..b93cf3f --- /dev/null +++ b/rust_compiler/libs/optimizer/src/lib.rs @@ -0,0 +1,14 @@ +pub fn add(left: u64, right: u64) -> u64 { + left + right +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn it_works() { + let result = add(2, 2); + assert_eq!(result, 4); + } +} diff --git a/rust_compiler/libs/parser/src/lib.rs b/rust_compiler/libs/parser/src/lib.rs index 35afdb2..66d0d99 100644 --- a/rust_compiler/libs/parser/src/lib.rs +++ b/rust_compiler/libs/parser/src/lib.rs @@ -4,6 +4,7 @@ mod test; pub mod tree_node; use crate::sys_call::{Math, System}; +use helpers::Span; use std::{borrow::Cow, io::SeekFrom}; use sys_call::SysCall; use thiserror::Error; diff --git a/rust_compiler/libs/parser/src/tree_node.rs b/rust_compiler/libs/parser/src/tree_node.rs index 42d624c..2f21aef 100644 --- a/rust_compiler/libs/parser/src/tree_node.rs +++ b/rust_compiler/libs/parser/src/tree_node.rs @@ -1,5 +1,6 @@ use super::sys_call::SysCall; use crate::sys_call; +use helpers::Span; use safer_ffi::prelude::*; use std::{borrow::Cow, ops::Deref}; use tokenizer::token::Number; @@ -301,44 +302,6 @@ impl<'a> std::fmt::Display for WhileExpression<'a> { } } -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct Span { - pub start_line: usize, - pub end_line: usize, - pub start_col: usize, - pub end_col: usize, -} - -impl From for lsp_types::Range { - fn from(value: Span) -> Self { - Self { - start: lsp_types::Position { - line: value.start_line as u32, - character: value.start_col as u32, - }, - end: lsp_types::Position { - line: value.end_line as u32, - character: value.end_col as u32, - }, - } - } -} - -impl From<&Span> for lsp_types::Range { - fn from(value: &Span) -> Self { - Self { - start: lsp_types::Position { - line: value.start_line as u32, - character: value.start_col as u32, - }, - end: lsp_types::Position { - line: value.end_line as u32, - character: value.end_col as u32, - }, - } - } -} - #[derive(Debug, Clone, PartialEq, Eq)] pub struct Spanned { pub span: Span, diff --git a/rust_compiler/libs/tokenizer/src/token.rs b/rust_compiler/libs/tokenizer/src/token.rs index 2b14066..ca70146 100644 --- a/rust_compiler/libs/tokenizer/src/token.rs +++ b/rust_compiler/libs/tokenizer/src/token.rs @@ -403,6 +403,12 @@ pub enum Number { Decimal(Decimal), } +impl From for Number { + fn from(value: bool) -> Self { + Self::Integer(if value { 1 } else { 0 }) + } +} + impl From for Decimal { fn from(value: Number) -> Self { match value { diff --git a/rust_compiler/src/ffi/mod.rs b/rust_compiler/src/ffi/mod.rs index a213572..e85f0ec 100644 --- a/rust_compiler/src/ffi/mod.rs +++ b/rust_compiler/src/ffi/mod.rs @@ -1,6 +1,6 @@ use compiler::{CompilationResult, Compiler}; -use helpers::Documentation; -use parser::{sys_call::SysCall, tree_node::Span, Parser}; +use helpers::{Documentation, Span}; +use parser::{sys_call::SysCall, Parser}; use safer_ffi::prelude::*; use std::io::BufWriter; use tokenizer::{