execute method
Execute the DartBlockProgram.
A new Isolate is spawned, on which the execution of the DartBlockProgram will occur.
This ensures that the UI is not frozen during the execution.
Additionally, a timer is applied. If the execution has not terminated after a set Duration, it is automatically interrupted by killing the Isolate and throwing a DartBlockException indicating that the user's program may contain an infinite loop or a faulty recursive function without a proper ending condition.
By default, the Duration is 5s, which is also the minimum duration allowed.
IMPORTANT: as Dart does not support Isolates on web platforms, the execution model is much more rudimentary:
- The DartBlockProgram is executed on the main thread, meaning the UI will freeze until the execution has finished.
- No timer is applied, meaning a faulty program whose execution never ends will lead to an indefinite stall of the app.
More info on the web platform and isolates: https://docs.flutter.dev/perf/isolates#web-platforms-and-compute
Implementation
Future<void> execute({Duration duration = const Duration(seconds: 5)}) async {
if (duration.inSeconds < 5) {
duration = Duration(seconds: 5);
}
// Reset the environment to wipe traces of the previous execution.
_reset();
if (kIsWeb) {
_executeWeb();
return;
}
bool finishedExecution = false;
try {
final resultPort = ReceivePort();
// Spawn a new isolate on which the DartBlockProgram should be executed.
final isolate = await Isolate.spawn(
(List<dynamic> args) async {
SendPort resultPort = args[0];
DartBlockExecutor executor = args[1];
try {
FunctionCallStatement.init("main", []).run(executor);
} on DartBlockException catch (ex) {
Isolate.exit(resultPort, [executor, ex]);
} on Exception catch (ex) {
Isolate.exit(resultPort, [executor, ex]);
} on StackOverflowError catch (_) {
// DartBlock relies on the StackOverflowError thrown by Dart's own execution engine.
Isolate.exit(resultPort, [
executor,
DartBlockException(
title: "Stack Overflow",
message:
"The program was killed due to a stack overflow error. This can occur if you have a recursive function without an appropriate ending condition.",
),
]);
} on Error catch (_) {
// Any other (unknown) type of error which may occur.
Isolate.exit(resultPort, [
executor,
DartBlockException(
title: "Critical Error",
message:
"The program was killed due to an unknown error. Ensure your program does not contain an infinite loop or a recursive function without an ending condition!",
),
]);
}
// Leave the isolate after the execution has finished and send back the DartBlockExecutor which contains the environment and execution output.
Isolate.exit(resultPort, [executor, null]);
},
[resultPort.sendPort, this],
/// Initially paused such that the timer can be started at the same time.
paused: true,
onExit: resultPort.sendPort,
);
/// Start the preventive timer, which aims to stop the execution (kill the isolate)
/// after a certain amount of time in case it has not finished execution yet.
Future.delayed(duration).then((value) {
if (!finishedExecution) {
isolate.kill(priority: Isolate.immediate);
}
});
isolate.resume(isolate.pauseCapability!);
final response = await resultPort.first;
finishedExecution = true;
/// This means the isolate was killed early.
if (response == null) {
_thrownException = DartBlockException(
title: "Infinite Loop",
message:
"The program was killed due to its execution taking too long. Ensure your program does not contain an infinite loop or a recursive function without an ending condition!",
);
} else {
DartBlockExecutor receivedExecutor = response[0];
copyFrom(receivedExecutor);
Exception? exception = response[1];
if (exception != null) {
if (exception is DartBlockException) {
_thrownException = exception;
printToConsole("Program execution interrupted by exception.");
} else {
_thrownException = DartBlockException.fromException(
exception: exception,
);
printToConsole("Program execution interrupted by exception.");
}
} else {
printToConsole("Program execution finished successfully.");
}
}
} on DartBlockException catch (ex) {
_thrownException = ex;
printToConsole("Program execution interrupted by exception.");
} on Exception catch (ex) {
_thrownException = DartBlockException.fromException(exception: ex);
printToConsole("Program execution interrupted by exception.");
} on StackOverflowError catch (_) {
_thrownException = DartBlockException(
title: "Stack Overflow",
message:
"The program was killed due to a stack overflow error. This can occur if you have a recursive function without an appropriate ending condition.",
);
printToConsole("Program execution interrupted by exception.");
} on Error catch (_) {
_thrownException = DartBlockException(
title: "Critical Error",
message:
"The program was killed due to an unknown error. Ensure your program does not contain an infinite loop or a recursive function without an ending condition!",
);
printToConsole("Program execution interrupted by exception.");
}
}