Compare commits

...

2 Commits

Author SHA1 Message Date
Moritz Hölting 7290806a2b fix compile error when compiling without shulkerbox feature 2025-03-14 13:20:24 +01:00
Moritz Hölting e4c06e56ee allow passing some variables into lua 2025-03-14 12:51:17 +01:00
6 changed files with 223 additions and 80 deletions

View File

@ -349,7 +349,7 @@ pub struct LuaCode {
left_parenthesis: Punctuation, left_parenthesis: Punctuation,
/// The arguments of the lua code. /// The arguments of the lua code.
#[get = "pub"] #[get = "pub"]
variables: Option<ConnectedList<Identifier, Punctuation>>, inputs: Option<ConnectedList<Identifier, Punctuation>>,
/// The right parenthesis of the lua code. /// The right parenthesis of the lua code.
#[get = "pub"] #[get = "pub"]
right_parenthesis: Punctuation, right_parenthesis: Punctuation,
@ -550,10 +550,7 @@ impl<'a> Parser<'a> {
Delimiter::Parenthesis, Delimiter::Parenthesis,
',', ',',
|parser| match parser.next_significant_token() { |parser| match parser.next_significant_token() {
Reading::Atomic(Token::Identifier(identifier)) => { Reading::Atomic(Token::Identifier(identifier)) => Ok(identifier),
parser.forward();
Ok(identifier)
}
unexpected => { unexpected => {
let err = Error::UnexpectedSyntax(UnexpectedSyntax { let err = Error::UnexpectedSyntax(UnexpectedSyntax {
expected: syntax::error::SyntaxKind::Identifier, expected: syntax::error::SyntaxKind::Identifier,
@ -597,7 +594,7 @@ impl<'a> Parser<'a> {
Ok(Primary::Lua(Box::new(LuaCode { Ok(Primary::Lua(Box::new(LuaCode {
lua_keyword, lua_keyword,
left_parenthesis: variables.open, left_parenthesis: variables.open,
variables: variables.list, inputs: variables.list,
right_parenthesis: variables.close, right_parenthesis: variables.close,
left_brace: tree.open, left_brace: tree.open,
code: tree.tree?, code: tree.tree?,

View File

@ -1,57 +1,50 @@
//! Conversion functions for converting between tokens/ast-nodes and [`shulkerbox`] types //! 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::{ use crate::{lexical::token::MacroStringLiteral, syntax::syntax_tree::AnyStringLiteral};
lexical::token::{MacroStringLiteral, MacroStringLiteralPart},
syntax::syntax_tree::AnyStringLiteral,
};
impl From<&AnyStringLiteral> for MacroString { use super::util::{MacroString, MacroStringPart};
fn from(value: &AnyStringLiteral) -> Self {
impl From<MacroString> for ExtMacroString {
fn from(value: MacroString) -> Self {
match value { match value {
AnyStringLiteral::StringLiteral(literal) => Self::from(literal.str_content().as_ref()), MacroString::String(s) => Self::String(s),
AnyStringLiteral::MacroStringLiteral(literal) => Self::from(literal), MacroString::MacroString(parts) => {
Self::MacroString(parts.into_iter().map(ExtMacroStringPart::from).collect())
}
} }
} }
} }
impl From<AnyStringLiteral> for MacroString { impl From<MacroStringPart> 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<AnyStringLiteral> for ExtMacroString {
fn from(value: AnyStringLiteral) -> Self { fn from(value: AnyStringLiteral) -> Self {
Self::from(&value) Self::from(&value)
} }
} }
impl From<&MacroStringLiteral> for MacroString { impl From<&MacroStringLiteral> for ExtMacroString {
fn from(value: &MacroStringLiteral) -> Self { fn from(value: &MacroStringLiteral) -> Self {
if value Self::from(MacroString::from(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<MacroStringLiteral> for MacroString { impl From<MacroStringLiteral> for ExtMacroString {
fn from(value: MacroStringLiteral) -> Self { fn from(value: MacroStringLiteral) -> Self {
Self::from(&value) Self::from(&value)
} }

View File

@ -2,7 +2,7 @@
use std::{fmt::Display, sync::Arc}; use std::{fmt::Display, sync::Arc};
use super::{Scope, VariableData}; use super::{util::MacroString, Scope, VariableData};
use crate::{ use crate::{
base::{self, Handler, VoidHandler}, base::{self, Handler, VoidHandler},
lexical::token::MacroStringLiteralPart, lexical::token::MacroStringLiteralPart,
@ -15,10 +15,7 @@ use crate::{
use enum_as_inner::EnumAsInner; use enum_as_inner::EnumAsInner;
#[cfg(feature = "shulkerbox")] #[cfg(feature = "shulkerbox")]
use shulkerbox::{ use shulkerbox::prelude::{Command, Condition, Execute};
prelude::{Command, Condition, Execute},
util::MacroString,
};
#[cfg(feature = "shulkerbox")] #[cfg(feature = "shulkerbox")]
use super::{ use super::{
@ -51,7 +48,7 @@ impl Display for ComptimeValue {
Self::Boolean(boolean) => write!(f, "{boolean}"), Self::Boolean(boolean) => write!(f, "{boolean}"),
Self::Integer(int) => write!(f, "{int}"), Self::Integer(int) => write!(f, "{int}"),
Self::String(string) => write!(f, "{string}"), Self::String(string) => write!(f, "{string}"),
Self::MacroString(macro_string) => write!(f, "{}", macro_string.compile()), Self::MacroString(macro_string) => write!(f, "{macro_string}"),
} }
} }
} }
@ -296,7 +293,7 @@ impl Primary {
Self::Lua(lua) => { Self::Lua(lua) => {
cfg_if::cfg_if! { cfg_if::cfg_if! {
if #[cfg(feature = "lua")] { if #[cfg(feature = "lua")] {
lua.eval(&VoidHandler).map_or(false, |value| match value { lua.eval(scope, &VoidHandler).map_or(false, |(value, _)| match value {
mlua::Value::Boolean(_) => matches!(r#type, ValueType::Boolean), mlua::Value::Boolean(_) => matches!(r#type, ValueType::Boolean),
mlua::Value::Integer(_) => matches!(r#type, ValueType::Integer), mlua::Value::Integer(_) => matches!(r#type, ValueType::Integer),
mlua::Value::String(_) => matches!(r#type, ValueType::String), mlua::Value::String(_) => matches!(r#type, ValueType::String),
@ -345,7 +342,7 @@ impl Primary {
}) })
} }
Self::Lua(lua) => lua Self::Lua(lua) => lua
.eval_comptime(&VoidHandler) .eval_comptime(scope, &VoidHandler)
.inspect_err(|err| { .inspect_err(|err| {
handler.receive(err.clone()); handler.receive(err.clone());
}) })
@ -621,7 +618,7 @@ impl Transpiler {
Primary::Lua(lua) => Primary::Lua(lua) =>
{ {
#[expect(clippy::option_if_let_else)] #[expect(clippy::option_if_let_else)]
if let Some(value) = lua.eval_comptime(handler)? { if let Some(value) = lua.eval_comptime(scope, handler)? {
self.store_comptime_value(&value, target, lua, handler) self.store_comptime_value(&value, target, lua, handler)
} else { } else {
let err = TranspileError::MissingValue(MissingValue { let err = TranspileError::MissingValue(MissingValue {
@ -1033,14 +1030,14 @@ impl Transpiler {
Err(err) Err(err)
} }
}, },
Primary::Lua(lua) => match lua.eval_comptime(handler)? { Primary::Lua(lua) => match lua.eval_comptime(scope, handler)? {
Some(ComptimeValue::String(value)) => Ok(( Some(ComptimeValue::String(value)) => Ok((
Vec::new(), Vec::new(),
ExtendedCondition::Runtime(Condition::Atom(value.into())), ExtendedCondition::Runtime(Condition::Atom(value.into())),
)), )),
Some(ComptimeValue::MacroString(value)) => Ok(( Some(ComptimeValue::MacroString(value)) => Ok((
Vec::new(), Vec::new(),
ExtendedCondition::Runtime(Condition::Atom(value)), ExtendedCondition::Runtime(Condition::Atom(value.into())),
)), )),
Some(ComptimeValue::Boolean(boolean)) => { Some(ComptimeValue::Boolean(boolean)) => {
Ok((Vec::new(), ExtendedCondition::Comptime(boolean))) Ok((Vec::new(), ExtendedCondition::Comptime(boolean)))
@ -1397,7 +1394,7 @@ impl Transpiler {
.. ..
} }
| DataLocation::Tag { .. } => self.store_condition_success( | DataLocation::Tag { .. } => self.store_condition_success(
ExtendedCondition::Runtime(Condition::Atom(value.clone())), ExtendedCondition::Runtime(Condition::Atom(value.clone().into())),
target, target,
source, source,
handler, handler,

View File

@ -2,6 +2,8 @@
#[cfg(feature = "lua")] #[cfg(feature = "lua")]
mod enabled { mod enabled {
use std::sync::Arc;
use mlua::{Lua, Value}; use mlua::{Lua, Value};
use crate::{ use crate::{
@ -10,6 +12,7 @@ mod enabled {
transpile::{ transpile::{
error::{LuaRuntimeError, TranspileError, TranspileResult}, error::{LuaRuntimeError, TranspileError, TranspileResult},
expression::ComptimeValue, expression::ComptimeValue,
Scope, VariableData,
}, },
}; };
@ -19,7 +22,11 @@ mod enabled {
/// # Errors /// # Errors
/// - If evaluation fails /// - If evaluation fails
#[tracing::instrument(level = "debug", name = "eval_lua", skip_all, ret)] #[tracing::instrument(level = "debug", name = "eval_lua", skip_all, ret)]
pub fn eval(&self, handler: &impl Handler<base::Error>) -> TranspileResult<mlua::Value> { pub fn eval(
&self,
scope: &Arc<Scope>,
handler: &impl Handler<base::Error>,
) -> TranspileResult<(mlua::Value, mlua::Lua)> {
tracing::debug!("Evaluating Lua code"); tracing::debug!("Evaluating Lua code");
let lua = Lua::new(); let lua = Lua::new();
@ -46,9 +53,17 @@ mod enabled {
) )
}; };
self.add_globals(&lua).unwrap(); if let Err(err) = self.add_globals(&lua, scope) {
let err = TranspileError::LuaRuntimeError(LuaRuntimeError::from_lua_err(
&err,
self.span(),
));
handler.receive(crate::Error::from(err.clone()));
return Err(err);
}
lua.load(self.code()) let res = lua
.load(self.code())
.set_name(name) .set_name(name)
.eval::<Value>() .eval::<Value>()
.map_err(|err| { .map_err(|err| {
@ -56,7 +71,12 @@ mod enabled {
TranspileError::from(LuaRuntimeError::from_lua_err(&err, self.span())); TranspileError::from(LuaRuntimeError::from_lua_err(&err, self.span()));
handler.receive(crate::Error::from(err.clone())); handler.receive(crate::Error::from(err.clone()));
err err
}) });
res.map(|v| {
tracing::debug!("Lua code evaluated successfully");
(v, lua)
})
} }
/// Evaluates the Lua code and returns the resulting [`ComptimeValue`]. /// Evaluates the Lua code and returns the resulting [`ComptimeValue`].
@ -66,17 +86,16 @@ mod enabled {
#[tracing::instrument(level = "debug", name = "eval_lua", skip_all, ret)] #[tracing::instrument(level = "debug", name = "eval_lua", skip_all, ret)]
pub fn eval_comptime( pub fn eval_comptime(
&self, &self,
scope: &Arc<Scope>,
handler: &impl Handler<base::Error>, handler: &impl Handler<base::Error>,
) -> TranspileResult<Option<ComptimeValue>> { ) -> TranspileResult<Option<ComptimeValue>> {
let lua_result = self.eval(handler)?; // required to keep the lua instance alive
let (lua_result, _lua) = self.eval(scope, handler)?;
self.handle_lua_result(lua_result, handler) self.handle_lua_result(lua_result, handler)
.inspect_err(|err| {
handler.receive(err.clone());
})
} }
fn add_globals(&self, lua: &Lua) -> mlua::Result<()> { fn add_globals(&self, lua: &Lua, scope: &Arc<Scope>) -> mlua::Result<()> {
let globals = lua.globals(); let globals = lua.globals();
let location = { let location = {
@ -86,6 +105,32 @@ mod enabled {
}; };
globals.set("shu_location", location.to_string_lossy())?; globals.set("shu_location", location.to_string_lossy())?;
if let Some(inputs) = self.inputs() {
for x in inputs.elements() {
let name = x.span.str();
let value = match scope.get_variable(name).as_deref() {
Some(VariableData::MacroParameter { macro_name, .. }) => {
Value::String(lua.create_string(format!("$({macro_name})"))?)
}
Some(VariableData::ScoreboardValue { objective, target }) => {
let table = lua.create_table()?;
table.set("objective", lua.create_string(objective)?)?;
table.set("target", lua.create_string(target)?)?;
Value::Table(table)
}
Some(VariableData::BooleanStorage { storage_name, path }) => {
let table = lua.create_table()?;
table.set("storage", lua.create_string(storage_name)?)?;
table.set("path", lua.create_string(path)?)?;
Value::Table(table)
}
Some(_) => todo!("allow other types"),
None => todo!("throw correct error"),
};
globals.set(name, value)?;
}
}
Ok(()) Ok(())
} }
@ -130,13 +175,15 @@ mod enabled {
#[cfg(not(feature = "lua"))] #[cfg(not(feature = "lua"))]
mod disabled { mod disabled {
use std::sync::Arc;
use crate::{ use crate::{
base::{self, Handler}, base::{self, Handler},
syntax::syntax_tree::expression::LuaCode, syntax::syntax_tree::expression::LuaCode,
transpile::error::{TranspileError, TranspileResult}, transpile::error::{TranspileError, TranspileResult},
}; };
use crate::transpile::expression::ComptimeValue; use crate::transpile::{expression::ComptimeValue, Scope};
impl LuaCode { impl LuaCode {
/// Will always return an error because Lua code evaluation is disabled. /// Will always return an error because Lua code evaluation is disabled.
@ -145,7 +192,12 @@ mod disabled {
/// # Errors /// # Errors
/// - Always, as the lua feature is disabled /// - Always, as the lua feature is disabled
#[tracing::instrument(level = "debug", name = "eval_lua", skip_all, ret)] #[tracing::instrument(level = "debug", name = "eval_lua", skip_all, ret)]
pub fn eval(&self, handler: &impl Handler<base::Error>) -> TranspileResult<()> { pub fn eval(
&self,
scope: &Arc<Scope>,
handler: &impl Handler<base::Error>,
) -> TranspileResult<()> {
let _ = scope;
handler.receive(TranspileError::LuaDisabled); handler.receive(TranspileError::LuaDisabled);
tracing::error!("Lua code evaluation is disabled"); tracing::error!("Lua code evaluation is disabled");
Err(TranspileError::LuaDisabled) Err(TranspileError::LuaDisabled)
@ -158,8 +210,10 @@ mod disabled {
/// - If Lua code evaluation is disabled. /// - If Lua code evaluation is disabled.
pub fn eval_comptime( pub fn eval_comptime(
&self, &self,
scope: &Arc<Scope>,
handler: &impl Handler<base::Error>, handler: &impl Handler<base::Error>,
) -> TranspileResult<Option<ComptimeValue>> { ) -> TranspileResult<Option<ComptimeValue>> {
let _ = scope;
handler.receive(TranspileError::LuaDisabled); handler.receive(TranspileError::LuaDisabled);
tracing::error!("Lua code evaluation is disabled"); tracing::error!("Lua code evaluation is disabled");
Err(TranspileError::LuaDisabled) Err(TranspileError::LuaDisabled)

View File

@ -8,10 +8,7 @@ use std::{
sync::{Arc, OnceLock}, sync::{Arc, OnceLock},
}; };
use shulkerbox::{ use shulkerbox::datapack::{self, Command, Datapack, Execute};
datapack::{self, Command, Datapack, Execute},
util::{MacroString, MacroStringPart},
};
use crate::{ use crate::{
base::{ base::{
@ -30,7 +27,10 @@ use crate::{
}, },
AnnotationAssignment, AnnotationAssignment,
}, },
transpile::error::{IllegalAnnotationContent, MissingFunctionDeclaration}, transpile::{
error::{IllegalAnnotationContent, MissingFunctionDeclaration},
util::{MacroString, MacroStringPart},
},
}; };
use super::{ use super::{
@ -439,7 +439,7 @@ impl Transpiler {
for expression in arguments.iter().flat_map(|x| x.iter()) { for expression in arguments.iter().flat_map(|x| x.iter()) {
let value = match expression { let value = match expression {
Expression::Primary(Primary::Lua(lua)) => { Expression::Primary(Primary::Lua(lua)) => {
lua.eval_comptime(handler).and_then(|val| match val { lua.eval_comptime(scope, handler).and_then(|val| match val {
Some(ComptimeValue::MacroString(s)) => Ok(Parameter::Static(s)), Some(ComptimeValue::MacroString(s)) => Ok(Parameter::Static(s)),
Some(val) => Ok(Parameter::Static(val.to_string().into())), Some(val) => Ok(Parameter::Static(val.to_string().into())),
None => { None => {
@ -604,16 +604,17 @@ impl Transpiler {
MacroString::String(s) => Command::Raw(format!( MacroString::String(s) => Command::Raw(format!(
r#"data merge storage shulkerscript:function_arguments {{{s}}}"# r#"data merge storage shulkerscript:function_arguments {{{s}}}"#
)), )),
MacroString::MacroString(_) => { MacroString::MacroString(_) => Command::UsesMacro(
Command::UsesMacro(super::util::join_macro_strings([ super::util::join_macro_strings([
MacroString::String( MacroString::String(
"data merge storage shulkerscript:function_arguments {" "data merge storage shulkerscript:function_arguments {"
.to_string(), .to_string(),
), ),
joined_statics, joined_statics,
MacroString::String("}".to_string()), MacroString::String("}".to_string()),
])) ])
} .into(),
),
}; };
setup_cmds.push(statics_cmd); setup_cmds.push(statics_cmd);
setup_cmds.extend(move_cmds); setup_cmds.extend(move_cmds);
@ -782,9 +783,9 @@ impl Transpiler {
Expression::Primary(Primary::MacroStringLiteral(string)) => { Expression::Primary(Primary::MacroStringLiteral(string)) => {
Ok(vec![Command::UsesMacro(string.into())]) Ok(vec![Command::UsesMacro(string.into())])
} }
Expression::Primary(Primary::Lua(code)) => match code.eval_comptime(handler)? { Expression::Primary(Primary::Lua(code)) => match code.eval_comptime(scope, handler)? {
Some(ComptimeValue::String(cmd)) => Ok(vec![Command::Raw(cmd)]), 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(_)) => { Some(ComptimeValue::Boolean(_) | ComptimeValue::Integer(_)) => {
let err = TranspileError::MismatchedTypes(MismatchedTypes { let err = TranspileError::MismatchedTypes(MismatchedTypes {
expected_type: ExpectedType::String, expected_type: ExpectedType::String,
@ -805,7 +806,7 @@ impl Transpiler {
), ),
Expression::Binary(bin) => match bin.comptime_eval(scope, handler) { Expression::Binary(bin) => match bin.comptime_eval(scope, handler) {
Some(ComptimeValue::String(cmd)) => Ok(vec![Command::Raw(cmd)]), 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 { let err = TranspileError::MismatchedTypes(MismatchedTypes {
expression: bin.span(), expression: bin.span(),
@ -870,7 +871,7 @@ impl Transpiler {
function_call.push_str(" {"); function_call.push_str(" {");
parts.insert(0, MacroStringPart::String(function_call)); parts.insert(0, MacroStringPart::String(function_call));
parts.push(MacroStringPart::String('}'.to_string())); parts.push(MacroStringPart::String('}'.to_string()));
Command::UsesMacro(MacroString::MacroString(parts)) Command::UsesMacro(MacroString::MacroString(parts).into())
} }
}; };

View File

@ -1,6 +1,48 @@
//! Utility methods for transpiling //! 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<MacroStringPart>),
}
/// 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<S>(identifier: S) -> String fn normalize_program_identifier<S>(identifier: S) -> String
where where
@ -71,3 +113,62 @@ where
}, },
}) })
} }
impl<S> From<S> for MacroString
where
S: Into<String>,
{
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<AnyStringLiteral> 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<MacroStringLiteral> for MacroString {
fn from(value: MacroStringLiteral) -> Self {
Self::from(&value)
}
}