diff --git a/.gitignore b/.gitignore index 039a5cf030f..446f9681ce8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .idea/** +.mvn/** **/*.iml **/target **/lib diff --git a/README.md b/README.md index 3058d5e1377..e8c47ddbd5d 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,29 @@ If you're making changes to the `Pure` codebase, it's highly recommended that yo - To start the server, please use the `Main` class `org.finos.legend.engine.ide.PureIDELight` with the parameters: `server legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light-http-server/src/main/resources/ideLightConfig.json`. - You can now access the IDE at http://127.0.0.1:9200/ide in a web browser. +#### Debugging Pure Code + +![Debugging](docs/debug.gif) + +To debug your `Pure` code, you need to use the `meta::pure::ide::debug()` function to create breakpoints. + +When you execute the `go` function using _F9_, the execution will be paused at the breakpoint, and a **_summary_** will be printed. + +This **_summary_** include the current stack (for easy navigation to the current breakpoint point) and the variables accessible on such breakpoint. + +Once in a breakpoint, using the Pure IDE terminal, you can take certain debugging actions: + +- `debug` or `debug summary`: print the aforementioned **_summary_**. +- `debug `: evaluate the given expression. All variables on the current breakpoint are available. + - ie. `debug $f->map(x | $x->type())`: introspect variable `f` and apply some functions to it. +- `debug abort`: stop the current execution. Pressing _F9_ after an abort command will start the execution from the beginning (ie. from the `go` function) + +To resume the execution to next breakpoint or to completion, just press _F9_ again. + +Caveats: +- Editing the code while on a breakpoint will lead to evaluation errors. You need to complete or abort current execution to pick new changes. +- Print commands within the debug expressions won't show on console. Avoid the print and evaluate to a string value instead. + ## Roadmap Visit our [roadmap](https://github.com/finos/legend#roadmap) to know more about the upcoming features. diff --git a/docs/debug.gif b/docs/debug.gif new file mode 100644 index 00000000000..d3c970a8b54 Binary files /dev/null and b/docs/debug.gif differ diff --git a/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light-http-server/src/main/java/org/finos/legend/engine/ide/api/execution/go/GoRun.java b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light-http-server/src/main/java/org/finos/legend/engine/ide/api/execution/go/GoRun.java index 31572b2ca5d..00cdb29ef1a 100644 --- a/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light-http-server/src/main/java/org/finos/legend/engine/ide/api/execution/go/GoRun.java +++ b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light-http-server/src/main/java/org/finos/legend/engine/ide/api/execution/go/GoRun.java @@ -22,6 +22,7 @@ import org.finos.legend.engine.ide.helpers.response.IDEResponse; import org.finos.legend.engine.ide.session.PureSession; import org.finos.legend.engine.ide.session.SimpleFunction; +import org.finos.legend.engine.pure.ide.interpreted.debug.FunctionExecutionInterpretedWithDebugSupport; import org.finos.legend.pure.m3.execution.Console; import org.finos.legend.pure.m3.execution.FunctionExecution; import org.finos.legend.pure.m3.serialization.runtime.PureRuntime; @@ -57,7 +58,14 @@ public void run(PureSession pureSession, JSONObject extraParams, JSONArray modif console = functionExecution.getConsole(); console.setPrintStream(new JSONPrintStream(outputStream)); console.setConsole(true); - functionExecution.start(function, FastList.newList()); + if (functionExecution instanceof FunctionExecutionInterpretedWithDebugSupport) + { + ((FunctionExecutionInterpretedWithDebugSupport) functionExecution).startDebug(function, FastList.newList()); + } + else + { + functionExecution.start(function, FastList.newList()); + } outputStream.write("\"".getBytes()); } catch (Exception ex) diff --git a/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light-interpreted-functions/src/main/java/org/finos/legend/engine/pure/ide/interpreted/debug/DebugState.java b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light-interpreted-functions/src/main/java/org/finos/legend/engine/pure/ide/interpreted/debug/DebugState.java index 6508e4e1c92..4aa846dd24a 100644 --- a/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light-interpreted-functions/src/main/java/org/finos/legend/engine/pure/ide/interpreted/debug/DebugState.java +++ b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light-interpreted-functions/src/main/java/org/finos/legend/engine/pure/ide/interpreted/debug/DebugState.java @@ -107,7 +107,7 @@ public String evaluate(String command) ListIterable newInstances = inMemoryCodeBlock.getNewInstances(); - CoreInstance result = this.debugSupport.startRaw(newInstances.get(0), Lists.fixedSize.of()); + CoreInstance result = this.debugSupport.start(newInstances.get(0), Lists.fixedSize.of()); CoreInstance lambda = Instance.getValueForMetaPropertyToOneResolved(result, M3Properties.values, this.debugSupport.getProcessorSupport()); ByteArrayOutputStream out = new ByteArrayOutputStream(); @@ -130,19 +130,23 @@ private static MutableList> computeVariables(Variable private static String computeVariableTypeAndMultiplicity(FunctionExecutionInterpretedWithDebugSupport debugSupport, CoreInstance coreInstance) { - // todo the GenericType.print has a bug with type arguments, and functions get printed wrong! - // ie. meta::pure::metamodel::function::ConcreteFunctionDefinition< {meta::pure::metamodel::function::Function<{->X[o]}>[1]->X[o]}> String type; + String multiplicity = Multiplicity.print(coreInstance.getValueForMetaPropertyToOne(M3Properties.multiplicity)); + + CoreInstance genericType = coreInstance.getValueForMetaPropertyToOne(M3Properties.genericType); ProcessorSupport processorSupport = debugSupport.getProcessorSupport(); - if (processorSupport.type_subTypeOf(coreInstance.getValueForMetaPropertyToOne(M3Properties.genericType).getValueForMetaPropertyToOne(M3Properties.rawType), debugSupport.getPureRuntime().getCoreInstance(M3Paths.Function))) + + // todo the GenericType.print has a bug with type arguments on functions, and get printed wrong + // ie. meta::pure::metamodel::function::ConcreteFunctionDefinition< {meta::pure::metamodel::function::Function<{->X[o]}>[1]->X[o]}> + if (processorSupport.type_subTypeOf(genericType.getValueForMetaPropertyToOne(M3Properties.rawType), debugSupport.getPureRuntime().getCoreInstance(M3Paths.ConcreteFunctionDefinition))) { - type = "Function"; + type = M3Paths.ConcreteFunctionDefinition + ""; } else { - type = GenericType.print(coreInstance.getValueForMetaPropertyToOne(M3Properties.genericType), true, processorSupport); + type = GenericType.print(genericType, true, processorSupport); } - String multiplicity = Multiplicity.print(coreInstance.getValueForMetaPropertyToOne(M3Properties.multiplicity)); + return type + multiplicity; } } diff --git a/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light-interpreted-functions/src/main/java/org/finos/legend/engine/pure/ide/interpreted/debug/FunctionExecutionInterpretedWithDebugSupport.java b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light-interpreted-functions/src/main/java/org/finos/legend/engine/pure/ide/interpreted/debug/FunctionExecutionInterpretedWithDebugSupport.java index 1641414605f..9144ab1d5d1 100644 --- a/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light-interpreted-functions/src/main/java/org/finos/legend/engine/pure/ide/interpreted/debug/FunctionExecutionInterpretedWithDebugSupport.java +++ b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light-interpreted-functions/src/main/java/org/finos/legend/engine/pure/ide/interpreted/debug/FunctionExecutionInterpretedWithDebugSupport.java @@ -15,16 +15,9 @@ package org.finos.legend.engine.pure.ide.interpreted.debug; -import java.io.IOException; -import java.io.OutputStream; -import java.io.UncheckedIOException; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionException; import org.eclipse.collections.api.list.ListIterable; -import org.finos.legend.pure.m3.exception.PureExecutionException; -import org.finos.legend.pure.m3.execution.OutputWriter; -import org.finos.legend.pure.m3.navigation.M3Properties; -import org.finos.legend.pure.m3.navigation.ValueSpecificationBootstrap; import org.finos.legend.pure.m3.statelistener.VoidExecutionActivityListener; import org.finos.legend.pure.m4.coreinstance.CoreInstance; import org.finos.legend.pure.runtime.java.interpreted.FunctionExecutionInterpreted; @@ -62,14 +55,13 @@ public void setDebugState(DebugState debugState) } } - @Override - public CoreInstance start(CoreInstance function, ListIterable arguments) + public void startDebug(CoreInstance function, ListIterable arguments) { this.resultHandler = new CompletableFuture<>(); if (this.currentExecution == null) { - this.currentExecution = CompletableFuture.supplyAsync(() -> this.startRaw(function, arguments)); + this.currentExecution = CompletableFuture.supplyAsync(() -> this.start(function, arguments)); this.currentExecution.whenComplete((v, e) -> { if (e != null) @@ -85,38 +77,17 @@ public CoreInstance start(CoreInstance function, ListIterable arguments) - { - return super.start(function, arguments); - } - - @Override - public void start(CoreInstance func, ListIterable arguments, OutputStream - outputStream, OutputWriter writer) - { - CoreInstance result = this.startRaw(func, arguments); - - try - { - ListIterable values = result.getValueForMetaPropertyToMany(M3Properties.values); - writer.write(values, outputStream); - } - catch (IOException e) - { - throw new UncheckedIOException("Failed to write to output stream", e); - } - } }