Compare commits
2 Commits
863bc784cc
...
7290806a2b
Author | SHA1 | Date |
---|---|---|
|
7290806a2b | |
|
e4c06e56ee |
|
@ -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?,
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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())
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue