Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
b98817c8a0
|
|||
|
6d5c179eac
|
|||
|
b7fbc499b6
|
|||
| 30b564a153 | |||
|
415e69628d
|
@@ -1,5 +1,14 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
[0.3.2]
|
||||||
|
|
||||||
|
- Fixed stack overflow due to incorrect optimization of 'leaf' functions
|
||||||
|
|
||||||
|
[0.3.1]
|
||||||
|
|
||||||
|
- Fixed possible `KeyNotFoundException` in C# code due to invalid
|
||||||
|
dictionary access when an IC housing has an error
|
||||||
|
|
||||||
[0.3.0]
|
[0.3.0]
|
||||||
|
|
||||||
- Implemented a multi-pass optimizer
|
- Implemented a multi-pass optimizer
|
||||||
|
|||||||
@@ -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.0</Version>
|
<Version>0.3.2</Version>
|
||||||
<Description>
|
<Description>
|
||||||
[h1]Slang: High-Level Programming for Stationeers[/h1]
|
[h1]Slang: High-Level Programming for Stationeers[/h1]
|
||||||
|
|
||||||
|
|||||||
@@ -56,6 +56,11 @@ public static class GlobalCode
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!sourceMaps[reference].ContainsKey(icErrorLine))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
var foundRange = sourceMaps[reference][icErrorLine];
|
var foundRange = sourceMaps[reference][icErrorLine];
|
||||||
|
|
||||||
if (foundRange is null)
|
if (foundRange is null)
|
||||||
|
|||||||
@@ -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.0";
|
public const string PluginVersion = "0.3.2";
|
||||||
|
|
||||||
public static Mod MOD = new Mod(PluginName, PluginVersion);
|
public static Mod MOD = new Mod(PluginName, PluginVersion);
|
||||||
|
|
||||||
|
|||||||
@@ -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.0</Version>
|
<Version>0.3.2</Version>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
<LangVersion>latest</LangVersion>
|
<LangVersion>latest</LangVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|||||||
2
rust_compiler/Cargo.lock
generated
2
rust_compiler/Cargo.lock
generated
@@ -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",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "slang"
|
name = "slang"
|
||||||
version = "0.3.0"
|
version = "0.3.2"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[workspace]
|
[workspace]
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
"
|
"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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:
|
||||||
"
|
"
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -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(
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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()?;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user