From 922ab500fc9a96755f42c64fa8f1f7121bb11615 Mon Sep 17 00:00:00 2001 From: ddalaklidhs Date: Mon, 13 Apr 2026 04:16:59 +0300 Subject: [PATCH 1/3] Centralize FusionInterrupt handling in embedding layer (#517) --- .../dev/ionfusion/fusion/StandardRuntime.java | 14 +- .../ionfusion/fusion/StandardTopLevel.java | 153 +++++++----------- 2 files changed, 65 insertions(+), 102 deletions(-) diff --git a/runtime/src/main/java/dev/ionfusion/fusion/StandardRuntime.java b/runtime/src/main/java/dev/ionfusion/fusion/StandardRuntime.java index efd92b82..e43cff74 100644 --- a/runtime/src/main/java/dev/ionfusion/fusion/StandardRuntime.java +++ b/runtime/src/main/java/dev/ionfusion/fusion/StandardRuntime.java @@ -37,8 +37,8 @@ final class StandardRuntime { IonSystem ionSystem = IonSystemBuilder.standard() - .withCatalog(builder.getDefaultIonCatalog()) - .build(); + .withCatalog(builder.getDefaultIonCatalog()) + .build(); myRegistry = new ModuleRegistry(); myDefaultLanguage = builder.getDefaultLanguage(); @@ -196,14 +196,15 @@ public ModuleBuilder makeModuleBuilder(String absoluteModulePath) } - //======================================================================== + @Override public IonValue ionize(Object fusionValue, ValueFactory factory) throws FusionException { - return FusionValue.copyToIonValue(myTopLevel.getEvaluator(), fusionValue, factory); + return myTopLevel.withEvaluator(() -> + FusionValue.copyToIonValue(myTopLevel.getEvaluator(), fusionValue, factory)); } @@ -211,11 +212,12 @@ public IonValue ionize(Object fusionValue, ValueFactory factory) public IonValue ionizeMaybe(Object fusionValue, ValueFactory factory) throws FusionException { - return FusionValue.copyToIonValueMaybe(myTopLevel.getEvaluator(), fusionValue, factory); + return myTopLevel.withEvaluator(() -> + FusionValue.copyToIonValueMaybe(myTopLevel.getEvaluator(), fusionValue, factory)); } - //======================================================================== + private class SandboxBuilderImpl diff --git a/runtime/src/main/java/dev/ionfusion/fusion/StandardTopLevel.java b/runtime/src/main/java/dev/ionfusion/fusion/StandardTopLevel.java index 65a1c4f4..3c3158ce 100644 --- a/runtime/src/main/java/dev/ionfusion/fusion/StandardTopLevel.java +++ b/runtime/src/main/java/dev/ionfusion/fusion/StandardTopLevel.java @@ -35,8 +35,8 @@ final class StandardTopLevel { CoverageCollector collector = globalState.myCoverageCollector; Evaluator eval = (collector == null - ? new Evaluator(globalState) - : new CoverageEvaluator(globalState, collector)); + ? new Evaluator(globalState) + : new CoverageEvaluator(globalState, collector)); if (continuationMarks.length != 0) { @@ -77,6 +77,28 @@ ModuleRegistry getRegistry() return myNamespace.getRegistry(); } + @FunctionalInterface + interface EvalTask + { + T run() throws FusionException; + } + + T withEvaluator(EvalTask task) + throws FusionException + { + try + { + return task.run(); + } + catch (FusionInterrupt e) + { + throw new FusionInterruptedException(e); + } + } + + + //======================================================================== + @Override public Object eval(String source, SourceName name) throws FusionInterruptedException, FusionException @@ -106,8 +128,7 @@ public Object eval(String source) public Object eval(IonReader source, SourceName name) throws FusionInterruptedException, FusionException { - try - { + return withEvaluator(() -> { Object result = voidValue(myEvaluator); if (source.getType() == null) source.next(); @@ -121,11 +142,7 @@ public Object eval(IonReader source, SourceName name) } return result; - } - catch (FusionInterrupt e) - { - throw new FusionInterruptedException(e); - } + }); } @@ -141,19 +158,12 @@ public Object eval(IonReader source) public Object load(File source) throws FusionInterruptedException, FusionException { - try - { + return withEvaluator(() -> { LoadHandler load = myEvaluator.getGlobalState().myLoadHandler; // This method parameterizes current_namespace for us: - return load.loadTopLevel(myEvaluator, - myNamespace, - source.toString()); - } - catch (FusionInterrupt e) - { - throw new FusionInterruptedException(e); - } + return load.loadTopLevel(myEvaluator, myNamespace, source.toString()); + }); } @@ -170,8 +180,7 @@ public void loadModule(String absoluteModulePath, throw new IllegalArgumentException(message); } - try - { + withEvaluator(() -> { // Make sure we use the registry on our namespace. Evaluator eval = myEvaluator.parameterizeCurrentNamespace(myNamespace); @@ -184,24 +193,15 @@ public void loadModule(String absoluteModulePath, ModuleLocation.forIonReader(source, name); resolver.loadModule(eval, id, loc, true /* reload it */); - } - catch (FusionInterrupt e) - { - throw new FusionInterruptedException(e); - } + return null; + }); } ModuleIdentity loadModule(String modulePath) throws FusionInterruptedException, FusionException { - try - { - return myNamespace.resolveAndLoadModule(myEvaluator, modulePath); - } - catch (FusionInterrupt e) - { - throw new FusionInterruptedException(e); - } + return withEvaluator(() -> + myNamespace.resolveAndLoadModule(myEvaluator, modulePath)); } /** @@ -210,42 +210,28 @@ ModuleIdentity loadModule(String modulePath) ModuleInstance instantiateLoadedModule(ModuleIdentity id) throws FusionInterruptedException, FusionException { - try - { - return getRegistry().instantiate(myEvaluator, id); - } - catch (FusionInterrupt e) - { - throw new FusionInterruptedException(e); - } + return withEvaluator(() -> + getRegistry().instantiate(myEvaluator, id)); } void attachModule(StandardTopLevel src, String modulePath) throws FusionInterruptedException, FusionException { - try - { + withEvaluator(() -> { myNamespace.attachModule(myEvaluator, src.myNamespace, modulePath); - } - catch (FusionInterrupt e) - { - throw new FusionInterruptedException(e); - } + return null; + }); } @Override public void requireModule(String modulePath) throws FusionInterruptedException, FusionException { - try - { + withEvaluator(() -> { myNamespace.require(myEvaluator, modulePath); - } - catch (FusionInterrupt e) - { - throw new FusionInterruptedException(e); - } + return null; + }); } @@ -262,14 +248,10 @@ public void define(String name, Object value) throw new IllegalArgumentException(msg); } - try - { + withEvaluator(() -> { myNamespace.bind(name, fv); - } - catch (FusionInterrupt e) - { - throw new FusionInterruptedException(e); - } + return null; + }); } @@ -277,24 +259,17 @@ public void define(String name, Object value) public Object lookup(String name) throws FusionInterruptedException, FusionException { - try - { - return myNamespace.lookup(name); - } - catch (FusionInterrupt e) - { - // I don't think this can happen, but I prefer to be consistent - // throughout this class to be more resilient to changes. - throw new FusionInterruptedException(e); - } + return withEvaluator(() -> + // I don't think this can happen, but I prefer to be consistent + // throughout this class to be more resilient to changes. + myNamespace.lookup(name)); } private Procedure lookupProcedure(String procedureName) throws FusionInterruptedException, FusionException { - try - { + return withEvaluator(() -> { Object proc = lookup(procedureName); if (proc instanceof Procedure) { @@ -310,11 +285,7 @@ private Procedure lookupProcedure(String procedureName) throw new FusionException(printQuotedSymbol(procedureName) + " is not a procedure: " + safeWriteToString(myEvaluator, proc)); - } - catch (FusionInterrupt e) - { - throw new FusionInterruptedException(e); - } + }); } @@ -336,15 +307,9 @@ private Object call(Procedure proc, Object... arguments) arguments[i] = fv; } - try - { - // TODO Should this set current_namespace? - return myEvaluator.callNonTail(proc, arguments); - } - catch (FusionInterrupt e) - { - throw new FusionInterruptedException(e); - } + return withEvaluator(() -> + // TODO Should this set current_namespace? + myEvaluator.callNonTail(proc, arguments)); } @@ -375,13 +340,9 @@ public Object call(Object procedure, Object... arguments) public void ionize(Object value, IonWriter out) throws FusionException { - try - { + withEvaluator(() -> { FusionIo.ionize(myEvaluator, out, value); - } - catch (FusionInterrupt e) - { - throw new FusionInterruptedException(e); - } + return null; + }); } } From 0b5e48f468bb3e6bdcd5fba6abfd440b8cd02e69 Mon Sep 17 00:00:00 2001 From: ddalaklidhs Date: Tue, 14 Apr 2026 03:11:00 +0300 Subject: [PATCH 2/3] Pass Evaluator to EvalTask.run() per review feedback --- .../dev/ionfusion/fusion/StandardRuntime.java | 11 ++-- .../ionfusion/fusion/StandardTopLevel.java | 60 +++++++++---------- 2 files changed, 34 insertions(+), 37 deletions(-) diff --git a/runtime/src/main/java/dev/ionfusion/fusion/StandardRuntime.java b/runtime/src/main/java/dev/ionfusion/fusion/StandardRuntime.java index e43cff74..85ec6c2f 100644 --- a/runtime/src/main/java/dev/ionfusion/fusion/StandardRuntime.java +++ b/runtime/src/main/java/dev/ionfusion/fusion/StandardRuntime.java @@ -203,8 +203,8 @@ public ModuleBuilder makeModuleBuilder(String absoluteModulePath) public IonValue ionize(Object fusionValue, ValueFactory factory) throws FusionException { - return myTopLevel.withEvaluator(() -> - FusionValue.copyToIonValue(myTopLevel.getEvaluator(), fusionValue, factory)); + return myTopLevel.withEvaluator(eval -> + FusionValue.copyToIonValue(eval, fusionValue, factory)); } @@ -212,14 +212,11 @@ public IonValue ionize(Object fusionValue, ValueFactory factory) public IonValue ionizeMaybe(Object fusionValue, ValueFactory factory) throws FusionException { - return myTopLevel.withEvaluator(() -> - FusionValue.copyToIonValueMaybe(myTopLevel.getEvaluator(), fusionValue, factory)); + return myTopLevel.withEvaluator(eval -> + FusionValue.copyToIonValueMaybe(eval, fusionValue, factory)); } - - - private class SandboxBuilderImpl implements SandboxBuilder { diff --git a/runtime/src/main/java/dev/ionfusion/fusion/StandardTopLevel.java b/runtime/src/main/java/dev/ionfusion/fusion/StandardTopLevel.java index 3c3158ce..d96700f2 100644 --- a/runtime/src/main/java/dev/ionfusion/fusion/StandardTopLevel.java +++ b/runtime/src/main/java/dev/ionfusion/fusion/StandardTopLevel.java @@ -80,7 +80,7 @@ ModuleRegistry getRegistry() @FunctionalInterface interface EvalTask { - T run() throws FusionException; + T run(Evaluator eval) throws FusionException; } T withEvaluator(EvalTask task) @@ -88,7 +88,7 @@ T withEvaluator(EvalTask task) { try { - return task.run(); + return task.run(myEvaluator); } catch (FusionInterrupt e) { @@ -128,16 +128,16 @@ public Object eval(String source) public Object eval(IonReader source, SourceName name) throws FusionInterruptedException, FusionException { - return withEvaluator(() -> { - Object result = voidValue(myEvaluator); + return withEvaluator(eval -> { + Object result = voidValue(eval); if (source.getType() == null) source.next(); while (source.getType() != null) { - SyntaxValue sourceExpr = readSyntax(myEvaluator, source, name); + SyntaxValue sourceExpr = readSyntax(eval, source, name); // This method parameterizes current_namespace for us: - result = FusionEval.eval(myEvaluator, sourceExpr, myNamespace); + result = FusionEval.eval(eval, sourceExpr, myNamespace); source.next(); } @@ -158,11 +158,11 @@ public Object eval(IonReader source) public Object load(File source) throws FusionInterruptedException, FusionException { - return withEvaluator(() -> { - LoadHandler load = myEvaluator.getGlobalState().myLoadHandler; + return withEvaluator(eval -> { + LoadHandler load = eval.getGlobalState().myLoadHandler; // This method parameterizes current_namespace for us: - return load.loadTopLevel(myEvaluator, myNamespace, source.toString()); + return load.loadTopLevel(eval, myNamespace, source.toString()); }); } @@ -180,19 +180,19 @@ public void loadModule(String absoluteModulePath, throw new IllegalArgumentException(message); } - withEvaluator(() -> { + withEvaluator(eval -> { // Make sure we use the registry on our namespace. - Evaluator eval = - myEvaluator.parameterizeCurrentNamespace(myNamespace); + Evaluator parameterized = + eval.parameterizeCurrentNamespace(myNamespace); ModuleNameResolver resolver = - myEvaluator.getGlobalState().myModuleNameResolver; + eval.getGlobalState().myModuleNameResolver; ModuleIdentity id = ModuleIdentity.forAbsolutePath(absoluteModulePath); ModuleLocation loc = ModuleLocation.forIonReader(source, name); - resolver.loadModule(eval, id, loc, true /* reload it */); + resolver.loadModule(parameterized, id, loc, true /* reload it */); return null; }); } @@ -200,8 +200,8 @@ public void loadModule(String absoluteModulePath, ModuleIdentity loadModule(String modulePath) throws FusionInterruptedException, FusionException { - return withEvaluator(() -> - myNamespace.resolveAndLoadModule(myEvaluator, modulePath)); + return withEvaluator(eval -> + myNamespace.resolveAndLoadModule(eval, modulePath)); } /** @@ -210,16 +210,16 @@ ModuleIdentity loadModule(String modulePath) ModuleInstance instantiateLoadedModule(ModuleIdentity id) throws FusionInterruptedException, FusionException { - return withEvaluator(() -> - getRegistry().instantiate(myEvaluator, id)); + return withEvaluator(eval -> + getRegistry().instantiate(eval, id)); } void attachModule(StandardTopLevel src, String modulePath) throws FusionInterruptedException, FusionException { - withEvaluator(() -> { - myNamespace.attachModule(myEvaluator, src.myNamespace, modulePath); + withEvaluator(eval -> { + myNamespace.attachModule(eval, src.myNamespace, modulePath); return null; }); } @@ -228,8 +228,8 @@ void attachModule(StandardTopLevel src, String modulePath) public void requireModule(String modulePath) throws FusionInterruptedException, FusionException { - withEvaluator(() -> { - myNamespace.require(myEvaluator, modulePath); + withEvaluator(eval -> { + myNamespace.require(eval, modulePath); return null; }); } @@ -248,7 +248,7 @@ public void define(String name, Object value) throw new IllegalArgumentException(msg); } - withEvaluator(() -> { + withEvaluator(eval -> { myNamespace.bind(name, fv); return null; }); @@ -259,7 +259,7 @@ public void define(String name, Object value) public Object lookup(String name) throws FusionInterruptedException, FusionException { - return withEvaluator(() -> + return withEvaluator(eval -> // I don't think this can happen, but I prefer to be consistent // throughout this class to be more resilient to changes. myNamespace.lookup(name)); @@ -269,7 +269,7 @@ public Object lookup(String name) private Procedure lookupProcedure(String procedureName) throws FusionInterruptedException, FusionException { - return withEvaluator(() -> { + return withEvaluator(eval -> { Object proc = lookup(procedureName); if (proc instanceof Procedure) { @@ -284,7 +284,7 @@ private Procedure lookupProcedure(String procedureName) throw new FusionException(printQuotedSymbol(procedureName) + " is not a procedure: " + - safeWriteToString(myEvaluator, proc)); + safeWriteToString(eval, proc)); }); } @@ -307,9 +307,9 @@ private Object call(Procedure proc, Object... arguments) arguments[i] = fv; } - return withEvaluator(() -> + return withEvaluator(eval -> // TODO Should this set current_namespace? - myEvaluator.callNonTail(proc, arguments)); + eval.callNonTail(proc, arguments)); } @@ -340,8 +340,8 @@ public Object call(Object procedure, Object... arguments) public void ionize(Object value, IonWriter out) throws FusionException { - withEvaluator(() -> { - FusionIo.ionize(myEvaluator, out, value); + withEvaluator(eval -> { + FusionIo.ionize(eval, out, value); return null; }); } From 6db446fa0ae8795e3f2155226ef9707ffd91c2e0 Mon Sep 17 00:00:00 2001 From: "Todd V. Jonker" Date: Tue, 14 Apr 2026 11:17:16 -0700 Subject: [PATCH 3/3] StandardTopLevel.java minor format cleanup --- .../dev/ionfusion/fusion/StandardTopLevel.java | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/runtime/src/main/java/dev/ionfusion/fusion/StandardTopLevel.java b/runtime/src/main/java/dev/ionfusion/fusion/StandardTopLevel.java index d96700f2..d94c5770 100644 --- a/runtime/src/main/java/dev/ionfusion/fusion/StandardTopLevel.java +++ b/runtime/src/main/java/dev/ionfusion/fusion/StandardTopLevel.java @@ -35,8 +35,8 @@ final class StandardTopLevel { CoverageCollector collector = globalState.myCoverageCollector; Evaluator eval = (collector == null - ? new Evaluator(globalState) - : new CoverageEvaluator(globalState, collector)); + ? new Evaluator(globalState) + : new CoverageEvaluator(globalState, collector)); if (continuationMarks.length != 0) { @@ -259,10 +259,7 @@ public void define(String name, Object value) public Object lookup(String name) throws FusionInterruptedException, FusionException { - return withEvaluator(eval -> - // I don't think this can happen, but I prefer to be consistent - // throughout this class to be more resilient to changes. - myNamespace.lookup(name)); + return withEvaluator(eval -> myNamespace.lookup(name)); } @@ -307,9 +304,8 @@ private Object call(Procedure proc, Object... arguments) arguments[i] = fv; } - return withEvaluator(eval -> - // TODO Should this set current_namespace? - eval.callNonTail(proc, arguments)); + // TODO Should this set current_namespace? + return withEvaluator(eval -> eval.callNonTail(proc, arguments)); }