236
Cargo.lock
generated
236
Cargo.lock
generated
@@ -128,9 +128,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "borsh"
|
||||
version = "1.5.7"
|
||||
version = "1.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ad8646f98db542e39fc66e68a20b2144f6a732636df7c2354e74645faaa433ce"
|
||||
checksum = "d1da5ab77c1437701eeff7c88d968729e7766172279eab0676857b3d63af7a6f"
|
||||
dependencies = [
|
||||
"borsh-derive",
|
||||
"cfg_aliases",
|
||||
@@ -138,15 +138,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "borsh-derive"
|
||||
version = "1.5.7"
|
||||
version = "1.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fdd1d3c0c2f5833f22386f252fe8ed005c7f59fdcddeef025c01b4c3b9fd9ac3"
|
||||
checksum = "0686c856aa6aac0c4498f936d7d6a02df690f614c03e4d906d1018062b5c5e2c"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"proc-macro-crate",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.110",
|
||||
"syn 2.0.111",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -226,7 +226,7 @@ dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.110",
|
||||
"syn 2.0.111",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -265,41 +265,6 @@ version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
|
||||
|
||||
[[package]]
|
||||
name = "ext-trait"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d772df1c1a777963712fb68e014235e80863d6a91a85c4e06ba2d16243a310e5"
|
||||
dependencies = [
|
||||
"ext-trait-proc_macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ext-trait-proc_macros"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ab7934152eaf26aa5aa9f7371408ad5af4c31357073c9e84c3b9d7f11ad639a"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "extension-traits"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a296e5a895621edf9fa8329c83aa1cb69a964643e36cf54d8d7a69b789089537"
|
||||
dependencies = [
|
||||
"ext-trait",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "extern-c"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "320bea982e85d42441eb25c49b41218e7eaa2657e8f90bc4eca7437376751e23"
|
||||
|
||||
[[package]]
|
||||
name = "funty"
|
||||
version = "2.0.0"
|
||||
@@ -363,15 +328,6 @@ dependencies = [
|
||||
"rustversion",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "inventory"
|
||||
version = "0.3.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bc61209c082fbeb19919bee74b176221b27223e27b65d781eb91af24eb1fb46e"
|
||||
dependencies = [
|
||||
"rustversion",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "is_terminal_polyfill"
|
||||
version = "1.70.2"
|
||||
@@ -400,22 +356,6 @@ version = "0.2.177"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976"
|
||||
|
||||
[[package]]
|
||||
name = "macro_rules_attribute"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf0c9b980bf4f3a37fd7b1c066941dd1b1d0152ce6ee6e8fe8c49b9f6810d862"
|
||||
dependencies = [
|
||||
"macro_rules_attribute-proc_macro",
|
||||
"paste",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "macro_rules_attribute-proc_macro"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "58093314a45e00c77d5c508f76e77c3396afbbc0d01506e7fae47b018bac2b1d"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.6"
|
||||
@@ -470,12 +410,6 @@ dependencies = [
|
||||
"tokenizer",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "paste"
|
||||
version = "1.0.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.21"
|
||||
@@ -495,16 +429,6 @@ dependencies = [
|
||||
"yansi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prettyplease"
|
||||
version = "0.1.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c8646e95016a7a6c4adea95bafa8a16baab64b583356217f2c85db4a39d9a86"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-crate"
|
||||
version = "3.4.0"
|
||||
@@ -654,15 +578,6 @@ version = "0.1.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace"
|
||||
|
||||
[[package]]
|
||||
name = "rustc_version"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92"
|
||||
dependencies = [
|
||||
"semver",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
version = "1.0.22"
|
||||
@@ -675,56 +590,12 @@ version = "1.0.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
|
||||
|
||||
[[package]]
|
||||
name = "safer-ffi"
|
||||
version = "0.1.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "435fdd58b61a6f1d8545274c1dfa458e905ff68c166e65e294a0130ef5e675bd"
|
||||
dependencies = [
|
||||
"extern-c",
|
||||
"inventory",
|
||||
"libc",
|
||||
"macro_rules_attribute",
|
||||
"paste",
|
||||
"safer_ffi-proc_macros",
|
||||
"scopeguard",
|
||||
"stabby",
|
||||
"uninit",
|
||||
"unwind_safe",
|
||||
"with_builtin_macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "safer_ffi-proc_macros"
|
||||
version = "0.1.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0f25be5ba5f319542edb31925517e0380245ae37df50a9752cdbc05ef948156"
|
||||
dependencies = [
|
||||
"macro_rules_attribute",
|
||||
"prettyplease",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||
|
||||
[[package]]
|
||||
name = "seahash"
|
||||
version = "4.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b"
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "1.0.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.228"
|
||||
@@ -751,7 +622,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.110",
|
||||
"syn 2.0.111",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -767,53 +638,12 @@ dependencies = [
|
||||
"serde_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha2-const-stable"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5f179d4e11094a893b82fff208f74d448a7512f99f5a0acbd5c679b705f83ed9"
|
||||
|
||||
[[package]]
|
||||
name = "simdutf8"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e"
|
||||
|
||||
[[package]]
|
||||
name = "stabby"
|
||||
version = "36.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "89b7e94eaf470c2e76b5f15fb2fb49714471a36cc512df5ee231e62e82ec79f8"
|
||||
dependencies = [
|
||||
"rustversion",
|
||||
"stabby-abi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stabby-abi"
|
||||
version = "36.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0dc7a63b8276b54e51bfffe3d85da56e7906b2dcfcb29018a8ab666c06734c1a"
|
||||
dependencies = [
|
||||
"rustc_version",
|
||||
"rustversion",
|
||||
"sha2-const-stable",
|
||||
"stabby-macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stabby-macros"
|
||||
version = "36.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eecb7ec5611ec93ec79d120fbe55f31bea234dc1bed1001d4a071bb688651615"
|
||||
dependencies = [
|
||||
"proc-macro-crate",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rand",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stationlang"
|
||||
version = "0.1.0"
|
||||
@@ -824,7 +654,6 @@ dependencies = [
|
||||
"parser",
|
||||
"quick-error",
|
||||
"rust_decimal",
|
||||
"safer-ffi",
|
||||
"tokenizer",
|
||||
]
|
||||
|
||||
@@ -847,9 +676,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.110"
|
||||
version = "2.0.111"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a99801b5bd34ede4cf3fc688c5919368fea4e4814a4664359503e6015b280aea"
|
||||
checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -922,21 +751,6 @@ version = "1.0.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
|
||||
|
||||
[[package]]
|
||||
name = "uninit"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3e130f2ed46ca5d8ec13c7ff95836827f92f5f5f37fd2b2bf16f33c408d98bb6"
|
||||
dependencies = [
|
||||
"extension-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unwind_safe"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0976c77def3f1f75c4ef892a292c31c0bbe9e3d0702c63044d7c76db298171a3"
|
||||
|
||||
[[package]]
|
||||
name = "utf8parse"
|
||||
version = "0.2.2"
|
||||
@@ -997,7 +811,7 @@ dependencies = [
|
||||
"bumpalo",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.110",
|
||||
"syn 2.0.111",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
@@ -1034,26 +848,6 @@ dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "with_builtin_macros"
|
||||
version = "0.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a59d55032495429b87f9d69954c6c8602e4d3f3e0a747a12dea6b0b23de685da"
|
||||
dependencies = [
|
||||
"with_builtin_macros-proc_macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "with_builtin_macros-proc_macros"
|
||||
version = "0.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "15bd7679c15e22924f53aee34d4e448c45b674feb6129689af88593e129f8f42"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wyz"
|
||||
version = "0.5.1"
|
||||
@@ -1071,20 +865,20 @@ checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049"
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.8.28"
|
||||
version = "0.8.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43fa6694ed34d6e57407afbccdeecfa268c470a7d2a5b0cf49ce9fcc345afb90"
|
||||
checksum = "4ea879c944afe8a2b25fef16bb4ba234f47c694565e97383b36f3a878219065c"
|
||||
dependencies = [
|
||||
"zerocopy-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy-derive"
|
||||
version = "0.8.28"
|
||||
version = "0.8.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c640b22cd9817fae95be82f0d2f90b11f7605f6c319d16705c459b27ac2cbc26"
|
||||
checksum = "cf955aa904d6040f70dc8e9384444cb1030aed272ba3cb09bbc4ab9e7c1f34f5"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.110",
|
||||
"syn 2.0.111",
|
||||
]
|
||||
|
||||
@@ -9,7 +9,6 @@ members = ["libs/*"]
|
||||
[workspace.dependencies]
|
||||
quick-error = "2"
|
||||
rust_decimal = "1"
|
||||
safer-ffi = { version = "^0.1" }
|
||||
|
||||
[profile.release]
|
||||
strip = true
|
||||
@@ -30,10 +29,7 @@ rust_decimal = { workspace = true }
|
||||
tokenizer = { path = "libs/tokenizer" }
|
||||
parser = { path = "libs/parser" }
|
||||
compiler = { path = "libs/compiler" }
|
||||
safer-ffi = { workspace = true }
|
||||
|
||||
[features]
|
||||
headers = ["safer-ffi/headers"]
|
||||
|
||||
[dev-dependencies]
|
||||
anyhow = { version = "^1.0", features = ["backtrace"] }
|
||||
|
||||
@@ -111,7 +111,7 @@ fn test_while_loop() -> anyhow::Result<()> {
|
||||
fn test_loop_continue() -> anyhow::Result<()> {
|
||||
let compiled = compile! {
|
||||
debug
|
||||
"
|
||||
r#"
|
||||
let a = 0;
|
||||
loop {
|
||||
a = a + 1;
|
||||
@@ -120,7 +120,7 @@ fn test_loop_continue() -> anyhow::Result<()> {
|
||||
}
|
||||
break;
|
||||
}
|
||||
"
|
||||
"#
|
||||
};
|
||||
|
||||
// Labels: L1 (start), L2 (end), L3 (if end)
|
||||
|
||||
@@ -47,3 +47,4 @@ mod declaration_literal;
|
||||
mod function_declaration;
|
||||
mod logic_expression;
|
||||
mod loops;
|
||||
mod syscall;
|
||||
|
||||
159
libs/compiler/src/test/syscall.rs
Normal file
159
libs/compiler/src/test/syscall.rs
Normal file
@@ -0,0 +1,159 @@
|
||||
use crate::compile;
|
||||
use indoc::indoc;
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
#[test]
|
||||
fn test_yield() -> anyhow::Result<()> {
|
||||
let compiled = compile! {
|
||||
debug
|
||||
"
|
||||
yield();
|
||||
"
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
compiled,
|
||||
indoc! {
|
||||
"
|
||||
j main
|
||||
main:
|
||||
yield
|
||||
"
|
||||
}
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sleep() -> anyhow::Result<()> {
|
||||
let compiled = compile! {
|
||||
debug
|
||||
"
|
||||
sleep(3);
|
||||
let sleepAmount = 15;
|
||||
sleep(sleepAmount);
|
||||
sleep(sleepAmount * 2);
|
||||
"
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
compiled,
|
||||
indoc! {
|
||||
"
|
||||
j main
|
||||
main:
|
||||
sleep 3
|
||||
move r8 15 #sleepAmount
|
||||
sleep r8
|
||||
mul r1 r8 2
|
||||
sleep r1
|
||||
"
|
||||
}
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_set_on_device() -> anyhow::Result<()> {
|
||||
let compiled = compile! {
|
||||
debug
|
||||
r#"
|
||||
device airConditioner = "d0";
|
||||
let internalTemp = 20c;
|
||||
|
||||
setOnDevice(airConditioner, "On", internalTemp > 25c);
|
||||
"#
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
compiled,
|
||||
indoc! {
|
||||
"
|
||||
j main
|
||||
main:
|
||||
move r8 293.15 #internalTemp
|
||||
sgt r1 r8 298.15
|
||||
s d0 On r1
|
||||
"
|
||||
}
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_set_on_device_batched() -> anyhow::Result<()> {
|
||||
let compiled = compile! {
|
||||
debug
|
||||
r#"
|
||||
let doorHash = hash("Door");
|
||||
setOnDeviceBatched(doorHash, "Lock", true);
|
||||
"#
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
compiled,
|
||||
indoc! {
|
||||
r#"
|
||||
j main
|
||||
main:
|
||||
move r15 HASH("Door") #hash_ret
|
||||
move r8 r15 #doorHash
|
||||
sb r8 Lock 1
|
||||
"#
|
||||
}
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_load_from_device() -> anyhow::Result<()> {
|
||||
let compiled = compile! {
|
||||
debug
|
||||
r#"
|
||||
device airCon = "d0";
|
||||
|
||||
let setting = loadFromDevice(airCon, "On");
|
||||
"#
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
compiled,
|
||||
indoc! {
|
||||
"
|
||||
j main
|
||||
main:
|
||||
l r15 d0 On
|
||||
move r8 r15 #setting
|
||||
"
|
||||
}
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hash() -> anyhow::Result<()> {
|
||||
let compiled = compile! {
|
||||
debug
|
||||
r#"
|
||||
let nameHash = hash("testValue");
|
||||
"#
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
compiled,
|
||||
indoc! {
|
||||
r#"
|
||||
j main
|
||||
main:
|
||||
move r15 HASH("testValue") #hash_ret
|
||||
move r8 r15 #nameHash
|
||||
"#
|
||||
}
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -1,10 +1,11 @@
|
||||
use crate::variable_manager::{self, LocationRequest, VariableLocation, VariableScope};
|
||||
use parser::{
|
||||
Parser as ASTParser,
|
||||
sys_call::{SysCall, System},
|
||||
tree_node::{
|
||||
AssignmentExpression, BinaryExpression, BlockExpression, DeviceDeclarationExpression,
|
||||
Expression, FunctionExpression, IfExpression, InvocationExpression, Literal,
|
||||
LogicalExpression, LoopExpression, WhileExpression,
|
||||
LiteralOrVariable, LogicalExpression, LoopExpression, WhileExpression,
|
||||
},
|
||||
};
|
||||
use quick_error::quick_error;
|
||||
@@ -152,6 +153,9 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
|
||||
self.expression_loop(expr_loop, scope)?;
|
||||
Ok(None)
|
||||
}
|
||||
Expression::Syscall(SysCall::System(system_syscall)) => {
|
||||
self.expression_syscall_system(system_syscall, scope)
|
||||
}
|
||||
Expression::While(expr_while) => {
|
||||
self.expression_while(expr_while, scope)?;
|
||||
Ok(None)
|
||||
@@ -169,11 +173,7 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
|
||||
Ok(None)
|
||||
}
|
||||
Expression::Declaration(var_name, expr) => {
|
||||
let loc = self.expression_declaration(var_name, *expr, scope)?;
|
||||
Ok(loc.map(|l| CompilationResult {
|
||||
location: l,
|
||||
temp_name: None,
|
||||
}))
|
||||
self.expression_declaration(var_name, *expr, scope)
|
||||
}
|
||||
Expression::Assignment(assign_expr) => {
|
||||
self.expression_assignment(assign_expr, scope)?;
|
||||
@@ -284,23 +284,26 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
|
||||
var_name: String,
|
||||
expr: Expression,
|
||||
scope: &mut VariableScope<'v>,
|
||||
) -> Result<Option<VariableLocation>, Error> {
|
||||
) -> Result<Option<CompilationResult>, Error> {
|
||||
// optimization. Check for a negated numeric literal
|
||||
if let Expression::Negation(box_expr) = &expr
|
||||
&& let Expression::Literal(Literal::Number(neg_num)) = &**box_expr
|
||||
{
|
||||
let loc = scope.add_variable(&var_name, LocationRequest::Persist)?;
|
||||
self.emit_variable_assignment(&var_name, &loc, format!("-{neg_num}"))?;
|
||||
return Ok(Some(loc));
|
||||
return Ok(Some(CompilationResult {
|
||||
location: loc,
|
||||
temp_name: None,
|
||||
}));
|
||||
}
|
||||
|
||||
let loc = match expr {
|
||||
let (loc, temp_name) = match expr {
|
||||
Expression::Literal(Literal::Number(num)) => {
|
||||
let var_location =
|
||||
scope.add_variable(var_name.clone(), LocationRequest::Persist)?;
|
||||
|
||||
self.emit_variable_assignment(&var_name, &var_location, num)?;
|
||||
var_location
|
||||
(var_location, None)
|
||||
}
|
||||
Expression::Literal(Literal::Boolean(b)) => {
|
||||
let val = if b { "1" } else { "0" };
|
||||
@@ -308,7 +311,7 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
|
||||
scope.add_variable(var_name.clone(), LocationRequest::Persist)?;
|
||||
|
||||
self.emit_variable_assignment(&var_name, &var_location, val)?;
|
||||
var_location
|
||||
(var_location, None)
|
||||
}
|
||||
Expression::Invocation(invoke_expr) => {
|
||||
self.expression_function_invocation(invoke_expr, scope)?;
|
||||
@@ -319,7 +322,21 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
|
||||
&loc,
|
||||
format!("r{}", VariableScope::RETURN_REGISTER),
|
||||
)?;
|
||||
loc
|
||||
(loc, None)
|
||||
}
|
||||
Expression::Syscall(SysCall::System(call)) => {
|
||||
if self.expression_syscall_system(call, scope)?.is_none() {
|
||||
return Err(Error::Unknown("SysCall did not return a value".into()));
|
||||
};
|
||||
|
||||
let loc = scope.add_variable(&var_name, LocationRequest::Persist)?;
|
||||
self.emit_variable_assignment(
|
||||
&var_name,
|
||||
&loc,
|
||||
format!("r{}", VariableScope::RETURN_REGISTER),
|
||||
)?;
|
||||
|
||||
(loc, None)
|
||||
}
|
||||
// Support assigning binary expressions to variables directly
|
||||
Expression::Binary(bin_expr) => {
|
||||
@@ -334,7 +351,7 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
|
||||
if let Some(name) = result.temp_name {
|
||||
scope.free_temp(name)?;
|
||||
}
|
||||
var_loc
|
||||
(var_loc, None)
|
||||
}
|
||||
Expression::Logical(log_expr) => {
|
||||
let result = self.expression_logical(log_expr, scope)?;
|
||||
@@ -348,7 +365,7 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
|
||||
if let Some(name) = result.temp_name {
|
||||
scope.free_temp(name)?;
|
||||
}
|
||||
var_loc
|
||||
(var_loc, None)
|
||||
}
|
||||
Expression::Variable(name) => {
|
||||
let src_loc = scope.get_location_of(&name)?;
|
||||
@@ -372,7 +389,7 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
|
||||
}
|
||||
};
|
||||
self.emit_variable_assignment(&var_name, &var_loc, src_str)?;
|
||||
var_loc
|
||||
(var_loc, None)
|
||||
}
|
||||
Expression::Priority(inner) => {
|
||||
return self.expression_declaration(var_name, *inner, scope);
|
||||
@@ -384,7 +401,10 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
|
||||
}
|
||||
};
|
||||
|
||||
Ok(Some(loc))
|
||||
Ok(Some(CompilationResult {
|
||||
location: loc,
|
||||
temp_name,
|
||||
}))
|
||||
}
|
||||
|
||||
fn expression_assignment<'v>(
|
||||
@@ -740,6 +760,18 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
|
||||
}
|
||||
}
|
||||
|
||||
fn compile_literal_or_variable(
|
||||
&mut self,
|
||||
val: LiteralOrVariable,
|
||||
scope: &mut VariableScope,
|
||||
) -> Result<(String, Option<String>), Error> {
|
||||
let expr = match val {
|
||||
LiteralOrVariable::Literal(l) => Expression::Literal(l),
|
||||
LiteralOrVariable::Variable(v) => Expression::Variable(v),
|
||||
};
|
||||
self.compile_operand(expr, scope)
|
||||
}
|
||||
|
||||
fn expression_binary<'v>(
|
||||
&mut self,
|
||||
expr: BinaryExpression,
|
||||
@@ -978,6 +1010,127 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
|
||||
Ok(VariableLocation::Persistant(VariableScope::RETURN_REGISTER))
|
||||
}
|
||||
|
||||
// syscalls that return values will be stored in the VariableScope::RETURN_REGISTER
|
||||
// register
|
||||
fn expression_syscall_system<'v>(
|
||||
&mut self,
|
||||
expr: System,
|
||||
scope: &mut VariableScope<'v>,
|
||||
) -> Result<Option<CompilationResult>, Error> {
|
||||
match expr {
|
||||
System::Yield => {
|
||||
self.write_output("yield")?;
|
||||
Ok(None)
|
||||
}
|
||||
System::Sleep(amt) => {
|
||||
let (var, cleanup) = self.compile_operand(*amt, scope)?;
|
||||
self.write_output(format!("sleep {var}"))?;
|
||||
if let Some(temp) = cleanup {
|
||||
scope.free_temp(temp)?;
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
System::Hash(hash_arg) => {
|
||||
let Literal::String(str_lit) = hash_arg else {
|
||||
return Err(Error::AgrumentMismatch(
|
||||
"Arg1 expected to be a string literal.".into(),
|
||||
));
|
||||
};
|
||||
|
||||
let loc = VariableLocation::Persistant(VariableScope::RETURN_REGISTER);
|
||||
self.emit_variable_assignment("hash_ret", &loc, format!(r#"HASH("{}")"#, str_lit))?;
|
||||
|
||||
Ok(Some(CompilationResult {
|
||||
location: loc,
|
||||
temp_name: None,
|
||||
}))
|
||||
}
|
||||
System::SetOnDevice(device, logic_type, variable) => {
|
||||
let (variable, var_cleanup) = self.compile_operand(*variable, scope)?;
|
||||
|
||||
let LiteralOrVariable::Variable(device) = device else {
|
||||
return Err(Error::AgrumentMismatch(
|
||||
"Arg1 expected to be a variable".into(),
|
||||
));
|
||||
};
|
||||
|
||||
let Some(device) = self.devices.get(&device) else {
|
||||
return Err(Error::InvalidDevice(device));
|
||||
};
|
||||
|
||||
let Literal::String(logic_type) = logic_type else {
|
||||
return Err(Error::AgrumentMismatch(
|
||||
"Arg2 expected to be a string".into(),
|
||||
));
|
||||
};
|
||||
|
||||
self.write_output(format!("s {} {} {}", device, logic_type, variable))?;
|
||||
|
||||
if let Some(temp_var) = var_cleanup {
|
||||
scope.free_temp(temp_var)?;
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
System::SetOnDeviceBatched(device_hash, logic_type, variable) => {
|
||||
let (var, var_cleanup) = self.compile_operand(*variable, scope)?;
|
||||
let (device_hash, device_hash_cleanup) =
|
||||
self.compile_literal_or_variable(device_hash, scope)?;
|
||||
let Literal::String(logic_type) = logic_type else {
|
||||
return Err(Error::AgrumentMismatch(
|
||||
"Arg2 expected to be a string".into(),
|
||||
));
|
||||
};
|
||||
|
||||
self.write_output(format!("sb {} {} {}", device_hash, logic_type, var))?;
|
||||
|
||||
if let Some(var_cleanup) = var_cleanup {
|
||||
scope.free_temp(var_cleanup)?;
|
||||
}
|
||||
|
||||
if let Some(device_cleanup) = device_hash_cleanup {
|
||||
scope.free_temp(device_cleanup)?;
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
System::LoadFromDevice(device, logic_type) => {
|
||||
let LiteralOrVariable::Variable(device) = device else {
|
||||
return Err(Error::AgrumentMismatch(
|
||||
"Arg1 expected to be a variable".into(),
|
||||
));
|
||||
};
|
||||
|
||||
let Some(device) = self.devices.get(&device) else {
|
||||
return Err(Error::InvalidDevice(device));
|
||||
};
|
||||
|
||||
let Literal::String(logic_type) = logic_type else {
|
||||
return Err(Error::AgrumentMismatch(
|
||||
"Arg2 expected to be a string".into(),
|
||||
));
|
||||
};
|
||||
|
||||
self.write_output(format!(
|
||||
"l r{} {} {}",
|
||||
VariableScope::RETURN_REGISTER,
|
||||
device,
|
||||
logic_type
|
||||
))?;
|
||||
|
||||
Ok(Some(CompilationResult {
|
||||
location: VariableLocation::Temporary(VariableScope::RETURN_REGISTER),
|
||||
temp_name: None,
|
||||
}))
|
||||
}
|
||||
|
||||
_ => {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Compile a function declaration.
|
||||
/// Calees are responsible for backing up any registers they wish to use.
|
||||
fn expression_function<'v>(
|
||||
@@ -1092,4 +1245,3 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
9
libs/compiler/test_files/deviceIo.slang
Normal file
9
libs/compiler/test_files/deviceIo.slang
Normal file
@@ -0,0 +1,9 @@
|
||||
device airConditioner = "d0";
|
||||
device gasSensor = "d1";
|
||||
|
||||
loop {
|
||||
yield();
|
||||
let indoorTemp = loadFromDevice(gasSensor, "Temperature");
|
||||
let shouldSet = indoorTemp > 30c;
|
||||
setOnDevice(airConditioner, "On", shouldSet);
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
fn addTemperatures(temp1, temp2) {
|
||||
return temp1 + temp2;
|
||||
};
|
||||
|
||||
|
||||
let newTemp1 = addTemperatures(15c, 120c);
|
||||
let newTemp2 = addTemperatures(50c, 20c);
|
||||
@@ -13,6 +13,8 @@ use tokenizer::{
|
||||
};
|
||||
use tree_node::*;
|
||||
|
||||
use crate::sys_call::System;
|
||||
|
||||
#[macro_export]
|
||||
/// A macro to create a boxed value.
|
||||
macro_rules! boxed {
|
||||
@@ -63,6 +65,12 @@ macro_rules! token_from_option {
|
||||
None => return Err(Error::UnexpectedEOF),
|
||||
}
|
||||
};
|
||||
(owned $token:expr) => {
|
||||
match $token {
|
||||
Some(token) => token,
|
||||
None => return Err(Error::UnexpectedEOF),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! extract_token_data {
|
||||
@@ -1039,9 +1047,22 @@ impl Parser {
|
||||
}
|
||||
"sleep" => {
|
||||
check_length(self, &invocation.arguments, 1)?;
|
||||
let mut arg = invocation.arguments.iter();
|
||||
let argument = literal_or_variable!(arg.next());
|
||||
Ok(SysCall::System(sys_call::System::Sleep(argument)))
|
||||
let mut arg = invocation.arguments.into_iter();
|
||||
let expr = token_from_option!(owned arg.next());
|
||||
Ok(SysCall::System(System::Sleep(boxed!(expr))))
|
||||
}
|
||||
"hash" => {
|
||||
check_length(self, &invocation.arguments, 1)?;
|
||||
let mut args = invocation.arguments.into_iter();
|
||||
let lit_str = literal_or_variable!(args.next());
|
||||
|
||||
let LiteralOrVariable::Literal(lit_str) = lit_str else {
|
||||
return Err(Error::UnexpectedToken(
|
||||
token_from_option!(self.current_token).clone(),
|
||||
));
|
||||
};
|
||||
|
||||
Ok(SysCall::System(System::Hash(lit_str)))
|
||||
}
|
||||
"loadFromDevice" => {
|
||||
check_length(self, &invocation.arguments, 2)?;
|
||||
@@ -1057,7 +1078,7 @@ impl Parser {
|
||||
|
||||
Ok(SysCall::System(sys_call::System::LoadFromDevice(
|
||||
device,
|
||||
LiteralOrVariable::Variable(variable.clone()),
|
||||
Literal::String(variable.clone()),
|
||||
)))
|
||||
}
|
||||
"loadBatch" => {
|
||||
@@ -1076,23 +1097,23 @@ impl Parser {
|
||||
}
|
||||
"loadBatchNamed" => {
|
||||
check_length(self, &invocation.arguments, 4)?;
|
||||
let mut args = invocation.arguments.iter();
|
||||
let mut args = invocation.arguments.into_iter();
|
||||
|
||||
let device_hash = literal_or_variable!(args.next());
|
||||
let name_hash = get_arg!(Literal, literal_or_variable!(args.next()));
|
||||
let name_hash = token_from_option!(owned args.next());
|
||||
let logic_type = get_arg!(Literal, literal_or_variable!(args.next()));
|
||||
let batch_mode = get_arg!(Literal, literal_or_variable!(args.next()));
|
||||
|
||||
Ok(SysCall::System(sys_call::System::LoadBatchNamed(
|
||||
device_hash,
|
||||
name_hash,
|
||||
boxed!(name_hash),
|
||||
logic_type,
|
||||
batch_mode,
|
||||
)))
|
||||
}
|
||||
"setOnDevice" => {
|
||||
check_length(self, &invocation.arguments, 3)?;
|
||||
let mut args = invocation.arguments.iter();
|
||||
let mut args = invocation.arguments.into_iter();
|
||||
|
||||
let device = literal_or_variable!(args.next());
|
||||
|
||||
@@ -1104,12 +1125,54 @@ impl Parser {
|
||||
));
|
||||
};
|
||||
|
||||
let variable = literal_or_variable!(args.next());
|
||||
let variable = token_from_option!(owned args.next());
|
||||
|
||||
Ok(SysCall::System(sys_call::System::SetOnDevice(
|
||||
device,
|
||||
Literal::String(logic_type),
|
||||
variable,
|
||||
boxed!(variable),
|
||||
)))
|
||||
}
|
||||
"setOnDeviceBatched" => {
|
||||
check_length(self, &invocation.arguments, 3)?;
|
||||
let mut args = invocation.arguments.into_iter();
|
||||
|
||||
let device = literal_or_variable!(args.next());
|
||||
let Literal::String(logic_type) =
|
||||
get_arg!(Literal, literal_or_variable!(args.next()))
|
||||
else {
|
||||
return Err(Error::UnexpectedToken(
|
||||
token_from_option!(self.current_token).clone(),
|
||||
));
|
||||
};
|
||||
let variable = token_from_option!(owned args.next());
|
||||
|
||||
Ok(SysCall::System(System::SetOnDeviceBatched(
|
||||
device,
|
||||
Literal::String(logic_type),
|
||||
boxed!(variable),
|
||||
)))
|
||||
}
|
||||
"setOnDeviceBatchedNamed" => {
|
||||
check_length(self, &invocation.arguments, 4)?;
|
||||
let mut args = invocation.arguments.into_iter();
|
||||
|
||||
let device = literal_or_variable!(args.next());
|
||||
let name = literal_or_variable!(args.next());
|
||||
let Literal::String(logic_type) =
|
||||
get_arg!(Literal, literal_or_variable!(args.next()))
|
||||
else {
|
||||
return Err(Error::UnexpectedToken(
|
||||
token_from_option!(self.current_token).clone(),
|
||||
));
|
||||
};
|
||||
let variable = token_from_option!(owned args.next());
|
||||
|
||||
Ok(SysCall::System(System::SetOnDeviceBatchedNamed(
|
||||
device,
|
||||
name,
|
||||
Literal::String(logic_type),
|
||||
boxed!(variable),
|
||||
)))
|
||||
}
|
||||
// math calls
|
||||
@@ -1202,4 +1265,3 @@ impl Parser {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::tree_node::Literal;
|
||||
use crate::tree_node::{Expression, Literal};
|
||||
|
||||
use super::LiteralOrVariable;
|
||||
|
||||
@@ -102,25 +102,25 @@ pub enum System {
|
||||
/// Represents a function that can be called to sleep for a certain amount of time.
|
||||
/// ## In Game
|
||||
/// `sleep a(r?|num)`
|
||||
Sleep(LiteralOrVariable),
|
||||
Sleep(Box<Expression>),
|
||||
/// Gets the in-game hash for a specific prefab name.
|
||||
/// ## In Game
|
||||
/// `HASH("prefabName")`
|
||||
Hash(LiteralOrVariable),
|
||||
Hash(Literal),
|
||||
/// Represents a function which loads a device variable into a register.
|
||||
/// ## In Game
|
||||
/// `l r? d? var`
|
||||
/// ## Examples
|
||||
/// `l r0 d0 Setting`
|
||||
/// `l r1 d5 Pressure`
|
||||
LoadFromDevice(LiteralOrVariable, LiteralOrVariable),
|
||||
LoadFromDevice(LiteralOrVariable, Literal),
|
||||
/// Function which gets a LogicType from all connected network devices that match
|
||||
/// the provided device hash and name, aggregating them via a batchMode
|
||||
/// ## In Game
|
||||
/// lbn r? deviceHash nameHash logicType batchMode
|
||||
/// ## Examples
|
||||
/// lbn r0 HASH("StructureWallLight") HASH("wallLight") On Minimum
|
||||
LoadBatchNamed(LiteralOrVariable, Literal, Literal, Literal),
|
||||
LoadBatchNamed(LiteralOrVariable, Box<Expression>, Literal, Literal),
|
||||
/// Loads a LogicType from all connected network devices, aggregating them via a
|
||||
/// batchMode
|
||||
/// ## In Game
|
||||
@@ -133,7 +133,26 @@ pub enum System {
|
||||
/// `s d? logicType r?`
|
||||
/// ## Example
|
||||
/// `s d0 Setting r0`
|
||||
SetOnDevice(LiteralOrVariable, Literal, LiteralOrVariable),
|
||||
SetOnDevice(LiteralOrVariable, Literal, Box<Expression>),
|
||||
/// Represents a function which stores a setting to all devices that match
|
||||
/// the given deviceHash
|
||||
/// ## In Game
|
||||
/// `sb deviceHash logictype r?`
|
||||
/// ## Example
|
||||
/// `sb HASH("Doors") Lock 1`
|
||||
SetOnDeviceBatched(LiteralOrVariable, Literal, Box<Expression>),
|
||||
/// Represents a function which stores a setting to all devices that match
|
||||
/// both the given deviceHash AND the given nameHash
|
||||
/// ## In Game
|
||||
/// `sbn deviceHash nameHash logicType r?`
|
||||
/// ## Example
|
||||
/// `sbn HASH("Doors") HASH("Exterior") Lock 1`
|
||||
SetOnDeviceBatchedNamed(
|
||||
LiteralOrVariable,
|
||||
LiteralOrVariable,
|
||||
Literal,
|
||||
Box<Expression>,
|
||||
),
|
||||
}
|
||||
|
||||
impl std::fmt::Display for System {
|
||||
@@ -141,13 +160,19 @@ impl std::fmt::Display for System {
|
||||
match self {
|
||||
System::Yield => write!(f, "yield()"),
|
||||
System::Sleep(a) => write!(f, "sleep({})", a),
|
||||
System::Hash(a) => write!(f, "HASH({})", a),
|
||||
System::Hash(a) => write!(f, "hash({})", a),
|
||||
System::LoadFromDevice(a, b) => write!(f, "loadFromDevice({}, {})", a, b),
|
||||
System::LoadBatch(a, b, c) => write!(f, "loadBatch({}, {}, {})", a, b, c),
|
||||
System::LoadBatchNamed(a, b, c, d) => {
|
||||
write!(f, "loadBatchNamed({}, {}, {}, {})", a, b, c, d)
|
||||
}
|
||||
System::SetOnDevice(a, b, c) => write!(f, "setOnDevice({}, {}, {})", a, b, c),
|
||||
System::SetOnDeviceBatched(a, b, c) => {
|
||||
write!(f, "setOnDeviceBatched({}, {}, {})", a, b, c)
|
||||
}
|
||||
System::SetOnDeviceBatchedNamed(a, b, c, d) => {
|
||||
write!(f, "setOnDeviceBatchedNamed({}, {}, {}, {})", a, b, c, d)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -175,9 +200,11 @@ impl SysCall {
|
||||
identifier,
|
||||
"yield"
|
||||
| "sleep"
|
||||
| "HASH"
|
||||
| "hash"
|
||||
| "loadFromDevice"
|
||||
| "setOnDevice"
|
||||
| "setOnDeviceBatched"
|
||||
| "setOnDeviceBatchedNamed"
|
||||
| "acos"
|
||||
| "asin"
|
||||
| "atan"
|
||||
|
||||
@@ -76,6 +76,12 @@ impl From<String> for Tokenizer {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&str> for Tokenizer {
|
||||
fn from(value: &str) -> Self {
|
||||
Self::from(value.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl Tokenizer {
|
||||
/// Consumes the tokenizer and returns the next token in the stream
|
||||
/// If there are no more tokens in the stream, this function returns None
|
||||
|
||||
58
src/lib.rs
58
src/lib.rs
@@ -1,34 +1,58 @@
|
||||
use compiler::Compiler;
|
||||
use parser::Parser;
|
||||
use safer_ffi::ffi_export;
|
||||
use std::io::BufWriter;
|
||||
use std::{
|
||||
ffi::{CStr, CString},
|
||||
io::BufWriter,
|
||||
};
|
||||
use tokenizer::Tokenizer;
|
||||
|
||||
#[ffi_export]
|
||||
fn compile_from_string(
|
||||
input: &safer_ffi::string::String,
|
||||
output: &mut safer_ffi::string::String,
|
||||
) -> bool {
|
||||
let mut writer = BufWriter::new(Vec::new());
|
||||
/// Takes a raw pointer to a string and compiles the `slang` code into valid IC10
|
||||
/// # Safety
|
||||
/// This must be called with a valid string pointer from C# (or wherever is calling this function)
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn compile_from_string(
|
||||
input_ptr: *const std::os::raw::c_char,
|
||||
) -> *mut std::os::raw::c_char {
|
||||
if input_ptr.is_null() {
|
||||
return std::ptr::null_mut();
|
||||
}
|
||||
|
||||
let tokenizer = Tokenizer::from(input.to_string());
|
||||
let c_str = unsafe { CStr::from_ptr(input_ptr) };
|
||||
|
||||
let Ok(input_str) = c_str.to_str() else {
|
||||
return std::ptr::null_mut();
|
||||
};
|
||||
|
||||
let mut writer = BufWriter::new(Vec::new());
|
||||
let tokenizer = Tokenizer::from(input_str);
|
||||
let parser = Parser::new(tokenizer);
|
||||
|
||||
let compiler = Compiler::new(parser, &mut writer, None);
|
||||
|
||||
let Ok(()) = compiler.compile() else {
|
||||
return false;
|
||||
return std::ptr::null_mut();
|
||||
};
|
||||
|
||||
let Ok(buffer) = writer.into_inner() else {
|
||||
return false;
|
||||
return std::ptr::null_mut();
|
||||
};
|
||||
|
||||
let Ok(output_string) = String::from_utf8(buffer) else {
|
||||
return false;
|
||||
};
|
||||
let c_string = CString::from_vec_unchecked(buffer);
|
||||
|
||||
*output = output_string.into();
|
||||
|
||||
return true;
|
||||
c_string.into_raw()
|
||||
}
|
||||
|
||||
/// Takes ownership of the string pointer and drops it, freeing the memory
|
||||
/// # Safety
|
||||
/// Must be called with a valid string pointer
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn free_slang_string(input_ptr: *mut std::os::raw::c_char) {
|
||||
if input_ptr.is_null() {
|
||||
return;
|
||||
}
|
||||
|
||||
unsafe {
|
||||
// Takes ownership of the input string, and then drops it immediately
|
||||
let _ = CString::from_raw(input_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user