diff --git a/grapher/data/.gitignore b/grapher/data/.gitignore new file mode 100644 index 000000000..2a874fed1 --- /dev/null +++ b/grapher/data/.gitignore @@ -0,0 +1,5 @@ +# Ignore everything in the folder +* + +# But don't ignore this file +!.gitignore diff --git a/grapher/data/ast.json b/grapher/data/ast.json deleted file mode 100644 index bbca4748f..000000000 --- a/grapher/data/ast.json +++ /dev/null @@ -1,243 +0,0 @@ -{ - "sourceText": "result = 1;\nwhile( true ) {\n result = result + 1;\n\tif( result > \"10\" ) {\n\t\tbreak;\n\t}\n}", - "ASTType": "BoxScript", - "statements": [ - { - "op": "Equal", - "left": { - "sourceText": "result", - "ASTType": "result", - "safe": false, - "position": { - "start": { - "line": 1, - "column": 0 - }, - "end": { - "line": 1, - "column": 0 - } - } - }, - "sourceText": "result = 1", - "ASTType": "BoxAssignment", - "position": { - "start": { - "line": 1, - "column": 0 - }, - "end": { - "line": 1, - "column": 9 - } - }, - "right": { - "sourceText": "1", - "ASTType": "BoxIntegerLiteral", - "position": { - "start": { - "line": 1, - "column": 9 - }, - "end": { - "line": 1, - "column": 9 - } - }, - "value": "1" - } - }, - { - "condition": { - "sourceText": "true", - "ASTType": "BoxBooleanLiteral", - "position": { - "start": { - "line": 2, - "column": 7 - }, - "end": { - "line": 2, - "column": 7 - } - }, - "value": "true" - }, - "sourceText": "while( true ) {\n result = result + 1;\n\tif( result > \"10\" ) {\n\t\tbreak;\n\t}\n}", - "ASTType": "BoxWhile", - "position": { - "start": { - "line": 2, - "column": 0 - }, - "end": { - "line": 7, - "column": 0 - } - }, - "body": [ - { - "op": "Equal", - "left": { - "sourceText": "result", - "ASTType": "result", - "safe": false, - "position": { - "start": { - "line": 3, - "column": 4 - }, - "end": { - "line": 3, - "column": 4 - } - } - }, - "sourceText": "result = result + 1", - "ASTType": "BoxAssignment", - "position": { - "start": { - "line": 3, - "column": 4 - }, - "end": { - "line": 3, - "column": 22 - } - }, - "right": { - "left": { - "sourceText": "result", - "ASTType": "result", - "safe": false, - "position": { - "start": { - "line": 3, - "column": 13 - }, - "end": { - "line": 3, - "column": 13 - } - } - }, - "sourceText": "result + 1", - "ASTType": "BoxBinaryOperation", - "position": { - "start": { - "line": 3, - "column": 13 - }, - "end": { - "line": 3, - "column": 22 - } - }, - "right": { - "sourceText": "1", - "ASTType": "BoxIntegerLiteral", - "position": { - "start": { - "line": 3, - "column": 22 - }, - "end": { - "line": 3, - "column": 22 - } - }, - "value": "1" - }, - "operator": "Plus" - } - }, - { - "condition": { - "left": { - "sourceText": "result", - "ASTType": "result", - "safe": false, - "position": { - "start": { - "line": 4, - "column": 5 - }, - "end": { - "line": 4, - "column": 5 - } - } - }, - "sourceText": "result > \"10\"", - "ASTType": "BoxComparisonOperation", - "position": { - "start": { - "line": 4, - "column": 5 - }, - "end": { - "line": 4, - "column": 17 - } - }, - "right": { - "sourceText": "\"10\"", - "ASTType": "BoxStringLiteral", - "position": { - "start": { - "line": 4, - "column": 14 - }, - "end": { - "line": 4, - "column": 17 - } - }, - "value": "10" - }, - "operator": "GreaterThan" - }, - "sourceText": "if( result > \"10\" ) {\n\t\tbreak;\n\t}", - "ASTType": "BoxIfElse", - "thenBody": [ - { - "sourceText": "break;", - "ASTType": "BoxBreak", - "position": { - "start": { - "line": 5, - "column": 2 - }, - "end": { - "line": 5, - "column": 7 - } - } - } - ], - "elseBody": [], - "position": { - "start": { - "line": 4, - "column": 1 - }, - "end": { - "line": 6, - "column": 1 - } - } - } - ] - } - ], - "position": { - "start": { - "line": 1, - "column": 0 - }, - "end": { - "line": 7, - "column": 0 - } - } - } \ No newline at end of file diff --git a/grapher/data/simple.json b/grapher/data/simple.json deleted file mode 100644 index e7fc5b075..000000000 --- a/grapher/data/simple.json +++ /dev/null @@ -1,62 +0,0 @@ -{ - "sourceText": "result = 1;\nwhile( true ) {\n result = result + 1;\n\tif( result > \"10\" ) {\n\t\tbreak;\n\t}\n}", - "ASTType": "BoxScript", - "statements": [ - { - "op": "Equal", - "left": { - "sourceText": "result", - "ASTType": "result", - "safe": false, - "position": { - "start": { - "line": 1, - "column": 0 - }, - "end": { - "line": 1, - "column": 0 - } - } - }, - "sourceText": "result = 1", - "ASTType": "BoxAssignment", - "position": { - "start": { - "line": 1, - "column": 0 - }, - "end": { - "line": 1, - "column": 9 - } - }, - "right": { - "sourceText": "1", - "ASTType": "BoxIntegerLiteral", - "position": { - "start": { - "line": 1, - "column": 9 - }, - "end": { - "line": 1, - "column": 9 - } - }, - "value": "1" - } - } - - ], - "position": { - "start": { - "line": 1, - "column": 0 - }, - "end": { - "line": 7, - "column": 0 - } - } - } \ No newline at end of file diff --git a/src/main/java/ortus/boxlang/ast/Node.java b/src/main/java/ortus/boxlang/ast/Node.java index 643cbb97d..f81045e57 100644 --- a/src/main/java/ortus/boxlang/ast/Node.java +++ b/src/main/java/ortus/boxlang/ast/Node.java @@ -134,10 +134,10 @@ public List walkAncestors() { public Map toMap() { Map map = new LinkedHashMap(); - map.put( "ASTType", getClass().getSimpleName() ); - map.put( "position", position.toMap() ); + map.put( "ASTType", getClass().getSimpleName() ); map.put( "ASTPackage", getClass().getPackageName() ); map.put( "sourceText", sourceText ); + map.put( "position", position.toMap() ); // I'm not sure if children is used at all right now // map.put( "children", children.stream().map( Node::toMap ).toList() ); diff --git a/src/main/java/ortus/boxlang/parser/BoxParser.java b/src/main/java/ortus/boxlang/parser/BoxParser.java index e9669cb55..d0d39a205 100644 --- a/src/main/java/ortus/boxlang/parser/BoxParser.java +++ b/src/main/java/ortus/boxlang/parser/BoxParser.java @@ -26,9 +26,13 @@ import ortus.boxlang.ast.BoxExpr; import ortus.boxlang.ast.BoxScript; import ortus.boxlang.ast.BoxStatement; +import ortus.boxlang.runtime.BoxRuntime; +import ortus.boxlang.runtime.types.Struct; public class BoxParser { + private static BoxRuntime runtime = BoxRuntime.getInstance(); + /** * Attempt to detect the type of source code based on the contents * @@ -129,11 +133,14 @@ public ParsingResult parse( File file ) throws IOException { throw new RuntimeException( "Unsupported file: " + file.getAbsolutePath() ); } } - ParsingResult result = parser.parse( file ); - // TODO: convert go interceptor announcement - if ( result.getRoot() != null ) - System.out.println( result.getRoot().toJSON().toString() ); - return result; + ParsingResult result = parser.parse( file ); + + Struct data = Struct.of( + "file", file, + "result", result + ); + runtime.announce( "onParse", data ); + return ( ParsingResult ) data.get( "result" ); } /** @@ -161,11 +168,14 @@ public ParsingResult parse( String code, BoxScriptType fileType ) throws IOExcep throw new RuntimeException( "Unsupported language" ); } } - ParsingResult result = parser.parse( code ); - // TODO: convert go interceptor announcement - if ( result.getRoot() != null ) - System.out.println( result.getRoot().toJSON().toString() ); - return result; + ParsingResult result = parser.parse( code ); + + Struct data = Struct.of( + "code", code, + "result", result + ); + runtime.announce( "onParse", data ); + return ( ParsingResult ) data.get( "result" ); } @@ -182,19 +192,25 @@ public ParsingResult parse( String code, BoxScriptType fileType ) throws IOExcep * @see BoxStatement */ public ParsingResult parseExpression( String code ) throws IOException { - ParsingResult result = new BoxCFParser().parseExpression( code ); - // TODO: convert go interceptor announcement - if ( result.getRoot() != null ) - System.out.println( result.getRoot().toJSON().toString() ); - return result; + ParsingResult result = new BoxCFParser().parseExpression( code ); + + Struct data = Struct.of( + "code", code, + "result", result + ); + runtime.announce( "onParse", data ); + return ( ParsingResult ) data.get( "result" ); } public ParsingResult parseStatement( String code ) throws IOException { - ParsingResult result = new BoxCFParser().parseStatement( code ); - // TODO: convert go interceptor announcement - if ( result.getRoot() != null ) - System.out.println( result.getRoot().toJSON().toString() ); - return result; + ParsingResult result = new BoxCFParser().parseStatement( code ); + + Struct data = Struct.of( + "code", code, + "result", result + ); + runtime.announce( "onParse", data ); + return ( ParsingResult ) data.get( "result" ); } } diff --git a/src/main/java/ortus/boxlang/runtime/BoxRuntime.java b/src/main/java/ortus/boxlang/runtime/BoxRuntime.java index 042b3ec93..e945b4ed5 100644 --- a/src/main/java/ortus/boxlang/runtime/BoxRuntime.java +++ b/src/main/java/ortus/boxlang/runtime/BoxRuntime.java @@ -38,6 +38,8 @@ import ortus.boxlang.runtime.context.IBoxContext; import ortus.boxlang.runtime.context.RuntimeBoxContext; import ortus.boxlang.runtime.context.ScriptingBoxContext; +import ortus.boxlang.runtime.interceptors.ASTCapture; +import ortus.boxlang.runtime.interop.DynamicObject; import ortus.boxlang.runtime.logging.LoggingConfigurator; import ortus.boxlang.runtime.runnables.BoxScript; import ortus.boxlang.runtime.runnables.BoxTemplate; @@ -79,7 +81,8 @@ public class BoxRuntime { "postFunctionInvoke", "onScopeCreation", "onConfigurationLoad", - "onConfigurationOverrideLoad" + "onConfigurationOverrideLoad", + "onParse" ); /** @@ -229,6 +232,12 @@ private void loadConfiguration( Boolean debugMode, String configPath ) { } this.logger.atInfo().log( "+ DebugMode detected in config, overriding to {}", this.debugMode ); } + if ( this.debugMode ) { + this.interceptorService.register( + DynamicObject.of( new ASTCapture( true, true ) ), + Key.of( "onParse" ) + ); + } } /** diff --git a/src/main/java/ortus/boxlang/runtime/interceptors/ASTCapture.java b/src/main/java/ortus/boxlang/runtime/interceptors/ASTCapture.java new file mode 100644 index 000000000..b47f77691 --- /dev/null +++ b/src/main/java/ortus/boxlang/runtime/interceptors/ASTCapture.java @@ -0,0 +1,65 @@ +/** + * [BoxLang] + * + * Copyright [2023] [Ortus Solutions, Corp] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ortus.boxlang.runtime.interceptors; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardOpenOption; + +import ortus.boxlang.parser.ParsingResult; +import ortus.boxlang.runtime.types.Struct; + +/** + * An interceptor state is an event state that is used to hold observers that want to listent + * to that specific state. For example, the "preProcess" state is used to hold observers that + * listen to "preProcess" events. + * + * The {@see InterceptorService} is in charge of managing all states and event registrations in BoxLang. + */ +public class ASTCapture { + + private boolean toConsole = false; + private boolean toFile = false; + // Default to current working directory + private Path filePath = Paths.get( "./grapher/data/" ); + + public ASTCapture( boolean toConsole, boolean toFile ) { + this.toConsole = toConsole; + this.toFile = toFile; + } + + public void onParse( Struct data ) { + ParsingResult result = ( ParsingResult ) data.get( "result" ); + if ( result.getRoot() != null && ( toConsole || toFile ) ) { + String JSON = result.getRoot().toJSON().toString(); + if ( toConsole ) { + System.out.println( JSON ); + } + if ( toFile ) { + Path file = Paths.get( filePath.toString(), "lastAST.json" ); + try { + Files.writeString( file, JSON, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING ); + } catch ( IOException e ) { + e.printStackTrace(); + } + } + } + } +}