From ac7d33d07418f7529a0e6f339994cb8c98e85242 Mon Sep 17 00:00:00 2001 From: Martin Zeller Date: Sun, 24 Sep 2023 04:13:20 +0200 Subject: [PATCH] Add support for lr Closes #13 --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- src/instructions.rs | 22 +++++++++++++++++-- src/main.rs | 52 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 75 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7bb870e..bc369c1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -895,9 +895,9 @@ dependencies = [ [[package]] name = "tree-sitter-ic10" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89d2f53ff25304719c9301799835c837c4da37482cffea9aeddc61d2da0dc021" +checksum = "0989008043f359c280ac8f935cab736530e944dbfbfc0c7fc14070edd84d39e6" dependencies = [ "cc", "tree-sitter", diff --git a/Cargo.toml b/Cargo.toml index 6e322f8..74428af 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,7 @@ serde_json = "1.0.94" tokio = {version="1.26.0", features=["full"]} tower-lsp = "0.19.0" tree-sitter = "0.20.9" -tree-sitter-ic10 = "0.5.1" +tree-sitter-ic10 = "0.5.2" [build-dependencies] phf_codegen = "0.11.1" diff --git a/src/instructions.rs b/src/instructions.rs index fc593c6..a870bef 100644 --- a/src/instructions.rs +++ b/src/instructions.rs @@ -11,6 +11,7 @@ pub(crate) enum DataType { SlotLogicType, Name, BatchMode, + ReagentMode, } #[derive(Debug)] @@ -25,6 +26,7 @@ const VALUE: Union = Union(&[DataType::Register, DataType::Number]); const LOGIC_TYPE: Union = Union(&[DataType::LogicType]); const SLOT_LOGIC_TYPE: Union = Union(&[DataType::SlotLogicType]); const BATCH_MODE: Union = Union(&[DataType::BatchMode, DataType::Number, DataType::Register]); +const REAGENT_MODE: Union = Union(&[DataType::ReagentMode, DataType::Number, DataType::Register]); pub(crate) const INSTRUCTIONS: phf::Map<&'static str, InstructionSignature> = phf_map! { "alias" => InstructionSignature(&[Union(&[DataType::Name]), Union(&[DataType::Register, DataType::Device])]), @@ -38,7 +40,7 @@ pub(crate) const INSTRUCTIONS: phf::Map<&'static str, InstructionSignature> = ph "brdse" => InstructionSignature(&[DEVICE,VALUE]), "l" => InstructionSignature(&[REGISTER,DEVICE,LOGIC_TYPE]), "lb" => InstructionSignature(&[REGISTER,VALUE,LOGIC_TYPE,BATCH_MODE]), - // "lr" => InstructionSignature(&[REGISTER,DEVICE,reagentMode,reagent]), + "lr" => InstructionSignature(&[REGISTER,DEVICE,REAGENT_MODE,VALUE]), "ls" => InstructionSignature(&[REGISTER,DEVICE,VALUE,SLOT_LOGIC_TYPE]), "s" => InstructionSignature(&[DEVICE,LOGIC_TYPE,VALUE]), "sb" => InstructionSignature(&[VALUE,LOGIC_TYPE,VALUE]), @@ -364,6 +366,18 @@ pub(crate) const BATCH_MODE_LOOKUP: phf::Map = phf_map! { 3u8 => "Maximum", }; +pub(crate) const REAGENT_MODES: phf::Set<&'static str> = phf_set! { + "Contents", + "Required", + "Recipe", +}; + +pub(crate) const REAGENT_MODE_LOOKUP: phf::Map = phf_map! { + 0u8 => "Contents", + 1u8 => "Required", + 2u8 => "Recipe", +}; + impl Display for DataType { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let val = match *self { @@ -374,6 +388,7 @@ impl Display for DataType { DataType::SlotLogicType => "slotType", DataType::Name => "name", DataType::BatchMode => "batchMode", + DataType::ReagentMode => "reagentMode", }; write!(f, "{}", val) } @@ -457,6 +472,9 @@ pub(crate) fn logictype_candidates(text: &str) -> Vec { if BATCH_MODES.contains(text) { ret.push(DataType::BatchMode); } + if REAGENT_MODES.contains(text) { + ret.push(DataType::ReagentMode); + } ret } @@ -469,7 +487,7 @@ pub(crate) const INSTRUCTION_DOCS: phf::Map<&'static str, &'static str> = phf_ma "s" => "Stores register value to var on device.", "sb" => "Stores register value to var on all output network devices with provided type hash.", "ls" => "Loads slot var on device to register.", - // "lr" => "Loads reagent of device's reagentMode to register. Contents (0), Required (1), Recipe (2). Can use either the word, or the number.", + "lr" => "Loads reagent of device's reagentMode to register. Contents (0), Required (1), Recipe (2). Can use either the word, or the number.", "alias" => "Labels register or device reference with name, device references also affect what shows on the screws on the IC base.", "define" => "Creates a label that will be replaced throughout the program with the provided value.", "move" => "Register = provided num or register value.", diff --git a/src/main.rs b/src/main.rs index eaa6025..077980e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -38,6 +38,7 @@ mod instructions; const LINT_ABSOLUTE_JUMP: &'static str = "L001"; const LINT_NUMBER_BATCH_MODE: &'static str = "L002"; +const LINT_NUMBER_REAGENT_MODE: &'static str = "L003"; const SEMANTIC_SYMBOL_LEGEND: &'static [SemanticTokenType] = &[ SemanticTokenType::KEYWORD, @@ -1433,6 +1434,9 @@ impl Backend { if instructions::BATCH_MODES.contains(ident) { types.push(DataType::BatchMode); } + if instructions::REAGENT_MODES.contains(ident) { + types.push(DataType::ReagentMode); + } instructions::Union(types.as_slice()) } "identifier" => { @@ -1773,6 +1777,54 @@ impl Backend { } } + // Number reagent mode + { + let mut cursor = QueryCursor::new(); + let query = Query::new( + tree_sitter_ic10::language(), + "(instruction (operation \"lr\") . (operand) . (operand) . (operand (number)@n))", + ) + .unwrap(); + + let captures = cursor.captures(&query, tree.root_node(), document.content.as_bytes()); + + for (capture, _) in captures { + let node = capture.captures[0].node; + + let Ok(value) = node + .utf8_text(document.content.as_bytes()) + .unwrap() + .parse::() else { + diagnostics.push(Diagnostic { + range: Range::from(node.range()).into(), + severity: Some(DiagnosticSeverity::ERROR), + message: "Use of non-integer reagent mode".to_string(), + ..Default::default() + }); + continue; + }; + + let Some(replacement) = instructions::REAGENT_MODE_LOOKUP.get(&value) else { + diagnostics.push(Diagnostic { + range: Range::from(node.range()).into(), + severity: Some(DiagnosticSeverity::ERROR), + message: "Invalid reagent mode".to_string(), + ..Default::default() + }); + continue; + }; + + diagnostics.push(Diagnostic { + range: Range::from(node.range()).into(), + severity: Some(DiagnosticSeverity::WARNING), + code: Some(NumberOrString::String(LINT_NUMBER_REAGENT_MODE.to_string())), + message: "Use of literal number for reagent mode".to_string(), + data: Some(Value::String(replacement.to_string())), + ..Default::default() + }); + } + } + self.client .publish_diagnostics(uri.to_owned(), diagnostics, None) .await;