Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d8fe9a0d7d | |||
|
089fe46d36
|
|||
|
14c641797a
|
|||
| fb5eacea02 | |||
|
9fd3a55182
|
@@ -1,5 +1,13 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
[0.5.1]
|
||||||
|
|
||||||
|
- Fixed optimizer bug where `StoreBatch` and `StoreBatchNamed` instructions
|
||||||
|
were not recognized as reading operands, causing incorrect elimination of
|
||||||
|
necessary device property loads
|
||||||
|
- Added comprehensive register read tracking for `StoreSlot`, `JumpRelative`,
|
||||||
|
and `Alias` instructions in the optimizer
|
||||||
|
|
||||||
[0.5.0]
|
[0.5.0]
|
||||||
|
|
||||||
- Added full tuple support: declarations, assignments, and returns
|
- Added full tuple support: declarations, assignments, and returns
|
||||||
|
|||||||
@@ -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.5.0</Version>
|
<Version>0.5.1</Version>
|
||||||
<Description>
|
<Description>
|
||||||
[h1]Slang: High-Level Programming for Stationeers[/h1]
|
[h1]Slang: High-Level Programming for Stationeers[/h1]
|
||||||
|
|
||||||
|
|||||||
@@ -39,7 +39,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.5.0";
|
public const string PluginVersion = "0.5.1";
|
||||||
|
|
||||||
private static Harmony? _harmony;
|
private static Harmony? _harmony;
|
||||||
|
|
||||||
|
|||||||
@@ -1,59 +1,73 @@
|
|||||||
|
using System;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
namespace Slang;
|
namespace Slang;
|
||||||
|
|
||||||
public static class TextMeshProFormatter
|
public static class TextMeshProFormatter
|
||||||
{
|
{
|
||||||
private const string CODE_COLOR = "#FFD700";
|
private const string CODE_COLOR = "#FFD700"; // Gold
|
||||||
|
private const string LINK_COLOR = "#0099FF"; // Blue
|
||||||
|
private const string QUOTE_COLOR = "#90EE90"; // Light Green
|
||||||
|
|
||||||
public static string FromMarkdown(string markdown)
|
public static string FromMarkdown(string markdown)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(markdown))
|
if (string.IsNullOrEmpty(markdown))
|
||||||
return "";
|
return "";
|
||||||
|
|
||||||
// 1. Normalize Line Endings
|
// Normalize Line Endings
|
||||||
string text = markdown.Replace("\r\n", "\n");
|
string text = markdown.Replace("\r\n", "\n");
|
||||||
|
|
||||||
// 2. Handle Code Blocks (```)
|
// Process code blocks FIRST (``` ... ```)
|
||||||
text = Regex.Replace(
|
text = Regex.Replace(
|
||||||
text,
|
text,
|
||||||
@"```\s*(.*?)\s*```",
|
@"```[^\n]*\n(.*?)\n```",
|
||||||
match =>
|
match =>
|
||||||
{
|
{
|
||||||
var codeContent = match.Groups[1].Value;
|
var codeContent = match.Groups[1].Value;
|
||||||
return $"<color={CODE_COLOR}>{codeContent}</color>"; // Gold color for code
|
return $"<color={CODE_COLOR}>{codeContent}</color>";
|
||||||
},
|
},
|
||||||
RegexOptions.Singleline
|
RegexOptions.Singleline
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Process headers - check for 1-6 hashes
|
||||||
|
text = Regex.Replace(text, @"^#{1}\s+(.+)$", "<size=120%><b>$1</b></size>", RegexOptions.Multiline);
|
||||||
|
text = Regex.Replace(text, @"^#{2}\s+(.+)$", "<size=110%><b>$1</b></size>", RegexOptions.Multiline);
|
||||||
|
text = Regex.Replace(text, @"^#{3}\s+(.+)$", "<size=100%><b>$1</b></size>", RegexOptions.Multiline);
|
||||||
|
text = Regex.Replace(text, @"^#{4}\s+(.+)$", "<size=90%><b>$1</b></size>", RegexOptions.Multiline);
|
||||||
|
text = Regex.Replace(text, @"^#{5}\s+(.+)$", "<size=80%><b>$1</b></size>", RegexOptions.Multiline);
|
||||||
|
text = Regex.Replace(text, @"^#{6}\s+(.+)$", "<size=70%><b>$1</b></size>", RegexOptions.Multiline);
|
||||||
|
|
||||||
|
// Process markdown links [text](url)
|
||||||
text = Regex.Replace(
|
text = Regex.Replace(
|
||||||
text,
|
text,
|
||||||
@"^\s*##\s+(.+)$",
|
@"\[([^\]]+)\]\(([^\)]+)\)",
|
||||||
"<size=110%><color=#ffffff><b>$1</b></color></size>",
|
$"<color={LINK_COLOR}><u>$1</u></color>"
|
||||||
RegexOptions.Multiline
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// 3. Handle # Headers SECOND (General)
|
// Process inline code (`code`)
|
||||||
text = Regex.Replace(
|
|
||||||
text,
|
|
||||||
@"^\s*#\s+(.+)$",
|
|
||||||
"<size=120%><color=#ffffff><b>$1</b></color></size>",
|
|
||||||
RegexOptions.Multiline
|
|
||||||
);
|
|
||||||
|
|
||||||
// 4. Handle Inline Code (`code`)
|
|
||||||
text = Regex.Replace(text, @"`([^`]+)`", $"<color={CODE_COLOR}>$1</color>");
|
text = Regex.Replace(text, @"`([^`]+)`", $"<color={CODE_COLOR}>$1</color>");
|
||||||
|
|
||||||
// 5. Handle Bold (**text**)
|
// Process bold (**text**)
|
||||||
text = Regex.Replace(text, @"\*\*(.+?)\*\*", "<b>$1</b>");
|
text = Regex.Replace(text, @"\*\*(.+?)\*\*", "<b>$1</b>");
|
||||||
|
|
||||||
// 6. Handle Italics (*text*)
|
// Process italics (*text*)
|
||||||
text = Regex.Replace(text, @"\*(.+?)\*", "<i>$1</i>");
|
text = Regex.Replace(text, @"(?<!\*)\*(?!\*)(.+?)(?<!\*)\*(?!\*)", "<i>$1</i>");
|
||||||
|
|
||||||
// 7. Convert Newlines to TMP Line Breaks
|
// Process block quotes (> text)
|
||||||
// Stationpedia needs <br> or explicit newlines.
|
text = Regex.Replace(
|
||||||
// Often just ensuring \n is preserved is enough, but <br> is safer for HTML-like parsers.
|
text,
|
||||||
text = text.Replace("\n", "<br>");
|
@"^>\s+(.+)$",
|
||||||
|
$"<color={QUOTE_COLOR}><i>$1</i></color>",
|
||||||
|
RegexOptions.Multiline
|
||||||
|
);
|
||||||
|
|
||||||
|
// Process unordered lists (- items)
|
||||||
|
text = Regex.Replace(
|
||||||
|
text,
|
||||||
|
@"^-\s+(.+)$",
|
||||||
|
" • $1",
|
||||||
|
RegexOptions.Multiline
|
||||||
|
);
|
||||||
|
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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.5.0</Version>
|
<Version>0.5.1</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
@@ -1039,7 +1039,7 @@ checksum = "bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "slang"
|
name = "slang"
|
||||||
version = "0.5.0"
|
version = "0.5.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"clap",
|
"clap",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "slang"
|
name = "slang"
|
||||||
version = "0.5.0"
|
version = "0.5.1"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[workspace]
|
[workspace]
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
use crc32fast::hash as crc32_hash;
|
use crc32fast::hash as crc32_hash;
|
||||||
|
|
||||||
/// This function takes an input which is meant to be hashed via the CRC32 algorithm, but it then
|
/// This function takes an input which is meant to be hashed via the CRC32 algorithm, but it then
|
||||||
/// converts the generated UNSIGNED number into it's SIGNED counterpart.
|
/// converts the generated UNSIGNED number into it's SIGNED counterpart.
|
||||||
pub fn crc_hash_signed(input: &str) -> i128 {
|
pub fn crc_hash_signed(input: &str) -> i128 {
|
||||||
@@ -9,3 +10,38 @@ pub fn crc_hash_signed(input: &str) -> i128 {
|
|||||||
|
|
||||||
hash_value_i32 as i128
|
hash_value_i32 as i128
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Removes common leading whitespace from all lines in a string (dedent).
|
||||||
|
/// This is useful for cleaning up documentation strings that have uniform indentation.
|
||||||
|
pub fn dedent(text: &str) -> String {
|
||||||
|
let lines: Vec<&str> = text.lines().collect();
|
||||||
|
|
||||||
|
// Find minimum indentation (excluding empty lines)
|
||||||
|
let mut min_indent = usize::MAX;
|
||||||
|
for line in &lines {
|
||||||
|
if !line.trim().is_empty() {
|
||||||
|
let indent = line.len() - line.trim_start().len();
|
||||||
|
min_indent = min_indent.min(indent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no lines or all empty, return as-is
|
||||||
|
if min_indent == usize::MAX {
|
||||||
|
return text.to_string();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove the common indentation
|
||||||
|
lines
|
||||||
|
.iter()
|
||||||
|
.map(|line| {
|
||||||
|
if line.trim().is_empty() {
|
||||||
|
""
|
||||||
|
} else if line.len() >= min_indent {
|
||||||
|
&line[min_indent..]
|
||||||
|
} else {
|
||||||
|
line
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join("\n")
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
mod helper_funcs;
|
mod helper_funcs;
|
||||||
|
pub use helper_funcs::dedent;
|
||||||
mod macros;
|
mod macros;
|
||||||
mod syscall;
|
mod syscall;
|
||||||
|
|
||||||
|
|||||||
@@ -99,12 +99,12 @@ macro_rules! documented {
|
|||||||
),*
|
),*
|
||||||
];
|
];
|
||||||
|
|
||||||
doc_lines.iter()
|
let combined = doc_lines.iter()
|
||||||
.filter_map(|&d| d)
|
.filter_map(|&d| d)
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.join("\n")
|
.join("\n");
|
||||||
.trim()
|
|
||||||
.to_string()
|
$crate::dedent(&combined).trim().to_string()
|
||||||
}
|
}
|
||||||
)*
|
)*
|
||||||
}
|
}
|
||||||
@@ -122,12 +122,13 @@ macro_rules! documented {
|
|||||||
documented!(@doc_filter #[ $($variant_attr)* ])
|
documented!(@doc_filter #[ $($variant_attr)* ])
|
||||||
),*
|
),*
|
||||||
];
|
];
|
||||||
doc_lines.iter()
|
|
||||||
|
let combined = doc_lines.iter()
|
||||||
.filter_map(|&d| d)
|
.filter_map(|&d| d)
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.join("\n")
|
.join("\n");
|
||||||
.trim()
|
|
||||||
.to_string()
|
$crate::dedent(&combined).trim().to_string()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
),*
|
),*
|
||||||
@@ -136,4 +137,3 @@ macro_rules! documented {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,12 @@ mod tests {
|
|||||||
let compiler = Compiler::new(parser, None);
|
let compiler = Compiler::new(parser, None);
|
||||||
let result = compiler.compile();
|
let result = compiler.compile();
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
result.errors.is_empty(),
|
||||||
|
"Compilation errors: {:?}",
|
||||||
|
result.errors
|
||||||
|
);
|
||||||
|
|
||||||
// Get unoptimized output
|
// Get unoptimized output
|
||||||
let mut unoptimized_writer = std::io::BufWriter::new(Vec::new());
|
let mut unoptimized_writer = std::io::BufWriter::new(Vec::new());
|
||||||
result
|
result
|
||||||
@@ -219,4 +225,20 @@ mod tests {
|
|||||||
let output = compile_with_and_without_optimization(source);
|
let output = compile_with_and_without_optimization(source);
|
||||||
insta::assert_snapshot!(output);
|
insta::assert_snapshot!(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_setbatched_with_member_access() {
|
||||||
|
let source = indoc! {r#"
|
||||||
|
const SENSOR = 20088;
|
||||||
|
const PANELS = hash("StructureSolarPanelDual");
|
||||||
|
|
||||||
|
loop {
|
||||||
|
setBatched(PANELS, "Horizontal", SENSOR.Horizontal);
|
||||||
|
setBatched(PANELS, "Vertical", SENSOR.Vertical + 90);
|
||||||
|
yield();
|
||||||
|
}
|
||||||
|
"#};
|
||||||
|
let output = compile_with_and_without_optimization(source);
|
||||||
|
insta::assert_snapshot!(output);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
---
|
||||||
|
source: libs/integration_tests/src/lib.rs
|
||||||
|
assertion_line: 242
|
||||||
|
expression: output
|
||||||
|
---
|
||||||
|
## Unoptimized Output
|
||||||
|
|
||||||
|
j main
|
||||||
|
main:
|
||||||
|
__internal_L1:
|
||||||
|
l r1 20088 Horizontal
|
||||||
|
sb -539224550 Horizontal r1
|
||||||
|
l r2 20088 Vertical
|
||||||
|
add r3 r2 90
|
||||||
|
sb -539224550 Vertical r3
|
||||||
|
yield
|
||||||
|
j __internal_L1
|
||||||
|
__internal_L2:
|
||||||
|
|
||||||
|
## Optimized Output
|
||||||
|
|
||||||
|
l r1 20088 Horizontal
|
||||||
|
sb -539224550 Horizontal r1
|
||||||
|
l r2 20088 Vertical
|
||||||
|
add r3 r2 90
|
||||||
|
sb -539224550 Vertical r3
|
||||||
|
yield
|
||||||
|
j 0
|
||||||
@@ -125,6 +125,9 @@ pub fn reg_is_read(instr: &Instruction, reg: u8) -> bool {
|
|||||||
| Instruction::Pow(_, a, b) => check(a) || check(b),
|
| Instruction::Pow(_, a, b) => check(a) || check(b),
|
||||||
Instruction::Load(_, a, _) => check(a),
|
Instruction::Load(_, a, _) => check(a),
|
||||||
Instruction::Store(a, _, b) => check(a) || check(b),
|
Instruction::Store(a, _, b) => check(a) || check(b),
|
||||||
|
Instruction::StoreBatch(a, _, b) => check(a) || check(b),
|
||||||
|
Instruction::StoreBatchNamed(a, b, _, c) => check(a) || check(b) || check(c),
|
||||||
|
Instruction::StoreSlot(a, b, _, c) => check(a) || check(b) || check(c),
|
||||||
Instruction::BranchEq(a, b, _)
|
Instruction::BranchEq(a, b, _)
|
||||||
| Instruction::BranchNe(a, b, _)
|
| Instruction::BranchNe(a, b, _)
|
||||||
| Instruction::BranchGt(a, b, _)
|
| Instruction::BranchGt(a, b, _)
|
||||||
@@ -167,6 +170,8 @@ pub fn reg_is_read(instr: &Instruction, reg: u8) -> bool {
|
|||||||
Instruction::Atan2(_, a, b) | Instruction::Max(_, a, b) | Instruction::Min(_, a, b) => {
|
Instruction::Atan2(_, a, b) | Instruction::Max(_, a, b) | Instruction::Min(_, a, b) => {
|
||||||
check(a) || check(b)
|
check(a) || check(b)
|
||||||
}
|
}
|
||||||
|
Instruction::JumpRelative(a) => check(a),
|
||||||
|
Instruction::Alias(_, a) => check(a),
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user