More documentation

This commit is contained in:
2025-12-01 23:43:40 -07:00
parent b3c732bbb7
commit 8aadb95f36
11 changed files with 195 additions and 54 deletions

View File

@@ -360,6 +360,10 @@ version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]]
name = "helpers"
version = "0.1.0"
[[package]] [[package]]
name = "indexmap" name = "indexmap"
version = "2.12.1" version = "2.12.1"
@@ -495,6 +499,7 @@ name = "parser"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"helpers",
"lsp-types", "lsp-types",
"pretty_assertions", "pretty_assertions",
"quick-error", "quick-error",
@@ -829,6 +834,7 @@ dependencies = [
"anyhow", "anyhow",
"clap", "clap",
"compiler", "compiler",
"helpers",
"lsp-types", "lsp-types",
"parser", "parser",
"quick-error", "quick-error",
@@ -926,6 +932,7 @@ name = "tokenizer"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"helpers",
"lsp-types", "lsp-types",
"quick-error", "quick-error",
"rust_decimal", "rust_decimal",

View File

@@ -40,6 +40,7 @@ rust_decimal = { workspace = true }
tokenizer = { path = "libs/tokenizer" } tokenizer = { path = "libs/tokenizer" }
parser = { path = "libs/parser" } parser = { path = "libs/parser" }
compiler = { path = "libs/compiler" } compiler = { path = "libs/compiler" }
helpers = { path = "libs/helpers" }
safer-ffi = { workspace = true } safer-ffi = { workspace = true }
[dev-dependencies] [dev-dependencies]

View File

@@ -0,0 +1,6 @@
[package]
name = "helpers"
version = "0.1.0"
edition = "2024"
[dependencies]

View File

@@ -0,0 +1,12 @@
mod macros;
/// 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 {
/// Retreive documentation for this specific item.
fn docs(&self) -> String;
}
pub mod prelude {
pub use super::{Documentation, documented};
}

View File

@@ -82,4 +82,3 @@ macro_rules! documented {
} }
}; };
} }

View File

@@ -6,6 +6,7 @@ edition = "2024"
[dependencies] [dependencies]
quick-error = { workspace = true } quick-error = { workspace = true }
tokenizer = { path = "../tokenizer" } tokenizer = { path = "../tokenizer" }
helpers = { path = "../helpers" }
lsp-types = { workspace = true } lsp-types = { workspace = true }

View File

@@ -1,4 +1,3 @@
mod macros;
#[cfg(test)] #[cfg(test)]
mod test; mod test;

View File

@@ -1,6 +1,6 @@
use super::LiteralOrVariable; use super::LiteralOrVariable;
use crate::tree_node::{Expression, Literal, Spanned}; use crate::tree_node::{Expression, Literal, Spanned};
use crate::{Documentation, documented}; use helpers::prelude::*;
documented! { documented! {
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq, Eq)]
@@ -48,7 +48,7 @@ documented! {
/// `(number|var).cos();` /// `(number|var).cos();`
Cos(LiteralOrVariable), Cos(LiteralOrVariable),
/// Rounds a number down to the nearest whole number. /// Rounds a number down to the nearest whole number.
/// ## In Game /// ## IC10
/// `floor r? a(r?|num)` /// `floor r? a(r?|num)`
/// ## Slang /// ## Slang
/// `(number|var).floor();` /// `(number|var).floor();`
@@ -131,30 +131,35 @@ documented! {
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq, Eq)]
pub enum System { pub enum System {
/// Pauses execution for exactly 1 tick and then resumes. /// Pauses execution for exactly 1 tick and then resumes.
/// ## In Game /// ## IC10
/// yield /// `yield`
/// ## Slang
/// `yield();`
Yield, Yield,
/// Represents a function that can be called to sleep for a certain amount of time. /// Represents a function that can be called to sleep for a certain amount of time.
/// ## In Game /// ## IC10
/// `sleep a(r?|num)` /// `sleep a(r?|num)`
/// ## Slang
/// `sleep(number|var);`
Sleep(Box<Spanned<Expression>>), Sleep(Box<Spanned<Expression>>),
/// Gets the in-game hash for a specific prefab name. /// Gets the in-game hash for a specific prefab name.
/// ## In Game /// ## IC10
/// `HASH("prefabName")` /// `HASH("prefabName")`
/// ## Slang
/// `HASH("prefabName");`
Hash(Literal), Hash(Literal),
/// Represents a function which loads a device variable into a register. /// Represents a function which loads a device variable into a register.
/// ## In Game /// ## IC10
/// `l r? d? var` /// `l r? d? var`
/// ## Examples /// ## Slang
/// `l r0 d0 Setting` /// `loadFromDevice(deviceType, "LogicType");`
/// `l r1 d5 Pressure`
LoadFromDevice(LiteralOrVariable, Literal), LoadFromDevice(LiteralOrVariable, Literal),
/// Function which gets a LogicType from all connected network devices that match /// Function which gets a LogicType from all connected network devices that match
/// the provided device hash and name, aggregating them via a batchMode /// the provided device hash and name, aggregating them via a batchMode
/// ## In Game /// ## IC10
/// lbn r? deviceHash nameHash logicType batchMode /// `lbn r? deviceHash nameHash logicType batchMode`
/// ## Examples /// ## Slang
/// lbn r0 HASH("StructureWallLight") HASH("wallLight") On Minimum /// `loadFromDeviceBatchedNamed(deviceHash, deviceName, "LogicType", "BatchMode");`
LoadBatchNamed( LoadBatchNamed(
LiteralOrVariable, LiteralOrVariable,
Box<Spanned<Expression>>, Box<Spanned<Expression>>,
@@ -163,30 +168,28 @@ documented! {
), ),
/// Loads a LogicType from all connected network devices, aggregating them via a /// Loads a LogicType from all connected network devices, aggregating them via a
/// batchMode /// batchMode
/// ## In Game /// ## IC10
/// lb r? deviceHash logicType batchMode /// `lb r? deviceHash logicType batchMode`
/// ## Examples /// ## Slang
/// lb r0 HASH("StructureWallLight") On Minimum /// `loadFromDeviceBatched(deviceHash, "Variable", "LogicType");`
LoadBatch(LiteralOrVariable, Literal, Literal), LoadBatch(LiteralOrVariable, Literal, Literal),
/// Represents a function which stores a setting into a specific device. /// Represents a function which stores a setting into a specific device.
/// ## In Game /// ## IC10
/// `s d? logicType r?` /// `s d? logicType r?`
/// ## Example /// ## Slang
/// `s d0 Setting r0` /// `setOnDevice(deviceType, "Variable", (number|var));`
SetOnDevice(LiteralOrVariable, Literal, Box<Spanned<Expression>>), SetOnDevice(LiteralOrVariable, Literal, Box<Spanned<Expression>>),
/// Represents a function which stores a setting to all devices that match /// Represents a function which stores a setting to all devices that match
/// the given deviceHash /// the given deviceHash
/// ## In Game /// ## IC10
/// `sb deviceHash logicType r?` /// `sb deviceHash logicType r?`
/// ## Example
/// `sb HASH("Doors") Lock 1`
SetOnDeviceBatched(LiteralOrVariable, Literal, Box<Spanned<Expression>>), SetOnDeviceBatched(LiteralOrVariable, Literal, Box<Spanned<Expression>>),
/// Represents a function which stores a setting to all devices that match /// Represents a function which stores a setting to all devices that match
/// both the given deviceHash AND the given nameHash /// both the given deviceHash AND the given nameHash
/// ## In Game /// ## IC10
/// `sbn deviceHash nameHash logicType r?` /// `sbn deviceHash nameHash logicType r?`
/// ## Example /// ## Slang
/// `sbn HASH("Doors") HASH("Exterior") Lock 1` /// `setOnDeviceBatchedNamed(deviceType, nameHash, "LogicType", (number|var))`
SetOnDeviceBatchedNamed( SetOnDeviceBatchedNamed(
LiteralOrVariable, LiteralOrVariable,
LiteralOrVariable, LiteralOrVariable,
@@ -226,6 +229,15 @@ pub enum SysCall {
Math(Math), Math(Math),
} }
impl Documentation for SysCall {
fn docs(&self) -> String {
match self {
Self::System(s) => s.docs(),
Self::Math(m) => m.docs(),
}
}
}
impl std::fmt::Display for SysCall { impl std::fmt::Display for SysCall {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self { match self {

View File

@@ -1,5 +1,5 @@
use crate::Documentation;
use crate::sys_call; use crate::sys_call;
use helpers::Documentation;
use pretty_assertions::assert_eq; use pretty_assertions::assert_eq;
#[test] #[test]

View File

@@ -7,6 +7,7 @@ edition = "2024"
rust_decimal = { workspace = true } rust_decimal = { workspace = true }
quick-error = { workspace = true } quick-error = { workspace = true }
lsp-types = { workspace = true } lsp-types = { workspace = true }
helpers = { path = "../helpers" }
[dev-dependencies] [dev-dependencies]
anyhow = { version = "^1" } anyhow = { version = "^1" }

View File

@@ -1,3 +1,4 @@
use helpers::prelude::*;
use rust_decimal::Decimal; use rust_decimal::Decimal;
#[derive(Debug, PartialEq, Eq, Clone)] #[derive(Debug, PartialEq, Eq, Clone)]
@@ -264,28 +265,130 @@ impl std::fmt::Display for Symbol {
} }
} }
documented! {
#[derive(Debug, PartialEq, Hash, Eq, Clone, Copy)] #[derive(Debug, PartialEq, Hash, Eq, Clone, Copy)]
pub enum Keyword { pub enum Keyword {
/// Represents the `continue` keyword /// Represents the `continue` keyword. This will allow you to bypass the current iteration in a loop and start the next one.
/// ## Example
/// ```
/// let item = 0;
/// loop {
/// if (item % 2 == 0) {
/// // This will NOT increment `item` and will continue with the next iteration of the
/// // loop
/// continue;
/// }
/// item = item + 1;
/// }
/// ```
Continue, Continue,
/// Represents the `let` keyword /// Represents the `let` keyword, used to declare variables within Slang.
/// ## Example
/// ```
/// // This variable now exists either in a register or the stack depending on how many
/// // free registers were available when declaring it.
/// let item = 0;
/// ```
Let, Let,
/// Represents the `fn` keyword /// Represents the `fn` keyword, used to declare functions within Slang.
/// ## Example
/// ```
/// // This allows you to now call `doSomething` with specific arguments.
/// fn doSomething(arg1, arg2) {
///
/// }
/// ```
Fn, Fn,
/// Represents the `if` keyword /// Represents the `if` keyword, allowing you to create branched logic.
/// ## Example
/// ```
/// let i = 0;
/// if (i == 0) {
/// i = 1;
/// }
/// // At this line, `i` is now `1`
/// ```
If, If,
/// Represents the `device` keyword. Useful for defining a device at a specific address (ex. d0, d1, d2, etc.) /// Represents the `device` keyword. Useful for defining a device at a specific address
/// (ex. d0, d1, d2, etc.). This also allows you to perform direct operations ON a device.
/// ## Example
/// ```
/// device self = "db";
///
/// // This is the same as `s db Setting 123`
/// self.Setting = 123;
/// ```
Device, Device,
/// Represents the `else` keyword /// Represents the `else` keyword. Useful if you want to check a condition but run run
/// seperate logic in case that condition fails.
/// ## Example
/// ```
/// device self = "db";
/// let i = 0;
/// if (i < 0) {
/// self.Setting = 0;
/// } else {
/// self.Setting = 1;
/// }
/// // Here, the `Setting` on the current housing is `1` because i was NOT less than 0
/// ```
Else, Else,
/// Represents the `return` keyword /// Represents the `return` keyword. Allows you to pass values from a function back to
/// the caller.
/// ## Example
/// ```
/// fn doSomething() {
/// return 1 + 2;
/// }
///
/// // `returnedValue` now holds the value `3`
/// let returnedValue = doSomething();
/// ```
Return, Return,
/// Represents the `enum` keyword /// Represents the `enum` keyword. This is currently not supported, but is kept as a
/// reserved keyword in the future case that this is implemented.
Enum, Enum,
/// Represents the `loop` keyword /// Represents the `loop` keyword. This allows you to create an infinate loop, but can be
/// broken with the `break` keyword.
/// ## Example
/// ```
/// device self = "db";
/// let i = 0;
/// loop {
/// i = i + 1;
/// // The current housing will infinately increment it's `Setting` value.
/// self.Setting = i;
/// }
/// ```
Loop, Loop,
/// Represents the `break` keyword /// Represents the `break` keyword. This allows you to "break out of" a loop prematurely,
/// such as when an if() conditon is true, etc.
/// ## Example
/// ```
/// let i = 0;
/// // This loop will run until the value of `i` is greater than 10,000,
/// // which will then trigger the `break` keyword and it will stop looping
/// loop {
/// if (i > 10_000) {
/// break;
/// }
/// i = i + 1;
/// }
/// ```
Break, Break,
/// Represents the `while` keyword /// Represents the `while` keyword. This is similar to the `loop` keyword but different in
/// that you don't need an `if` statement to break out of a loop, that is handled
/// automatically when invoking `while`
/// ## Example
/// ```
/// let i = 0;
/// // This loop will run until the value of `i` is greater than 10,000, in which case the
/// // while loop will automatically stop running and code will continue AFTER the last
/// // bracket.
/// while (i < 10_000) {
/// i = i + 1;
/// }
/// ```
While, While,
} }
}