reimplement semantic checking
This commit is contained in:
parent
f3b3d5d3b6
commit
32d453ebef
|
@ -2,10 +2,7 @@
|
|||
|
||||
#![allow(missing_docs)]
|
||||
|
||||
use std::{collections::HashSet, fmt::Display};
|
||||
|
||||
use getset::Getters;
|
||||
use itertools::Itertools as _;
|
||||
use std::fmt::Display;
|
||||
|
||||
use crate::{
|
||||
base::{
|
||||
|
@ -14,6 +11,10 @@ use crate::{
|
|||
},
|
||||
lexical::token::StringLiteral,
|
||||
syntax::syntax_tree::expression::Expression,
|
||||
transpile::error::{
|
||||
AssignmentError, IllegalIndexing, MismatchedTypes, MissingFunctionDeclaration,
|
||||
UnknownIdentifier,
|
||||
},
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, thiserror::Error)]
|
||||
|
@ -31,77 +32,20 @@ pub enum Error {
|
|||
UnresolvedMacroUsage(#[from] UnresolvedMacroUsage),
|
||||
#[error(transparent)]
|
||||
IncompatibleFunctionAnnotation(#[from] IncompatibleFunctionAnnotation),
|
||||
#[error(transparent)]
|
||||
IllegalIndexing(#[from] IllegalIndexing),
|
||||
#[error(transparent)]
|
||||
MismatchedTypes(#[from] MismatchedTypes),
|
||||
#[error(transparent)]
|
||||
UnknownIdentifier(#[from] UnknownIdentifier),
|
||||
#[error(transparent)]
|
||||
AssignmentError(#[from] AssignmentError),
|
||||
#[error("Lua is disabled, but a Lua function was used.")]
|
||||
LuaDisabled,
|
||||
#[error("Other: {0}")]
|
||||
Other(String),
|
||||
}
|
||||
|
||||
// TODO: remove duplicate error (also in transpile)
|
||||
/// An error that occurs when a function declaration is missing.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Getters)]
|
||||
pub struct MissingFunctionDeclaration {
|
||||
#[get = "pub"]
|
||||
span: Span,
|
||||
#[get = "pub"]
|
||||
alternatives: Vec<String>,
|
||||
}
|
||||
|
||||
impl MissingFunctionDeclaration {
|
||||
#[expect(dead_code)]
|
||||
pub(super) fn from_context(identifier_span: Span, functions: &HashSet<String>) -> Self {
|
||||
let own_name = identifier_span.str();
|
||||
let alternatives = functions
|
||||
.iter()
|
||||
.filter_map(|function_name| {
|
||||
let normalized_distance =
|
||||
strsim::normalized_damerau_levenshtein(own_name, function_name);
|
||||
(normalized_distance > 0.8
|
||||
|| strsim::damerau_levenshtein(own_name, function_name) < 3)
|
||||
.then_some((normalized_distance, function_name))
|
||||
})
|
||||
.sorted_by(|a, b| a.0.partial_cmp(&b.0).unwrap_or(std::cmp::Ordering::Equal))
|
||||
.map(|(_, data)| data)
|
||||
.take(8)
|
||||
.cloned()
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
Self {
|
||||
alternatives,
|
||||
span: identifier_span,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for MissingFunctionDeclaration {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
use std::fmt::Write;
|
||||
|
||||
let message = format!(
|
||||
"no matching function declaration found for invocation of function `{}`",
|
||||
self.span.str()
|
||||
);
|
||||
write!(f, "{}", Message::new(Severity::Error, message))?;
|
||||
|
||||
let help_message = if self.alternatives.is_empty() {
|
||||
None
|
||||
} else {
|
||||
let mut message = String::from("did you mean ");
|
||||
for (i, alternative) in self.alternatives.iter().enumerate() {
|
||||
if i > 0 {
|
||||
message.push_str(", ");
|
||||
}
|
||||
write!(message, "`{alternative}`")?;
|
||||
}
|
||||
Some(message + "?")
|
||||
};
|
||||
|
||||
write!(
|
||||
f,
|
||||
"\n{}",
|
||||
SourceCodeDisplay::new(&self.span, help_message.as_ref())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for MissingFunctionDeclaration {}
|
||||
|
||||
/// An error that occurs when a function declaration is missing.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct UnexpectedExpression(pub Expression);
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,95 @@
|
|||
use std::{collections::HashMap, sync::RwLock};
|
||||
|
||||
/// Type of variable
|
||||
#[derive(Clone, Debug, Copy, PartialEq, Eq)]
|
||||
pub enum VariableType {
|
||||
/// A function.
|
||||
Function,
|
||||
/// A macro function parameter.
|
||||
MacroParameter,
|
||||
/// A scoreboard.
|
||||
Scoreboard,
|
||||
/// A scoreboard value.
|
||||
ScoreboardValue,
|
||||
/// Multiple values stored in scoreboard.
|
||||
ScoreboardArray,
|
||||
/// A tag applied to entities.
|
||||
Tag,
|
||||
/// A boolean stored in a data storage.
|
||||
BooleanStorage,
|
||||
/// Multiple booleans stored in a data storage array.
|
||||
BooleanStorageArray,
|
||||
/// Compiler internal function.
|
||||
InternalFunction,
|
||||
}
|
||||
|
||||
/// A scope that stores variables.
|
||||
#[derive(Debug, Default)]
|
||||
pub struct SemanticScope<'a> {
|
||||
/// Parent scope where variables are inherited from.
|
||||
parent: Option<&'a Self>,
|
||||
/// Variables stored in the scope.
|
||||
variables: RwLock<HashMap<String, VariableType>>,
|
||||
}
|
||||
|
||||
impl<'a> SemanticScope<'a> {
|
||||
/// Creates a new scope.
|
||||
#[must_use]
|
||||
pub fn new() -> Self {
|
||||
let scope = Self::default();
|
||||
|
||||
scope.set_variable("print", VariableType::InternalFunction);
|
||||
|
||||
scope
|
||||
}
|
||||
|
||||
/// Creates a new scope with a parent.
|
||||
#[must_use]
|
||||
pub fn with_parent(parent: &'a Self) -> Self {
|
||||
Self {
|
||||
parent: Some(parent),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets a variable from the scope.
|
||||
pub fn get_variable(&self, name: &str) -> Option<VariableType> {
|
||||
let var = self.variables.read().unwrap().get(name).copied();
|
||||
if var.is_some() {
|
||||
var
|
||||
} else {
|
||||
self.parent
|
||||
.as_ref()
|
||||
.and_then(|parent| parent.get_variable(name))
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets a variable in the scope.
|
||||
pub fn set_variable(&self, name: &str, var: VariableType) {
|
||||
self.variables
|
||||
.write()
|
||||
.unwrap()
|
||||
.insert(name.to_string(), var);
|
||||
}
|
||||
|
||||
/// Gets the variables stored in the current scope.
|
||||
pub fn get_local_variables(&self) -> &RwLock<HashMap<String, VariableType>> {
|
||||
&self.variables
|
||||
}
|
||||
|
||||
/// Gets all variables stored in the scope.
|
||||
///
|
||||
/// This function does not return a reference to the variables, but clones them.
|
||||
pub fn get_all_variables(&self) -> HashMap<String, VariableType> {
|
||||
let mut variables = self.variables.read().unwrap().clone();
|
||||
if let Some(parent) = self.parent.as_ref() {
|
||||
variables.extend(parent.get_all_variables());
|
||||
}
|
||||
variables
|
||||
}
|
||||
|
||||
/// Gets the parent scope.
|
||||
pub fn get_parent(&self) -> Option<&Self> {
|
||||
self.parent
|
||||
}
|
||||
}
|
|
@ -247,6 +247,14 @@ impl SourceElement for Parenthesized {
|
|||
}
|
||||
}
|
||||
|
||||
impl std::ops::Deref for Parenthesized {
|
||||
type Target = Expression;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.expression
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents a indexed expression in the syntax tree.
|
||||
///
|
||||
/// Syntax Synopsis:
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
//! Execute block statement syntax tree.
|
||||
|
||||
use std::collections::HashSet;
|
||||
|
||||
use derive_more::From;
|
||||
use enum_as_inner::EnumAsInner;
|
||||
use getset::Getters;
|
||||
|
@ -998,10 +996,10 @@ pub trait ExecuteBlockHeadItem {
|
|||
#[expect(clippy::missing_errors_doc)]
|
||||
fn analyze_semantics(
|
||||
&self,
|
||||
macro_names: &HashSet<String>,
|
||||
scope: &crate::semantic::SemanticScope,
|
||||
handler: &impl Handler<base::Error>,
|
||||
) -> Result<(), crate::semantic::error::Error> {
|
||||
self.selector().analyze_semantics(macro_names, handler)
|
||||
self.selector().analyze_semantics(scope, handler)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -44,6 +44,8 @@ pub enum TranspileError {
|
|||
MissingValue(#[from] MissingValue),
|
||||
#[error(transparent)]
|
||||
IllegalIndexing(#[from] IllegalIndexing),
|
||||
#[error(transparent)]
|
||||
InvalidArgument(#[from] InvalidArgument),
|
||||
}
|
||||
|
||||
/// The result of a transpilation operation.
|
||||
|
@ -52,8 +54,10 @@ pub type TranspileResult<T> = Result<T, TranspileError>;
|
|||
/// An error that occurs when a function declaration is missing.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Getters)]
|
||||
pub struct MissingFunctionDeclaration {
|
||||
/// The span of the identifier that is missing.
|
||||
#[get = "pub"]
|
||||
span: Span,
|
||||
/// Possible alternatives for the missing function declaration.
|
||||
#[get = "pub"]
|
||||
alternatives: Vec<FunctionData>,
|
||||
}
|
||||
|
@ -127,11 +131,26 @@ impl Display for MissingFunctionDeclaration {
|
|||
|
||||
impl std::error::Error for MissingFunctionDeclaration {}
|
||||
|
||||
impl std::hash::Hash for MissingFunctionDeclaration {
|
||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||
self.span.hash(state);
|
||||
for alternative in &self.alternatives {
|
||||
alternative.identifier_span.hash(state);
|
||||
alternative.namespace.hash(state);
|
||||
alternative.parameters.hash(state);
|
||||
alternative.public.hash(state);
|
||||
alternative.statements.hash(state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An error that occurs when a function declaration is missing.
|
||||
#[allow(clippy::module_name_repetitions)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct LuaRuntimeError {
|
||||
/// The span of the code block that caused the error.
|
||||
pub code_block: Span,
|
||||
/// The error message of the Lua runtime.
|
||||
pub error_message: String,
|
||||
}
|
||||
|
||||
|
@ -155,6 +174,8 @@ impl std::error::Error for LuaRuntimeError {}
|
|||
|
||||
#[cfg(feature = "lua")]
|
||||
impl LuaRuntimeError {
|
||||
/// Creates a new Lua runtime error from an mlua error.
|
||||
#[must_use]
|
||||
pub fn from_lua_err(err: &mlua::Error, span: Span) -> Self {
|
||||
let err_string = err.to_string();
|
||||
Self {
|
||||
|
@ -168,9 +189,13 @@ impl LuaRuntimeError {
|
|||
}
|
||||
|
||||
/// An error that occurs when an annotation has an illegal content.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Getters)]
|
||||
pub struct IllegalAnnotationContent {
|
||||
/// The span of the annotation.
|
||||
#[get = "pub"]
|
||||
pub annotation: Span,
|
||||
/// The error message.
|
||||
#[get = "pub"]
|
||||
pub message: String,
|
||||
}
|
||||
|
||||
|
@ -194,9 +219,13 @@ impl Display for IllegalAnnotationContent {
|
|||
impl std::error::Error for IllegalAnnotationContent {}
|
||||
|
||||
/// An error that occurs when an expression can not evaluate to the wanted type.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Getters)]
|
||||
pub struct MismatchedTypes {
|
||||
/// The expression that can not evaluate to the wanted type.
|
||||
#[get = "pub"]
|
||||
pub expression: Span,
|
||||
/// The expected type.
|
||||
#[get = "pub"]
|
||||
pub expected_type: ExpectedType,
|
||||
}
|
||||
|
||||
|
@ -216,9 +245,13 @@ impl Display for MismatchedTypes {
|
|||
impl std::error::Error for MismatchedTypes {}
|
||||
|
||||
/// An error that occurs when an expression can not evaluate to the wanted type.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Getters)]
|
||||
pub struct FunctionArgumentsNotAllowed {
|
||||
/// The arguments that are not allowed.
|
||||
#[get = "pub"]
|
||||
pub arguments: Span,
|
||||
/// The error message.
|
||||
#[get = "pub"]
|
||||
pub message: String,
|
||||
}
|
||||
|
||||
|
@ -237,9 +270,13 @@ impl Display for FunctionArgumentsNotAllowed {
|
|||
impl std::error::Error for FunctionArgumentsNotAllowed {}
|
||||
|
||||
/// An error that occurs when an expression can not evaluate to the wanted type.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Getters)]
|
||||
pub struct AssignmentError {
|
||||
/// The identifier that is assigned to.
|
||||
#[get = "pub"]
|
||||
pub identifier: Span,
|
||||
/// The error message.
|
||||
#[get = "pub"]
|
||||
pub message: String,
|
||||
}
|
||||
|
||||
|
@ -258,8 +295,10 @@ impl Display for AssignmentError {
|
|||
impl std::error::Error for AssignmentError {}
|
||||
|
||||
/// An error that occurs when an unknown identifier is used.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Getters)]
|
||||
pub struct UnknownIdentifier {
|
||||
/// The unknown identifier.
|
||||
#[get = "pub"]
|
||||
pub identifier: Span,
|
||||
}
|
||||
|
||||
|
@ -285,8 +324,10 @@ impl Display for UnknownIdentifier {
|
|||
impl std::error::Error for UnknownIdentifier {}
|
||||
|
||||
/// An error that occurs when there is a value expected but none provided.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Getters)]
|
||||
pub struct MissingValue {
|
||||
/// The expression that is missing a value.
|
||||
#[get = "pub"]
|
||||
pub expression: Span,
|
||||
}
|
||||
|
||||
|
@ -312,9 +353,13 @@ impl Display for MissingValue {
|
|||
impl std::error::Error for MissingValue {}
|
||||
|
||||
/// An error that occurs when an indexing operation is not permitted.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Getters)]
|
||||
pub struct IllegalIndexing {
|
||||
/// The reason why the indexing operation is not permitted.
|
||||
#[get = "pub"]
|
||||
pub reason: IllegalIndexingReason,
|
||||
/// The expression that is the reason for the indexing being illegal.
|
||||
#[get = "pub"]
|
||||
pub expression: Span,
|
||||
}
|
||||
|
||||
|
@ -333,11 +378,24 @@ impl Display for IllegalIndexing {
|
|||
impl std::error::Error for IllegalIndexing {}
|
||||
|
||||
/// The reason why an indexing operation is not permitted.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum IllegalIndexingReason {
|
||||
/// The expression is not an identifier.
|
||||
NotIdentifier,
|
||||
InvalidComptimeType { expected: ExpectedType },
|
||||
IndexOutOfBounds { index: usize, length: usize },
|
||||
/// The expression cannot be indexed.
|
||||
NotIndexable,
|
||||
/// The expression can only be indexed with a specific type that can be evaluated at compile time.
|
||||
InvalidComptimeType {
|
||||
/// The expected type.
|
||||
expected: ExpectedType,
|
||||
},
|
||||
/// The index is out of bounds.
|
||||
IndexOutOfBounds {
|
||||
/// The index that is out of bounds.
|
||||
index: usize,
|
||||
/// The length indexed object.
|
||||
length: usize,
|
||||
},
|
||||
}
|
||||
|
||||
impl Display for IllegalIndexingReason {
|
||||
|
@ -346,6 +404,9 @@ impl Display for IllegalIndexingReason {
|
|||
Self::NotIdentifier => {
|
||||
write!(f, "The expression is not an identifier.")
|
||||
}
|
||||
Self::NotIndexable => {
|
||||
write!(f, "The expression cannot be indexed.")
|
||||
}
|
||||
Self::InvalidComptimeType { expected } => {
|
||||
write!(
|
||||
f,
|
||||
|
@ -361,3 +422,28 @@ impl Display for IllegalIndexingReason {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An error that occurs when an indexing operation is not permitted.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Getters)]
|
||||
pub struct InvalidArgument {
|
||||
/// The span of the argument.
|
||||
#[get = "pub"]
|
||||
pub span: Span,
|
||||
/// The reason why the argument is invalid.
|
||||
#[get = "pub"]
|
||||
pub reason: String,
|
||||
}
|
||||
|
||||
impl Display for InvalidArgument {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", Message::new(Severity::Error, &self.reason))?;
|
||||
|
||||
write!(
|
||||
f,
|
||||
"\n{}",
|
||||
SourceCodeDisplay::new(&self.span, Option::<u8>::None)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for InvalidArgument {}
|
||||
|
|
|
@ -85,7 +85,7 @@ impl Display for ValueType {
|
|||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum ExpectedType {
|
||||
Boolean,
|
||||
Integer,
|
||||
|
@ -915,7 +915,7 @@ impl Transpiler {
|
|||
}
|
||||
}
|
||||
|
||||
fn transpile_binary_expression(
|
||||
pub(super) fn transpile_binary_expression(
|
||||
&mut self,
|
||||
binary: &Binary,
|
||||
target: &DataLocation,
|
||||
|
|
|
@ -361,7 +361,18 @@ impl Transpiler {
|
|||
path: std::mem::take(&mut temp_path[0]),
|
||||
})
|
||||
}
|
||||
_ => todo!("other variable types"),
|
||||
_ => {
|
||||
let err = TranspileError::MismatchedTypes(MismatchedTypes {
|
||||
expression: expression.span(),
|
||||
expected_type: ExpectedType::AnyOf(vec![
|
||||
ExpectedType::Integer,
|
||||
ExpectedType::Boolean,
|
||||
ExpectedType::String,
|
||||
]),
|
||||
});
|
||||
handler.receive(err.clone());
|
||||
Err(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
Expression::Primary(
|
||||
|
|
|
@ -5,6 +5,7 @@ use std::{
|
|||
sync::Arc,
|
||||
};
|
||||
|
||||
use cfg_if::cfg_if;
|
||||
use shulkerbox::prelude::{Command, Execute};
|
||||
|
||||
use serde_json::{json, Value as JsonValue};
|
||||
|
@ -15,8 +16,8 @@ use crate::{
|
|||
semantic::error::{InvalidFunctionArguments, UnexpectedExpression},
|
||||
syntax::syntax_tree::expression::{Expression, FunctionCall, Primary},
|
||||
transpile::{
|
||||
error::{IllegalIndexing, IllegalIndexingReason, LuaRuntimeError, UnknownIdentifier},
|
||||
expression::{ComptimeValue, DataLocation, StorageType},
|
||||
error::{IllegalIndexing, IllegalIndexingReason, UnknownIdentifier},
|
||||
expression::{ComptimeValue, DataLocation, ExpectedType, StorageType},
|
||||
util::MacroString,
|
||||
TranspileError,
|
||||
},
|
||||
|
@ -210,17 +211,24 @@ fn print_function(
|
|||
Vec::new(),
|
||||
vec![JsonValue::String(string.str_content().to_string())],
|
||||
)),
|
||||
#[cfg_attr(not(feature = "lua"), expect(unused_variables))]
|
||||
Primary::Lua(lua) => {
|
||||
let (ret, _lua) = lua.eval(scope, &VoidHandler)?;
|
||||
Ok((
|
||||
Vec::new(),
|
||||
vec![JsonValue::String(ret.to_string().map_err(|err| {
|
||||
TranspileError::LuaRuntimeError(LuaRuntimeError::from_lua_err(
|
||||
&err,
|
||||
lua.span(),
|
||||
cfg_if! {
|
||||
if #[cfg(feature = "lua")] {
|
||||
let (ret, _lua) = lua.eval(scope, &VoidHandler)?;
|
||||
Ok((
|
||||
Vec::new(),
|
||||
vec![JsonValue::String(ret.to_string().map_err(|err| {
|
||||
TranspileError::LuaRuntimeError(super::error::LuaRuntimeError::from_lua_err(
|
||||
&err,
|
||||
lua.span(),
|
||||
))
|
||||
})?)],
|
||||
))
|
||||
})?)],
|
||||
))
|
||||
} else {
|
||||
Err(TranspileError::LuaDisabled)
|
||||
}
|
||||
}
|
||||
}
|
||||
Primary::Identifier(ident) => {
|
||||
let (cur_contains_macro, cmd, part) =
|
||||
|
@ -244,7 +252,13 @@ fn print_function(
|
|||
);
|
||||
Ok((cmd.into_iter().collect(), vec![value]))
|
||||
} else {
|
||||
todo!("allow macro string, but throw error when index is not constant string")
|
||||
// TODO: allow macro string, but throw error when index is not constant string
|
||||
Err(TranspileError::IllegalIndexing(IllegalIndexing {
|
||||
reason: IllegalIndexingReason::InvalidComptimeType {
|
||||
expected: ExpectedType::String,
|
||||
},
|
||||
expression: indexed.index().span(),
|
||||
}))
|
||||
}
|
||||
}
|
||||
Some(VariableData::ScoreboardArray { objective, targets }) => {
|
||||
|
@ -274,7 +288,12 @@ fn print_function(
|
|||
}))
|
||||
}
|
||||
} else {
|
||||
todo!("throw error when index is not constant integer")
|
||||
Err(TranspileError::IllegalIndexing(IllegalIndexing {
|
||||
reason: IllegalIndexingReason::InvalidComptimeType {
|
||||
expected: ExpectedType::Integer,
|
||||
},
|
||||
expression: indexed.index().span(),
|
||||
}))
|
||||
}
|
||||
}
|
||||
Some(VariableData::BooleanStorageArray {
|
||||
|
@ -308,10 +327,18 @@ fn print_function(
|
|||
}))
|
||||
}
|
||||
} else {
|
||||
todo!("throw error when index is not constant integer")
|
||||
Err(TranspileError::IllegalIndexing(IllegalIndexing {
|
||||
reason: IllegalIndexingReason::InvalidComptimeType {
|
||||
expected: ExpectedType::Integer,
|
||||
},
|
||||
expression: indexed.index().span(),
|
||||
}))
|
||||
}
|
||||
}
|
||||
_ => todo!("catch illegal indexing"),
|
||||
_ => Err(TranspileError::IllegalIndexing(IllegalIndexing {
|
||||
reason: IllegalIndexingReason::NotIndexable,
|
||||
expression: indexed.object().span(),
|
||||
})),
|
||||
}
|
||||
}
|
||||
_ => Err(TranspileError::IllegalIndexing(IllegalIndexing {
|
||||
|
@ -339,9 +366,43 @@ fn print_function(
|
|||
Ok((cmds, parts))
|
||||
}
|
||||
|
||||
_ => todo!("print_function Primary"),
|
||||
primary => {
|
||||
let (storage_name, mut storage_paths) = transpiler.get_temp_storage_locations(1);
|
||||
let location = DataLocation::Storage {
|
||||
storage_name,
|
||||
path: std::mem::take(&mut storage_paths[0]),
|
||||
r#type: StorageType::Int,
|
||||
};
|
||||
let cmds = transpiler.transpile_primary_expression(
|
||||
primary,
|
||||
&location,
|
||||
scope,
|
||||
&VoidHandler,
|
||||
)?;
|
||||
let (cmd, part) = get_data_location(&location, transpiler);
|
||||
|
||||
Ok((
|
||||
cmds.into_iter().chain(cmd.into_iter()).collect(),
|
||||
vec![part],
|
||||
))
|
||||
}
|
||||
},
|
||||
Expression::Binary(_) => todo!("print_function Binary"),
|
||||
Expression::Binary(binary) => {
|
||||
let (storage_name, mut storage_paths) = transpiler.get_temp_storage_locations(1);
|
||||
let location = DataLocation::Storage {
|
||||
storage_name,
|
||||
path: std::mem::take(&mut storage_paths[0]),
|
||||
r#type: StorageType::Int,
|
||||
};
|
||||
let cmds =
|
||||
transpiler.transpile_binary_expression(binary, &location, scope, &VoidHandler)?;
|
||||
let (cmd, part) = get_data_location(&location, transpiler);
|
||||
|
||||
Ok((
|
||||
cmds.into_iter().chain(cmd.into_iter()).collect(),
|
||||
vec![part],
|
||||
))
|
||||
}
|
||||
}?;
|
||||
|
||||
// TODO: prepend prefix with datapack name to parts and remove following
|
||||
|
|
|
@ -12,7 +12,7 @@ mod enabled {
|
|||
syntax::syntax_tree::expression::LuaCode,
|
||||
transpile::{
|
||||
error::{
|
||||
LuaRuntimeError, MismatchedTypes, TranspileError, TranspileResult,
|
||||
InvalidArgument, LuaRuntimeError, MismatchedTypes, TranspileError, TranspileResult,
|
||||
UnknownIdentifier,
|
||||
},
|
||||
expression::{ComptimeValue, ExpectedType},
|
||||
|
@ -263,7 +263,11 @@ mod enabled {
|
|||
Value::Table(table)
|
||||
}
|
||||
Some(VariableData::Function { .. } | VariableData::InternalFunction { .. }) => {
|
||||
todo!("(internal) functions are not supported yet");
|
||||
// TODO: add support for functions
|
||||
return Err(TranspileError::InvalidArgument(InvalidArgument {
|
||||
reason: "functions cannot be passed to Lua".to_string(),
|
||||
span: identifier.span(),
|
||||
}));
|
||||
}
|
||||
None => {
|
||||
return Err(TranspileError::UnknownIdentifier(UnknownIdentifier {
|
||||
|
@ -397,7 +401,7 @@ mod disabled {
|
|||
&self,
|
||||
scope: &Arc<Scope>,
|
||||
handler: &impl Handler<base::Error>,
|
||||
) -> TranspileResult<()> {
|
||||
) -> TranspileResult<((), ())> {
|
||||
let _ = scope;
|
||||
handler.receive(TranspileError::LuaDisabled);
|
||||
tracing::error!("Lua code evaluation is disabled");
|
||||
|
|
|
@ -16,7 +16,7 @@ use crate::{
|
|||
#[doc(hidden)]
|
||||
#[cfg(feature = "shulkerbox")]
|
||||
pub mod conversions;
|
||||
mod error;
|
||||
pub mod error;
|
||||
|
||||
pub mod expression;
|
||||
|
||||
|
@ -58,7 +58,7 @@ pub struct FunctionData {
|
|||
|
||||
/// Possible values for an annotation.
|
||||
#[expect(clippy::module_name_repetitions)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, EnumIs)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, EnumIs)]
|
||||
pub enum TranspileAnnotationValue {
|
||||
/// No value.
|
||||
None,
|
||||
|
|
|
@ -489,7 +489,15 @@ impl Transpiler {
|
|||
target: s,
|
||||
}),
|
||||
Some(ComptimeValue::MacroString(s)) => {
|
||||
todo!("indexing scoreboard with macro string: {s:?}")
|
||||
// TODO: allow indexing with macro string
|
||||
let err = TranspileError::IllegalIndexing(IllegalIndexing {
|
||||
reason: IllegalIndexingReason::InvalidComptimeType {
|
||||
expected: ExpectedType::String,
|
||||
},
|
||||
expression: expression.span(),
|
||||
});
|
||||
handler.receive(err.clone());
|
||||
return Err(err);
|
||||
}
|
||||
Some(_) => {
|
||||
let err = TranspileError::IllegalIndexing(IllegalIndexing {
|
||||
|
@ -621,7 +629,15 @@ impl Transpiler {
|
|||
entity: s,
|
||||
}),
|
||||
Some(ComptimeValue::MacroString(s)) => {
|
||||
todo!("indexing tag with macro string: {s:?}")
|
||||
// TODO: allow indexing tag with macro string
|
||||
let err = TranspileError::IllegalIndexing(IllegalIndexing {
|
||||
expression: expression.span(),
|
||||
reason: IllegalIndexingReason::InvalidComptimeType {
|
||||
expected: ExpectedType::String,
|
||||
},
|
||||
});
|
||||
handler.receive(err.clone());
|
||||
return Err(err);
|
||||
}
|
||||
Some(_) => {
|
||||
let err = TranspileError::IllegalIndexing(IllegalIndexing {
|
||||
|
@ -931,7 +947,15 @@ impl Transpiler {
|
|||
Ok((name, targets))
|
||||
}
|
||||
TranspileAnnotationValue::Map(map) => {
|
||||
todo!("allow map deobfuscate annotation for array variables")
|
||||
// TODO: implement when map deobfuscate annotation is implemented
|
||||
let error =
|
||||
TranspileError::IllegalAnnotationContent(IllegalAnnotationContent {
|
||||
annotation: deobfuscate_annotation.span(),
|
||||
message: "Deobfuscate annotation value must be a string or none."
|
||||
.to_string(),
|
||||
});
|
||||
handler.receive(error.clone());
|
||||
Err(error)
|
||||
}
|
||||
TranspileAnnotationValue::Expression(_) => {
|
||||
let error =
|
||||
|
|
Loading…
Reference in New Issue