Compare commits

..

No commits in common. "7290806a2bc8eb059a102a68042d6246ee3a0e21" and "863bc784cc4a2dd4fd80c5c77559ff8185487fc5" have entirely different histories.

6 changed files with 81 additions and 224 deletions

View File

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

View File

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

View File

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

View File

@ -2,8 +2,6 @@
#[cfg(feature = "lua")]
mod enabled {
use std::sync::Arc;
use mlua::{Lua, Value};
use crate::{
@ -12,7 +10,6 @@ mod enabled {
transpile::{
error::{LuaRuntimeError, TranspileError, TranspileResult},
expression::ComptimeValue,
Scope, VariableData,
},
};
@ -22,11 +19,7 @@ mod enabled {
/// # Errors
/// - If evaluation fails
#[tracing::instrument(level = "debug", name = "eval_lua", skip_all, ret)]
pub fn eval(
&self,
scope: &Arc<Scope>,
handler: &impl Handler<base::Error>,
) -> TranspileResult<(mlua::Value, mlua::Lua)> {
pub fn eval(&self, handler: &impl Handler<base::Error>) -> TranspileResult<mlua::Value> {
tracing::debug!("Evaluating Lua code");
let lua = Lua::new();
@ -53,17 +46,9 @@ mod enabled {
)
};
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);
}
self.add_globals(&lua).unwrap();
let res = lua
.load(self.code())
lua.load(self.code())
.set_name(name)
.eval::<Value>()
.map_err(|err| {
@ -71,12 +56,7 @@ mod enabled {
TranspileError::from(LuaRuntimeError::from_lua_err(&err, self.span()));
handler.receive(crate::Error::from(err.clone()));
err
});
res.map(|v| {
tracing::debug!("Lua code evaluated successfully");
(v, lua)
})
})
}
/// Evaluates the Lua code and returns the resulting [`ComptimeValue`].
@ -86,16 +66,17 @@ mod enabled {
#[tracing::instrument(level = "debug", name = "eval_lua", skip_all, ret)]
pub fn eval_comptime(
&self,
scope: &Arc<Scope>,
handler: &impl Handler<base::Error>,
) -> TranspileResult<Option<ComptimeValue>> {
// required to keep the lua instance alive
let (lua_result, _lua) = self.eval(scope, handler)?;
let lua_result = self.eval(handler)?;
self.handle_lua_result(lua_result, handler)
.inspect_err(|err| {
handler.receive(err.clone());
})
}
fn add_globals(&self, lua: &Lua, scope: &Arc<Scope>) -> mlua::Result<()> {
fn add_globals(&self, lua: &Lua) -> mlua::Result<()> {
let globals = lua.globals();
let location = {
@ -105,32 +86,6 @@ mod enabled {
};
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(())
}
@ -175,15 +130,13 @@ 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, Scope};
use crate::transpile::expression::ComptimeValue;
impl LuaCode {
/// Will always return an error because Lua code evaluation is disabled.
@ -192,12 +145,7 @@ mod disabled {
/// # Errors
/// - Always, as the lua feature is disabled
#[tracing::instrument(level = "debug", name = "eval_lua", skip_all, ret)]
pub fn eval(
&self,
scope: &Arc<Scope>,
handler: &impl Handler<base::Error>,
) -> TranspileResult<()> {
let _ = scope;
pub fn eval(&self, handler: &impl Handler<base::Error>) -> TranspileResult<()> {
handler.receive(TranspileError::LuaDisabled);
tracing::error!("Lua code evaluation is disabled");
Err(TranspileError::LuaDisabled)
@ -210,10 +158,8 @@ mod disabled {
/// - If Lua code evaluation is disabled.
pub fn eval_comptime(
&self,
scope: &Arc<Scope>,
handler: &impl Handler<base::Error>,
) -> TranspileResult<Option<ComptimeValue>> {
let _ = scope;
handler.receive(TranspileError::LuaDisabled);
tracing::error!("Lua code evaluation is disabled");
Err(TranspileError::LuaDisabled)

View File

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

View File

@ -1,48 +1,6 @@
//! Utility methods for transpiling
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(())
}
}
}
}
use shulkerbox::util::{MacroString, MacroStringPart};
fn normalize_program_identifier<S>(identifier: S) -> String
where
@ -113,62 +71,3 @@ 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)
}
}