diff --git a/src/transpile/conversions.rs b/src/transpile/conversions.rs index dbfdfdf..adcdad0 100644 --- a/src/transpile/conversions.rs +++ b/src/transpile/conversions.rs @@ -1,57 +1,50 @@ //! Conversion functions for converting between tokens/ast-nodes and [`shulkerbox`] types -use shulkerbox::util::{MacroString, MacroStringPart}; +use shulkerbox::util::{MacroString as ExtMacroString, MacroStringPart as ExtMacroStringPart}; -use crate::{ - lexical::token::{MacroStringLiteral, MacroStringLiteralPart}, - syntax::syntax_tree::AnyStringLiteral, -}; +use crate::{lexical::token::MacroStringLiteral, syntax::syntax_tree::AnyStringLiteral}; -impl From<&AnyStringLiteral> for MacroString { - fn from(value: &AnyStringLiteral) -> Self { +use super::util::{MacroString, MacroStringPart}; + +impl From for ExtMacroString { + fn from(value: MacroString) -> Self { match value { - AnyStringLiteral::StringLiteral(literal) => Self::from(literal.str_content().as_ref()), - AnyStringLiteral::MacroStringLiteral(literal) => Self::from(literal), + MacroString::String(s) => Self::String(s), + MacroString::MacroString(parts) => { + Self::MacroString(parts.into_iter().map(ExtMacroStringPart::from).collect()) + } } } } -impl From for MacroString { +impl From for ExtMacroStringPart { + fn from(value: MacroStringPart) -> Self { + match value { + MacroStringPart::String(s) => Self::String(s), + MacroStringPart::MacroUsage(m) => Self::MacroUsage(m), + } + } +} + +impl From<&AnyStringLiteral> for ExtMacroString { + fn from(value: &AnyStringLiteral) -> Self { + Self::from(MacroString::from(value)) + } +} + +impl From for ExtMacroString { fn from(value: AnyStringLiteral) -> Self { Self::from(&value) } } -impl From<&MacroStringLiteral> for MacroString { +impl From<&MacroStringLiteral> for ExtMacroString { fn from(value: &MacroStringLiteral) -> Self { - if value - .parts() - .iter() - .any(|p| matches!(p, MacroStringLiteralPart::MacroUsage { .. })) - { - Self::MacroString( - value - .parts() - .iter() - .map(|part| match part { - MacroStringLiteralPart::Text(span) => MacroStringPart::String( - crate::util::unescape_macro_string(span.str()).to_string(), - ), - MacroStringLiteralPart::MacroUsage { identifier, .. } => { - MacroStringPart::MacroUsage( - crate::util::identifier_to_macro(identifier.span.str()).to_string(), - ) - } - }) - .collect(), - ) - } else { - Self::String(value.str_content()) - } + Self::from(MacroString::from(value)) } } -impl From for MacroString { +impl From for ExtMacroString { fn from(value: MacroStringLiteral) -> Self { Self::from(&value) } diff --git a/src/transpile/expression.rs b/src/transpile/expression.rs index e6688d6..fdf6656 100644 --- a/src/transpile/expression.rs +++ b/src/transpile/expression.rs @@ -2,7 +2,7 @@ use std::{fmt::Display, sync::Arc}; -use super::{Scope, VariableData}; +use super::{util::MacroString, Scope, VariableData}; use crate::{ base::{self, Handler, VoidHandler}, lexical::token::MacroStringLiteralPart, @@ -15,10 +15,7 @@ use crate::{ use enum_as_inner::EnumAsInner; #[cfg(feature = "shulkerbox")] -use shulkerbox::{ - prelude::{Command, Condition, Execute}, - util::MacroString, -}; +use shulkerbox::prelude::{Command, Condition, Execute}; #[cfg(feature = "shulkerbox")] use super::{ @@ -51,7 +48,7 @@ impl Display for ComptimeValue { Self::Boolean(boolean) => write!(f, "{boolean}"), Self::Integer(int) => write!(f, "{int}"), Self::String(string) => write!(f, "{string}"), - Self::MacroString(macro_string) => write!(f, "{}", macro_string.compile()), + Self::MacroString(macro_string) => write!(f, "{macro_string}"), } } } @@ -1040,7 +1037,7 @@ impl Transpiler { )), Some(ComptimeValue::MacroString(value)) => Ok(( Vec::new(), - ExtendedCondition::Runtime(Condition::Atom(value)), + ExtendedCondition::Runtime(Condition::Atom(value.into())), )), Some(ComptimeValue::Boolean(boolean)) => { Ok((Vec::new(), ExtendedCondition::Comptime(boolean))) @@ -1397,7 +1394,7 @@ impl Transpiler { .. } | DataLocation::Tag { .. } => self.store_condition_success( - ExtendedCondition::Runtime(Condition::Atom(value.clone())), + ExtendedCondition::Runtime(Condition::Atom(value.clone().into())), target, source, handler, diff --git a/src/transpile/lua.rs b/src/transpile/lua.rs index 081f668..bcb6367 100644 --- a/src/transpile/lua.rs +++ b/src/transpile/lua.rs @@ -10,6 +10,8 @@ mod enabled { base::{self, source_file::SourceElement, Handler}, syntax::syntax_tree::expression::LuaCode, transpile::{ + error::{LuaRuntimeError, TranspileError, TranspileResult}, + expression::ComptimeValue, Scope, VariableData, }, }; @@ -173,13 +175,15 @@ mod enabled { #[cfg(not(feature = "lua"))] mod disabled { + use std::sync::Arc; + use crate::{ base::{self, Handler}, syntax::syntax_tree::expression::LuaCode, transpile::error::{TranspileError, TranspileResult}, }; - use crate::transpile::expression::ComptimeValue; + use crate::transpile::{expression::ComptimeValue, Scope}; impl LuaCode { /// Will always return an error because Lua code evaluation is disabled. @@ -193,6 +197,7 @@ mod disabled { scope: &Arc, handler: &impl Handler, ) -> TranspileResult<()> { + let _ = scope; handler.receive(TranspileError::LuaDisabled); tracing::error!("Lua code evaluation is disabled"); Err(TranspileError::LuaDisabled) @@ -208,6 +213,7 @@ mod disabled { scope: &Arc, handler: &impl Handler, ) -> TranspileResult> { + let _ = scope; handler.receive(TranspileError::LuaDisabled); tracing::error!("Lua code evaluation is disabled"); Err(TranspileError::LuaDisabled) diff --git a/src/transpile/transpiler.rs b/src/transpile/transpiler.rs index 1594a70..4e2d7ed 100644 --- a/src/transpile/transpiler.rs +++ b/src/transpile/transpiler.rs @@ -8,10 +8,7 @@ use std::{ sync::{Arc, OnceLock}, }; -use shulkerbox::{ - datapack::{self, Command, Datapack, Execute}, - util::{MacroString, MacroStringPart}, -}; +use shulkerbox::datapack::{self, Command, Datapack, Execute}; use crate::{ base::{ @@ -30,7 +27,10 @@ use crate::{ }, AnnotationAssignment, }, - transpile::error::{IllegalAnnotationContent, MissingFunctionDeclaration}, + transpile::{ + error::{IllegalAnnotationContent, MissingFunctionDeclaration}, + util::{MacroString, MacroStringPart}, + }, }; use super::{ @@ -604,16 +604,17 @@ impl Transpiler { MacroString::String(s) => Command::Raw(format!( r#"data merge storage shulkerscript:function_arguments {{{s}}}"# )), - MacroString::MacroString(_) => { - Command::UsesMacro(super::util::join_macro_strings([ + MacroString::MacroString(_) => Command::UsesMacro( + super::util::join_macro_strings([ MacroString::String( "data merge storage shulkerscript:function_arguments {" .to_string(), ), joined_statics, MacroString::String("}".to_string()), - ])) - } + ]) + .into(), + ), }; setup_cmds.push(statics_cmd); setup_cmds.extend(move_cmds); @@ -784,7 +785,7 @@ impl Transpiler { } Expression::Primary(Primary::Lua(code)) => match code.eval_comptime(scope, handler)? { Some(ComptimeValue::String(cmd)) => Ok(vec![Command::Raw(cmd)]), - Some(ComptimeValue::MacroString(cmd)) => Ok(vec![Command::UsesMacro(cmd)]), + Some(ComptimeValue::MacroString(cmd)) => Ok(vec![Command::UsesMacro(cmd.into())]), Some(ComptimeValue::Boolean(_) | ComptimeValue::Integer(_)) => { let err = TranspileError::MismatchedTypes(MismatchedTypes { expected_type: ExpectedType::String, @@ -805,7 +806,7 @@ impl Transpiler { ), Expression::Binary(bin) => match bin.comptime_eval(scope, handler) { Some(ComptimeValue::String(cmd)) => Ok(vec![Command::Raw(cmd)]), - Some(ComptimeValue::MacroString(cmd)) => Ok(vec![Command::UsesMacro(cmd)]), + Some(ComptimeValue::MacroString(cmd)) => Ok(vec![Command::UsesMacro(cmd.into())]), _ => { let err = TranspileError::MismatchedTypes(MismatchedTypes { expression: bin.span(), @@ -870,7 +871,7 @@ impl Transpiler { function_call.push_str(" {"); parts.insert(0, MacroStringPart::String(function_call)); parts.push(MacroStringPart::String('}'.to_string())); - Command::UsesMacro(MacroString::MacroString(parts)) + Command::UsesMacro(MacroString::MacroString(parts).into()) } }; diff --git a/src/transpile/util.rs b/src/transpile/util.rs index d83711c..4e77c3a 100644 --- a/src/transpile/util.rs +++ b/src/transpile/util.rs @@ -1,6 +1,48 @@ //! Utility methods for transpiling -use shulkerbox::util::{MacroString, MacroStringPart}; +use std::fmt::Display; + +use crate::{ + lexical::token::{MacroStringLiteral, MacroStringLiteralPart}, + syntax::syntax_tree::AnyStringLiteral, +}; + +/// String that can contain macros +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub enum MacroString { + /// A normal string + String(String), + /// A string containing macros + MacroString(Vec), +} + +/// Part of a [`MacroString`] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub enum MacroStringPart { + /// A normal string + String(String), + /// A macro usage + MacroUsage(String), +} + +impl Display for MacroString { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::String(s) => s.fmt(f), + Self::MacroString(parts) => { + for part in parts { + match part { + MacroStringPart::String(s) => s.fmt(f)?, + MacroStringPart::MacroUsage(m) => write!(f, "$({m})")?, + } + } + Ok(()) + } + } + } +} fn normalize_program_identifier(identifier: S) -> String where @@ -71,3 +113,62 @@ where }, }) } + +impl From for MacroString +where + S: Into, +{ + fn from(value: S) -> Self { + Self::String(value.into()) + } +} + +impl From<&AnyStringLiteral> for MacroString { + fn from(value: &AnyStringLiteral) -> Self { + match value { + AnyStringLiteral::StringLiteral(literal) => Self::from(literal.str_content().as_ref()), + AnyStringLiteral::MacroStringLiteral(literal) => Self::from(literal), + } + } +} + +impl From for MacroString { + fn from(value: AnyStringLiteral) -> Self { + Self::from(&value) + } +} + +impl From<&MacroStringLiteral> for MacroString { + fn from(value: &MacroStringLiteral) -> Self { + if value + .parts() + .iter() + .any(|p| matches!(p, MacroStringLiteralPart::MacroUsage { .. })) + { + Self::MacroString( + value + .parts() + .iter() + .map(|part| match part { + MacroStringLiteralPart::Text(span) => MacroStringPart::String( + crate::util::unescape_macro_string(span.str()).to_string(), + ), + MacroStringLiteralPart::MacroUsage { identifier, .. } => { + MacroStringPart::MacroUsage( + crate::util::identifier_to_macro(identifier.span.str()).to_string(), + ) + } + }) + .collect(), + ) + } else { + Self::String(value.str_content()) + } + } +} + +impl From for MacroString { + fn from(value: MacroStringLiteral) -> Self { + Self::from(&value) + } +}