implement comptime while loops
This commit is contained in:
parent
e367920922
commit
389d791ac1
|
@ -25,7 +25,7 @@ impl Block {
|
|||
{
|
||||
let err = TranspileError::AssignmentError(AssignmentError {
|
||||
identifier: ident.span.clone(),
|
||||
message: "cannot assign to a compile-time variable in a conditional execute block"
|
||||
message: "cannot assign to a compile-time variable declared before a runtime conditional block"
|
||||
.to_string(),
|
||||
});
|
||||
handler.receive(Box::new(err.clone()));
|
||||
|
|
|
@ -49,8 +49,6 @@ pub enum TranspileError {
|
|||
InvalidArgument(#[from] InvalidArgument),
|
||||
#[error(transparent)]
|
||||
NotComptime(#[from] NotComptime),
|
||||
#[error(transparent)]
|
||||
InfiniteLoop(#[from] InfiniteLoop),
|
||||
}
|
||||
|
||||
/// The result of a transpilation operation.
|
||||
|
@ -444,29 +442,3 @@ impl Display for NotComptime {
|
|||
}
|
||||
|
||||
impl std::error::Error for NotComptime {}
|
||||
|
||||
/// An error that occurs when a loop never terminates.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, thiserror::Error)]
|
||||
pub struct InfiniteLoop {
|
||||
/// The condition making it not terminate.
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
impl Display for InfiniteLoop {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
Message::new(Severity::Error, "Loop never terminates.")
|
||||
)?;
|
||||
|
||||
write!(
|
||||
f,
|
||||
"\n{}",
|
||||
SourceCodeDisplay::new(
|
||||
&self.span,
|
||||
Some("You may want to use a separate function with the `#[tick]` annotation.")
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2139,6 +2139,14 @@ impl Transpiler {
|
|||
scope: &Arc<super::Scope>,
|
||||
handler: &impl Handler<base::Error>,
|
||||
) -> TranspileResult<(Vec<Command>, ShulkerboxMacroStringMap, ExtendedCondition)> {
|
||||
if let Ok(ComptimeValue::Boolean(val)) = binary.comptime_eval(scope, handler) {
|
||||
return Ok((
|
||||
Vec::new(),
|
||||
BTreeMap::new(),
|
||||
ExtendedCondition::Comptime(val),
|
||||
));
|
||||
}
|
||||
|
||||
match binary.operator() {
|
||||
BinaryOperator::Equal(..)
|
||||
| BinaryOperator::NotEqual(..)
|
||||
|
|
|
@ -22,13 +22,13 @@ use crate::{
|
|||
program::{Namespace, ProgramFile},
|
||||
statement::{
|
||||
execute_block::{Conditional, Else, ExecuteBlock, ExecuteBlockHead, ExecuteBlockTail},
|
||||
Block, ReturnStatement, SemicolonStatement, Statement,
|
||||
Block, ReturnStatement, SemicolonStatement, Statement, WhileLoop,
|
||||
},
|
||||
AnnotationAssignment,
|
||||
},
|
||||
transpile::{
|
||||
conversions::ShulkerboxMacroStringMap,
|
||||
error::{IllegalAnnotationContent, InfiniteLoop},
|
||||
error::IllegalAnnotationContent,
|
||||
expression::DataLocation,
|
||||
util::{MacroString, MacroStringPart},
|
||||
variables::FunctionVariableDataType,
|
||||
|
@ -42,6 +42,8 @@ use super::{
|
|||
FunctionData, TranspileAnnotationValue, TranspiledFunctionArguments,
|
||||
};
|
||||
|
||||
const LOOP_LIMIT: usize = 4_096;
|
||||
|
||||
/// A transpiler for `Shulkerscript`.
|
||||
#[derive(Debug)]
|
||||
pub struct Transpiler {
|
||||
|
@ -429,37 +431,9 @@ impl Transpiler {
|
|||
}
|
||||
}
|
||||
Statement::WhileLoop(while_loop) => {
|
||||
let (mut condition_commands, prepare_variables, condition) =
|
||||
self.transpile_expression_as_condition(while_loop.condition(), scope, handler)?;
|
||||
|
||||
match condition {
|
||||
ExtendedCondition::Comptime(false) => Ok(Vec::new()),
|
||||
ExtendedCondition::Comptime(true) => {
|
||||
let err = TranspileError::InfiniteLoop(InfiniteLoop {
|
||||
span: while_loop.condition().span(),
|
||||
});
|
||||
handler.receive(Box::new(err.clone()));
|
||||
Err(err)
|
||||
}
|
||||
ExtendedCondition::Runtime(condition) => {
|
||||
let loop_commands = self.transpile_block(
|
||||
while_loop.block(),
|
||||
program_identifier,
|
||||
scope,
|
||||
handler,
|
||||
)?;
|
||||
|
||||
condition_commands
|
||||
.push(Command::While(WhileCmd::new(condition, loop_commands)));
|
||||
|
||||
self.transpile_commands_with_variable_macros(
|
||||
condition_commands,
|
||||
prepare_variables,
|
||||
handler,
|
||||
)
|
||||
}
|
||||
}
|
||||
self.transpile_while_loop(while_loop, program_identifier, scope, handler)
|
||||
}
|
||||
|
||||
Statement::Semicolon(semi) => match semi.statement() {
|
||||
SemicolonStatement::Expression(expr) => match expr {
|
||||
Expression::Primary(Primary::FunctionCall(func)) => {
|
||||
|
@ -1422,6 +1396,60 @@ impl Transpiler {
|
|||
})
|
||||
}
|
||||
|
||||
fn transpile_while_loop(
|
||||
&mut self,
|
||||
while_loop: &WhileLoop,
|
||||
program_identifier: &str,
|
||||
scope: &Arc<Scope>,
|
||||
handler: &impl Handler<base::Error>,
|
||||
) -> TranspileResult<Vec<Command>> {
|
||||
let mut cmds = Vec::new();
|
||||
|
||||
for _ in 0..LOOP_LIMIT {
|
||||
let (mut condition_commands, prepare_variables, condition) =
|
||||
self.transpile_expression_as_condition(while_loop.condition(), scope, handler)?;
|
||||
|
||||
match condition {
|
||||
ExtendedCondition::Comptime(false) => {
|
||||
break;
|
||||
}
|
||||
ExtendedCondition::Comptime(true) => {
|
||||
let loop_commands = self.transpile_block(
|
||||
while_loop.block(),
|
||||
program_identifier,
|
||||
scope,
|
||||
handler,
|
||||
)?;
|
||||
cmds.extend(condition_commands.into_iter().chain(loop_commands));
|
||||
}
|
||||
ExtendedCondition::Runtime(condition) => {
|
||||
// TODO: allow comptime assignments when wrapped in comptime checks
|
||||
while_loop
|
||||
.block()
|
||||
.check_no_comptime_assignments(scope, handler)?;
|
||||
let loop_commands = self.transpile_block(
|
||||
while_loop.block(),
|
||||
program_identifier,
|
||||
scope,
|
||||
handler,
|
||||
)?;
|
||||
|
||||
condition_commands
|
||||
.push(Command::While(WhileCmd::new(condition, loop_commands)));
|
||||
|
||||
cmds.extend(self.transpile_commands_with_variable_macros(
|
||||
condition_commands,
|
||||
prepare_variables,
|
||||
handler,
|
||||
)?);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(cmds)
|
||||
}
|
||||
|
||||
pub(crate) fn transpile_commands_with_variable_macros(
|
||||
&mut self,
|
||||
cmds: Vec<Command>,
|
||||
|
|
Loading…
Reference in New Issue