From e5ba63b3076db24444aa442c2d5ac2469b8c8f8a Mon Sep 17 00:00:00 2001 From: cardillan <122014763+cardillan@users.noreply.github.com> Date: Sat, 28 Sep 2024 23:38:22 +0200 Subject: [PATCH] Multiple input files to Mindcode compilation --- CHANGELOG.markdown | 5 +- README.markdown | 9 +- .../cmdline/CompileMindcodeAction.java | 23 +- .../templates/TOOLS-CMDLINE_template.markdown | 8 +- doc/syntax/SYNTAX-1-VARIABLES.markdown | 2 +- doc/syntax/SYNTAX-6-OPTIMIZATIONS.markdown | 35 +- doc/syntax/SYNTAX.markdown | 2 +- doc/syntax/TOOLS-CMDLINE.markdown | 15 +- doc/syntax/TROUBLESHOOTING.markdown | 4 +- .../info/teksol/mindcode/ast/Assignment.java | 5 +- .../info/teksol/mindcode/ast/AstNode.java | 3 + .../teksol/mindcode/ast/AstNodeBuilder.java | 198 +++-- .../info/teksol/mindcode/ast/BaseAstNode.java | 23 +- .../info/teksol/mindcode/ast/BinaryOp.java | 5 +- .../teksol/mindcode/ast/BoolBinaryOp.java | 5 +- .../teksol/mindcode/ast/BooleanLiteral.java | 5 +- .../teksol/mindcode/ast/BreakStatement.java | 5 +- .../teksol/mindcode/ast/CaseAlternative.java | 9 +- .../teksol/mindcode/ast/CaseExpression.java | 5 +- .../info/teksol/mindcode/ast/Constant.java | 5 +- .../teksol/mindcode/ast/ConstantAstNode.java | 5 +- .../mindcode/ast/ContinueStatement.java | 5 +- .../info/teksol/mindcode/ast/Control.java | 5 +- .../mindcode/ast/ControlBlockAstNode.java | 21 +- .../info/teksol/mindcode/ast/Directive.java | 5 +- .../mindcode/ast/DoWhileExpression.java | 5 +- .../teksol/mindcode/ast/ExclusiveRange.java | 5 +- .../mindcode/ast/ForEachExpression.java | 5 +- .../mindcode/ast/FormattableLiteral.java | 5 +- .../teksol/mindcode/ast/FunctionCall.java | 9 +- .../mindcode/ast/FunctionDeclaration.java | 5 +- .../info/teksol/mindcode/ast/HeapAccess.java | 13 +- .../teksol/mindcode/ast/HeapAllocation.java | 12 +- .../teksol/mindcode/ast/IfExpression.java | 5 +- .../teksol/mindcode/ast/InclusiveRange.java | 5 +- .../info/teksol/mindcode/ast/Iterator.java | 5 +- .../java/info/teksol/mindcode/ast/NoOp.java | 2 +- .../info/teksol/mindcode/ast/NullLiteral.java | 5 +- .../teksol/mindcode/ast/NumericLiteral.java | 9 +- .../teksol/mindcode/ast/NumericValue.java | 7 +- .../info/teksol/mindcode/ast/Parameter.java | 5 +- .../teksol/mindcode/ast/PropertyAccess.java | 5 +- .../java/info/teksol/mindcode/ast/Range.java | 5 +- .../mindcode/ast/RangedForExpression.java | 5 +- .../java/info/teksol/mindcode/ast/Ref.java | 5 +- .../teksol/mindcode/ast/ReturnStatement.java | 5 +- .../java/info/teksol/mindcode/ast/Seq.java | 17 +- .../teksol/mindcode/ast/StackAllocation.java | 16 +- .../teksol/mindcode/ast/StringLiteral.java | 5 +- .../info/teksol/mindcode/ast/UnaryOp.java | 5 +- .../java/info/teksol/mindcode/ast/VarRef.java | 5 +- .../teksol/mindcode/ast/WhileExpression.java | 5 +- .../teksol/mindcode/compiler/Compiler.java | 4 +- .../mindcode/compiler/CompilerFacade.java | 9 +- .../compiler/LogicInstructionPrinter.java | 22 +- .../mindcode/compiler/MindcodeCompiler.java | 32 +- .../mindcode/compiler/MindcodeMessage.java | 4 + .../teksol/mindcode/compiler/SourceFile.java | 10 + .../compiler/generator/CallGraph.java | 2 +- .../ConstantExpressionEvaluator.java | 8 +- .../mindcode/processor/AbstractVariable.java | 12 +- .../info/teksol/mindcode/AbstractAstTest.java | 5 +- .../mindcode/ast/AstNodeBuilderTest.java | 830 +++++++++--------- .../compiler/AbstractGeneratorTest.java | 2 +- .../compiler/DirectiveProcessorTest.java | 18 +- .../compiler/MindcodeCompilerTest.java | 33 +- .../compiler/generator/AstContextTest.java | 10 +- .../mindcode/grammar/AbstractParserTest.java | 10 +- .../teksol/mindcode/webapp/SamplesTest.java | 7 +- 69 files changed, 889 insertions(+), 721 deletions(-) create mode 100644 mindcode/src/main/java/info/teksol/mindcode/compiler/SourceFile.java diff --git a/CHANGELOG.markdown b/CHANGELOG.markdown index 63d194bb7..70ff2694b 100644 --- a/CHANGELOG.markdown +++ b/CHANGELOG.markdown @@ -27,8 +27,9 @@ Experimental features may contain bugs or produce suboptimal code, and are subje * Added support for multiple loop variables in [list iteration loops](doc/syntax/SYNTAX-3-STATEMENTS.markdown#list-iteration-loops). Each iteration processes as many elements from the list as there are loop variables. * Added an `out` keyword to be used with loop control variables in list iteration loop, allowing [list elements to be modified](/doc/syntax/SYNTAX-3-STATEMENTS.markdown#modifications-of-values-in-the-list). * Added a new GUI option to choose optimization level in the web app when compiling Mindcode or building Schemacode. -* Added a capability to run the compiled code on an emulated processor, by using a `Compile and Run` button in the web app, or the [`--run` command line option](/doc/syntax/TOOLS-CMDLINE.markdown#running-the-compiled-code). The output is shown in a separate control in the web app, or written to the log when using the command line tool. -* Added new optimization level, `experimental`. On this setting, the Data Flow optimizer doesn't assume the assignments to global variables might be changed by editing the compiled code, allowing to perform more optimizations on them. Program parameters must be used instead of global variables for program parametrization if this optimization level is used. +* Added a capability to run the compiled code on an emulated processor, by using a `Compile and Run` button in the web app, or the [`--run` command line option](/doc/syntax/TOOLS-CMDLINE.markdown#running-the-compiled-code). The output is shown in a separate control in the web app, or written to the log when using the command line tool. +* Added a capability to the command line tool to compile several source files at once using the [`--append` command line argument](doc/syntax/TOOLS-CMDLINE.markdown#additional-input-files). +* Added new optimization level, `experimental`. On this setting, the [Data Flow optimizer](doc/syntax/SYNTAX-6-OPTIMIZATIONS.markdown#data-flow-optimization) doesn't assume the assignments to global variables might be changed by editing the compiled code, allowing to perform more optimizations on them. Program parameters must be used instead of global variables for program parametrization if this optimization level is used. * Added [formattable string literals](doc/syntax/SYNTAX.markdown#formattable-string-literals), which allow formatting outputs of the `print` and `println` functions the same way as `printf` does. * Added [enhanced comments](doc/syntax/SYNTAX-4-FUNCTIONS.markdown#enhanced-comments), an alternative way to enter remarks. * Added new [`sort-variables` compiler directive](doc/syntax/SYNTAX-5-OTHER.markdown#option-sort-variables) which ensures that user variables will be accessed in a well-defined order, to make inspecting the variables in the Mindustry processors **Vars** screen easier. diff --git a/README.markdown b/README.markdown index 3c1bc5dcd..3cbae0527 100644 --- a/README.markdown +++ b/README.markdown @@ -4,11 +4,10 @@ Welcome to **Mindcode**, a high-level language for [Mindustry](https://github.com/Anuken/Mindustry). Mindustry is a game in the tower-defense genre. Mindustry added Logic in late 2020. Logic is a programming language, closer to assembly than a high-level language. Mindcode aims to make Mindustry programming easier for everyone. -Mindcode focuses of the following priorities: +The perils of using a high-level language for Mindustry code are inefficient code generation and the possibility of compiler bugs. Mindcode strives to address both of these issues: -* Simplicity: support for easy creation of short scripts as well as larger projects. Names and identifiers for Mindustry Logic objects and functions are derived from Mindustry Logic itself with minimal alterations. -* Efficiency: while there's still a lot of room for improvement, the mlog code produced by Mindcode is remarkably efficient thanks to many different [optimizations](doc/syntax/SYNTAX-6-OPTIMIZATIONS.markdown). Especially optimizations which [reduce runtime by increasing code size](doc/syntax/SYNTAX-6-OPTIMIZATIONS.markdown#optimization-for-speed) are quite unique among mlog compilers. -* Reliability: the project uses a battery of automated tests, including running the compiled code on an emulated processor, to ensure the compiled code works as expected. While [bugs do occur](https://github.com/cardillan/mindcode/issues?q=label%3Abug+), they often pertain to new functionality and get usually resolved quickly. +* Efficiency: while there's still a lot of room for improvement, the mlog code produced by Mindcode is quite efficient today. Mindcode is capable of simplifying expressions, removing unnecessary or unreachable code and using available instruction space to produce faster code by unrolling loops or inlining functions automatically. +* Reliability: this project uses a battery of automated tests, including running the compiled code on an emulated processor, to ensure the compiled code works as expected. While [bugs do occur](https://github.com/cardillan/mindcode/issues?q=label%3Abug+), they usually get resolved quickly. > [!NOTE] > Please have a look at planned [upcoming changes to Mindcode](https://github.com/cardillan/mindcode/discussions/142). These changes will be substantial, and any comments and suggestions are welcome now while the changes are still being deliberated. @@ -33,7 +32,7 @@ A [changelog](CHANGELOG.markdown) is now maintained for releases. Mindcode is available at http://mindcode.herokuapp.com/. Write some Mindcode in the _Mindcode Source Code_ text area, then press the **Compile** button. The _Mindustry Logic_ text area will contain the Logic version of your Mindcode. Copy the compiled version. Back in Mindustry, edit your processor, then use the **Edit** button in the Logic UI. Select **Import from Clipboard**. Mindustry is now ready to execute your code. -You can also use the **Compile and Run** button to execute the compiled code right away on an emulated processor. If your code doesn't interact with a contents of the Mindustry world, the output produced by your code will be displayed. +You can also use the **Compile and Run** button to execute the compiled code right away on an emulated processor. If your code doesn't interact with a contents of the Mindustry world, the output produced by `print` statements in your code will be displayed. It is also possible use the [command line tool](doc/syntax/TOOLS-CMDLINE.markdown) to compile your files, even copying the compiled code into the clipboard automatically if desired. The command line compiler can be set up in the following way: diff --git a/compiler/src/main/java/info/teksol/mindcode/cmdline/CompileMindcodeAction.java b/compiler/src/main/java/info/teksol/mindcode/cmdline/CompileMindcodeAction.java index 59aef35bf..707c57eef 100644 --- a/compiler/src/main/java/info/teksol/mindcode/cmdline/CompileMindcodeAction.java +++ b/compiler/src/main/java/info/teksol/mindcode/cmdline/CompileMindcodeAction.java @@ -4,6 +4,7 @@ import info.teksol.mindcode.compiler.CompilerMessage; import info.teksol.mindcode.compiler.CompilerOutput; import info.teksol.mindcode.compiler.CompilerProfile; +import info.teksol.mindcode.compiler.SourceFile; import net.sourceforge.argparse4j.impl.Arguments; import net.sourceforge.argparse4j.impl.type.FileArgumentType; import net.sourceforge.argparse4j.inf.ArgumentGroup; @@ -12,6 +13,7 @@ import net.sourceforge.argparse4j.inf.Subparsers; import java.io.File; +import java.util.ArrayList; import java.util.List; import static info.teksol.mindcode.compiler.CompilerFacade.compile; @@ -49,6 +51,12 @@ Subparser appendSubparser(Subparsers subparsers, FileArgumentType inputFileType, .nargs("?") .setDefault(new File("-")); + files.addArgument("-a", "--append") + .help("Additional Mindcode source file to be compiled along with the input file. Such additional files may " + + "contain common functions. More than one file may be added this way.") + .type(Arguments.fileType().verifyCanRead()) + .nargs("*"); + addCompilerOptions(subparser, defaults); addRunOptions(subparser, defaults); addOptimizationOptions(subparser, defaults); @@ -77,12 +85,23 @@ from the Mindustry World. Sole exceptions are memory cells (cell1 to cell9) and .setDefault(defaults.getStepLimit()); } + private SourceFile readFile(File file, boolean multiple) { + return new SourceFile(isStdInOut(file) || !multiple ? "" : file.getPath(), readInput(file)); + } + @Override void handle(Namespace arguments) { CompilerProfile compilerProfile = createCompilerProfile(arguments); - String sourceCode = readInput(arguments.get("input")); + List inputs = new ArrayList<>(); + inputs.add(arguments.get("input")); + List others = arguments.get("append"); + if (others != null) { + inputs.addAll(others); + } + + List sourceFiles = inputs.stream().map(f -> readFile(f, inputs.size() >1)).toList(); - final CompilerOutput result = compile(sourceCode, compilerProfile); + final CompilerOutput result = compile(sourceFiles, compilerProfile); File output = resolveOutputFile(arguments.get("input"), arguments.get("output"), ".mlog"); File logFile = resolveOutputFile(arguments.get("input"), arguments.get("log"), ".log"); diff --git a/compiler/src/test/resources/templates/TOOLS-CMDLINE_template.markdown b/compiler/src/test/resources/templates/TOOLS-CMDLINE_template.markdown index 127a1277f..05eedebf6 100644 --- a/compiler/src/test/resources/templates/TOOLS-CMDLINE_template.markdown +++ b/compiler/src/test/resources/templates/TOOLS-CMDLINE_template.markdown @@ -20,7 +20,13 @@ which must be one of the following: All actions take the name of input file and the name of output file as an argument. When the given input or output is a text file, the argument is optional and when not specified, the standard input/output is used. Use `-` to explicitly -specify standard input or output for input or output file. +specify standard input or output for input or output file. + +### Additional input files + +When performing the _Compile Mindcode_ action, it is possible to use the `-a` or `--append` command line parameter to specify additional source files to be compiled along with the input file. The source files are parsed separately and error messages that may be generated during the compilation include the name of the file where the error occurred. + +This feature is experimental and will be ultimately replaced by [support for modules](https://github.com/cardillan/mindcode/issues/149). ## Log file diff --git a/doc/syntax/SYNTAX-1-VARIABLES.markdown b/doc/syntax/SYNTAX-1-VARIABLES.markdown index 4df20cefd..574ea6d56 100644 --- a/doc/syntax/SYNTAX-1-VARIABLES.markdown +++ b/doc/syntax/SYNTAX-1-VARIABLES.markdown @@ -533,7 +533,7 @@ the entire `if DEBUG ... end` statement will be skipped and not included in the > > `const FMT = $"Position: ($x, $y)"; > -> The formattable string literal must be passed directly into the `print` or `println` functions. +> The formattable string literal must be passed directly into the `print`, `println`, `printf` or `remark` functions. ## Built-in icons diff --git a/doc/syntax/SYNTAX-6-OPTIMIZATIONS.markdown b/doc/syntax/SYNTAX-6-OPTIMIZATIONS.markdown index 811878aca..1d173f383 100644 --- a/doc/syntax/SYNTAX-6-OPTIMIZATIONS.markdown +++ b/doc/syntax/SYNTAX-6-OPTIMIZATIONS.markdown @@ -17,10 +17,10 @@ updated to replace the temporary variable with the target variable used in the s The optimization is performed only when the following conditions are met: -1. The `set` instruction assigns from a temporary variable. -2. The temporary variable is used in exactly one other instruction. The other instruction +* The `set` instruction assigns from a temporary variable. +* The temporary variable is used in exactly one other instruction. The other instruction immediately precedes the instruction producing the temporary variable. -3. All arguments of the other instruction referencing the temporary variable are output ones. +* All arguments of the other instruction referencing the temporary variable are output ones. `push` and `pop` instructions are ignored by the above algorithm. `push`/`pop` instructions of any eliminated variables are removed by the [Stack Optimization](#stack-optimization) down the line. @@ -35,11 +35,9 @@ statement. The optimization is performed only when the following conditions are met: -1. The set instruction assigns to a case-expression temporary variable. -2. The set instruction is the first of all those using the temporary variable (the check is based on absolute - instruction sequence in the program, not on the actual program flow). -3. Each subsequent instruction using the temporary variable conforms to the code generated by the compiler - (i.e. has the form of `jump target __astX testValue`) +* The set instruction assigns to a case-expression temporary variable. +* The set instruction is the first of all those using the temporary variable (the check is based on absolute instruction sequence in the program, not on the actual program flow). +* Each subsequent instruction using the temporary variable conforms to the code generated by the compiler (i.e. has the form of `jump target __astX testValue`) `push` and `pop` instructions are ignored by the above algorithm. `push`/`pop` instructions of any eliminated variables are removed by the stack usage optimization down the line. @@ -93,19 +91,18 @@ jump label / A B Prerequisites: -1. `jump` is an `equal`/`notEqual` comparison to `false`, -2. `var` is a temporary variable, -3. `var` is not used anywhere in the program except these two instructions, -4. `` has an inverse/`` exists as a condition. +* `jump` is an `equal`/`notEqual` comparison to `false`, +* `var` is a temporary variable, +* `var` is not used anywhere in the program except these two instructions, +* `` has an inverse/`` exists as a condition. ## Single Step Elimination This optimizer simplifies the following sequences of jump that are a result of certain combinations of optimizations: -1. A conditional or unconditional jump targeting the next instruction (such a jump is obviously unnecessary). -2. A conditional or unconditional jump identical to the next instruction (unconditional jumps would be also - eliminated by Unreachable Code Elimination, but that isn't true for conditional jumps). -3. On the `advanced` level, the `end` instruction at the very end of the program is removed, as the processor will jump to the first instruction of the program upon reaching the end of the instruction list anyway. +* A conditional or unconditional jump targeting the next instruction (such a jump is obviously unnecessary). +* A conditional or unconditional jump identical to the next instruction (unconditional jumps would be also eliminated by Unreachable Code Elimination, but that isn't true for conditional jumps). +* On the `advanced` level, the `end` instruction at the very end of the program is removed, as the processor will jump to the first instruction of the program upon reaching the end of the instruction list anyway. ## Expression Optimization @@ -324,7 +321,7 @@ understandable, but the optimizer would have to be more complex and therefore mo > code. > > **On basic and advanced optimization levels, global variables are handled in the same way as program parameters. On the experimental level, global -> variables are fully optimized in a way similar to main or local variables. Always use program parameters for allowing program +> variables are fully optimized in a way similar to main or local variables. Always use program parameters for program > parametrization.** ### Optimization levels @@ -757,7 +754,7 @@ The loop optimization improves loops with the condition at the beginning by perf The result of the first two optimizations in the list can be seen here: ``` -LIMIT = 10; +param LIMIT = 10; for i in 0 ... LIMIT do cell1[i] = 1; end; @@ -966,7 +963,7 @@ end; copy(cell1, cell2, 10); // This produces a loop that CANNOT be unrolled: SIZE is not a constant value -SIZE = 10; +param SIZE = 10; copy(cell1, cell2, SIZE); // Some loops containing expressions in the condition can still be unrolled, diff --git a/doc/syntax/SYNTAX.markdown b/doc/syntax/SYNTAX.markdown index 81a60df34..83530bc5f 100644 --- a/doc/syntax/SYNTAX.markdown +++ b/doc/syntax/SYNTAX.markdown @@ -35,7 +35,7 @@ Supporting tools: Additional information on Mindcode and Mindustry Logic: -* [Troubleshooting Mindcode](TROUBLESHOOTING.markdown)) +* [Troubleshooting Mindcode](TROUBLESHOOTING.markdown) * [Mindustry Tips and Tricks](MINDUSTRY-TIPS-N-TRICKS.markdown) --- diff --git a/doc/syntax/TOOLS-CMDLINE.markdown b/doc/syntax/TOOLS-CMDLINE.markdown index f089977e1..32d7fa14f 100644 --- a/doc/syntax/TOOLS-CMDLINE.markdown +++ b/doc/syntax/TOOLS-CMDLINE.markdown @@ -20,7 +20,13 @@ which must be one of the following: All actions take the name of input file and the name of output file as an argument. When the given input or output is a text file, the argument is optional and when not specified, the standard input/output is used. Use `-` to explicitly -specify standard input or output for input or output file. +specify standard input or output for input or output file. + +### Additional input files + +When performing the _Compile Mindcode_ action, it is possible to use the `-a` or `--append` command line parameter to specify additional source files to be compiled along with the input file. The source files are parsed separately and error messages that may be generated during the compilation include the name of the file where the error occurred. + +This feature is provisional and will be ultimately replaced by [Mindcode modules](https://github.com/cardillan/mindcode/issues/149). ## Log file @@ -87,8 +93,8 @@ Actions: ## Compile Mindcode action help ``` -usage: mindcode cm [-h] [-c] [-l [LOG]] [-t {6,7s,7w,7as,7aw}] [-i {1..100000}] [-e {1..1000}] [-g {SIZE,SPEED,AUTO}] - [-r {NONE,PASSIVE,ACTIVE}] +usage: mindcode cm [-h] [-c] [-l [LOG]] [-a [APPEND [APPEND ...]]] [-t {6,7s,7w,7as,7aw}] [-i {1..100000}] + [-e {1..1000}] [-g {SIZE,SPEED,AUTO}] [-r {NONE,PASSIVE,ACTIVE}] [--sort-variables [{LINKED,PARAMS,GLOBALS,MAIN,LOCALS,ALL,NONE} [{LINKED,PARAMS,GLOBALS,MAIN,LOCALS,ALL,NONE} ...]]] [--no-signature] [--run] [--run-steps {1..1000000000}] [-o LEVEL] [--temp-variables-elimination LEVEL] [--case-expression-optimization LEVEL] [--dead-code-elimination LEVEL] [--jump-normalization LEVEL] @@ -112,6 +118,9 @@ input/output files: specified, or stdout when input is stdin. Use "-" to force stdout output. -l, --log [LOG] Output file to receive compiler messages; uses input file with .log extension when no file is specified. + -a, --append [APPEND [APPEND ...]] + Additional Mindcode source file to be compiled along with the input file. Such additional + files may contain common functions. More than one file may be added this way. compiler options: -t, --target {6,7s,7w,7as,7aw} diff --git a/doc/syntax/TROUBLESHOOTING.markdown b/doc/syntax/TROUBLESHOOTING.markdown index 329b7a3b7..6587461aa 100644 --- a/doc/syntax/TROUBLESHOOTING.markdown +++ b/doc/syntax/TROUBLESHOOTING.markdown @@ -25,7 +25,7 @@ The main advantage is that the entire output of the program can be displayed and The other option to debug a Mindcode program is to examine its behavior in actual Mindustry World. Mindustry provides a way to inspect the program's variables in the **Vars** screen of the Mindustry processor shows all variables and their values, but the variables are displayed in the order in which they were created. This typically results in a very chaotic order of variables, where variables defined by the user are mixed with temporary variables, making it quite difficult to find a specific variable in sufficiently large programs. -It is possible to use the [`sort-variables`](SYNTAX-5-OTHER.markdown#option-sort-variables) compiler directive, or the `--sort-variables` command-line option, to make variables be displayed in a Mindustry processor in a well-defined order. Mindcode compiler ensures that by prepending a special block at the beginning of the program which creates user-defined variables in a specific order without altering their value. (The `packcolor` instruction is used, which can read - and therefore create - up to four variables per instruction. The result is not stored anywhere so that the variable-ordering code block doesn't change values of any variables, and therefore the behavior of the program remains unaltered, except for possible difference in timing.) +It is possible to use the [`sort-variables`](SYNTAX-5-OTHER.markdown#option-sort-variables) compiler directive, or the `--sort-variables` command-line option, to make variables be displayed in a Mindustry processor in a well-defined order. Mindcode compiler ensures that by prepending a special block at the beginning of the program which creates user-defined variables in a specific order without altering their value. (The `packcolor` instruction is used, which can read - and therefore create - up to four variables per instruction, without any side effects. The result is not stored anywhere so that the variable-ordering code block doesn't change values of any variables, and therefore the behavior of the program remains unaltered, except for an unavoidable difference in total runtime of the program.) An example of a program created with sorting variables: @@ -78,7 +78,7 @@ print "\n" end ``` -The number of variables being sorted is limited by the [instruction limit](#option-instruction-limit). Should the resulting program size exceeds the instruction limit, some or all variables will remain unordered. +The number of variables being sorted is limited by the [instruction limit](#option-instruction-limit). Should the resulting program size exceed the instruction limit, some or all variables will remain unordered. --- diff --git a/mindcode/src/main/java/info/teksol/mindcode/ast/Assignment.java b/mindcode/src/main/java/info/teksol/mindcode/ast/Assignment.java index 600d34abd..7f642a161 100644 --- a/mindcode/src/main/java/info/teksol/mindcode/ast/Assignment.java +++ b/mindcode/src/main/java/info/teksol/mindcode/ast/Assignment.java @@ -1,5 +1,6 @@ package info.teksol.mindcode.ast; +import info.teksol.mindcode.compiler.SourceFile; import info.teksol.mindcode.compiler.generator.AstContextType; import org.antlr.v4.runtime.Token; @@ -9,8 +10,8 @@ public class Assignment extends BaseAstNode { private final AstNode var; private final AstNode value; - public Assignment(Token startToken, AstNode var, AstNode value) { - super(startToken, var, value); + public Assignment(Token startToken, SourceFile sourceFile, AstNode var, AstNode value) { + super(startToken, sourceFile, var, value); this.var = var; this.value = value; } diff --git a/mindcode/src/main/java/info/teksol/mindcode/ast/AstNode.java b/mindcode/src/main/java/info/teksol/mindcode/ast/AstNode.java index 708c11961..9e1444c93 100644 --- a/mindcode/src/main/java/info/teksol/mindcode/ast/AstNode.java +++ b/mindcode/src/main/java/info/teksol/mindcode/ast/AstNode.java @@ -1,5 +1,6 @@ package info.teksol.mindcode.ast; +import info.teksol.mindcode.compiler.SourceFile; import info.teksol.mindcode.compiler.generator.AstContextType; import info.teksol.mindcode.compiler.generator.AstSubcontextType; import org.antlr.v4.runtime.Token; @@ -11,6 +12,8 @@ public interface AstNode { Token startToken(); + SourceFile sourceFile(); + AstContextType getContextType(); AstSubcontextType getSubcontextType(); diff --git a/mindcode/src/main/java/info/teksol/mindcode/ast/AstNodeBuilder.java b/mindcode/src/main/java/info/teksol/mindcode/ast/AstNodeBuilder.java index ce4c96455..a3ca20c25 100644 --- a/mindcode/src/main/java/info/teksol/mindcode/ast/AstNodeBuilder.java +++ b/mindcode/src/main/java/info/teksol/mindcode/ast/AstNodeBuilder.java @@ -2,6 +2,7 @@ import info.teksol.mindcode.MindcodeException; import info.teksol.mindcode.MindcodeInternalError; +import info.teksol.mindcode.compiler.SourceFile; import info.teksol.mindcode.grammar.MindcodeBaseVisitor; import info.teksol.mindcode.grammar.MindcodeParser; @@ -9,13 +10,18 @@ public class AstNodeBuilder extends MindcodeBaseVisitor { public static final String AST_PREFIX = "__ast"; + private final SourceFile sourceFile; private final Map heapAllocations = new HashMap<>(); private int temp; private HeapAllocation allocatedHeap; private StackAllocation allocatedStack; - public static Seq generate(MindcodeParser.ProgramContext program) { - final AstNodeBuilder builder = new AstNodeBuilder(); + public AstNodeBuilder(SourceFile sourceFile) { + this.sourceFile = sourceFile; + } + + public static Seq generate(SourceFile sourceFile, MindcodeParser.ProgramContext program) { + final AstNodeBuilder builder = new AstNodeBuilder(sourceFile); final AstNode node = builder.visit(program); return (Seq) node; } @@ -36,11 +42,11 @@ private void allocateHeap(MindcodeParser.Alloc_listContext ctx) { if (ctx.alloc_range() != null) { range = (Range) visit(ctx.alloc_range()); } else { - range = new ExclusiveRange(ctx.getStart(), - new NumericLiteral(ctx.getStart(), "0"), new NumericLiteral(ctx.getStart(), "64")); + range = new ExclusiveRange(ctx.getStart(), sourceFile, + new NumericLiteral(ctx.getStart(), sourceFile, "0"), new NumericLiteral(ctx.getStart(), sourceFile, "64")); } - allocatedHeap = new HeapAllocation(ctx.getStart(), name, range); + allocatedHeap = new HeapAllocation(ctx.getStart(), sourceFile, name, range); } private void allocateStack(MindcodeParser.Alloc_listContext ctx) { @@ -50,9 +56,9 @@ private void allocateStack(MindcodeParser.Alloc_listContext ctx) { final String name = ctx.id().getText(); if (ctx.alloc_range() != null) { - allocatedStack = new StackAllocation(ctx.getStart(), name, (Range) visit(ctx.alloc_range())); + allocatedStack = new StackAllocation(ctx.getStart(), sourceFile, name, (Range) visit(ctx.alloc_range())); } else { - allocatedStack = new StackAllocation(ctx.getStart(), name); + allocatedStack = new StackAllocation(ctx.getStart(), sourceFile, name); } } @@ -79,7 +85,7 @@ private List createListOfValues(MindcodeParser.When_value_listContext v nodes = new NoOp(); } - gatherValues(new Seq(values.getStart(), nodes, visit(values.when_expression())), result); + gatherValues(new Seq(values.getStart(), sourceFile, nodes, visit(values.when_expression())), result); } return result; @@ -132,7 +138,7 @@ public AstNode visitAllocation(MindcodeParser.AllocationContext ctx) { alloc_list = alloc_list.alloc_list(); } - return new Seq(ctx.getStart(), + return new Seq(ctx.getStart(), sourceFile, Objects.requireNonNullElseGet(allocatedHeap, NoOp::new), Objects.requireNonNullElseGet(allocatedStack, NoOp::new) ); @@ -140,15 +146,15 @@ public AstNode visitAllocation(MindcodeParser.AllocationContext ctx) { @Override public AstNode visitAlternative(MindcodeParser.AlternativeContext ctx) { - return new CaseAlternative(ctx.getStart(), + return new CaseAlternative(ctx.getStart(), sourceFile, createListOfValues(ctx.values), - ctx.body == null ? new Seq(ctx.getStart(), new NoOp()) : visit(ctx.body)); + ctx.body == null ? new Seq(ctx.getStart(), sourceFile, new NoOp()) : visit(ctx.body)); } @Override public AstNode visitAlternative_list(MindcodeParser.Alternative_listContext ctx) { if (ctx.alternative_list() != null) { - return new Seq(ctx.getStart(), visit(ctx.alternative_list()), visit(ctx.alternative())); + return new Seq(ctx.getStart(), sourceFile, visit(ctx.alternative_list()), visit(ctx.alternative())); } else { return visit(ctx.alternative()); } @@ -164,29 +170,29 @@ public AstNode visitArg_decl_list(MindcodeParser.Arg_decl_listContext ctx) { } final AstNode last = visit(ctx.var_ref()); - return new Seq(ctx.getStart(), rest, last); + return new Seq(ctx.getStart(), sourceFile, rest, last); } @Override public AstNode visitArg_list(MindcodeParser.Arg_listContext ctx) { if (ctx.arg_list() != null) { - return new Seq(ctx.getStart(), visit(ctx.arg_list()), visit(ctx.arg())); + return new Seq(ctx.getStart(), sourceFile, visit(ctx.arg_list()), visit(ctx.arg())); } else { final AstNode last = visit(ctx.arg()); - return new Seq(ctx.getStart(), last); + return new Seq(ctx.getStart(), sourceFile, last); } } @Override public AstNode visitBinop_and(MindcodeParser.Binop_andContext ctx) { return ctx.op.getText().equals("and") - ? new BoolBinaryOp(ctx.getStart(), visit(ctx.left), "and", visit(ctx.right)) - : new BinaryOp(ctx.getStart(), visit(ctx.left), "and", visit(ctx.right)); + ? new BoolBinaryOp(ctx.getStart(), sourceFile, visit(ctx.left), "and", visit(ctx.right)) + : new BinaryOp(ctx.getStart(), sourceFile, visit(ctx.left), "and", visit(ctx.right)); } @Override public AstNode visitBinop_bitwise_and(MindcodeParser.Binop_bitwise_andContext ctx) { - return new BinaryOp(ctx.getStart(), + return new BinaryOp(ctx.getStart(), sourceFile, visit(ctx.left), "&", visit(ctx.right) @@ -195,23 +201,23 @@ public AstNode visitBinop_bitwise_and(MindcodeParser.Binop_bitwise_andContext ct @Override public AstNode visitBinop_bitwise_or(MindcodeParser.Binop_bitwise_orContext ctx) { - return new BinaryOp(ctx.getStart(), visit(ctx.left), ctx.op.getText(), visit(ctx.right)); + return new BinaryOp(ctx.getStart(), sourceFile, visit(ctx.left), ctx.op.getText(), visit(ctx.right)); } @Override public AstNode visitBinop_equality_comparison(MindcodeParser.Binop_equality_comparisonContext ctx) { if (ctx.op.getText().equals("!==")) { - return new BinaryOp(ctx.getStart(), - new BinaryOp(ctx.getStart(), + return new BinaryOp(ctx.getStart(), sourceFile, + new BinaryOp(ctx.getStart(), sourceFile, visit(ctx.left), "===", visit(ctx.right) ), "==", - new BooleanLiteral(ctx.getStart(), false) + new BooleanLiteral(ctx.getStart(), sourceFile, false) ); } else { - return new BinaryOp(ctx.getStart(), + return new BinaryOp(ctx.getStart(), sourceFile, visit(ctx.left), ctx.op.getText(), visit(ctx.right) @@ -221,7 +227,7 @@ public AstNode visitBinop_equality_comparison(MindcodeParser.Binop_equality_comp @Override public AstNode visitBinop_exp(MindcodeParser.Binop_expContext ctx) { - return new BinaryOp(ctx.getStart(), + return new BinaryOp(ctx.getStart(), sourceFile, visit(ctx.left), "**", visit(ctx.right) @@ -230,7 +236,7 @@ public AstNode visitBinop_exp(MindcodeParser.Binop_expContext ctx) { @Override public AstNode visitBinop_inequality_comparison(MindcodeParser.Binop_inequality_comparisonContext ctx) { - return new BinaryOp(ctx.getStart(), + return new BinaryOp(ctx.getStart(), sourceFile, visit(ctx.left), ctx.op.getText(), visit(ctx.right) @@ -239,7 +245,7 @@ public AstNode visitBinop_inequality_comparison(MindcodeParser.Binop_inequality_ @Override public AstNode visitBinop_mul_div_mod(MindcodeParser.Binop_mul_div_modContext ctx) { - return new BinaryOp(ctx.getStart(), + return new BinaryOp(ctx.getStart(), sourceFile, visit(ctx.left), ctx.op.getText(), visit(ctx.right) @@ -249,13 +255,13 @@ public AstNode visitBinop_mul_div_mod(MindcodeParser.Binop_mul_div_modContext ct @Override public AstNode visitBinop_or(MindcodeParser.Binop_orContext ctx) { return ctx.op.getText().equals("or") - ? new BoolBinaryOp(ctx.getStart(), visit(ctx.left), "or", visit(ctx.right)) - : new BinaryOp(ctx.getStart(), visit(ctx.left), "or", visit(ctx.right)); + ? new BoolBinaryOp(ctx.getStart(), sourceFile, visit(ctx.left), "or", visit(ctx.right)) + : new BinaryOp(ctx.getStart(), sourceFile, visit(ctx.left), "or", visit(ctx.right)); } @Override public AstNode visitBinop_plus_minus(MindcodeParser.Binop_plus_minusContext ctx) { - return new BinaryOp(ctx.getStart(), + return new BinaryOp(ctx.getStart(), sourceFile, visit(ctx.left), ctx.op.getText(), visit(ctx.right) @@ -264,18 +270,18 @@ public AstNode visitBinop_plus_minus(MindcodeParser.Binop_plus_minusContext ctx) @Override public AstNode visitBinop_shift(MindcodeParser.Binop_shiftContext ctx) { - return new BinaryOp(ctx.getStart(), visit(ctx.left), ctx.op.getText(), visit(ctx.right)); + return new BinaryOp(ctx.getStart(), sourceFile, visit(ctx.left), ctx.op.getText(), visit(ctx.right)); } @Override public AstNode visitBitwise_not_expr(MindcodeParser.Bitwise_not_exprContext ctx) { - return new UnaryOp(ctx.getStart(), "~", visit(ctx.expression())); + return new UnaryOp(ctx.getStart(), sourceFile, "~", visit(ctx.expression())); } @Override public AstNode visitBreak_exp(MindcodeParser.Break_expContext ctx) { String label = ctx.break_st().label == null ? null : ctx.break_st().label.getText(); - return new BreakStatement(ctx.getStart(), label); + return new BreakStatement(ctx.getStart(), sourceFile, label); } @Override @@ -291,12 +297,12 @@ public AstNode visitCase_expression(MindcodeParser.Case_expressionContext ctx) { final List alternatives = new ArrayList<>(); gatherAlternatives(visit(ctx.case_expr().alternative_list()), alternatives); - return new Seq(ctx.getStart(), - new Assignment(ctx.getStart(), - new VarRef(ctx.getStart(), tmp), + return new Seq(ctx.getStart(), sourceFile, + new Assignment(ctx.getStart(), sourceFile, + new VarRef(ctx.getStart(), sourceFile, tmp), visit(ctx.case_expr().cond)), - new CaseExpression(ctx.getStart(), - new VarRef(ctx.getStart(), tmp), + new CaseExpression(ctx.getStart(), sourceFile, + new VarRef(ctx.getStart(), sourceFile, tmp), alternatives, elseBranch ) @@ -306,9 +312,9 @@ public AstNode visitCase_expression(MindcodeParser.Case_expressionContext ctx) { @Override public AstNode visitCompound_assign(MindcodeParser.Compound_assignContext ctx) { final AstNode target = visit(ctx.target); - return new Assignment(ctx.getStart(), + return new Assignment(ctx.getStart(), sourceFile, target, - new BinaryOp(ctx.getStart(), + new BinaryOp(ctx.getStart(), sourceFile, target, ctx.op.getText().replace("=", ""), visit(ctx.value) @@ -320,24 +326,24 @@ public AstNode visitCompound_assign(MindcodeParser.Compound_assignContext ctx) { public AstNode visitConst_decl(MindcodeParser.Const_declContext ctx) { final String name = ctx.name.getText(); final AstNode value = visit(ctx.value); - return new Constant(ctx.getStart(), name, value); + return new Constant(ctx.getStart(), sourceFile, name, value); } @Override public AstNode visitContinue_exp(MindcodeParser.Continue_expContext ctx) { String label = ctx.continue_st().label == null ? null : ctx.continue_st().label.getText(); - return new ContinueStatement(ctx.getStart(), label); + return new ContinueStatement(ctx.getStart(), sourceFile, label); } @Override public AstNode visitDo_while_expression(MindcodeParser.Do_while_expressionContext ctx) { String label = ctx.label == null ? null : ctx.label.getText(); - return new DoWhileExpression(ctx.getStart(), label, visit(ctx.loop_body()), visit(ctx.cond)); + return new DoWhileExpression(ctx.getStart(), sourceFile, label, visit(ctx.loop_body()), visit(ctx.cond)); } @Override public AstNode visitExclusive_range_exp(MindcodeParser.Exclusive_range_expContext ctx) { - return new ExclusiveRange(ctx.getStart(),visit(ctx.start), visit(ctx.end)); + return new ExclusiveRange(ctx.getStart(), sourceFile,visit(ctx.start), visit(ctx.end)); } @Override @@ -345,11 +351,11 @@ public AstNode visitExpression_list(MindcodeParser.Expression_listContext ctx) { if (ctx.expression_list() != null) { final AstNode rest = visit(ctx.expression_list()); final AstNode expr = visit(ctx.expression()); - return new Seq(ctx.getStart(), rest, expr); + return new Seq(ctx.getStart(), sourceFile, rest, expr); } else if (ctx.expression() != null) { final AstNode expr = visit(ctx.expression()); if (expr instanceof Seq) return expr; - return new Seq(ctx.getStart(), expr); + return new Seq(ctx.getStart(), sourceFile, expr); } else { return new NoOp(); } @@ -357,18 +363,18 @@ public AstNode visitExpression_list(MindcodeParser.Expression_listContext ctx) { @Override public AstNode visitFalse_bool_literal(MindcodeParser.False_bool_literalContext ctx) { - return new BooleanLiteral(ctx.getStart(), false); + return new BooleanLiteral(ctx.getStart(), sourceFile, false); } @Override public AstNode visitFloat_t(MindcodeParser.Float_tContext ctx) { - return new NumericLiteral(ctx.getStart(), ctx.getText()); + return new NumericLiteral(ctx.getStart(), sourceFile, ctx.getText()); } @Override public AstNode visitFor_each_1(MindcodeParser.For_each_1Context ctx) { String label = ctx.label == null ? null : ctx.label.getText(); - return new ForEachExpression(ctx.getStart(), label, + return new ForEachExpression(ctx.getStart(), sourceFile, label, createListOfIterators(ctx.iterators), createListOfValues(ctx.values), visit(ctx.loop_body())); @@ -377,7 +383,7 @@ public AstNode visitFor_each_1(MindcodeParser.For_each_1Context ctx) { @Override public AstNode visitFor_each_2(MindcodeParser.For_each_2Context ctx) { String label = ctx.label == null ? null : ctx.label.getText(); - return new ForEachExpression(ctx.getStart(), label, + return new ForEachExpression(ctx.getStart(), sourceFile, label, createListOfIterators(ctx.iterators), createListOfValues(ctx.values), visit(ctx.loop_body())); @@ -395,13 +401,13 @@ public AstNode visitFunction_call(MindcodeParser.Function_callContext ctx) { nodes = new NoOp(); } - gatherArgs(new Seq(ctx.getStart(), nodes, visit(ctx.funcall().params.arg())), params); + gatherArgs(new Seq(ctx.getStart(), sourceFile, nodes, visit(ctx.funcall().params.arg())), params); } if (ctx.funcall().END() != null) { // The end function is a bit special: because the keyword "end" is also used to // close blocks, the grammar needed to special-case the end function directly. - return new FunctionCall(ctx.getStart(), "end"); + return new FunctionCall(ctx.getStart(), sourceFile, "end"); } else if (ctx.funcall().obj != null) { final AstNode target; if (ctx.funcall().obj.unit_ref() != null) { @@ -412,14 +418,14 @@ public AstNode visitFunction_call(MindcodeParser.Function_callContext ctx) { throw new MindcodeInternalError("Failed to parse function call on a property access at " + ctx.getText()); } - return new Control(ctx.getStart(), + return new Control(ctx.getStart(), sourceFile, target, ctx.funcall().obj.prop.getText(), params ); } else { final String name = ctx.funcall().name.getText(); - return new FunctionCall(ctx.getStart(), name, params); + return new FunctionCall(ctx.getStart(), sourceFile, name, params); } } @@ -436,7 +442,7 @@ public AstNode visitFunction_declaration(MindcodeParser.Function_declarationCont gatherArgs(args, params); String strInline = ctx.fundecl().inline == null ? null : ctx.fundecl().inline.getText(); - return new FunctionDeclaration(ctx.getStart(), + return new FunctionDeclaration(ctx.getStart(), sourceFile, "inline".equals(strInline), "noinline".equals(strInline), ctx.fundecl().name.getText(), @@ -460,12 +466,12 @@ public AstNode visitGlobal_ref(MindcodeParser.Global_refContext ctx) { heapAllocations.put(name, location); } - return new HeapAccess(ctx.getStart(), allocatedHeap.getName(), location); + return new HeapAccess(ctx.getStart(), sourceFile, allocatedHeap.getName(), location); } @Override public AstNode visitHeap_ref(MindcodeParser.Heap_refContext ctx) { - return new HeapAccess(ctx.getStart(), + return new HeapAccess(ctx.getStart(), sourceFile, ctx.name.getText(), visit(ctx.address) ); @@ -480,9 +486,9 @@ public AstNode visitIf_expression(MindcodeParser.If_expressionContext ctx) { trailer = new NoOp(); } - return new IfExpression(ctx.getStart(), + return new IfExpression(ctx.getStart(), sourceFile, visit(ctx.if_expr().cond), - ctx.if_expr().true_branch == null ? new Seq(ctx.getStart(), new NoOp()) : visit(ctx.if_expr().true_branch), + ctx.if_expr().true_branch == null ? new Seq(ctx.getStart(), sourceFile, new NoOp()) : visit(ctx.if_expr().true_branch), trailer ); } @@ -497,12 +503,12 @@ public AstNode visitIf_trailer(MindcodeParser.If_trailerContext ctx) { trailer = new NoOp(); } - return new IfExpression(ctx.getStart(), + return new IfExpression(ctx.getStart(), sourceFile, visit(ctx.cond), - ctx.true_branch == null ? new Seq(ctx.getStart(), new NoOp()) : visit(ctx.true_branch), + ctx.true_branch == null ? new Seq(ctx.getStart(), sourceFile, new NoOp()) : visit(ctx.true_branch), trailer); } else if (ctx.ELSE() != null) { - return ctx.false_branch == null ? new Seq(ctx.getStart(), new NoOp()) : visit(ctx.false_branch); + return ctx.false_branch == null ? new Seq(ctx.getStart(), sourceFile, new NoOp()) : visit(ctx.false_branch); } else { throw new MindcodeInternalError("Unhandled if/elsif/else; neither ELSIF nor ELSE were true in " + ctx.getText()); } @@ -510,14 +516,14 @@ public AstNode visitIf_trailer(MindcodeParser.If_trailerContext ctx) { @Override public AstNode visitInclusive_range_exp(MindcodeParser.Inclusive_range_expContext ctx) { - return new InclusiveRange(ctx.getStart(),visit(ctx.start), visit(ctx.end)); + return new InclusiveRange(ctx.getStart(), sourceFile,visit(ctx.start), visit(ctx.end)); } @Override public AstNode visitIncr_list(MindcodeParser.Incr_listContext ctx) { if (ctx.incr_list() != null) { final AstNode down = visit(ctx.incr_list()); - return new Seq(ctx.getStart(), down, visit(ctx.expression())); + return new Seq(ctx.getStart(), sourceFile, down, visit(ctx.expression())); } else { return visit(ctx.expression()); } @@ -525,14 +531,14 @@ public AstNode visitIncr_list(MindcodeParser.Incr_listContext ctx) { @Override public AstNode visitIndirectpropaccess(MindcodeParser.IndirectpropaccessContext ctx) { - return new PropertyAccess(ctx.getStart(), visit(ctx.target), visit(ctx.expr)); + return new PropertyAccess(ctx.getStart(), sourceFile, visit(ctx.target), visit(ctx.expr)); } @Override public AstNode visitInit_list(MindcodeParser.Init_listContext ctx) { if (ctx.init_list() != null) { final AstNode down = visit(ctx.init_list()); - return new Seq(ctx.getStart(), down, visit(ctx.expression())); + return new Seq(ctx.getStart(), sourceFile, down, visit(ctx.expression())); } else { return visit(ctx.expression()); } @@ -540,13 +546,13 @@ public AstNode visitInit_list(MindcodeParser.Init_listContext ctx) { @Override public AstNode visitInt_t(MindcodeParser.Int_tContext ctx) { - return new NumericLiteral(ctx.getStart(), ctx.getText()); + return new NumericLiteral(ctx.getStart(), sourceFile, ctx.getText()); } @Override public AstNode visitIterated_for(MindcodeParser.Iterated_forContext ctx) { String label = ctx.label == null ? null : ctx.label.getText(); - return new WhileExpression(ctx.getStart(), + return new WhileExpression(ctx.getStart(), sourceFile, label, visit(ctx.init), visit(ctx.cond), @@ -560,64 +566,64 @@ public AstNode visitIterator(MindcodeParser.IteratorContext ctx) { // At this point, no other modifier is allowed by the syntax boolean outModifier = ctx.modifier != null; final VarRef varRef = (VarRef) visit(ctx.lvalue()); - return new Iterator(ctx.getStart(), true, outModifier, varRef); + return new Iterator(ctx.getStart(), sourceFile, true, outModifier, varRef); } @Override public AstNode visitLiteral_minus(MindcodeParser.Literal_minusContext ctx) { - return new NumericLiteral(ctx.getStart(), ctx.getText()); + return new NumericLiteral(ctx.getStart(), sourceFile, ctx.getText()); } @Override public AstNode visitLiteral_null(MindcodeParser.Literal_nullContext ctx) { - return new NullLiteral(ctx.getStart()); + return new NullLiteral(ctx.getStart(), sourceFile); } @Override public AstNode visitLiteral_string(MindcodeParser.Literal_stringContext ctx) { final String str = ctx.getText(); - return new StringLiteral(ctx.getStart(), str.substring(1, str.length() - 1).replaceAll("\\\\\"", "\"")); + return new StringLiteral(ctx.getStart(), sourceFile, str.substring(1, str.length() - 1).replaceAll("\\\\\"", "\"")); } @Override public AstNode visitList_directive(MindcodeParser.List_directiveContext ctx) { if (ctx.directive_list() == null) { - return new Directive(ctx.getStart(), ctx.option.getText(), ""); + return new Directive(ctx.getStart(), sourceFile, ctx.option.getText(), ""); } else { - return new Directive(ctx.getStart(), ctx.option.getText(), ctx.directive_list().getText()); + return new Directive(ctx.getStart(), sourceFile, ctx.option.getText(), ctx.directive_list().getText()); } } @Override public AstNode visitLiteral_formattable(MindcodeParser.Literal_formattableContext ctx) { final String str = ctx.getText(); - return new FormattableLiteral(ctx.getStart(), str.substring(2, str.length() - 1)); + return new FormattableLiteral(ctx.getStart(), sourceFile, str.substring(2, str.length() - 1)); } @Override public AstNode visitNot_expr(MindcodeParser.Not_exprContext ctx) { - return new BinaryOp(ctx.getStart(), + return new BinaryOp(ctx.getStart(), sourceFile, visit(ctx.expression()), "==", - new BooleanLiteral(ctx.getStart(), false)); + new BooleanLiteral(ctx.getStart(), sourceFile, false)); } @Override public AstNode visitNumeric_directive(MindcodeParser.Numeric_directiveContext ctx) { - return new Directive(ctx.getStart(), ctx.option.getText(), ctx.value.getText()); + return new Directive(ctx.getStart(), sourceFile, ctx.option.getText(), ctx.value.getText()); } @Override public AstNode visitParam_decl(MindcodeParser.Param_declContext ctx) { final String name = ctx.name.getText(); final AstNode value = visit(ctx.value); - return new Parameter(ctx.getStart(), name, value); + return new Parameter(ctx.getStart(), sourceFile, name, value); } @Override public AstNode visitProgram(MindcodeParser.ProgramContext ctx) { final AstNode parent = super.visitProgram(ctx); - if (parent == null) return new Seq(ctx.getStart(), new NoOp()); + if (parent == null) return new Seq(ctx.getStart(), sourceFile, new NoOp()); return parent; } @@ -632,7 +638,7 @@ public AstNode visitPropaccess(MindcodeParser.PropaccessContext ctx) { throw new MindcodeInternalError("Expected var ref or unit ref in " + ctx.getText()); } - return new PropertyAccess(ctx.getStart(), target, new Ref(ctx.getStart(), ctx.prop.getText())); + return new PropertyAccess(ctx.getStart(), sourceFile, target, new Ref(ctx.getStart(), sourceFile, ctx.prop.getText())); } @Override @@ -641,30 +647,30 @@ public AstNode visitRanged_for(MindcodeParser.Ranged_forContext ctx) { final AstNode var = visit(ctx.lvalue()); final Range range = (Range) visit(ctx.range_expression()); final AstNode body = visit(ctx.loop_body()); - return new RangedForExpression(ctx.getStart(), label, var, range, body); + return new RangedForExpression(ctx.getStart(), sourceFile, label, var, range, body); } @Override public AstNode visitReturn_exp(MindcodeParser.Return_expContext ctx) { - AstNode retval = ctx.return_st().retval == null ? new NullLiteral(ctx.getStart()) : visit(ctx.return_st().retval); - return new ReturnStatement(ctx.getStart(), retval); + AstNode retval = ctx.return_st().retval == null ? new NullLiteral(ctx.getStart(), sourceFile) : visit(ctx.return_st().retval); + return new ReturnStatement(ctx.getStart(), sourceFile, retval); } @Override public AstNode visitSimple_assign(MindcodeParser.Simple_assignContext ctx) { final AstNode lvalue = visit(ctx.target); final AstNode value = visit(ctx.value); - return new Assignment(ctx.getStart(),lvalue, value); + return new Assignment(ctx.getStart(), sourceFile,lvalue, value); } @Override public AstNode visitString_directive(MindcodeParser.String_directiveContext ctx) { - return new Directive(ctx.getStart(), ctx.option.getText(), ctx.value.getText()); + return new Directive(ctx.getStart(), sourceFile, ctx.option.getText(), ctx.value.getText()); } @Override public AstNode visitTernary_op(MindcodeParser.Ternary_opContext ctx) { - return new IfExpression(ctx.getStart(), + return new IfExpression(ctx.getStart(), sourceFile, visit(ctx.cond), visit(ctx.true_branch), visit(ctx.false_branch) @@ -673,41 +679,41 @@ public AstNode visitTernary_op(MindcodeParser.Ternary_opContext ctx) { @Override public AstNode visitTrue_bool_literal(MindcodeParser.True_bool_literalContext ctx) { - return new BooleanLiteral(ctx.getStart(), true); + return new BooleanLiteral(ctx.getStart(), sourceFile, true); } @Override public AstNode visitUnary_minus(MindcodeParser.Unary_minusContext ctx) { - return new BinaryOp(ctx.getStart(), - new NumericLiteral(ctx.getStart(), "-1"), + return new BinaryOp(ctx.getStart(), sourceFile, + new NumericLiteral(ctx.getStart(), sourceFile, "-1"), "*", visit(ctx.expression())); } @Override public AstNode visitUnit_ref(MindcodeParser.Unit_refContext ctx) { - return new Ref(ctx.getStart(), ctx.ref().getText()); + return new Ref(ctx.getStart(), sourceFile, ctx.ref().getText()); } @Override public AstNode visitVar_ref(MindcodeParser.Var_refContext ctx) { - return new VarRef(ctx.getStart(), ctx.getText()); + return new VarRef(ctx.getStart(), sourceFile, ctx.getText()); } @Override public AstNode visitWhen_value_list(MindcodeParser.When_value_listContext ctx) { if (ctx.when_value_list()!= null) { - return new Seq(ctx.getStart(), visit(ctx.when_value_list()), visit(ctx.when_expression())); + return new Seq(ctx.getStart(), sourceFile, visit(ctx.when_value_list()), visit(ctx.when_expression())); } else { final AstNode last = visit(ctx.when_expression()); - return new Seq(ctx.getStart(), last); + return new Seq(ctx.getStart(), sourceFile, last); } } @Override public AstNode visitWhile_expression(MindcodeParser.While_expressionContext ctx) { String label = ctx.label == null ? null : ctx.label.getText(); - return new WhileExpression(ctx.getStart(),label, new NoOp(), + return new WhileExpression(ctx.getStart(), sourceFile,label, new NoOp(), visit(ctx.cond), visit(ctx.loop_body()), new NoOp()); } @@ -715,8 +721,8 @@ public AstNode visitWhile_expression(MindcodeParser.While_expressionContext ctx) @Override public AstNode visitRem_comment(MindcodeParser.Rem_commentContext ctx) { String str = ctx.getText().substring(3).strip(); - StringLiteral text = new StringLiteral(ctx.getStart(), str); + StringLiteral text = new StringLiteral(ctx.getStart(), sourceFile, str); List params = List.of(text); - return new FunctionCall(ctx.getStart(), "remark", params); + return new FunctionCall(ctx.getStart(), sourceFile, "remark", params); } } diff --git a/mindcode/src/main/java/info/teksol/mindcode/ast/BaseAstNode.java b/mindcode/src/main/java/info/teksol/mindcode/ast/BaseAstNode.java index c64798368..06a42a2a2 100644 --- a/mindcode/src/main/java/info/teksol/mindcode/ast/BaseAstNode.java +++ b/mindcode/src/main/java/info/teksol/mindcode/ast/BaseAstNode.java @@ -1,5 +1,6 @@ package info.teksol.mindcode.ast; +import info.teksol.mindcode.compiler.SourceFile; import info.teksol.mindcode.compiler.generator.AstContextType; import info.teksol.mindcode.compiler.generator.AstSubcontextType; import org.antlr.v4.runtime.Token; @@ -9,34 +10,40 @@ import java.util.List; public abstract class BaseAstNode implements AstNode { - private final List children; private final Token startToken; + private final SourceFile sourceFile; + private final List children; - protected BaseAstNode(Token startToken) { + protected BaseAstNode(Token startToken, SourceFile sourceFile) { this.startToken = startToken; + this.sourceFile = sourceFile; this.children = List.of(); } - protected BaseAstNode(Token startToken, AstNode... children) { + protected BaseAstNode(Token startToken, SourceFile sourceFile, AstNode... children) { this.startToken = startToken; + this.sourceFile = sourceFile; this.children = List.of(children); } - protected BaseAstNode(Token startToken, List children) { + protected BaseAstNode(Token startToken, SourceFile sourceFile, List children) { this.startToken = startToken; + this.sourceFile = sourceFile; this.children = List.copyOf(children); } - protected BaseAstNode(Token startToken, List children1, List children2, AstNode... other) { + protected BaseAstNode(Token startToken, SourceFile sourceFile, List children1, List children2, AstNode... other) { this.startToken = startToken; + this.sourceFile = sourceFile; List tmp = new ArrayList<>(children1); tmp.addAll(children2); tmp.addAll(Arrays.asList(other)); this.children = List.copyOf(tmp); } - protected BaseAstNode(Token startToken, List children, AstNode... other) { + protected BaseAstNode(Token startToken, SourceFile sourceFile, List children, AstNode... other) { this.startToken = startToken; + this.sourceFile = sourceFile; List tmp = new ArrayList<>(children); tmp.addAll(Arrays.asList(other)); this.children = List.copyOf(tmp); @@ -47,6 +54,10 @@ public Token startToken() { return startToken; } + public SourceFile sourceFile() { + return sourceFile; + } + @Override public List getChildren() { return children; diff --git a/mindcode/src/main/java/info/teksol/mindcode/ast/BinaryOp.java b/mindcode/src/main/java/info/teksol/mindcode/ast/BinaryOp.java index 5b11bc5d9..aac35f759 100644 --- a/mindcode/src/main/java/info/teksol/mindcode/ast/BinaryOp.java +++ b/mindcode/src/main/java/info/teksol/mindcode/ast/BinaryOp.java @@ -1,5 +1,6 @@ package info.teksol.mindcode.ast; +import info.teksol.mindcode.compiler.SourceFile; import info.teksol.mindcode.compiler.generator.AstContextType; import org.antlr.v4.runtime.Token; @@ -11,8 +12,8 @@ public class BinaryOp extends BaseAstNode { protected final String op; protected final AstNode right; - public BinaryOp(Token startToken, AstNode left, String op, AstNode right) { - super(startToken, left, right); + public BinaryOp(Token startToken, SourceFile sourceFile, AstNode left, String op, AstNode right) { + super(startToken, sourceFile, left, right); this.left = left; this.op = op; this.right = right; diff --git a/mindcode/src/main/java/info/teksol/mindcode/ast/BoolBinaryOp.java b/mindcode/src/main/java/info/teksol/mindcode/ast/BoolBinaryOp.java index ac5086b7b..10b66661b 100644 --- a/mindcode/src/main/java/info/teksol/mindcode/ast/BoolBinaryOp.java +++ b/mindcode/src/main/java/info/teksol/mindcode/ast/BoolBinaryOp.java @@ -1,11 +1,12 @@ package info.teksol.mindcode.ast; +import info.teksol.mindcode.compiler.SourceFile; import org.antlr.v4.runtime.Token; public class BoolBinaryOp extends BinaryOp { - public BoolBinaryOp(Token startToken, AstNode left, String op, AstNode right) { - super(startToken, left, op, right); + public BoolBinaryOp(Token startToken, SourceFile sourceFile, AstNode left, String op, AstNode right) { + super(startToken, sourceFile, left,op, right); } public String toString() { diff --git a/mindcode/src/main/java/info/teksol/mindcode/ast/BooleanLiteral.java b/mindcode/src/main/java/info/teksol/mindcode/ast/BooleanLiteral.java index a214d1d0e..d7967f6da 100644 --- a/mindcode/src/main/java/info/teksol/mindcode/ast/BooleanLiteral.java +++ b/mindcode/src/main/java/info/teksol/mindcode/ast/BooleanLiteral.java @@ -1,5 +1,6 @@ package info.teksol.mindcode.ast; +import info.teksol.mindcode.compiler.SourceFile; import info.teksol.mindcode.compiler.instructions.InstructionProcessor; import info.teksol.mindcode.logic.LogicBoolean; import org.antlr.v4.runtime.Token; @@ -9,8 +10,8 @@ public class BooleanLiteral extends ConstantAstNode { private final boolean value; - public BooleanLiteral(Token startToken, boolean value) { - super(startToken); + public BooleanLiteral(Token startToken, SourceFile sourceFile, boolean value) { + super(startToken, sourceFile); this.value = value; } diff --git a/mindcode/src/main/java/info/teksol/mindcode/ast/BreakStatement.java b/mindcode/src/main/java/info/teksol/mindcode/ast/BreakStatement.java index 87031fbde..64a11106a 100644 --- a/mindcode/src/main/java/info/teksol/mindcode/ast/BreakStatement.java +++ b/mindcode/src/main/java/info/teksol/mindcode/ast/BreakStatement.java @@ -1,5 +1,6 @@ package info.teksol.mindcode.ast; +import info.teksol.mindcode.compiler.SourceFile; import info.teksol.mindcode.compiler.generator.AstContextType; import org.antlr.v4.runtime.Token; @@ -8,8 +9,8 @@ public class BreakStatement extends ControlBlockAstNode { private final String label; - BreakStatement(Token startToken, String label) { - super(startToken); + BreakStatement(Token startToken, SourceFile sourceFile, String label) { + super(startToken, sourceFile); this.label = label; } diff --git a/mindcode/src/main/java/info/teksol/mindcode/ast/CaseAlternative.java b/mindcode/src/main/java/info/teksol/mindcode/ast/CaseAlternative.java index 13d551bc3..65414543c 100644 --- a/mindcode/src/main/java/info/teksol/mindcode/ast/CaseAlternative.java +++ b/mindcode/src/main/java/info/teksol/mindcode/ast/CaseAlternative.java @@ -1,5 +1,6 @@ package info.teksol.mindcode.ast; +import info.teksol.mindcode.compiler.SourceFile; import org.antlr.v4.runtime.Token; import java.util.List; @@ -9,14 +10,14 @@ public class CaseAlternative extends ControlBlockAstNode { private final List values; private final AstNode body; - CaseAlternative(Token startToken, AstNode value, AstNode body) { - super(startToken, value, body); + CaseAlternative(Token startToken, SourceFile sourceFile, AstNode value, AstNode body) { + super(startToken, sourceFile, value, body); this.values = List.of(value); this.body = body; } - CaseAlternative(Token startToken, List values, AstNode body) { - super(startToken, values, body); + CaseAlternative(Token startToken, SourceFile sourceFile, List values, AstNode body) { + super(startToken, sourceFile, values, body); this.values = values; this.body = body; } diff --git a/mindcode/src/main/java/info/teksol/mindcode/ast/CaseExpression.java b/mindcode/src/main/java/info/teksol/mindcode/ast/CaseExpression.java index a58e045da..41f56e434 100644 --- a/mindcode/src/main/java/info/teksol/mindcode/ast/CaseExpression.java +++ b/mindcode/src/main/java/info/teksol/mindcode/ast/CaseExpression.java @@ -1,5 +1,6 @@ package info.teksol.mindcode.ast; +import info.teksol.mindcode.compiler.SourceFile; import info.teksol.mindcode.compiler.generator.AstContextType; import org.antlr.v4.runtime.Token; @@ -11,8 +12,8 @@ public class CaseExpression extends ControlBlockAstNode { private final List alternatives; private final AstNode elseBranch; - CaseExpression(Token startToken, AstNode condition, List alternatives, AstNode elseBranch) { - super(startToken, alternatives, condition, elseBranch); + CaseExpression(Token startToken, SourceFile sourceFile, AstNode condition, List alternatives, AstNode elseBranch) { + super(startToken, sourceFile, alternatives, condition, elseBranch); this.condition = condition; this.alternatives = alternatives; this.elseBranch = elseBranch; diff --git a/mindcode/src/main/java/info/teksol/mindcode/ast/Constant.java b/mindcode/src/main/java/info/teksol/mindcode/ast/Constant.java index b3de79f20..68b3bbd2e 100644 --- a/mindcode/src/main/java/info/teksol/mindcode/ast/Constant.java +++ b/mindcode/src/main/java/info/teksol/mindcode/ast/Constant.java @@ -1,5 +1,6 @@ package info.teksol.mindcode.ast; +import info.teksol.mindcode.compiler.SourceFile; import org.antlr.v4.runtime.Token; import java.util.Objects; @@ -8,8 +9,8 @@ public class Constant extends BaseAstNode { private final String name; private final AstNode value; - public Constant(Token startToken, String name, AstNode value) { - super(startToken); + public Constant(Token startToken, SourceFile sourceFile, String name, AstNode value) { + super(startToken, sourceFile); this.name = name; this.value = value; } diff --git a/mindcode/src/main/java/info/teksol/mindcode/ast/ConstantAstNode.java b/mindcode/src/main/java/info/teksol/mindcode/ast/ConstantAstNode.java index 887a24489..ce6efb08c 100644 --- a/mindcode/src/main/java/info/teksol/mindcode/ast/ConstantAstNode.java +++ b/mindcode/src/main/java/info/teksol/mindcode/ast/ConstantAstNode.java @@ -1,5 +1,6 @@ package info.teksol.mindcode.ast; +import info.teksol.mindcode.compiler.SourceFile; import info.teksol.mindcode.compiler.instructions.InstructionProcessor; import info.teksol.mindcode.logic.LogicLiteral; import org.antlr.v4.runtime.Token; @@ -7,8 +8,8 @@ // Base class for nodes that represent constants public abstract class ConstantAstNode extends BaseAstNode { - public ConstantAstNode(Token startToken) { - super(startToken); + public ConstantAstNode(Token startToken, SourceFile sourceFile) { + super(startToken, sourceFile); } public abstract double getAsDouble(); diff --git a/mindcode/src/main/java/info/teksol/mindcode/ast/ContinueStatement.java b/mindcode/src/main/java/info/teksol/mindcode/ast/ContinueStatement.java index 02235e0cd..2bbaf21f9 100644 --- a/mindcode/src/main/java/info/teksol/mindcode/ast/ContinueStatement.java +++ b/mindcode/src/main/java/info/teksol/mindcode/ast/ContinueStatement.java @@ -1,5 +1,6 @@ package info.teksol.mindcode.ast; +import info.teksol.mindcode.compiler.SourceFile; import info.teksol.mindcode.compiler.generator.AstContextType; import org.antlr.v4.runtime.Token; @@ -8,8 +9,8 @@ public class ContinueStatement extends ControlBlockAstNode { private final String label; - ContinueStatement(Token startToken, String label) { - super(startToken); + ContinueStatement(Token startToken, SourceFile sourceFile, String label) { + super(startToken, sourceFile); this.label = label; } diff --git a/mindcode/src/main/java/info/teksol/mindcode/ast/Control.java b/mindcode/src/main/java/info/teksol/mindcode/ast/Control.java index f9ed6b683..766158269 100644 --- a/mindcode/src/main/java/info/teksol/mindcode/ast/Control.java +++ b/mindcode/src/main/java/info/teksol/mindcode/ast/Control.java @@ -1,5 +1,6 @@ package info.teksol.mindcode.ast; +import info.teksol.mindcode.compiler.SourceFile; import info.teksol.mindcode.compiler.generator.AstContextType; import org.antlr.v4.runtime.Token; @@ -11,8 +12,8 @@ public class Control extends BaseAstNode { private final String property; private final List params; - Control(Token startToken, AstNode target, String property, List params) { - super(startToken, params, target); + Control(Token startToken, SourceFile sourceFile, AstNode target, String property, List params) { + super(startToken, sourceFile, params, target); this.target = target; this.property = property; this.params = params; diff --git a/mindcode/src/main/java/info/teksol/mindcode/ast/ControlBlockAstNode.java b/mindcode/src/main/java/info/teksol/mindcode/ast/ControlBlockAstNode.java index a2efddb4e..443d4ac81 100644 --- a/mindcode/src/main/java/info/teksol/mindcode/ast/ControlBlockAstNode.java +++ b/mindcode/src/main/java/info/teksol/mindcode/ast/ControlBlockAstNode.java @@ -1,5 +1,6 @@ package info.teksol.mindcode.ast; +import info.teksol.mindcode.compiler.SourceFile; import org.antlr.v4.runtime.Token; import java.util.List; @@ -7,23 +8,23 @@ // Base class for nodes that represent control blocks public abstract class ControlBlockAstNode extends BaseAstNode { - public ControlBlockAstNode(Token startToken) { - super(startToken); + public ControlBlockAstNode(Token startToken, SourceFile sourceFile) { + super(startToken, sourceFile); } - public ControlBlockAstNode(Token startToken, AstNode... children) { - super(startToken, children); + public ControlBlockAstNode(Token startToken, SourceFile sourceFile, AstNode... children) { + super(startToken, sourceFile, children); } - public ControlBlockAstNode(Token startToken, List children) { - super(startToken, children); + public ControlBlockAstNode(Token startToken, SourceFile sourceFile, List children) { + super(startToken, sourceFile, children); } - public ControlBlockAstNode(Token startToken, List children1, List children2, AstNode... other) { - super(startToken, children1, children2, other); + public ControlBlockAstNode(Token startToken, SourceFile sourceFile, List children1, List children2, AstNode... other) { + super(startToken, sourceFile, children1, children2, other); } - public ControlBlockAstNode(Token startToken, List children, AstNode... other) { - super(startToken, children, other); + public ControlBlockAstNode(Token startToken, SourceFile sourceFile, List children, AstNode... other) { + super(startToken, sourceFile, children, other); } } diff --git a/mindcode/src/main/java/info/teksol/mindcode/ast/Directive.java b/mindcode/src/main/java/info/teksol/mindcode/ast/Directive.java index bec1507be..ac0ece72c 100644 --- a/mindcode/src/main/java/info/teksol/mindcode/ast/Directive.java +++ b/mindcode/src/main/java/info/teksol/mindcode/ast/Directive.java @@ -1,5 +1,6 @@ package info.teksol.mindcode.ast; +import info.teksol.mindcode.compiler.SourceFile; import org.antlr.v4.runtime.Token; import java.util.Objects; @@ -8,8 +9,8 @@ public class Directive extends BaseAstNode { private final String option; private final String value; - public Directive(Token startToken, String option, String value) { - super(startToken); + public Directive(Token startToken, SourceFile sourceFile, String option, String value) { + super(startToken, sourceFile); this.option = option; this.value = value; } diff --git a/mindcode/src/main/java/info/teksol/mindcode/ast/DoWhileExpression.java b/mindcode/src/main/java/info/teksol/mindcode/ast/DoWhileExpression.java index 22e7fa8f9..725c97863 100644 --- a/mindcode/src/main/java/info/teksol/mindcode/ast/DoWhileExpression.java +++ b/mindcode/src/main/java/info/teksol/mindcode/ast/DoWhileExpression.java @@ -1,5 +1,6 @@ package info.teksol.mindcode.ast; +import info.teksol.mindcode.compiler.SourceFile; import info.teksol.mindcode.compiler.generator.AstContextType; import org.antlr.v4.runtime.Token; @@ -10,8 +11,8 @@ public class DoWhileExpression extends ControlBlockAstNode { private final AstNode body; private final AstNode condition; - DoWhileExpression(Token startToken, String label, AstNode body, AstNode condition) { - super(startToken, body, condition); + DoWhileExpression(Token startToken, SourceFile sourceFile, String label, AstNode body, AstNode condition) { + super(startToken, sourceFile, body, condition); this.label = label; this.body = body; this.condition = condition; diff --git a/mindcode/src/main/java/info/teksol/mindcode/ast/ExclusiveRange.java b/mindcode/src/main/java/info/teksol/mindcode/ast/ExclusiveRange.java index 3c2c1d3de..c12fb269b 100644 --- a/mindcode/src/main/java/info/teksol/mindcode/ast/ExclusiveRange.java +++ b/mindcode/src/main/java/info/teksol/mindcode/ast/ExclusiveRange.java @@ -1,11 +1,12 @@ package info.teksol.mindcode.ast; +import info.teksol.mindcode.compiler.SourceFile; import info.teksol.mindcode.logic.Condition; import org.antlr.v4.runtime.Token; public class ExclusiveRange extends Range { - ExclusiveRange(Token startToken, AstNode firstValue, AstNode lastValue) { - super(startToken,firstValue, lastValue); + ExclusiveRange(Token startToken, SourceFile sourceFile, AstNode firstValue, AstNode lastValue) { + super(startToken,sourceFile, firstValue, lastValue); } @Override diff --git a/mindcode/src/main/java/info/teksol/mindcode/ast/ForEachExpression.java b/mindcode/src/main/java/info/teksol/mindcode/ast/ForEachExpression.java index 21284a227..52f0078a6 100644 --- a/mindcode/src/main/java/info/teksol/mindcode/ast/ForEachExpression.java +++ b/mindcode/src/main/java/info/teksol/mindcode/ast/ForEachExpression.java @@ -1,5 +1,6 @@ package info.teksol.mindcode.ast; +import info.teksol.mindcode.compiler.SourceFile; import info.teksol.mindcode.compiler.generator.AstContextType; import org.antlr.v4.runtime.Token; @@ -12,8 +13,8 @@ public class ForEachExpression extends ControlBlockAstNode { private final List values; private final AstNode body; - ForEachExpression(Token startToken, String label, List iterators, List values, AstNode body) { - super(startToken, iterators, values, body); + ForEachExpression(Token startToken, SourceFile sourceFile, String label, List iterators, List values, AstNode body) { + super(startToken, sourceFile, iterators, values, body); this.label = label; this.iterators = iterators; this.values = values; diff --git a/mindcode/src/main/java/info/teksol/mindcode/ast/FormattableLiteral.java b/mindcode/src/main/java/info/teksol/mindcode/ast/FormattableLiteral.java index 9cfab8e58..c548ca768 100644 --- a/mindcode/src/main/java/info/teksol/mindcode/ast/FormattableLiteral.java +++ b/mindcode/src/main/java/info/teksol/mindcode/ast/FormattableLiteral.java @@ -1,6 +1,7 @@ package info.teksol.mindcode.ast; import info.teksol.mindcode.MindcodeInternalError; +import info.teksol.mindcode.compiler.SourceFile; import info.teksol.mindcode.compiler.instructions.InstructionProcessor; import info.teksol.mindcode.logic.LogicLiteral; import org.antlr.v4.runtime.Token; @@ -9,8 +10,8 @@ public class FormattableLiteral extends StringLiteral { - public FormattableLiteral(Token startToken, String text) { - super(startToken, text); + public FormattableLiteral(Token startToken, SourceFile sourceFile, String text) { + super(startToken, sourceFile, text); } @Override diff --git a/mindcode/src/main/java/info/teksol/mindcode/ast/FunctionCall.java b/mindcode/src/main/java/info/teksol/mindcode/ast/FunctionCall.java index f9f913750..987c64941 100644 --- a/mindcode/src/main/java/info/teksol/mindcode/ast/FunctionCall.java +++ b/mindcode/src/main/java/info/teksol/mindcode/ast/FunctionCall.java @@ -1,5 +1,6 @@ package info.teksol.mindcode.ast; +import info.teksol.mindcode.compiler.SourceFile; import info.teksol.mindcode.compiler.generator.AstContextType; import org.antlr.v4.runtime.Token; @@ -10,12 +11,12 @@ public class FunctionCall extends ControlBlockAstNode { private final String functionName; private final List params; - FunctionCall(Token startToken, String functionName, AstNode... params) { - this(startToken, functionName, List.of(params)); + FunctionCall(Token startToken, SourceFile sourceFile, String functionName, AstNode... params) { + this(startToken, sourceFile, functionName, List.of(params)); } - FunctionCall(Token startToken, String functionName, List params) { - super(startToken, params); + FunctionCall(Token startToken, SourceFile sourceFile, String functionName, List params) { + super(startToken, sourceFile, params); this.functionName = functionName; this.params = params; } diff --git a/mindcode/src/main/java/info/teksol/mindcode/ast/FunctionDeclaration.java b/mindcode/src/main/java/info/teksol/mindcode/ast/FunctionDeclaration.java index f3e0a4480..a45a5df66 100644 --- a/mindcode/src/main/java/info/teksol/mindcode/ast/FunctionDeclaration.java +++ b/mindcode/src/main/java/info/teksol/mindcode/ast/FunctionDeclaration.java @@ -1,5 +1,6 @@ package info.teksol.mindcode.ast; +import info.teksol.mindcode.compiler.SourceFile; import info.teksol.mindcode.compiler.generator.AstContextType; import info.teksol.mindcode.compiler.generator.AstSubcontextType; import org.antlr.v4.runtime.Token; @@ -15,8 +16,8 @@ public class FunctionDeclaration extends BaseAstNode { private final List params; private final AstNode body; - public FunctionDeclaration(Token startToken, boolean inline, boolean noinline, String name, List params, AstNode body) { - super(startToken, body); + public FunctionDeclaration(Token startToken, SourceFile sourceFile, boolean inline, boolean noinline, String name, List params, AstNode body) { + super(startToken, sourceFile, body); if (inline && noinline) { throw new IllegalArgumentException("Both inline and noinline specified."); } diff --git a/mindcode/src/main/java/info/teksol/mindcode/ast/HeapAccess.java b/mindcode/src/main/java/info/teksol/mindcode/ast/HeapAccess.java index b155c047e..495db10e0 100644 --- a/mindcode/src/main/java/info/teksol/mindcode/ast/HeapAccess.java +++ b/mindcode/src/main/java/info/teksol/mindcode/ast/HeapAccess.java @@ -1,6 +1,7 @@ package info.teksol.mindcode.ast; +import info.teksol.mindcode.compiler.SourceFile; import info.teksol.mindcode.compiler.generator.AstContextType; import org.antlr.v4.runtime.Token; @@ -11,19 +12,19 @@ public class HeapAccess extends BaseAstNode { private final AstNode address; private final boolean absolute; - private HeapAccess(Token startToken, String cellName, AstNode address, boolean absolute) { - super(startToken, address); + private HeapAccess(Token startToken, SourceFile sourceFile, String cellName, AstNode address, boolean absolute) { + super(startToken, sourceFile, address); this.cellName = cellName; this.address = address; this.absolute = absolute; } - public HeapAccess(Token startToken, String cellName, AstNode address) { - this(startToken, cellName, address, true); + public HeapAccess(Token startToken, SourceFile sourceFile, String cellName, AstNode address) { + this(startToken, sourceFile, cellName, address, true); } - public HeapAccess(Token startToken, String cellName, int index) { - this(startToken, cellName, new NumericLiteral(startToken, index), false); + public HeapAccess(Token startToken, SourceFile sourceFile, String cellName, int index) { + this(startToken, sourceFile, cellName, new NumericLiteral(startToken, sourceFile, index), false); } public String getCellName() { diff --git a/mindcode/src/main/java/info/teksol/mindcode/ast/HeapAllocation.java b/mindcode/src/main/java/info/teksol/mindcode/ast/HeapAllocation.java index 666fb0e4e..87ae1d552 100644 --- a/mindcode/src/main/java/info/teksol/mindcode/ast/HeapAllocation.java +++ b/mindcode/src/main/java/info/teksol/mindcode/ast/HeapAllocation.java @@ -1,6 +1,7 @@ package info.teksol.mindcode.ast; +import info.teksol.mindcode.compiler.SourceFile; import info.teksol.mindcode.compiler.generator.AstContextType; import org.antlr.v4.runtime.Token; @@ -10,15 +11,16 @@ public class HeapAllocation extends BaseAstNode { private final String name; private final Range range; - HeapAllocation(Token startToken, String name, Range range) { - super(startToken, range); + HeapAllocation(Token startToken, SourceFile sourceFile, String name, Range range) { + super(startToken, sourceFile, range); this.name = name; this.range = range; } - public HeapAllocation(Token startToken, String name, int first, int last) { - this(startToken, name, new InclusiveRange(startToken, - new NumericLiteral(startToken,first), new NumericLiteral(startToken, last))); + public HeapAllocation(Token startToken, SourceFile sourceFile, String name, int first, int last) { + this(startToken, sourceFile, name, new InclusiveRange(startToken, sourceFile, + new NumericLiteral(startToken, sourceFile, first), + new NumericLiteral(startToken, sourceFile, last))); } public String getName() { diff --git a/mindcode/src/main/java/info/teksol/mindcode/ast/IfExpression.java b/mindcode/src/main/java/info/teksol/mindcode/ast/IfExpression.java index 41cf0305c..e59334caa 100644 --- a/mindcode/src/main/java/info/teksol/mindcode/ast/IfExpression.java +++ b/mindcode/src/main/java/info/teksol/mindcode/ast/IfExpression.java @@ -1,5 +1,6 @@ package info.teksol.mindcode.ast; +import info.teksol.mindcode.compiler.SourceFile; import info.teksol.mindcode.compiler.generator.AstContextType; import org.antlr.v4.runtime.Token; @@ -10,8 +11,8 @@ public class IfExpression extends ControlBlockAstNode { private final AstNode trueBranch; private final AstNode falseBranch; - IfExpression(Token startToken, AstNode condition, AstNode trueBranch, AstNode falseBranch) { - super(startToken, condition, trueBranch, falseBranch); + IfExpression(Token startToken, SourceFile sourceFile, AstNode condition, AstNode trueBranch, AstNode falseBranch) { + super(startToken, sourceFile, condition, trueBranch, falseBranch); this.condition = condition; this.trueBranch = trueBranch; this.falseBranch = falseBranch; diff --git a/mindcode/src/main/java/info/teksol/mindcode/ast/InclusiveRange.java b/mindcode/src/main/java/info/teksol/mindcode/ast/InclusiveRange.java index 10783a154..473a808f9 100644 --- a/mindcode/src/main/java/info/teksol/mindcode/ast/InclusiveRange.java +++ b/mindcode/src/main/java/info/teksol/mindcode/ast/InclusiveRange.java @@ -1,11 +1,12 @@ package info.teksol.mindcode.ast; +import info.teksol.mindcode.compiler.SourceFile; import info.teksol.mindcode.logic.Condition; import org.antlr.v4.runtime.Token; public class InclusiveRange extends Range { - InclusiveRange(Token startToken, AstNode firstValue, AstNode lastValue) { - super(startToken, firstValue, lastValue); + InclusiveRange(Token startToken, SourceFile sourceFile, AstNode firstValue, AstNode lastValue) { + super(startToken, sourceFile, firstValue, lastValue); } @Override diff --git a/mindcode/src/main/java/info/teksol/mindcode/ast/Iterator.java b/mindcode/src/main/java/info/teksol/mindcode/ast/Iterator.java index 030f3dc51..b635ce0c5 100644 --- a/mindcode/src/main/java/info/teksol/mindcode/ast/Iterator.java +++ b/mindcode/src/main/java/info/teksol/mindcode/ast/Iterator.java @@ -1,5 +1,6 @@ package info.teksol.mindcode.ast; +import info.teksol.mindcode.compiler.SourceFile; import org.antlr.v4.runtime.Token; import java.util.Objects; @@ -9,8 +10,8 @@ public class Iterator extends BaseAstNode { private final boolean outModifier; private final VarRef varRef; - public Iterator(Token startToken, boolean inModifier, boolean outModifier, VarRef varRef) { - super(startToken); + public Iterator(Token startToken, SourceFile sourceFile, boolean inModifier, boolean outModifier, VarRef varRef) { + super(startToken, sourceFile); this.inModifier = inModifier; this.outModifier = outModifier; this.varRef = varRef; diff --git a/mindcode/src/main/java/info/teksol/mindcode/ast/NoOp.java b/mindcode/src/main/java/info/teksol/mindcode/ast/NoOp.java index fb64c30b6..9222eccab 100644 --- a/mindcode/src/main/java/info/teksol/mindcode/ast/NoOp.java +++ b/mindcode/src/main/java/info/teksol/mindcode/ast/NoOp.java @@ -3,7 +3,7 @@ public class NoOp extends BaseAstNode { public NoOp() { - super(null); + super(null, null); } @Override diff --git a/mindcode/src/main/java/info/teksol/mindcode/ast/NullLiteral.java b/mindcode/src/main/java/info/teksol/mindcode/ast/NullLiteral.java index f19e432d2..29c5c2326 100644 --- a/mindcode/src/main/java/info/teksol/mindcode/ast/NullLiteral.java +++ b/mindcode/src/main/java/info/teksol/mindcode/ast/NullLiteral.java @@ -1,5 +1,6 @@ package info.teksol.mindcode.ast; +import info.teksol.mindcode.compiler.SourceFile; import info.teksol.mindcode.compiler.instructions.InstructionProcessor; import info.teksol.mindcode.logic.LogicLiteral; import info.teksol.mindcode.logic.LogicNull; @@ -7,8 +8,8 @@ public class NullLiteral extends ConstantAstNode { - public NullLiteral(Token startToken) { - super(startToken); + public NullLiteral(Token startToken, SourceFile sourceFile) { + super(startToken, sourceFile); } @Override diff --git a/mindcode/src/main/java/info/teksol/mindcode/ast/NumericLiteral.java b/mindcode/src/main/java/info/teksol/mindcode/ast/NumericLiteral.java index cf2d73815..607e744c1 100644 --- a/mindcode/src/main/java/info/teksol/mindcode/ast/NumericLiteral.java +++ b/mindcode/src/main/java/info/teksol/mindcode/ast/NumericLiteral.java @@ -1,6 +1,7 @@ package info.teksol.mindcode.ast; import info.teksol.mindcode.MindcodeException; +import info.teksol.mindcode.compiler.SourceFile; import info.teksol.mindcode.compiler.instructions.InstructionProcessor; import info.teksol.mindcode.logic.LogicLiteral; import info.teksol.mindcode.logic.LogicNumber; @@ -11,13 +12,13 @@ public class NumericLiteral extends ConstantAstNode { private final String literal; - public NumericLiteral(Token startToken, String literal) { - super(startToken); + public NumericLiteral(Token startToken, SourceFile sourceFile, String literal) { + super(startToken, sourceFile); this.literal = literal; } - public NumericLiteral(Token startToken, int value) { - super(startToken); + public NumericLiteral(Token startToken, SourceFile sourceFile, int value) { + super(startToken, sourceFile); this.literal = String.valueOf(value); } diff --git a/mindcode/src/main/java/info/teksol/mindcode/ast/NumericValue.java b/mindcode/src/main/java/info/teksol/mindcode/ast/NumericValue.java index 06bd08689..75026f850 100644 --- a/mindcode/src/main/java/info/teksol/mindcode/ast/NumericValue.java +++ b/mindcode/src/main/java/info/teksol/mindcode/ast/NumericValue.java @@ -1,5 +1,6 @@ package info.teksol.mindcode.ast; +import info.teksol.mindcode.compiler.SourceFile; import info.teksol.mindcode.compiler.instructions.InstructionProcessor; import info.teksol.mindcode.logic.LogicLiteral; import org.antlr.v4.runtime.Token; @@ -13,8 +14,8 @@ public class NumericValue extends ConstantAstNode { private final double value; - public NumericValue(Token startToken, double value) { - super(startToken); + public NumericValue(Token startToken, SourceFile sourceFile, double value) { + super(startToken, sourceFile); this.value = value; } @@ -24,7 +25,7 @@ public NumericValue(Token startToken, double value) { * @return numeric literal representation of the value, or null if literal representation doesn't exist */ public NumericLiteral toNumericLiteral(InstructionProcessor instructionProcessor) { - return instructionProcessor.mlogFormat(value).map(str -> new NumericLiteral(startToken(),str)).orElse(null); + return instructionProcessor.mlogFormat(value).map(str -> new NumericLiteral(startToken(), sourceFile(), str)).orElse(null); } @Override diff --git a/mindcode/src/main/java/info/teksol/mindcode/ast/Parameter.java b/mindcode/src/main/java/info/teksol/mindcode/ast/Parameter.java index 348cea296..2ed4fadf9 100644 --- a/mindcode/src/main/java/info/teksol/mindcode/ast/Parameter.java +++ b/mindcode/src/main/java/info/teksol/mindcode/ast/Parameter.java @@ -1,5 +1,6 @@ package info.teksol.mindcode.ast; +import info.teksol.mindcode.compiler.SourceFile; import org.antlr.v4.runtime.Token; import java.util.Objects; @@ -8,8 +9,8 @@ public class Parameter extends BaseAstNode { private final String name; private final AstNode value; - public Parameter(Token startToken, String name, AstNode value) { - super(startToken); + public Parameter(Token startToken, SourceFile sourceFile, String name, AstNode value) { + super(startToken, sourceFile); this.name = name; this.value = value; } diff --git a/mindcode/src/main/java/info/teksol/mindcode/ast/PropertyAccess.java b/mindcode/src/main/java/info/teksol/mindcode/ast/PropertyAccess.java index ae56ee5d4..af36486d9 100644 --- a/mindcode/src/main/java/info/teksol/mindcode/ast/PropertyAccess.java +++ b/mindcode/src/main/java/info/teksol/mindcode/ast/PropertyAccess.java @@ -1,5 +1,6 @@ package info.teksol.mindcode.ast; +import info.teksol.mindcode.compiler.SourceFile; import info.teksol.mindcode.compiler.generator.AstContextType; import org.antlr.v4.runtime.Token; @@ -9,8 +10,8 @@ public class PropertyAccess extends BaseAstNode { private final AstNode target; private final AstNode property; - PropertyAccess(Token startToken, AstNode target, AstNode property) { - super(startToken, target, property); + PropertyAccess(Token startToken, SourceFile sourceFile, AstNode target, AstNode property) { + super(startToken, sourceFile, target, property); this.target = target; this.property = property; } diff --git a/mindcode/src/main/java/info/teksol/mindcode/ast/Range.java b/mindcode/src/main/java/info/teksol/mindcode/ast/Range.java index 361529edc..7cadf1e6d 100644 --- a/mindcode/src/main/java/info/teksol/mindcode/ast/Range.java +++ b/mindcode/src/main/java/info/teksol/mindcode/ast/Range.java @@ -1,5 +1,6 @@ package info.teksol.mindcode.ast; +import info.teksol.mindcode.compiler.SourceFile; import info.teksol.mindcode.logic.Condition; import org.antlr.v4.runtime.Token; @@ -9,8 +10,8 @@ public abstract class Range extends BaseAstNode { private final AstNode firstValue; private final AstNode lastValue; - Range(Token startToken, AstNode firstValue, AstNode lastValue) { - super(startToken, firstValue, lastValue); + Range(Token startToken, SourceFile sourceFile, AstNode firstValue, AstNode lastValue) { + super(startToken, sourceFile, firstValue, lastValue); this.firstValue = firstValue; this.lastValue = lastValue; } diff --git a/mindcode/src/main/java/info/teksol/mindcode/ast/RangedForExpression.java b/mindcode/src/main/java/info/teksol/mindcode/ast/RangedForExpression.java index 3ee467309..fafebff8d 100644 --- a/mindcode/src/main/java/info/teksol/mindcode/ast/RangedForExpression.java +++ b/mindcode/src/main/java/info/teksol/mindcode/ast/RangedForExpression.java @@ -1,5 +1,6 @@ package info.teksol.mindcode.ast; +import info.teksol.mindcode.compiler.SourceFile; import info.teksol.mindcode.compiler.generator.AstContextType; import org.antlr.v4.runtime.Token; @@ -11,8 +12,8 @@ public class RangedForExpression extends ControlBlockAstNode { private final Range range; private final AstNode body; - public RangedForExpression(Token startToken, String label, AstNode variable, Range range, AstNode body) { - super(startToken, variable, range, body); + public RangedForExpression(Token startToken, SourceFile sourceFile, String label, AstNode variable, Range range, AstNode body) { + super(startToken, sourceFile, variable, range, body); this.label = label; this.variable = variable; this.range = range; diff --git a/mindcode/src/main/java/info/teksol/mindcode/ast/Ref.java b/mindcode/src/main/java/info/teksol/mindcode/ast/Ref.java index f6aa58a70..abb68daa2 100644 --- a/mindcode/src/main/java/info/teksol/mindcode/ast/Ref.java +++ b/mindcode/src/main/java/info/teksol/mindcode/ast/Ref.java @@ -1,5 +1,6 @@ package info.teksol.mindcode.ast; +import info.teksol.mindcode.compiler.SourceFile; import org.antlr.v4.runtime.Token; import java.util.Objects; @@ -7,8 +8,8 @@ public class Ref extends BaseAstNode { protected final String name; - Ref(Token startToken, String name) { - super(startToken); + Ref(Token startToken, SourceFile sourceFile, String name) { + super(startToken, sourceFile); this.name = name; } diff --git a/mindcode/src/main/java/info/teksol/mindcode/ast/ReturnStatement.java b/mindcode/src/main/java/info/teksol/mindcode/ast/ReturnStatement.java index 3b8d83909..0e7304dbd 100644 --- a/mindcode/src/main/java/info/teksol/mindcode/ast/ReturnStatement.java +++ b/mindcode/src/main/java/info/teksol/mindcode/ast/ReturnStatement.java @@ -1,5 +1,6 @@ package info.teksol.mindcode.ast; +import info.teksol.mindcode.compiler.SourceFile; import info.teksol.mindcode.compiler.generator.AstContextType; import org.antlr.v4.runtime.Token; @@ -8,8 +9,8 @@ public class ReturnStatement extends ControlBlockAstNode { private final AstNode retval; - ReturnStatement(Token startToken, AstNode expression) { - super(startToken, expression); + ReturnStatement(Token startToken, SourceFile sourceFile, AstNode expression) { + super(startToken, sourceFile, expression); this.retval = expression; } diff --git a/mindcode/src/main/java/info/teksol/mindcode/ast/Seq.java b/mindcode/src/main/java/info/teksol/mindcode/ast/Seq.java index 12484993a..ce90c283f 100644 --- a/mindcode/src/main/java/info/teksol/mindcode/ast/Seq.java +++ b/mindcode/src/main/java/info/teksol/mindcode/ast/Seq.java @@ -1,5 +1,6 @@ package info.teksol.mindcode.ast; +import info.teksol.mindcode.compiler.SourceFile; import org.antlr.v4.runtime.Token; import java.util.Objects; @@ -8,18 +9,26 @@ public class Seq extends BaseAstNode { private final AstNode rest; private final AstNode last; - public Seq(Token startToken, AstNode last) { - super(startToken, last); + public Seq(Token startToken, SourceFile sourceFile, AstNode last) { + super(startToken, sourceFile, last); this.rest = new NoOp(); this.last = last; } - public Seq(Token startToken, AstNode rest, AstNode last) { - super(startToken, rest, last); + public Seq(Token startToken, SourceFile sourceFile, AstNode rest, AstNode last) { + super(startToken, sourceFile, rest, last); this.rest = rest; this.last = last; } + public static Seq append(Seq current, Seq next) { + if (current == null) { + return next; + } else { + return new Seq(next.startToken(), current.sourceFile(), current, next); + } + } + public AstNode getRest() { return rest; } diff --git a/mindcode/src/main/java/info/teksol/mindcode/ast/StackAllocation.java b/mindcode/src/main/java/info/teksol/mindcode/ast/StackAllocation.java index 7ed8ee5df..762b1d47a 100644 --- a/mindcode/src/main/java/info/teksol/mindcode/ast/StackAllocation.java +++ b/mindcode/src/main/java/info/teksol/mindcode/ast/StackAllocation.java @@ -1,5 +1,6 @@ package info.teksol.mindcode.ast; +import info.teksol.mindcode.compiler.SourceFile; import info.teksol.mindcode.compiler.generator.AstContextType; import info.teksol.mindcode.logic.LogicVariable; import org.antlr.v4.runtime.Token; @@ -10,19 +11,20 @@ public class StackAllocation extends BaseAstNode { private final LogicVariable stack; private final Range range; - StackAllocation(Token startToken, String stack, Range range) { - super(startToken); + StackAllocation(Token startToken, SourceFile sourceFile, String stack, Range range) { + super(startToken, sourceFile); this.stack = LogicVariable.block(stack); this.range = range; } - StackAllocation(Token startToken, String stack, int first, int last) { - this(startToken, stack, new InclusiveRange(startToken, - new NumericLiteral(startToken, first), new NumericLiteral(startToken, last))); + StackAllocation(Token startToken, SourceFile sourceFile, String stack, int first, int last) { + this(startToken, sourceFile, stack, new InclusiveRange(startToken, sourceFile, + new NumericLiteral(startToken, sourceFile, first), + new NumericLiteral(startToken, sourceFile, last))); } - StackAllocation(Token startToken, String stack) { - super(startToken); + StackAllocation(Token startToken, SourceFile sourceFile, String stack) { + super(startToken, sourceFile); this.stack = LogicVariable.block(stack); this.range = null; } diff --git a/mindcode/src/main/java/info/teksol/mindcode/ast/StringLiteral.java b/mindcode/src/main/java/info/teksol/mindcode/ast/StringLiteral.java index 13879abf5..ff2a50b4b 100644 --- a/mindcode/src/main/java/info/teksol/mindcode/ast/StringLiteral.java +++ b/mindcode/src/main/java/info/teksol/mindcode/ast/StringLiteral.java @@ -1,5 +1,6 @@ package info.teksol.mindcode.ast; +import info.teksol.mindcode.compiler.SourceFile; import info.teksol.mindcode.compiler.instructions.InstructionProcessor; import info.teksol.mindcode.logic.LogicLiteral; import info.teksol.mindcode.logic.LogicString; @@ -10,8 +11,8 @@ public class StringLiteral extends ConstantAstNode { protected final String text; - public StringLiteral(Token startToken, String text) { - super(startToken); + public StringLiteral(Token startToken, SourceFile sourceFile, String text) { + super(startToken, sourceFile); this.text = text; } diff --git a/mindcode/src/main/java/info/teksol/mindcode/ast/UnaryOp.java b/mindcode/src/main/java/info/teksol/mindcode/ast/UnaryOp.java index 97212f45f..f0ecada32 100644 --- a/mindcode/src/main/java/info/teksol/mindcode/ast/UnaryOp.java +++ b/mindcode/src/main/java/info/teksol/mindcode/ast/UnaryOp.java @@ -1,5 +1,6 @@ package info.teksol.mindcode.ast; +import info.teksol.mindcode.compiler.SourceFile; import info.teksol.mindcode.compiler.generator.AstContextType; import org.antlr.v4.runtime.Token; @@ -9,8 +10,8 @@ public class UnaryOp extends BaseAstNode { private final String op; private final AstNode expression; - UnaryOp(Token startToken, String op, AstNode expression) { - super(startToken, expression); + UnaryOp(Token startToken, SourceFile sourceFile, String op, AstNode expression) { + super(startToken, sourceFile, expression); this.op = op; this.expression = expression; } diff --git a/mindcode/src/main/java/info/teksol/mindcode/ast/VarRef.java b/mindcode/src/main/java/info/teksol/mindcode/ast/VarRef.java index d7a059196..fc9cedc31 100644 --- a/mindcode/src/main/java/info/teksol/mindcode/ast/VarRef.java +++ b/mindcode/src/main/java/info/teksol/mindcode/ast/VarRef.java @@ -1,6 +1,7 @@ package info.teksol.mindcode.ast; +import info.teksol.mindcode.compiler.SourceFile; import org.antlr.v4.runtime.Token; import java.util.Objects; @@ -8,8 +9,8 @@ public class VarRef extends BaseAstNode { private final String name; - public VarRef(Token startToken, String name) { - super(startToken); + public VarRef(Token startToken, SourceFile sourceFile, String name) { + super(startToken, sourceFile); this.name = name; } diff --git a/mindcode/src/main/java/info/teksol/mindcode/ast/WhileExpression.java b/mindcode/src/main/java/info/teksol/mindcode/ast/WhileExpression.java index 7eca579d7..c04c1a605 100644 --- a/mindcode/src/main/java/info/teksol/mindcode/ast/WhileExpression.java +++ b/mindcode/src/main/java/info/teksol/mindcode/ast/WhileExpression.java @@ -1,5 +1,6 @@ package info.teksol.mindcode.ast; +import info.teksol.mindcode.compiler.SourceFile; import info.teksol.mindcode.compiler.generator.AstContextType; import org.antlr.v4.runtime.Token; @@ -12,8 +13,8 @@ public class WhileExpression extends ControlBlockAstNode { private final AstNode body; private final AstNode update; - WhileExpression(Token startToken, String label, AstNode initialization, AstNode condition, AstNode body, AstNode update) { - super(startToken, initialization, condition, body); + WhileExpression(Token startToken, SourceFile sourceFile, String label, AstNode initialization, AstNode condition, AstNode body, AstNode update) { + super(startToken, sourceFile, initialization, condition, body); this.label = label; this.initialization = initialization; this.condition = condition; diff --git a/mindcode/src/main/java/info/teksol/mindcode/compiler/Compiler.java b/mindcode/src/main/java/info/teksol/mindcode/compiler/Compiler.java index 0341f8f65..acdcef52b 100644 --- a/mindcode/src/main/java/info/teksol/mindcode/compiler/Compiler.java +++ b/mindcode/src/main/java/info/teksol/mindcode/compiler/Compiler.java @@ -1,7 +1,9 @@ package info.teksol.mindcode.compiler; +import java.util.List; + public interface Compiler { - CompilerOutput compile(String sourceCode); + CompilerOutput compile(List sourceFiles); } diff --git a/mindcode/src/main/java/info/teksol/mindcode/compiler/CompilerFacade.java b/mindcode/src/main/java/info/teksol/mindcode/compiler/CompilerFacade.java index 6a84ba85e..41d1a4712 100644 --- a/mindcode/src/main/java/info/teksol/mindcode/compiler/CompilerFacade.java +++ b/mindcode/src/main/java/info/teksol/mindcode/compiler/CompilerFacade.java @@ -2,6 +2,8 @@ import info.teksol.mindcode.compiler.optimization.OptimizationLevel; +import java.util.List; + public class CompilerFacade { public static CompilerOutput compile(boolean webApplication, String sourceCode, OptimizationLevel optimizationLevel, boolean run) { @@ -12,6 +14,11 @@ public static CompilerOutput compile(boolean webApplication, String sour public static CompilerOutput compile(String sourceCode, CompilerProfile profile) { MindcodeCompiler compiler = new MindcodeCompiler(profile); - return compiler.compile(sourceCode); + return compiler.compile(SourceFile.code(sourceCode)); + } + + public static CompilerOutput compile(List sourceFiles, CompilerProfile profile) { + MindcodeCompiler compiler = new MindcodeCompiler(profile); + return compiler.compile(sourceFiles); } } diff --git a/mindcode/src/main/java/info/teksol/mindcode/compiler/LogicInstructionPrinter.java b/mindcode/src/main/java/info/teksol/mindcode/compiler/LogicInstructionPrinter.java index d594839d6..1bd13df77 100644 --- a/mindcode/src/main/java/info/teksol/mindcode/compiler/LogicInstructionPrinter.java +++ b/mindcode/src/main/java/info/teksol/mindcode/compiler/LogicInstructionPrinter.java @@ -8,9 +8,7 @@ import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; -import java.util.LinkedList; -import java.util.List; -import java.util.Locale; +import java.util.*; import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; @@ -113,9 +111,9 @@ public static String toStringWithContextsShort(InstructionProcessor instructionP return buffer.toString(); } - public static String toStringWithSourceCode(InstructionProcessor instructionProcessor, List instructions, String sourceCode) { + public static String toStringWithSourceCode(InstructionProcessor instructionProcessor, List instructions) { AtomicInteger lineNumber = new AtomicInteger(0); - final List lines = sourceCode.lines().toList(); + final Map> allLines = new HashMap<>(); int prevLine = -1; final StringBuilder buffer = new StringBuilder(); @@ -128,13 +126,21 @@ public static String toStringWithSourceCode(InstructionProcessor instructionProc lineBuffer.append(instruction.getOpcode().getOpcode()); addArgs(instructionProcessor.getPrintArgumentCount(instruction), lineBuffer, instruction); - if (instruction.getAstContext().node() != null && instruction.getAstContext().node().startToken() != null) { + AstContext astContext = instruction.getAstContext(); + if (astContext.node() != null && astContext.node().startToken() != null && astContext.node().sourceFile() != null) { + SourceFile file = astContext.node().sourceFile(); String srcLine = "** Corresponding source code line not found! **"; - int line = instruction.getAstContext().node().startToken().getLine() - 1; + List lines = allLines.get(file); + if (lines == null) { + lines = file.code().lines().toList(); + allLines.put(file, lines); + } + + int line = astContext.node().startToken().getLine() - 1; if (line == prevLine) { srcLine = "..."; } else if (line >= 0 && line < lines.size()) { - srcLine = lines.get(line).trim(); + srcLine = (file.fileName().isEmpty() ? "" : file.fileName() + ": ") + lines.get(line).trim(); prevLine = line; } diff --git a/mindcode/src/main/java/info/teksol/mindcode/compiler/MindcodeCompiler.java b/mindcode/src/main/java/info/teksol/mindcode/compiler/MindcodeCompiler.java index 008a11a07..01dff61b1 100644 --- a/mindcode/src/main/java/info/teksol/mindcode/compiler/MindcodeCompiler.java +++ b/mindcode/src/main/java/info/teksol/mindcode/compiler/MindcodeCompiler.java @@ -32,21 +32,25 @@ public class MindcodeCompiler implements Compiler { private InstructionProcessor instructionProcessor; private final List messages = new ArrayList<>(); - private final ANTLRErrorListener errorListener = new ErrorListener(messages); + private final ErrorListener errorListener = new ErrorListener(messages); public MindcodeCompiler(CompilerProfile profile) { this.profile = profile; } @Override - public CompilerOutput compile(String sourceCode) { + public CompilerOutput compile(List sourceFiles) { String instructions = ""; RunResults runResults = new RunResults(null,0); try { long parseStart = System.nanoTime(); - final Seq program = parse(sourceCode); - if (messages.stream().anyMatch(CompilerMessage::isError)) { - return new CompilerOutput<>("", messages, null, 0); + Seq program = null; + for (SourceFile sourceFile : sourceFiles) { + final Seq next = parse(sourceFile); + program = Seq.append(program, next); + if (messages.stream().anyMatch(CompilerMessage::isError)) { + return new CompilerOutput<>("", messages, null, 0); + } } printParseTree(program); long parseTime = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - parseStart); @@ -76,7 +80,7 @@ public CompilerOutput compile(String sourceCode) { case PLAIN -> LogicInstructionPrinter.toStringWithLineNumbers(instructionProcessor, result); case FLAT_AST -> LogicInstructionPrinter.toStringWithContextsShort(instructionProcessor, result); case DEEP_AST -> LogicInstructionPrinter.toStringWithContextsFull(instructionProcessor, result); - case SOURCE -> LogicInstructionPrinter.toStringWithSourceCode(instructionProcessor, result, sourceCode); + case SOURCE -> LogicInstructionPrinter.toStringWithSourceCode(instructionProcessor, result); }; debug(output); } @@ -110,15 +114,16 @@ public CompilerOutput compile(String sourceCode) { /** * Parses the source code using ANTLR generated parser. */ - private Seq parse(String sourceCode) { - final MindcodeLexer lexer = new MindcodeLexer(CharStreams.fromString(sourceCode)); + private Seq parse(SourceFile sourceFile) { + errorListener.setFileName(sourceFile.fileName()); + final MindcodeLexer lexer = new MindcodeLexer(CharStreams.fromString(sourceFile.code())); lexer.removeErrorListeners(); lexer.addErrorListener(errorListener); final MindcodeParser parser = new MindcodeParser(new BufferedTokenStream(lexer)); parser.removeErrorListeners(); parser.addErrorListener(errorListener); final MindcodeParser.ProgramContext context = parser.program(); - return AstNodeBuilder.generate(context); + return AstNodeBuilder.generate(sourceFile, context); } /** Prints the parse tree according to level */ @@ -185,18 +190,23 @@ private void debug(String message) { private static class ErrorListener extends BaseErrorListener { private final List errors; + private String fileNameText; public ErrorListener(List errors) { this.errors = errors; } + public void setFileName(String fileName) { + this.fileNameText = fileName.isEmpty() ? "" : " in " + fileName; + } + @Override public void syntaxError(Recognizer recognizer, Object offendingSymbol, int line, int charPositionInLine, String msg, RecognitionException e) { if (offendingSymbol == null) { - errors.add(MindcodeMessage.error("Syntax error on line " + line + ":" + charPositionInLine + ": " + msg)); + errors.add(MindcodeMessage.error("Syntax error%s on line %d:%d: %s", fileNameText, line, charPositionInLine, msg)); } else { - errors.add(MindcodeMessage.error("Syntax error: " + offendingSymbol + " on line " + line + ":" + charPositionInLine + ": " + msg)); + errors.add(MindcodeMessage.error("Syntax error: %s%s on line %d:%d: %s", offendingSymbol, fileNameText, line, charPositionInLine, msg)); } } } diff --git a/mindcode/src/main/java/info/teksol/mindcode/compiler/MindcodeMessage.java b/mindcode/src/main/java/info/teksol/mindcode/compiler/MindcodeMessage.java index 82366e562..c5ae1dd5e 100644 --- a/mindcode/src/main/java/info/teksol/mindcode/compiler/MindcodeMessage.java +++ b/mindcode/src/main/java/info/teksol/mindcode/compiler/MindcodeMessage.java @@ -16,6 +16,10 @@ public static MindcodeMessage error(String message) { return new MindcodeMessage(MessageLevel.ERROR, message); } + public static MindcodeMessage error(@PrintFormat String format, Object... args) { + return new MindcodeMessage(MessageLevel.ERROR, String.format(Locale.US, format, args)); + } + public static MindcodeMessage warn(String message) { return new MindcodeMessage(MessageLevel.WARNING, message); } diff --git a/mindcode/src/main/java/info/teksol/mindcode/compiler/SourceFile.java b/mindcode/src/main/java/info/teksol/mindcode/compiler/SourceFile.java new file mode 100644 index 000000000..82a484ce8 --- /dev/null +++ b/mindcode/src/main/java/info/teksol/mindcode/compiler/SourceFile.java @@ -0,0 +1,10 @@ +package info.teksol.mindcode.compiler; + +import java.util.List; + +public record SourceFile(String fileName, String code) { + + public static List code(String code) { + return List.of(new SourceFile("", code)); + } +} diff --git a/mindcode/src/main/java/info/teksol/mindcode/compiler/generator/CallGraph.java b/mindcode/src/main/java/info/teksol/mindcode/compiler/generator/CallGraph.java index 1e6df8231..751ec8af2 100644 --- a/mindcode/src/main/java/info/teksol/mindcode/compiler/generator/CallGraph.java +++ b/mindcode/src/main/java/info/teksol/mindcode/compiler/generator/CallGraph.java @@ -24,7 +24,7 @@ public final class CallGraph { this.allocatedStack = allocatedStack; // Create mock function declaration representing main program body. - addFunction(new FunctionDeclaration(null, true, false, MAIN, List.of(), new NoOp())); + addFunction(new FunctionDeclaration(null, null,true, false, MAIN, List.of(), new NoOp())); } public static CallGraph createEmpty() { diff --git a/mindcode/src/main/java/info/teksol/mindcode/compiler/generator/ConstantExpressionEvaluator.java b/mindcode/src/main/java/info/teksol/mindcode/compiler/generator/ConstantExpressionEvaluator.java index 8f1c4acd3..cdf4a69ad 100644 --- a/mindcode/src/main/java/info/teksol/mindcode/compiler/generator/ConstantExpressionEvaluator.java +++ b/mindcode/src/main/java/info/teksol/mindcode/compiler/generator/ConstantExpressionEvaluator.java @@ -61,7 +61,7 @@ private AstNode evaluateBinaryOp(BinaryOp node) { if (a != null && b != null) { if (operation == Operation.ADD && (a instanceof StringVariable || b instanceof StringVariable)) { String concat = a.toString().concat(b.toString()); - return new StringLiteral(node.startToken(), concat); + return new StringLiteral(node.startToken(), node.sourceFile(), concat); } else { Variable result = DoubleVariable.newNullValue(false, "result"); eval.execute(result, a, b); @@ -86,15 +86,15 @@ private AstNode evaluatePartially(BinaryOp node, Variable fixed, AstNode exp) { case "|" -> fixed.getDoubleValue() == 0 ? exp : node; // If the fixed value is zero, evaluates to zero - case "&" -> fixed.getDoubleValue() == 0 ? new NumericLiteral(node.startToken(), "0") : node; + case "&" -> fixed.getDoubleValue() == 0 ? new NumericLiteral(node.startToken(), node.sourceFile(), "0") : node; // If the fixed value is zero (= false), evaluates to false // TODO: return exp instead of node if exp is known to be a boolean expression - case "or", "||" -> fixed.getDoubleValue() != 0 ? new BooleanLiteral(node.startToken(), true) : node; + case "or", "||" -> fixed.getDoubleValue() != 0 ? new BooleanLiteral(node.startToken(), node.sourceFile(), true) : node; // If the fixed value is zero (= false), evaluates to false // TODO: return exp instead of node if exp is known to be a boolean expression - case "and", "&&" -> fixed.getDoubleValue() == 0 ? new BooleanLiteral(node.startToken(), false) : node; + case "and", "&&" -> fixed.getDoubleValue() == 0 ? new BooleanLiteral(node.startToken(), node.sourceFile(), false) : node; default -> node; }; } diff --git a/mindcode/src/main/java/info/teksol/mindcode/processor/AbstractVariable.java b/mindcode/src/main/java/info/teksol/mindcode/processor/AbstractVariable.java index b5c08c7d9..9144880b2 100644 --- a/mindcode/src/main/java/info/teksol/mindcode/processor/AbstractVariable.java +++ b/mindcode/src/main/java/info/teksol/mindcode/processor/AbstractVariable.java @@ -78,15 +78,15 @@ public String toString() { }; } - // TODO track original token for constants + // TODO track original token/source file for constants @Override public AstNode toAstNode() { return switch (getMindustryValueType()) { - case NULL -> new NullLiteral(null); - case BOOLEAN -> new BooleanLiteral(null, getIntValue() != 0); - case LONG -> new NumericLiteral(null, String.valueOf(getLongValue())); - case DOUBLE -> new NumericValue(null, getDoubleValue()); - case OBJECT -> new StringLiteral(null, String.valueOf(object)); + case NULL -> new NullLiteral(null, null); + case BOOLEAN -> new BooleanLiteral(null, null, getIntValue() != 0); + case LONG -> new NumericLiteral(null, null, String.valueOf(getLongValue())); + case DOUBLE -> new NumericValue(null, null, getDoubleValue()); + case OBJECT -> new StringLiteral(null, null, String.valueOf(object)); }; } } diff --git a/mindcode/src/test/java/info/teksol/mindcode/AbstractAstTest.java b/mindcode/src/test/java/info/teksol/mindcode/AbstractAstTest.java index ecfd2ede4..61fe9f404 100644 --- a/mindcode/src/test/java/info/teksol/mindcode/AbstractAstTest.java +++ b/mindcode/src/test/java/info/teksol/mindcode/AbstractAstTest.java @@ -3,6 +3,7 @@ import info.teksol.mindcode.ast.AstNode; import info.teksol.mindcode.ast.AstNodeBuilder; import info.teksol.mindcode.ast.AstPrettyPrinter; +import info.teksol.mindcode.compiler.SourceFile; import info.teksol.mindcode.compiler.instructions.InstructionProcessor; import info.teksol.mindcode.compiler.instructions.InstructionProcessorFactory; import info.teksol.mindcode.grammar.AbstractParserTest; @@ -11,8 +12,8 @@ public class AbstractAstTest extends AbstractParserTest { - public AstNode translateToAst(String program) { - return AstNodeBuilder.generate(parse(program)); + public AstNode translateToAst(String code) { + return AstNodeBuilder.generate(new SourceFile("", code), parse(code)); } protected String prettyPrint(AstNode node) { diff --git a/mindcode/src/test/java/info/teksol/mindcode/ast/AstNodeBuilderTest.java b/mindcode/src/test/java/info/teksol/mindcode/ast/AstNodeBuilderTest.java index fe9eb8557..735377392 100644 --- a/mindcode/src/test/java/info/teksol/mindcode/ast/AstNodeBuilderTest.java +++ b/mindcode/src/test/java/info/teksol/mindcode/ast/AstNodeBuilderTest.java @@ -13,7 +13,7 @@ class AstNodeBuilderTest extends AbstractAstTest { @Test void parsesTheEmptyProgram() { assertEquals( - new Seq(null, new NoOp()), + new Seq(null, null, new NoOp()), translateToAst("") ); } @@ -21,8 +21,8 @@ void parsesTheEmptyProgram() { @Test void parsesLiteralInt() { assertEquals( - new Seq(null, - new NumericLiteral(null, "156") + new Seq(null, null, + new NumericLiteral(null, null, "156") ), translateToAst("156") @@ -32,8 +32,8 @@ void parsesLiteralInt() { @Test void parsesLiteralFloat() { assertEquals( - new Seq(null, - new NumericLiteral(null, "156.156") + new Seq(null, null, + new NumericLiteral(null, null, "156.156") ), translateToAst("156.156") @@ -43,8 +43,8 @@ void parsesLiteralFloat() { @Test void parsesLiteralString() { assertEquals( - new Seq(null, - new StringLiteral(null, "156") + new Seq(null, null, + new StringLiteral(null, null, "156") ), translateToAst("\"156\"") @@ -54,8 +54,8 @@ void parsesLiteralString() { @Test void parsesVarRef() { assertEquals( - new Seq(null, - new VarRef(null, "a") + new Seq(null, null, + new VarRef(null, null, "a") ), translateToAst("a") @@ -65,10 +65,10 @@ void parsesVarRef() { @Test void parsesSimpleAssignment() { assertEquals( - new Seq(null, - new Assignment(null, - new VarRef(null, "a"), - new NumericLiteral(null, "1") + new Seq(null, null, + new Assignment(null, null, + new VarRef(null, null, "a"), + new NumericLiteral(null, null, "1") ) ), translateToAst("a = 1") @@ -79,15 +79,15 @@ void parsesSimpleAssignment() { @Test void parsesSimpleBinOpPlusMinus() { assertEquals( - new Seq(null, - new BinaryOp(null, - new BinaryOp(null, - new NumericLiteral(null, "1"), + new Seq(null, null, + new BinaryOp(null, null, + new BinaryOp(null, null, + new NumericLiteral(null, null, "1"), "+", - new NumericLiteral(null, "2") + new NumericLiteral(null, null, "2") ), "-", - new NumericLiteral(null, "3") + new NumericLiteral(null, null, "3") ) ), translateToAst("1 + 2 - 3") @@ -98,11 +98,11 @@ void parsesSimpleBinOpPlusMinus() { @Test void parsesSimpleBinOpExp() { assertEquals( - new Seq(null, - new BinaryOp(null, - new NumericLiteral(null, "3.1415"), + new Seq(null, null, + new BinaryOp(null, null, + new NumericLiteral(null, null, "3.1415"), "**", - new NumericLiteral(null, "2") + new NumericLiteral(null, null, "2") ) ), translateToAst("3.1415 ** 2") @@ -113,15 +113,15 @@ void parsesSimpleBinOpExp() { @Test void parsesSimpleBinOpMulDiv() { assertEquals( - new Seq(null, - new BinaryOp(null, - new BinaryOp(null, - new NumericLiteral(null, "1"), + new Seq(null, null, + new BinaryOp(null, null, + new BinaryOp(null, null, + new NumericLiteral(null, null, "1"), "*", - new NumericLiteral(null, "2") + new NumericLiteral(null, null, "2") ), "/", - new NumericLiteral(null, "3") + new NumericLiteral(null, null, "3") ) ), translateToAst("1 * 2 / 3") @@ -132,8 +132,8 @@ void parsesSimpleBinOpMulDiv() { @Test void parsesUnaryOperation() { assertEquals( - new Seq(null, - new BinaryOp(null, new VarRef(null, "ready"), "==", new BooleanLiteral(null, false)) + new Seq(null, null, + new BinaryOp(null, null, new VarRef(null, null, "ready"), "==", new BooleanLiteral(null, null, false)) ), translateToAst("not ready") ); @@ -142,14 +142,14 @@ void parsesUnaryOperation() { @Test void respectsArithmeticOrderOfOperations() { assertEquals( - new Seq(null, - new BinaryOp(null, - new NumericLiteral(null, "1"), + new Seq(null, null, + new BinaryOp(null, null, + new NumericLiteral(null, null, "1"), "+", - new BinaryOp(null, - new NumericLiteral(null, "2"), + new BinaryOp(null, null, + new NumericLiteral(null, null, "2"), "*", - new NumericLiteral(null, "3") + new NumericLiteral(null, null, "3") ) ) ), @@ -160,15 +160,15 @@ void respectsArithmeticOrderOfOperations() { @Test void parsesParenthesis() { assertEquals( - new Seq(null, - new BinaryOp(null, - new BinaryOp(null, - new NumericLiteral(null, "1"), + new Seq(null, null, + new BinaryOp(null, null, + new BinaryOp(null, null, + new NumericLiteral(null, null, "1"), "+", - new NumericLiteral(null, "2") + new NumericLiteral(null, null, "2") ), "*", - new NumericLiteral(null, "3") + new NumericLiteral(null, null, "3") ) ), translateToAst("(1 + 2) * 3") @@ -178,31 +178,31 @@ void parsesParenthesis() { @Test void parsesComplexConditionalExpression() { assertEquals( - new Seq(null, - new BinaryOp(null, - new BoolBinaryOp(null, - new BinaryOp(null, - new VarRef(null, "a"), + new Seq(null, null, + new BinaryOp(null, null, + new BoolBinaryOp(null, null, + new BinaryOp(null, null, + new VarRef(null, null, "a"), "<", - new VarRef(null, "b") + new VarRef(null, null, "b") ), "and", - new BinaryOp(null, - new VarRef(null, "c"), + new BinaryOp(null, null, + new VarRef(null, null, "c"), ">", - new BinaryOp(null, - new BinaryOp(null, - new NumericLiteral(null, "4"), + new BinaryOp(null, null, + new BinaryOp(null, null, + new NumericLiteral(null, null, "4"), "*", - new VarRef(null, "r") + new VarRef(null, null, "r") ), ">", - new NumericLiteral(null, "5") + new NumericLiteral(null, null, "5") ) ) ), "==", - new BooleanLiteral(null, false) + new BooleanLiteral(null, null, false) ) ), translateToAst("not (a < b and c > (4 * r > 5))") @@ -212,30 +212,30 @@ void parsesComplexConditionalExpression() { @Test void parsesFunctionCalls() { assertEquals( - new Seq(null, - new Seq(null, - new Seq(null, - new Seq(null, - new FunctionCall(null, + new Seq(null, null, + new Seq(null, null, + new Seq(null, null, + new Seq(null, null, + new FunctionCall(null, null, "print", List.of( - new StringLiteral(null, "\"a\": "), - new VarRef(null, "a") + new StringLiteral(null, null, "\"a\": "), + new VarRef(null, null, "a") ) ) ), - new FunctionCall(null, "random", List.of()) + new FunctionCall(null, null, "random", List.of()) ), - new FunctionCall(null, "print", List.of(new VarRef(null, "r"))) + new FunctionCall(null, null, "print", List.of(new VarRef(null, null, "r"))) ), - new FunctionCall(null, + new FunctionCall(null, null, "print", List.of( - new StringLiteral(null, "\\nb: "), - new BinaryOp(null, - new VarRef(null, "b"), + new StringLiteral(null, null, "\\nb: "), + new BinaryOp(null, null, + new VarRef(null, null, "b"), "/", - new NumericLiteral(null, "3.1415") + new NumericLiteral(null, null, "3.1415") ) ) ) @@ -250,26 +250,26 @@ void parsesFunctionCalls() { @Test void parsesUnaryMinus() { assertEquals( - new Seq(null, - new Seq(null, - new Seq(null, - new Assignment(null, - new VarRef(null, "dx"), - new BinaryOp(null, - new VarRef(null, "dx"), + new Seq(null, null, + new Seq(null, null, + new Seq(null, null, + new Assignment(null, null, + new VarRef(null, null, "dx"), + new BinaryOp(null, null, + new VarRef(null, null, "dx"), "*", - new NumericLiteral(null, "-1") + new NumericLiteral(null, null, "-1") ) ) ), - new Assignment(null, new VarRef(null, "dy"), new NumericLiteral(null, "-1")) + new Assignment(null, null, new VarRef(null, null, "dy"), new NumericLiteral(null, null, "-1")) ), - new Assignment(null, - new VarRef(null, "dz"), - new BinaryOp(null, - new NumericLiteral(null, "2"), + new Assignment(null, null, + new VarRef(null, null, "dz"), + new BinaryOp(null, null, + new NumericLiteral(null, null, "2"), "-", - new NumericLiteral(null, "1") + new NumericLiteral(null, null, "1") ) ) ), @@ -280,10 +280,10 @@ void parsesUnaryMinus() { @Test void parsesHeapAccesses() { assertEquals( - new Seq(null, - new Assignment(null, - new HeapAccess(null, "cell2", new NumericLiteral(null, "1")), - new HeapAccess(null, "cell3", new NumericLiteral(null, "0")) + new Seq(null, null, + new Assignment(null, null, + new HeapAccess(null, null, "cell2", new NumericLiteral(null, null, "1")), + new HeapAccess(null, null, "cell3", new NumericLiteral(null, null, "0")) ) ), translateToAst("cell2[1] = cell3[0]") @@ -293,20 +293,20 @@ void parsesHeapAccesses() { @Test void parsesGlobalReferences() { assertEquals( - new Seq(null, - new Seq(null, - new Seq(null, new HeapAllocation(null, "cell2", 4, 5), new NoOp()), - new Assignment(null, - new HeapAccess(null, "cell2", 0), - new NumericLiteral(null, "1") + new Seq(null, null, + new Seq(null, null, + new Seq(null, null, new HeapAllocation(null, null, "cell2", 4, 5), new NoOp()), + new Assignment(null, null, + new HeapAccess(null, null, "cell2", 0), + new NumericLiteral(null, null, "1") ) ), - new Assignment(null, - new HeapAccess(null, "cell2", 1), - new BinaryOp(null, - new HeapAccess(null, "cell2", 0), + new Assignment(null, null, + new HeapAccess(null, null, "cell2", 1), + new BinaryOp(null, null, + new HeapAccess(null, null, "cell2", 0), "+", - new NumericLiteral(null, "42") + new NumericLiteral(null, null, "42") ) ) ), @@ -318,16 +318,16 @@ void parsesGlobalReferences() { @Test void parsesExponentiationAssignment() { assertEquals( - new Seq(null, - new Assignment(null, - new HeapAccess(null, "cell1" ,new NumericLiteral(null, "0")), - new FunctionCall(null, + new Seq(null, null, + new Assignment(null, null, + new HeapAccess(null, null, "cell1" ,new NumericLiteral(null, null, "0")), + new FunctionCall(null, null, "rand", List.of( - new BinaryOp(null, - new NumericLiteral(null, "9"), + new BinaryOp(null, null, + new NumericLiteral(null, null, "9"), "**", - new NumericLiteral(null, "9") + new NumericLiteral(null, null, "9") ) ) ) @@ -340,10 +340,10 @@ void parsesExponentiationAssignment() { @Test void parsesHeapReferencesWithRvalues() { assertEquals( - new Seq(null, - new Assignment(null, - new HeapAccess(null, "cell1", new VarRef(null, "dx")), - new NumericLiteral(null, "1") + new Seq(null, null, + new Assignment(null, null, + new HeapAccess(null, null, "cell1", new VarRef(null, null, "dx")), + new NumericLiteral(null, null, "1") ) ), translateToAst("cell1[dx] = 1") @@ -353,8 +353,8 @@ void parsesHeapReferencesWithRvalues() { @Test void parsesComments() { assertEquals( - new Seq(null, - new Assignment(null, new VarRef(null, "wasInitialized"), new NumericLiteral(null, "1")) + new Seq(null, null, + new Assignment(null, null, new VarRef(null, null, "wasInitialized"), new NumericLiteral(null, null, "1")) ), translateToAst( "// Remember that we initialized ourselves\n// This is required otherwise we'll repeat ourselves\nwasInitialized = 1\n" @@ -365,25 +365,25 @@ void parsesComments() { @Test void parsesMathFunctions() { assertEquals( - new Seq(null, - new Assignment(null, - new VarRef(null, "x"), - new FunctionCall(null, + new Seq(null, null, + new Assignment(null, null, + new VarRef(null, null, "x"), + new FunctionCall(null, null, "ceil", - new FunctionCall(null, + new FunctionCall(null, null, "floor", - new FunctionCall(null, + new FunctionCall(null, null, "sin", - new FunctionCall(null, + new FunctionCall(null, null, "log", - new FunctionCall(null, + new FunctionCall(null, null, "cos", - new FunctionCall(null, + new FunctionCall(null, null, "abs", - new FunctionCall(null, + new FunctionCall(null, null, "tan", - new FunctionCall(null, "rand", - new NumericLiteral(null, "1") + new FunctionCall(null, null, "rand", + new NumericLiteral(null, null, "1") ) ) ) @@ -401,15 +401,15 @@ void parsesMathFunctions() { @Test void parsesRefsWithDashInThem() { assertEquals( - new Seq(null, - new FunctionCall(null, + new Seq(null, null, + new FunctionCall(null, null, "build", List.of( - new VarRef(null, "x"), - new VarRef(null, "y"), - new Ref(null, "titanium-conveyor"), - new NumericLiteral(null, "0"), - new NumericLiteral(null, "0") + new VarRef(null, null, "x"), + new VarRef(null, null, "y"), + new Ref(null, null, "titanium-conveyor"), + new NumericLiteral(null, null, "0"), + new NumericLiteral(null, null, "0") ) ) ), @@ -420,11 +420,11 @@ void parsesRefsWithDashInThem() { @Test void parsesFlagAssignment() { assertEquals( - new Seq(null, + new Seq(null, null, new NoOp(), - new FunctionCall(null, + new FunctionCall(null, null, "flag", - List.of(new VarRef(null, "FLAG")) + List.of(new VarRef(null, null, "FLAG")) ) ), translateToAst("flag(FLAG)") @@ -434,25 +434,25 @@ void parsesFlagAssignment() { @Test void parsesAddressCalculationReferences() { assertEquals( - new Seq(null, - new Assignment(null, - new HeapAccess(null, "cell1", new VarRef(null, "ptr")), - new BinaryOp(null, - new HeapAccess(null, + new Seq(null, null, + new Assignment(null, null, + new HeapAccess(null, null, "cell1", new VarRef(null, null, "ptr")), + new BinaryOp(null, null, + new HeapAccess(null, null, "cell1", - new BinaryOp(null, - new VarRef(null, "ptr"), + new BinaryOp(null, null, + new VarRef(null, null, "ptr"), "-", - new NumericLiteral(null, "1") + new NumericLiteral(null, null, "1") ) ), "+", - new HeapAccess(null, + new HeapAccess(null, null, "cell1", - new BinaryOp(null, - new VarRef(null, "ptr"), + new BinaryOp(null, null, + new VarRef(null, null, "ptr"), "-", - new NumericLiteral(null, "2") + new NumericLiteral(null, null, "2") ) ) @@ -466,8 +466,8 @@ void parsesAddressCalculationReferences() { @Test void parsesHeapAllocationWithExclusiveRange() { assertEquals( - new Seq(null, - new HeapAllocation(null, "cell2", new ExclusiveRange(null, new NumericLiteral(null, 0), new NumericLiteral(null, 64))), + new Seq(null, null, + new HeapAllocation(null, null, "cell2", new ExclusiveRange(null, null, new NumericLiteral(null, null, 0), new NumericLiteral(null, null, 64))), new NoOp() ), translateToAst("allocate heap in cell2[ 0 ... 64 ]") @@ -477,8 +477,8 @@ void parsesHeapAllocationWithExclusiveRange() { @Test void parsesHeapAllocationWithInclusiveRange() { assertEquals( - new Seq(null, - new HeapAllocation(null, "cell2", 0, 30), + new Seq(null, null, + new HeapAllocation(null, null, "cell2", 0, 30), new NoOp() ), translateToAst("allocate heap in cell2[0 .. 30]") @@ -493,18 +493,18 @@ void rejectsHeapUsageWhenUnallocated() { @Test void parsesPropertyAccesses() { assertEquals( - new Seq(null, - new Seq(null, - new BinaryOp(null, - new PropertyAccess(null, new VarRef(null, "foundation1"), new Ref(null, "copper")), + new Seq(null, null, + new Seq(null, null, + new BinaryOp(null, null, + new PropertyAccess(null, null, new VarRef(null, null, "foundation1"), new Ref(null, null, "copper")), "<", - new PropertyAccess(null, new VarRef(null, "foundation1"), new Ref(null, "itemCapacity")) + new PropertyAccess(null, null, new VarRef(null, null, "foundation1"), new Ref(null, null, "itemCapacity")) ) ), - new BinaryOp(null, - new PropertyAccess(null, new VarRef(null, "reactor1"), new Ref(null, "cryofluid")), + new BinaryOp(null, null, + new PropertyAccess(null, null, new VarRef(null, null, "reactor1"), new Ref(null, null, "cryofluid")), "<", - new NumericLiteral(null, "10") + new NumericLiteral(null, null, "10") ) ), translateToAst("foundation1.copper < foundation1.itemCapacity\nreactor1.cryofluid < 10") @@ -514,13 +514,13 @@ void parsesPropertyAccesses() { @Test void parsesWriteToPropertyAccess() { assertEquals( - new Seq(null, - new Assignment(null, - new PropertyAccess(null, new VarRef(null, "conveyor1"), new Ref(null, "enabled")), - new BinaryOp(null, - new PropertyAccess(null, new VarRef(null, "CORE"), new Ref(null, "copper")), + new Seq(null, null, + new Assignment(null, null, + new PropertyAccess(null, null, new VarRef(null, null, "conveyor1"), new Ref(null, null, "enabled")), + new BinaryOp(null, null, + new PropertyAccess(null, null, new VarRef(null, null, "CORE"), new Ref(null, null, "copper")), "<", - new PropertyAccess(null, new VarRef(null, "CORE"), new Ref(null, "itemCapacity")) + new PropertyAccess(null, null, new VarRef(null, null, "CORE"), new Ref(null, null, "itemCapacity")) ) ) ), @@ -531,20 +531,20 @@ void parsesWriteToPropertyAccess() { @Test void parsesUsefulWhileLoop() { assertEquals( - new Seq(null, - new Seq(null, - new Assignment(null, new VarRef(null, "n"), new NumericLiteral(null, "5")) + new Seq(null, null, + new Seq(null, null, + new Assignment(null, null, new VarRef(null, null, "n"), new NumericLiteral(null, null, "5")) ), - new WhileExpression(null, null, + new WhileExpression(null, null, null, new NoOp(), - new BinaryOp(null, new VarRef(null, "n"), ">", new NumericLiteral(null, "0")), - new Seq(null, - new Assignment(null, - new VarRef(null, "n"), - new BinaryOp(null, - new VarRef(null, "n"), + new BinaryOp(null, null, new VarRef(null, null, "n"), ">", new NumericLiteral(null, null, "0")), + new Seq(null, null, + new Assignment(null, null, + new VarRef(null, null, "n"), + new BinaryOp(null, null, + new VarRef(null, null, "n"), "-", - new NumericLiteral(null, "1") + new NumericLiteral(null, null, "1") ) ) ), @@ -559,12 +559,12 @@ void parsesUsefulWhileLoop() { @Test void parsesInclusiveIteratorStyleLoop() { assertEquals( - new Seq(null, - new RangedForExpression(null, + new Seq(null, null, + new RangedForExpression(null, null, null, - new VarRef(null, "n"), - new InclusiveRange(null, new NumericLiteral(null, 1), new NumericLiteral(null, 17)), - new Seq(null, new FunctionCall(null, "print", new VarRef(null, "n"))) + new VarRef(null, null, "n"), + new InclusiveRange(null, null, new NumericLiteral(null, null, 1), new NumericLiteral(null, null, 17)), + new Seq(null, null, new FunctionCall(null, null, "print", new VarRef(null, null, "n"))) ) ), translateToAst("for n in 1 .. 17\nprint(n)\nend\n") @@ -574,12 +574,12 @@ void parsesInclusiveIteratorStyleLoop() { @Test void parsesExclusiveIteratorStyleLoop() { assertEquals( - new Seq(null, - new RangedForExpression(null, + new Seq(null, null, + new RangedForExpression(null, null, null, - new VarRef(null, "n"), - new ExclusiveRange(null, new NumericLiteral(null, 1), new NumericLiteral(null, 17)), - new Seq(null, new FunctionCall(null, "print", new VarRef(null, "n"))) + new VarRef(null, null, "n"), + new ExclusiveRange(null, null, new NumericLiteral(null, null, 1), new NumericLiteral(null, null, 17)), + new Seq(null, null, new FunctionCall(null, null, "print", new VarRef(null, null, "n"))) ) ), translateToAst("for n in 1 ... 17\nprint(n)\nend\n") @@ -589,21 +589,21 @@ void parsesExclusiveIteratorStyleLoop() { @Test void parsesForEachLoop() { assertEquals( - new Seq(null, - new ForEachExpression(null, + new Seq(null, null, + new ForEachExpression(null, null, null, List.of( - new Iterator(null, true, false, new VarRef(null, "a")) + new Iterator(null, null, true, false, new VarRef(null, null, "a")) ), List.of( - new Ref(null, "mono"), - new Ref(null, "poly"), - new Ref(null, "mega") + new Ref(null, null, "mono"), + new Ref(null, null, "poly"), + new Ref(null, null, "mega") ), - new Seq(null, - new FunctionCall(null, + new Seq(null, null, + new FunctionCall(null, null, "print", - List.of(new VarRef(null, "a")) + List.of(new VarRef(null, null, "a")) ) ) ) @@ -614,35 +614,35 @@ void parsesForEachLoop() { @Test void parsesCStyleLoop() { - assertEquals(new Seq(null, - new WhileExpression(null, null, - new Seq(null, - new Assignment(null, new VarRef(null, "i"), new NumericLiteral(null, "0")), - new Assignment(null, new VarRef(null, "j"), new NumericLiteral(null, "-5")) + assertEquals(new Seq(null, null, + new WhileExpression(null, null, null, + new Seq(null, null, + new Assignment(null, null, new VarRef(null, null, "i"), new NumericLiteral(null, null, "0")), + new Assignment(null, null, new VarRef(null, null, "j"), new NumericLiteral(null, null, "-5")) ), - new BinaryOp(null, - new VarRef(null, "i"), + new BinaryOp(null, null, + new VarRef(null, null, "i"), "<", - new NumericLiteral(null, "5") + new NumericLiteral(null, null, "5") ), - new Seq(null, - new FunctionCall(null, "print", new VarRef(null, "n")) + new Seq(null, null, + new FunctionCall(null, null, "print", new VarRef(null, null, "n")) ), - new Seq(null, - new Assignment(null, - new VarRef(null, "j"), - new BinaryOp(null, - new VarRef(null, "j"), + new Seq(null, null, + new Assignment(null, null, + new VarRef(null, null, "j"), + new BinaryOp(null, null, + new VarRef(null, null, "j"), "-", - new NumericLiteral(null, "1") + new NumericLiteral(null, null, "1") ) ), - new Assignment(null, - new VarRef(null, "i"), - new BinaryOp(null, - new VarRef(null, "i"), + new Assignment(null, null, + new VarRef(null, null, "i"), + new BinaryOp(null, null, + new VarRef(null, null, "i"), "+", - new NumericLiteral(null, "1") + new NumericLiteral(null, null, "1") ) ) ) @@ -655,19 +655,19 @@ void parsesCStyleLoop() { @Test void parsesRefs() { assertEquals( - new Seq(null, + new Seq(null, null, new NoOp(), - new WhileExpression(null, null, + new WhileExpression(null, null, null, new NoOp(), - new BinaryOp(null, - new Ref(null, "unit"), + new BinaryOp(null, null, + new Ref(null, null, "unit"), "===", - new NullLiteral(null) + new NullLiteral(null, null) ), - new Seq(null, - new FunctionCall(null, + new Seq(null, null, + new FunctionCall(null, null, "ubind", - List.of(new VarRef(null, "poly")) + List.of(new VarRef(null, null, "poly")) ) ), new NoOp() @@ -681,20 +681,20 @@ void parsesRefs() { @Test void parsesIfExpression() { assertEquals( - new Seq(null, - new IfExpression(null, - new BinaryOp(null, - new VarRef(null, "n"), + new Seq(null, null, + new IfExpression(null, null, + new BinaryOp(null, null, + new VarRef(null, null, "n"), ">", - new NumericLiteral(null, "4") + new NumericLiteral(null, null, "4") ), - new Seq(null, - new Assignment(null, - new HeapAccess(null, "cell1", new NumericLiteral(null, "2")), - new BinaryOp(null, - new HeapAccess(null, "cell1", new NumericLiteral(null, "2")), + new Seq(null, null, + new Assignment(null, null, + new HeapAccess(null, null, "cell1", new NumericLiteral(null, null, "2")), + new BinaryOp(null, null, + new HeapAccess(null, null, "cell1", new NumericLiteral(null, null, "2")), "+", - new NumericLiteral(null, "1") + new NumericLiteral(null, null, "1") ) ) ), @@ -708,29 +708,29 @@ void parsesIfExpression() { @Test void parsesIfElseExpression() { assertEquals( - new Seq(null, - new Assignment(null, - new VarRef(null, "value"), - new IfExpression(null, - new BinaryOp(null, - new HeapAccess(null, "cell1", new NumericLiteral(null, "4")), + new Seq(null, null, + new Assignment(null, null, + new VarRef(null, null, "value"), + new IfExpression(null, null, + new BinaryOp(null, null, + new HeapAccess(null, null, "cell1", new NumericLiteral(null, null, "4")), "==", - new NumericLiteral(null, "0") + new NumericLiteral(null, null, "0") ), - new Seq(null, new BooleanLiteral(null, false)), - new Seq(null, - new Seq(null, - new Assignment(null, - new HeapAccess(null, "cell1", new NumericLiteral(null, "4")), - new BooleanLiteral(null, true) + new Seq(null, null, new BooleanLiteral(null, null, false)), + new Seq(null, null, + new Seq(null, null, + new Assignment(null, null, + new HeapAccess(null, null, "cell1", new NumericLiteral(null, null, "4")), + new BooleanLiteral(null, null, true) ) ), - new Assignment(null, - new VarRef(null, "n"), - new BinaryOp(null, - new VarRef(null, "n"), + new Assignment(null, null, + new VarRef(null, null, "n"), + new BinaryOp(null, null, + new VarRef(null, null, "n"), "+", - new NumericLiteral(null, "1") + new NumericLiteral(null, null, "1") ) ) ) @@ -744,23 +744,23 @@ void parsesIfElseExpression() { @Test void parsesIfElseIf() { assertEquals( - new Seq(null, - new IfExpression(null, - new BinaryOp(null, - new VarRef(null, "state"), + new Seq(null, null, + new IfExpression(null, null, + new BinaryOp(null, null, + new VarRef(null, null, "state"), "==", - new NumericLiteral(null, "1")), - new Seq(null, new FunctionCall(null, + new NumericLiteral(null, null, "1")), + new Seq(null, null, new FunctionCall(null, null, "print", - List.of(new VarRef(null, "m")))), - new Seq(null, new IfExpression(null, - new BinaryOp(null, - new VarRef(null, "state"), + List.of(new VarRef(null, null, "m")))), + new Seq(null, null, new IfExpression(null, null, + new BinaryOp(null, null, + new VarRef(null, null, "state"), "==", - new NumericLiteral(null, "2")), - new Seq(null, new FunctionCall(null, + new NumericLiteral(null, null, "2")), + new Seq(null, null, new FunctionCall(null, null, "print", - List.of(new VarRef(null, "n")))), + List.of(new VarRef(null, null, "n")))), new NoOp())))), translateToAst("if state == 1\nprint(m)\nelse\nif state == 2\nprint(n)\nend\nend\n") ); @@ -769,15 +769,15 @@ void parsesIfElseIf() { @Test void parsesCaseWhen() { assertEquals( - new Seq(null, - new Assignment(null, new VarRef(null, "__ast0"), new VarRef(null, "n")), - new CaseExpression(null, - new VarRef(null, "__ast0"), + new Seq(null, null, + new Assignment(null, null, new VarRef(null, null, "__ast0"), new VarRef(null, null, "n")), + new CaseExpression(null, null, + new VarRef(null, null, "__ast0"), List.of( - new CaseAlternative(null, new NumericLiteral(null, "1"), new Seq(null, new StringLiteral(null, "1"))), - new CaseAlternative(null, new NumericLiteral(null, "2"), new Seq(null, new StringLiteral(null, "two"))) + new CaseAlternative(null, null, new NumericLiteral(null, null, "1"), new Seq(null, null, new StringLiteral(null, null, "1"))), + new CaseAlternative(null, null, new NumericLiteral(null, null, "2"), new Seq(null, null, new StringLiteral(null, null, "two"))) ), - new Seq(null, new StringLiteral(null, "otherwise")) + new Seq(null, null, new StringLiteral(null, null, "otherwise")) ) ), translateToAst("case n\nwhen 1\n\"1\"\nwhen 2\n\"two\"\nelse\n\"otherwise\"end\n") @@ -787,19 +787,19 @@ void parsesCaseWhen() { @Test void parsesCaseWhenMultipleWithRange() { assertEquals( - new Seq(null, - new Assignment(null, new VarRef(null, "__ast0"), new VarRef(null, "n")), - new CaseExpression(null, - new VarRef(null, "__ast0"), + new Seq(null, null, + new Assignment(null, null, new VarRef(null, null, "__ast0"), new VarRef(null, null, "n")), + new CaseExpression(null, null, + new VarRef(null, null, "__ast0"), List.of( - new CaseAlternative(null, + new CaseAlternative(null, null, List.of( - new InclusiveRange(null, new NumericLiteral(null, "0"), new NumericLiteral(null, "4")), - new InclusiveRange(null, new NumericLiteral(null, "6"), new NumericLiteral(null, "8")), - new NumericLiteral(null, "10"), - new NumericLiteral(null, "12") + new InclusiveRange(null, null, new NumericLiteral(null, null, "0"), new NumericLiteral(null, null, "4")), + new InclusiveRange(null, null, new NumericLiteral(null, null, "6"), new NumericLiteral(null, null, "8")), + new NumericLiteral(null, null, "10"), + new NumericLiteral(null, null, "12") ), - new Seq(null, new StringLiteral(null, "A number I like")) + new Seq(null, null, new StringLiteral(null, null, "A number I like")) ) ), new NoOp() @@ -812,11 +812,11 @@ void parsesCaseWhenMultipleWithRange() { @Test void acceptsSemicolonAsStatementSeparator() { assertEquals( - new Seq(null, - new Seq(null, - new Assignment(null, new VarRef(null, "a"), new NumericLiteral(null, "0")) + new Seq(null, null, + new Seq(null, null, + new Assignment(null, null, new VarRef(null, null, "a"), new NumericLiteral(null, null, "0")) ), - new Assignment(null, new VarRef(null, "b"), new NumericLiteral(null, "1")) + new Assignment(null, null, new VarRef(null, null, "b"), new NumericLiteral(null, null, "1")) ), translateToAst("a=0;b=1") ); @@ -825,15 +825,15 @@ void acceptsSemicolonAsStatementSeparator() { @Test void supportsCallingTheEndFunction() { assertEquals( - new Seq(null, - new IfExpression(null, - new BinaryOp(null, - new VarRef(null, "some_cond"), + new Seq(null, null, + new IfExpression(null, null, + new BinaryOp(null, null, + new VarRef(null, null, "some_cond"), "==", - new BooleanLiteral(null, false) + new BooleanLiteral(null, null, false) ), - new Seq(null, - new FunctionCall(null, "end") + new Seq(null, null, + new FunctionCall(null, null, "end") ), new NoOp() ) @@ -845,17 +845,17 @@ void supportsCallingTheEndFunction() { @Test void supportsModuloOperator() { assertEquals( - new Seq(null, - new Assignment(null, - new VarRef(null, "running"), - new BinaryOp(null, - new BinaryOp(null, - new Ref(null, "tick"), + new Seq(null, null, + new Assignment(null, null, + new VarRef(null, null, "running"), + new BinaryOp(null, null, + new BinaryOp(null, null, + new Ref(null, null, "tick"), "%", - new NumericLiteral(null, "2") + new NumericLiteral(null, null, "2") ), "==", - new NumericLiteral(null, "0") + new NumericLiteral(null, null, "0") ) ) ), @@ -866,7 +866,7 @@ void supportsModuloOperator() { @Test void supportsDeclaringAStack() { assertEquals( - new Seq(null, new StackAllocation(null, "cell1", 0, 63)), + new Seq(null, null, new StackAllocation(null, null, "cell1", 0, 63)), translateToAst("allocate stack in cell1[0..63]") ); } @@ -882,39 +882,39 @@ void rejectsDualStackAllocation() { void supportFunctionDeclarations() { assertEquals( prettyPrint( - new Seq(null, - new FunctionDeclaration(null, false, false, + new Seq(null, null, + new FunctionDeclaration(null, null, false, false, "delay", List.of(), - new Seq(null, - new Seq(null, - new Seq(null, - new Assignment(null, - new VarRef(null, "n"), new NumericLiteral(null, "0") + new Seq(null, null, + new Seq(null, null, + new Seq(null, null, + new Assignment(null, null, + new VarRef(null, null, "n"), new NumericLiteral(null, null, "0") ) ), - new Assignment(null, - new VarRef(null, "deadline"), - new BinaryOp(null, - new Ref(null, "tick"), + new Assignment(null, null, + new VarRef(null, null, "deadline"), + new BinaryOp(null, null, + new Ref(null, null, "tick"), "+", - new NumericLiteral(null, "60") + new NumericLiteral(null, null, "60") ) ) ), - new WhileExpression(null, null, + new WhileExpression(null, null, null, new NoOp(), - new BinaryOp(null, - new Ref(null, "tick"), + new BinaryOp(null, null, + new Ref(null, null, "tick"), "<", - new VarRef(null, "deadline") + new VarRef(null, null, "deadline") ), - new Seq(null, - new Assignment(null, - new VarRef(null, "n"), - new BinaryOp(null, new VarRef(null, "n"), + new Seq(null, null, + new Assignment(null, null, + new VarRef(null, null, "n"), + new BinaryOp(null, null, new VarRef(null, null, "n"), "+", - new NumericLiteral(null, "1") + new NumericLiteral(null, null, "1") ) ) ), @@ -942,19 +942,19 @@ void supportFunctionDeclarations() { void supportsCallingDeclaredFunctions() { assertEquals( prettyPrint( - new Seq(null, - new Seq(null, - new FunctionDeclaration(null, false, false, + new Seq(null, null, + new Seq(null, null, + new FunctionDeclaration(null, null, false, false, "foo", List.of(), - new Seq(null, - new Assignment(null, new VarRef(null, "n"), - new BinaryOp(null, new VarRef(null, "n"), "+", new NumericLiteral(null, "1")) + new Seq(null, null, + new Assignment(null, null, new VarRef(null, null, "n"), + new BinaryOp(null, null, new VarRef(null, null, "n"), "+", new NumericLiteral(null, null, "1")) ) ) ) ), - new FunctionCall(null, "foo") + new FunctionCall(null, null, "foo") ) ), prettyPrint( @@ -973,17 +973,17 @@ void supportsCallingDeclaredFunctions() { void supportsDeclaringFunctionsThatAcceptParameters() { assertEquals( prettyPrint( - new Seq(null, - new Seq(null, - new FunctionDeclaration(null, false, false, + new Seq(null, null, + new Seq(null, null, + new FunctionDeclaration(null, null, false, false, "foo", - List.of(new VarRef(null, "s")), - new Seq(null, - new BinaryOp(null, new VarRef(null, "s"), "+", new NumericLiteral(null, "1")) + List.of(new VarRef(null, null, "s")), + new Seq(null, null, + new BinaryOp(null, null, new VarRef(null, null, "s"), "+", new NumericLiteral(null, null, "1")) ) ) ), - new FunctionCall(null, "foo", new NumericLiteral(null, "1")) + new FunctionCall(null, null, "foo", new NumericLiteral(null, null, "1")) ) ), prettyPrint( @@ -1002,21 +1002,21 @@ def foo(s) void supportsDeclaringFunctionsWithInitializers() { assertEquals( prettyPrint( - new Seq(null, - new Seq(null, - new FunctionDeclaration(null, false, false, + new Seq(null, null, + new Seq(null, null, + new FunctionDeclaration(null, null, false, false, "foo", - List.of(new VarRef(null, "s"), new VarRef(null, "r")), - new Seq(null, - new BinaryOp(null, - new BinaryOp(null, new VarRef(null, "s"), "+", new NumericLiteral(null, "1")), + List.of(new VarRef(null, null, "s"), new VarRef(null, null, "r")), + new Seq(null, null, + new BinaryOp(null, null, + new BinaryOp(null, null, new VarRef(null, null, "s"), "+", new NumericLiteral(null, null, "1")), "+", - new VarRef(null, "r") + new VarRef(null, null, "r") ) ) ) ), - new FunctionCall(null, "foo", new NumericLiteral(null, "1"), new NumericLiteral(null, "6")) + new FunctionCall(null, null, "foo", new NumericLiteral(null, null, "1"), new NumericLiteral(null, null, "6")) ) ), prettyPrint( @@ -1035,14 +1035,14 @@ def foo(s, r) void supportsControllingBuildingsThroughPropAccessFunctionCalls() { assertEquals( prettyPrint( - new Seq(null, - new Control(null, - new VarRef(null, "turret"), + new Seq(null, null, + new Control(null, null, + new VarRef(null, null, "turret"), "shoot", List.of( - new PropertyAccess(null, new VarRef(null, "leader"), new Ref(null, "shootX")), - new PropertyAccess(null, new VarRef(null, "leader"), new Ref(null, "shootY")), - new PropertyAccess(null, new VarRef(null, "leader"), new Ref(null, "shooting")) + new PropertyAccess(null, null, new VarRef(null, null, "leader"), new Ref(null, null, "shootX")), + new PropertyAccess(null, null, new VarRef(null, null, "leader"), new Ref(null, null, "shootY")), + new PropertyAccess(null, null, new VarRef(null, null, "leader"), new Ref(null, null, "shooting")) ) ) ) @@ -1057,26 +1057,26 @@ void supportsControllingBuildingsThroughPropAccessFunctionCalls() { void supportsBitwiseAndOrXorShiftLeftAndShiftRight() { assertEquals( prettyPrint( - new Seq(null, - new BinaryOp(null, - new BinaryOp(null, - new BinaryOp(null, - new NumericLiteral(null, "9842"), + new Seq(null, null, + new BinaryOp(null, null, + new BinaryOp(null, null, + new BinaryOp(null, null, + new NumericLiteral(null, null, "9842"), "&", - new NumericLiteral(null, "1") + new NumericLiteral(null, null, "1") ), "^", - new BinaryOp(null, - new NumericLiteral(null, "1"), + new BinaryOp(null, null, + new NumericLiteral(null, null, "1"), "<<", - new NumericLiteral(null, "4") + new NumericLiteral(null, null, "4") ) ), "|", - new BinaryOp(null, - new VarRef(null, "y"), + new BinaryOp(null, null, + new VarRef(null, null, "y"), ">>", - new NumericLiteral(null, "1") + new NumericLiteral(null, null, "1") ) ) ) @@ -1090,14 +1090,14 @@ void supportsBitwiseAndOrXorShiftLeftAndShiftRight() { @Test void correctlyParsesElsif() { assertEquals( - new Seq(null, - new IfExpression(null, - new BooleanLiteral(null, false), - new Seq(null, new NumericLiteral(null, 1)), - new IfExpression(null, - new BooleanLiteral(null, true), - new Seq(null, new NumericLiteral(null, 2)), - new Seq(null, new NumericLiteral(null, 3)) + new Seq(null, null, + new IfExpression(null, null, + new BooleanLiteral(null, null, false), + new Seq(null, null, new NumericLiteral(null, null, 1)), + new IfExpression(null, null, + new BooleanLiteral(null, null, true), + new Seq(null, null, new NumericLiteral(null, null, 2)), + new Seq(null, null, new NumericLiteral(null, null, 3)) ) ) ), @@ -1110,18 +1110,18 @@ void correctlyParsesElsif() { @Test void correctlyParsesIndirectPropertyReference() { assertEquals( - new Seq(null, - new Seq(null, - new Assignment(null, new VarRef(null, "resource"), new Ref(null, "silicon")) + new Seq(null, null, + new Seq(null, null, + new Assignment(null, null, new VarRef(null, null, "resource"), new Ref(null, null, "silicon")) ), - new IfExpression(null, - new BinaryOp(null, - new PropertyAccess(null, new VarRef(null, "vault1"), new VarRef(null, "resource")), + new IfExpression(null, null, + new BinaryOp(null, null, + new PropertyAccess(null, null, new VarRef(null, null, "vault1"), new VarRef(null, null, "resource")), "<", - new PropertyAccess(null, new VarRef(null, "vault1"), new Ref(null, "itemCapacity")) + new PropertyAccess(null, null, new VarRef(null, null, "vault1"), new Ref(null, null, "itemCapacity")) ), - new Seq(null, - new FunctionCall(null, "harvest", new VarRef(null, "vault1"), new VarRef(null, "resource")) + new Seq(null, null, + new FunctionCall(null, null, "harvest", new VarRef(null, null, "vault1"), new VarRef(null, null, "resource")) ), new NoOp() ) @@ -1139,17 +1139,17 @@ void correctlyParsesIndirectPropertyReference() { @Test void correctlyReadsTernaryOperator() { assertEquals( - new Seq(null, - new FunctionCall(null, + new Seq(null, null, + new FunctionCall(null, null, "print", - new StringLiteral(null, "\\nsm.enabled: "), - new IfExpression(null, - new PropertyAccess(null, - new VarRef(null, "smelter1"), - new Ref(null, "enabled") + new StringLiteral(null, null, "\\nsm.enabled: "), + new IfExpression(null, null, + new PropertyAccess(null, null, + new VarRef(null, null, "smelter1"), + new Ref(null, null, "enabled") ), - new StringLiteral(null, "true"), - new StringLiteral(null, "false") + new StringLiteral(null, null, "true"), + new StringLiteral(null, null, "false") ) ) ), @@ -1160,17 +1160,17 @@ void correctlyReadsTernaryOperator() { @Test void correctlyParsesStrictNotEqual() { assertEquals( - new Seq(null, - new Assignment(null, - new VarRef(null, "a"), - new BinaryOp(null, - new BinaryOp(null, - new Ref(null, "unit"), + new Seq(null, null, + new Assignment(null, null, + new VarRef(null, null, "a"), + new BinaryOp(null, null, + new BinaryOp(null, null, + new Ref(null, null, "unit"), "===", - new NullLiteral(null) + new NullLiteral(null, null) ), "==", - new BooleanLiteral(null, false) + new BooleanLiteral(null, null, false) ) ) ), @@ -1181,18 +1181,18 @@ void correctlyParsesStrictNotEqual() { @Test void correctlyParsesBreakContinue() { assertEquals( - new Seq(null, - new Seq(null, - new WhileExpression(null, null, + new Seq(null, null, + new Seq(null, null, + new WhileExpression(null, null, null, new NoOp(), - new VarRef(null, "a"), - new Seq(null, - new IfExpression(null, - new VarRef(null, "b"), - new Seq(null, new ContinueStatement(null, null)), - new IfExpression(null, - new VarRef(null, "c"), - new Seq(null, new BreakStatement(null, null)), + new VarRef(null, null, "a"), + new Seq(null, null, + new IfExpression(null, null, + new VarRef(null, null, "b"), + new Seq(null, null, new ContinueStatement(null, null, null)), + new IfExpression(null, null, + new VarRef(null, null, "c"), + new Seq(null, null, new BreakStatement(null, null, null)), new NoOp() ) ) @@ -1200,7 +1200,7 @@ void correctlyParsesBreakContinue() { new NoOp() ) ), - new FunctionCall(null, "print", new StringLiteral(null, "End")) + new FunctionCall(null, null, "print", new StringLiteral(null, null, "End")) ), translateToAst(""" @@ -1220,8 +1220,8 @@ void correctlyParsesBreakContinue() { @Test void parsesListDirective() { assertEquals( - new Seq(null, - new Directive(null, "sort-variables", "PARAMS,GLOBALS") + new Seq(null, null, + new Directive(null, null, "sort-variables", "PARAMS,GLOBALS") ), translateToAst("#set sort-variables = PARAMS, GLOBALS;") @@ -1231,8 +1231,8 @@ void parsesListDirective() { @Test void parsesEmptyListDirective() { assertEquals( - new Seq(null, - new Directive(null, "sort-variables", "") + new Seq(null, null, + new Directive(null, null, "sort-variables", "") ), translateToAst("#set sort-variables;") diff --git a/mindcode/src/test/java/info/teksol/mindcode/compiler/AbstractGeneratorTest.java b/mindcode/src/test/java/info/teksol/mindcode/compiler/AbstractGeneratorTest.java index 6261c150f..dee47b16c 100644 --- a/mindcode/src/test/java/info/teksol/mindcode/compiler/AbstractGeneratorTest.java +++ b/mindcode/src/test/java/info/teksol/mindcode/compiler/AbstractGeneratorTest.java @@ -182,7 +182,7 @@ protected InstructionProcessor createInstructionProcessor(CompilerProfile profil // Code generation protected Seq generateAstTree(String code) { - return AstNodeBuilder.generate(parse(code)); + return AstNodeBuilder.generate(new SourceFile("", code),parse(code)); } // This class always creates unoptimized code. diff --git a/mindcode/src/test/java/info/teksol/mindcode/compiler/DirectiveProcessorTest.java b/mindcode/src/test/java/info/teksol/mindcode/compiler/DirectiveProcessorTest.java index 368f08380..b909f97fb 100644 --- a/mindcode/src/test/java/info/teksol/mindcode/compiler/DirectiveProcessorTest.java +++ b/mindcode/src/test/java/info/teksol/mindcode/compiler/DirectiveProcessorTest.java @@ -17,7 +17,7 @@ class DirectiveProcessorTest { @Test void processesDirectiveTarget() { CompilerProfile profile = CompilerProfile.noOptimizations(false); - Seq seq = new Seq(null, new Directive(null, "target", "ML6")); + Seq seq = new Seq(null, null, new Directive(null, null, "target", "ML6")); DirectiveProcessor.processDirectives(seq, profile, m -> {}); assertEquals(ProcessorVersion.V6, profile.getProcessorVersion()); } @@ -25,7 +25,7 @@ void processesDirectiveTarget() { @Test void processesDirectiveOptimization() { CompilerProfile profile = CompilerProfile.noOptimizations(false); - Seq seq = new Seq(null, new Directive(null, "optimization", "basic")); + Seq seq = new Seq(null, null, new Directive(null, null, "optimization", "basic")); DirectiveProcessor.processDirectives(seq, profile, m -> {}); assertTrue(profile.getOptimizationLevels().values().stream().allMatch(l -> l == OptimizationLevel.BASIC)); } @@ -34,7 +34,7 @@ void processesDirectiveOptimization() { void processesDirectiveInstructionLimit() { CompilerProfile profile = CompilerProfile.noOptimizations(false); profile.setInstructionLimit(1); - Seq seq = new Seq(null, new Directive(null, "instruction-limit", "900")); + Seq seq = new Seq(null, null, new Directive(null, null, "instruction-limit", "900")); DirectiveProcessor.processDirectives(seq, profile, m -> {}); assertEquals(900, profile.getInstructionLimit()); } @@ -43,7 +43,7 @@ void processesDirectiveInstructionLimit() { void processesDirectivePasses() { CompilerProfile profile = CompilerProfile.noOptimizations(false); profile.setOptimizationPasses(1); - Seq seq = new Seq(null, new Directive(null, "passes", "10")); + Seq seq = new Seq(null, null, new Directive(null, null, "passes", "10")); DirectiveProcessor.processDirectives(seq, profile, m -> {}); assertEquals(10, profile.getOptimizationPasses()); } @@ -52,7 +52,7 @@ void processesDirectivePasses() { void processesDirectiveGoal() { CompilerProfile profile = CompilerProfile.noOptimizations(false); profile.setGoal(GenerationGoal.SIZE); - Seq seq = new Seq(null, new Directive(null, "goal", "speed")); + Seq seq = new Seq(null, null, new Directive(null, null, "goal", "speed")); DirectiveProcessor.processDirectives(seq, profile, m -> {}); assertEquals(GenerationGoal.SPEED, profile.getGoal()); } @@ -61,7 +61,7 @@ void processesDirectiveGoal() { void processesDirectiveRemarks() { CompilerProfile profile = CompilerProfile.noOptimizations(false); profile.setRemarks(Remarks.NONE); - Seq seq = new Seq(null, new Directive(null, "remarks", "active")); + Seq seq = new Seq(null, null, new Directive(null, null, "remarks", "active")); DirectiveProcessor.processDirectives(seq, profile, m -> {}); assertEquals(Remarks.ACTIVE, profile.getRemarks()); } @@ -69,7 +69,7 @@ void processesDirectiveRemarks() { @Test void processesDirectiveSortVariables() { CompilerProfile profile = CompilerProfile.noOptimizations(false); - Seq seq = new Seq(null, new Directive(null, "sort-variables", "params,globals")); + Seq seq = new Seq(null, null, new Directive(null, null, "sort-variables", "params,globals")); DirectiveProcessor.processDirectives(seq, profile, m -> {}); assertEquals(List.of(SortCategory.PARAMS, SortCategory.GLOBALS), profile.getSortVariables()); } @@ -77,7 +77,7 @@ void processesDirectiveSortVariables() { @Test void refusesInvalidOption() { CompilerProfile profile = CompilerProfile.noOptimizations(false); - Seq seq = new Seq(null, new Directive(null, "fluffyBunny", "basic")); + Seq seq = new Seq(null, null, new Directive(null, null, "fluffyBunny", "basic")); List messages = new ArrayList<>(); DirectiveProcessor.processDirectives(seq, profile, messages::add); assertEquals(List.of(MindcodeMessage.error("Unknown compiler directive 'fluffyBunny'.")), messages); @@ -86,7 +86,7 @@ void refusesInvalidOption() { @Test void refusesInvalidValue() { CompilerProfile profile = CompilerProfile.noOptimizations(false); - Seq seq = new Seq(null, new Directive(null, "target", "fluffyBunny")); + Seq seq = new Seq(null, null, new Directive(null, null, "target", "fluffyBunny")); List messages = new ArrayList<>(); DirectiveProcessor.processDirectives(seq, profile, messages::add); assertEquals(List.of(MindcodeMessage.error("Invalid value 'fluffyBunny' of compiler directive 'target'.")), messages); diff --git a/mindcode/src/test/java/info/teksol/mindcode/compiler/MindcodeCompilerTest.java b/mindcode/src/test/java/info/teksol/mindcode/compiler/MindcodeCompilerTest.java index 03252dcb8..839e3ac0f 100644 --- a/mindcode/src/test/java/info/teksol/mindcode/compiler/MindcodeCompilerTest.java +++ b/mindcode/src/test/java/info/teksol/mindcode/compiler/MindcodeCompilerTest.java @@ -4,6 +4,8 @@ import info.teksol.util.CollectionUtils; import org.junit.jupiter.api.Test; +import java.util.List; + import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -17,13 +19,13 @@ class MindcodeCompilerTest { @Test public void producesAllOutputs() { - CompilerOutput result = compiler.compile(""" + CompilerOutput result = compiler.compile(SourceFile.code(""" remark("This is a parameter"); param value = true; if value then print("Hello"); end; - """); + """)); assertEquals(""" jump 2 always 0 0 @@ -51,4 +53,31 @@ public void producesAllOutputs() { 4: print "Hello" """, message.message()); } + + + @Test + public void handlesMultipleFiles() { + SourceFile file1 = new SourceFile("file1.mnd", "print(\"File1\")"); + SourceFile file2 = new SourceFile("file2.mnd", "print(\"File2\")"); + + CompilerOutput result = compiler.compile(List.of(file1, file2)); + + assertEquals(""" + print "File1File2" + """, + result.output()); + + assertEquals("File1File2", result.textBuffer()); + + int index = CollectionUtils.findFirstIndex(result.messages(), + m -> m.message().contains("Final code before resolving virtual instructions")); + assertTrue(index >= 0, "Failed to locate code output in the log."); + + CompilerMessage message = result.messages().get(index + 1); + + // Indenting is crucial here + assertEquals(""" + 0: print "File1File2" + """, message.message()); + } } diff --git a/mindcode/src/test/java/info/teksol/mindcode/compiler/generator/AstContextTest.java b/mindcode/src/test/java/info/teksol/mindcode/compiler/generator/AstContextTest.java index 20944c0c6..c4f610b7b 100644 --- a/mindcode/src/test/java/info/teksol/mindcode/compiler/generator/AstContextTest.java +++ b/mindcode/src/test/java/info/teksol/mindcode/compiler/generator/AstContextTest.java @@ -4,6 +4,7 @@ import info.teksol.mindcode.ast.FunctionDeclaration; import info.teksol.mindcode.ast.NoOp; import info.teksol.mindcode.compiler.CompilerProfile; +import info.teksol.mindcode.compiler.SourceFile; import info.teksol.mindcode.compiler.generator.CallGraph.LogicFunction; import org.antlr.v4.runtime.Token; import org.junit.jupiter.api.BeforeEach; @@ -17,8 +18,8 @@ class AstContextTest { private final CompilerProfile profile = CompilerProfile.standardOptimizations(false); private final AstContext root = AstContext.createRootNode(profile); private final CallGraph callGraph = CallGraph.createEmpty(); - private final FunctionDeclaration functionDeclaration1 = new FunctionDeclaration(null, false, false, "test1",List.of(), new NoOp()); - private final FunctionDeclaration functionDeclaration2 = new FunctionDeclaration(null, false, false, "test2",List.of(), new NoOp()); + private final FunctionDeclaration functionDeclaration1 = new FunctionDeclaration(null, null, false, false, "test1",List.of(), new NoOp()); + private final FunctionDeclaration functionDeclaration2 = new FunctionDeclaration(null, null, false, false, "test2",List.of(), new NoOp()); private LogicFunction function1; private LogicFunction function2; private AstContext context; @@ -254,6 +255,11 @@ public Token startToken() { return null; } + @Override + public SourceFile sourceFile() { + return null; + } + @Override public AstContextType getContextType() { return contextType; diff --git a/mindcode/src/test/java/info/teksol/mindcode/grammar/AbstractParserTest.java b/mindcode/src/test/java/info/teksol/mindcode/grammar/AbstractParserTest.java index 50a03b949..252fabf76 100644 --- a/mindcode/src/test/java/info/teksol/mindcode/grammar/AbstractParserTest.java +++ b/mindcode/src/test/java/info/teksol/mindcode/grammar/AbstractParserTest.java @@ -2,21 +2,17 @@ import info.teksol.mindcode.MindcodeInternalError; import info.teksol.mindcode.Tuple2; -import org.antlr.v4.runtime.BaseErrorListener; -import org.antlr.v4.runtime.BufferedTokenStream; -import org.antlr.v4.runtime.CharStreams; -import org.antlr.v4.runtime.RecognitionException; -import org.antlr.v4.runtime.Recognizer; +import org.antlr.v4.runtime.*; import java.util.ArrayList; import java.util.List; public abstract class AbstractParserTest { - protected MindcodeParser.ProgramContext parse(String program) { + protected MindcodeParser.ProgramContext parse(String code) { final List errors = new ArrayList<>(); ErrorListener errorListener = new ErrorListener(errors); - final MindcodeLexer lexer = new MindcodeLexer(CharStreams.fromString(program)); + final MindcodeLexer lexer = new MindcodeLexer(CharStreams.fromString(code)); lexer.removeErrorListeners(); lexer.addErrorListener(errorListener); diff --git a/webapp/src/test/java/info/teksol/mindcode/webapp/SamplesTest.java b/webapp/src/test/java/info/teksol/mindcode/webapp/SamplesTest.java index 7c3721c0d..575cbfde5 100644 --- a/webapp/src/test/java/info/teksol/mindcode/webapp/SamplesTest.java +++ b/webapp/src/test/java/info/teksol/mindcode/webapp/SamplesTest.java @@ -2,10 +2,7 @@ import info.teksol.mindcode.ast.AstNodeBuilder; import info.teksol.mindcode.ast.Seq; -import info.teksol.mindcode.compiler.CompilerMessage; -import info.teksol.mindcode.compiler.CompilerProfile; -import info.teksol.mindcode.compiler.LogicInstructionLabelResolver; -import info.teksol.mindcode.compiler.LogicInstructionPrinter; +import info.teksol.mindcode.compiler.*; import info.teksol.mindcode.compiler.generator.GeneratorOutput; import info.teksol.mindcode.compiler.generator.LogicInstructionGenerator; import info.teksol.mindcode.compiler.instructions.InstructionProcessor; @@ -89,7 +86,7 @@ private void compile(String source, File file) throws IOException { parser.addErrorListener(errorListener); final MindcodeParser.ProgramContext context = parser.program(); - final Seq program = AstNodeBuilder.generate(context); + final Seq program = AstNodeBuilder.generate(new SourceFile(file.getPath(), source),context); List unoptimized = generateUnoptimized(program); List optimized = generateAndOptimize(program);