3 Commits
0.3.1 ... 0.3.2

16 changed files with 89 additions and 72 deletions

View File

@@ -1,5 +1,9 @@
# Changelog # Changelog
[0.3.2]
- Fixed stack overflow due to incorrect optimization of 'leaf' functions
[0.3.1] [0.3.1]
- Fixed possible `KeyNotFoundException` in C# code due to invalid - Fixed possible `KeyNotFoundException` in C# code due to invalid

View File

@@ -2,7 +2,7 @@
<ModMetadata xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <ModMetadata xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Name>Slang</Name> <Name>Slang</Name>
<Author>JoeDiertay</Author> <Author>JoeDiertay</Author>
<Version>0.3.1</Version> <Version>0.3.2</Version>
<Description> <Description>
[h1]Slang: High-Level Programming for Stationeers[/h1] [h1]Slang: High-Level Programming for Stationeers[/h1]

View File

@@ -41,7 +41,7 @@ namespace Slang
{ {
public const string PluginGuid = "com.biddydev.slang"; public const string PluginGuid = "com.biddydev.slang";
public const string PluginName = "Slang"; public const string PluginName = "Slang";
public const string PluginVersion = "0.3.1"; public const string PluginVersion = "0.3.2";
public static Mod MOD = new Mod(PluginName, PluginVersion); public static Mod MOD = new Mod(PluginName, PluginVersion);

View File

@@ -5,7 +5,7 @@
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<AssemblyName>StationeersSlang</AssemblyName> <AssemblyName>StationeersSlang</AssemblyName>
<Description>Slang Compiler Bridge</Description> <Description>Slang Compiler Bridge</Description>
<Version>0.3.1</Version> <Version>0.3.2</Version>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<LangVersion>latest</LangVersion> <LangVersion>latest</LangVersion>
</PropertyGroup> </PropertyGroup>

View File

@@ -930,7 +930,7 @@ checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e"
[[package]] [[package]]
name = "slang" name = "slang"
version = "0.3.0" version = "0.3.2"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"clap", "clap",

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "slang" name = "slang"
version = "0.3.1" version = "0.3.2"
edition = "2021" edition = "2021"
[workspace] [workspace]

View File

@@ -52,8 +52,8 @@ fn nested_binary_expressions() -> Result<()> {
add r1 r10 r9 add r1 r10 r9
mul r2 r1 r8 mul r2 r1 r8
move r15 r2 move r15 r2
j L1 j __internal_L1
L1: __internal_L1:
sub r0 sp 1 sub r0 sp 1
get ra db r0 get ra db r0
sub sp sp 1 sub sp sp 1

View File

@@ -22,9 +22,9 @@ fn test_if_statement() -> anyhow::Result<()> {
main: main:
move r8 10 move r8 10
sgt r1 r8 5 sgt r1 r8 5
beqz r1 L1 beqz r1 __internal_L1
move r8 20 move r8 20
L1: __internal_L1:
" "
} }
); );
@@ -54,12 +54,12 @@ fn test_if_else_statement() -> anyhow::Result<()> {
main: main:
move r8 0 move r8 0
sgt r1 10 5 sgt r1 10 5
beqz r1 L2 beqz r1 __internal_L2
move r8 1 move r8 1
j L1 j __internal_L1
L2: __internal_L2:
move r8 2 move r8 2
L1: __internal_L1:
" "
} }
); );
@@ -91,18 +91,18 @@ fn test_if_else_if_statement() -> anyhow::Result<()> {
main: main:
move r8 0 move r8 0
seq r1 r8 1 seq r1 r8 1
beqz r1 L2 beqz r1 __internal_L2
move r8 10 move r8 10
j L1 j __internal_L1
L2: __internal_L2:
seq r2 r8 2 seq r2 r8 2
beqz r2 L4 beqz r2 __internal_L4
move r8 20 move r8 20
j L3 j __internal_L3
L4: __internal_L4:
move r8 30 move r8 30
L3: __internal_L3:
L1: __internal_L1:
" "
} }
); );
@@ -145,10 +145,10 @@ fn test_spilled_variable_update_in_branch() -> anyhow::Result<()> {
move r14 7 move r14 7
push 8 push 8
seq r1 r8 1 seq r1 r8 1
beqz r1 L1 beqz r1 __internal_L1
sub r0 sp 1 sub r0 sp 1
put db r0 99 put db r0 99
L1: __internal_L1:
sub sp sp 1 sub sp sp 1
" "
} }

View File

@@ -17,7 +17,7 @@ fn no_arguments() -> anyhow::Result<()> {
j main j main
doSomething: doSomething:
push ra push ra
L1: __internal_L1:
sub r0 sp 1 sub r0 sp 1
get ra db r0 get ra db r0
sub sp sp 1 sub sp sp 1
@@ -59,14 +59,14 @@ fn let_var_args() -> anyhow::Result<()> {
push ra push ra
mul r1 r8 2 mul r1 r8 2
move r15 r1 move r15 r1
j L1 j __internal_L1
L1: __internal_L1:
sub r0 sp 1 sub r0 sp 1
get ra db r0 get ra db r0
sub sp sp 1 sub sp sp 1
j ra j ra
main: main:
L2: __internal_L2:
move r8 123 move r8 123
push r8 push r8
push r8 push r8
@@ -77,8 +77,8 @@ fn let_var_args() -> anyhow::Result<()> {
move r9 r15 move r9 r15
pow r1 r9 2 pow r1 r9 2
move r9 r1 move r9 r1
j L2 j __internal_L2
L3: __internal_L3:
" "
} }
); );
@@ -127,8 +127,8 @@ fn inline_literal_args() -> anyhow::Result<()> {
pop r9 pop r9
push ra push ra
move r15 5 move r15 5
j L1 j __internal_L1
L1: __internal_L1:
sub r0 sp 1 sub r0 sp 1
get ra db r0 get ra db r0
sub sp sp 1 sub sp sp 1
@@ -170,7 +170,7 @@ fn mixed_args() -> anyhow::Result<()> {
pop r8 pop r8
pop r9 pop r9
push ra push ra
L1: __internal_L1:
sub r0 sp 1 sub r0 sp 1
get ra db r0 get ra db r0
sub sp sp 1 sub sp sp 1
@@ -214,8 +214,8 @@ fn with_return_statement() -> anyhow::Result<()> {
pop r8 pop r8
push ra push ra
move r15 456 move r15 456
j L1 j __internal_L1
L1: __internal_L1:
sub r0 sp 1 sub r0 sp 1
get ra db r0 get ra db r0
sub sp sp 1 sub sp sp 1
@@ -251,7 +251,7 @@ fn with_negative_return_literal() -> anyhow::Result<()> {
doSomething: doSomething:
push ra push ra
move r15 -1 move r15 -1
L1: __internal_L1:
sub r0 sp 1 sub r0 sp 1
get ra db r0 get ra db r0
sub sp sp 1 sub sp sp 1

View File

@@ -133,8 +133,8 @@ fn test_boolean_return() -> anyhow::Result<()> {
getTrue: getTrue:
push ra push ra
move r15 1 move r15 1
j L1 j __internal_L1
L1: __internal_L1:
sub r0 sp 1 sub r0 sp 1
get ra db r0 get ra db r0
sub sp sp 1 sub sp sp 1

View File

@@ -21,7 +21,7 @@ fn test_function_declaration_with_spillover_params() -> anyhow::Result<()> {
pop r13 pop r13
pop r14 pop r14
push ra push ra
L1: __internal_L1:
sub r0 sp 1 sub r0 sp 1
get ra db r0 get ra db r0
sub sp sp 3 sub sp sp 3
@@ -54,12 +54,12 @@ fn test_early_return() -> anyhow::Result<()> {
doSomething: doSomething:
push ra push ra
seq r1 1 1 seq r1 1 1
beqz r1 L2 beqz r1 __internal_L2
j L1 j __internal_L1
L2: __internal_L2:
move r8 3 move r8 3
j L1 j __internal_L1
L1: __internal_L1:
sub r0 sp 1 sub r0 sp 1
get ra db r0 get ra db r0
sub sp sp 1 sub sp sp 1
@@ -90,7 +90,7 @@ fn test_function_declaration_with_register_params() -> anyhow::Result<()> {
pop r8 pop r8
pop r9 pop r9
push ra push ra
L1: __internal_L1:
sub r0 sp 1 sub r0 sp 1
get ra db r0 get ra db r0
sub sp sp 1 sub sp sp 1

View File

@@ -14,7 +14,7 @@ fn test_infinite_loop() -> anyhow::Result<()> {
" "
}; };
// Labels: L1 (start), L2 (end) // __internal_Labels: L1 (start), L2 (end)
assert_eq!( assert_eq!(
compiled, compiled,
indoc! { indoc! {
@@ -22,11 +22,11 @@ fn test_infinite_loop() -> anyhow::Result<()> {
j main j main
main: main:
move r8 0 move r8 0
L1: __internal_L1:
add r1 r8 1 add r1 r8 1
move r8 r1 move r8 r1
j L1 j __internal_L1
L2: __internal_L2:
" "
} }
); );
@@ -49,7 +49,7 @@ fn test_loop_break() -> anyhow::Result<()> {
" "
}; };
// Labels: L1 (start), L2 (end), L3 (if end - implicit else label) // __internal_Labels: L1 (start), L2 (end), L3 (if end - implicit else label)
assert_eq!( assert_eq!(
compiled, compiled,
indoc! { indoc! {
@@ -57,15 +57,15 @@ fn test_loop_break() -> anyhow::Result<()> {
j main j main
main: main:
move r8 0 move r8 0
L1: __internal_L1:
add r1 r8 1 add r1 r8 1
move r8 r1 move r8 r1
sgt r2 r8 10 sgt r2 r8 10
beqz r2 L3 beqz r2 __internal_L3
j L2 j __internal_L2
L3: __internal_L3:
j L1 j __internal_L1
L2: __internal_L2:
" "
} }
); );
@@ -85,7 +85,7 @@ fn test_while_loop() -> anyhow::Result<()> {
" "
}; };
// Labels: L1 (start), L2 (end) // __internal_Labels: L1 (start), L2 (end)
assert_eq!( assert_eq!(
compiled, compiled,
indoc! { indoc! {
@@ -93,13 +93,13 @@ fn test_while_loop() -> anyhow::Result<()> {
j main j main
main: main:
move r8 0 move r8 0
L1: __internal_L1:
slt r1 r8 10 slt r1 r8 10
beqz r1 L2 beqz r1 __internal_L2
add r2 r8 1 add r2 r8 1
move r8 r2 move r8 r2
j L1 j __internal_L1
L2: __internal_L2:
" "
} }
); );
@@ -123,7 +123,7 @@ fn test_loop_continue() -> anyhow::Result<()> {
"# "#
}; };
// Labels: L1 (start), L2 (end), L3 (if end) // __internal_Labels: L1 (start), L2 (end), L3 (if end)
assert_eq!( assert_eq!(
compiled, compiled,
indoc! { indoc! {
@@ -131,16 +131,16 @@ fn test_loop_continue() -> anyhow::Result<()> {
j main j main
main: main:
move r8 0 move r8 0
L1: __internal_L1:
add r1 r8 1 add r1 r8 1
move r8 r1 move r8 r1
slt r2 r8 5 slt r2 r8 5
beqz r2 L3 beqz r2 __internal_L3
j L1 j __internal_L1
L3: __internal_L3:
j L2 j __internal_L2
j L1 j __internal_L1
L2: __internal_L2:
" "
} }
); );

View File

@@ -264,7 +264,7 @@ impl<'a> Compiler<'a> {
fn next_label_name(&mut self) -> Cow<'a, str> { fn next_label_name(&mut self) -> Cow<'a, str> {
self.label_counter += 1; self.label_counter += 1;
Cow::from(format!("L{}", self.label_counter)) Cow::from(format!("__internal_L{}", self.label_counter))
} }
fn expression( fn expression(

View File

@@ -14,6 +14,10 @@ pub fn find_leaf_functions(instructions: &[InstructionNode]) -> HashSet<String>
for node in instructions { for node in instructions {
match &node.instruction { match &node.instruction {
Instruction::LabelDef(label) => { Instruction::LabelDef(label) => {
if label.starts_with("__internal_L") {
continue;
}
// If we were tracking a function, and it remained a leaf until now, save it. // If we were tracking a function, and it remained a leaf until now, save it.
if let Some(name) = current_label.take() if let Some(name) = current_label.take()
&& is_current_leaf && is_current_leaf

View File

@@ -99,7 +99,7 @@ fn optimize_leaf_functions<'a>(
// First scan: Identify instructions to remove and capture RA offsets // First scan: Identify instructions to remove and capture RA offsets
for (i, node) in input.iter().enumerate() { for (i, node) in input.iter().enumerate() {
match &node.instruction { match &node.instruction {
Instruction::LabelDef(label) => { Instruction::LabelDef(label) if !label.starts_with("__internal_L") => {
current_function = Some(label.to_string()); current_function = Some(label.to_string());
function_start_indices.insert(label.to_string(), i); function_start_indices.insert(label.to_string(), i);
} }
@@ -174,7 +174,9 @@ fn optimize_leaf_functions<'a>(
continue; // SKIP (Remove) continue; // SKIP (Remove)
} }
if let Instruction::LabelDef(l) = &node.instruction { if let Instruction::LabelDef(l) = &node.instruction
&& !l.starts_with("__internal_L")
{
processing_function = Some(l.to_string()); processing_function = Some(l.to_string());
} }

View File

@@ -53,6 +53,9 @@ struct Args {
/// The output file for the compiled program. If not set, output will go to stdout. /// The output file for the compiled program. If not set, output will go to stdout.
#[arg(short, long)] #[arg(short, long)]
output_file: Option<PathBuf>, output_file: Option<PathBuf>,
/// Should Slang attempt to optimize the output?
#[arg(short = 'z', long)]
optimize: bool,
} }
fn run_logic<'a>() -> Result<(), Error<'a>> { fn run_logic<'a>() -> Result<(), Error<'a>> {
@@ -107,7 +110,11 @@ fn run_logic<'a>() -> Result<(), Error<'a>> {
} }
} }
optimizer::optimize(instructions).write(&mut writer)?; if args.optimize {
optimizer::optimize(instructions).write(&mut writer)?;
} else {
instructions.write(&mut writer)?;
}
writer.flush()?; writer.flush()?;