From 1fb9c8b3c580c00e14f606ae6766dd4dfe2b6c3d Mon Sep 17 00:00:00 2001 From: aNNiMON Date: Wed, 4 Oct 2023 15:09:44 +0300 Subject: [PATCH] Show function call position in call stack --- .../com/annimon/ownlang/lib/CallStack.java | 20 +++++++++++++++---- .../java/com/annimon/ownlang/util}/Pos.java | 2 +- .../java/com/annimon/ownlang/util}/Range.java | 6 ++++-- .../annimon/ownlang/util/SourceLocation.java | 13 ++++++++++++ .../exceptions/BaseParserException.java | 2 +- .../ownlang/exceptions/ParseException.java | 2 +- .../ownlang/lib/UserDefinedFunction.java | 2 +- .../com/annimon/ownlang/parser/Lexer.java | 2 ++ .../com/annimon/ownlang/parser/Parser.java | 4 ++++ .../com/annimon/ownlang/parser/Token.java | 2 ++ .../parser/ast/FunctionalExpression.java | 19 +++++++++++++++--- .../ownlang/parser/error/ParseError.java | 2 +- .../error/ParseErrorsFormatterStage.java | 4 ++-- .../java/com/annimon/ownlang/utils/Repl.java | 1 + 14 files changed, 65 insertions(+), 16 deletions(-) rename {ownlang-parser/src/main/java/com/annimon/ownlang/parser => ownlang-core/src/main/java/com/annimon/ownlang/util}/Pos.java (90%) rename {ownlang-parser/src/main/java/com/annimon/ownlang/parser => ownlang-core/src/main/java/com/annimon/ownlang/util}/Range.java (75%) create mode 100644 ownlang-core/src/main/java/com/annimon/ownlang/util/SourceLocation.java diff --git a/ownlang-core/src/main/java/com/annimon/ownlang/lib/CallStack.java b/ownlang-core/src/main/java/com/annimon/ownlang/lib/CallStack.java index 5a0b00d..e0a8cfe 100644 --- a/ownlang-core/src/main/java/com/annimon/ownlang/lib/CallStack.java +++ b/ownlang-core/src/main/java/com/annimon/ownlang/lib/CallStack.java @@ -13,8 +13,16 @@ public final class CallStack { calls.clear(); } - public static synchronized void enter(String name, Function function) { - calls.push(new CallInfo(name, function.toString())); + public static synchronized void enter(String name, Function function, String position) { + String func = function.toString(); + if (func.contains("com.annimon.ownlang.modules")) { + func = func.replaceAll( + "com.annimon.ownlang.modules.(\\w+)\\.?\\1?", "module $1"); + } + if (func.contains("\n")) { + func = func.substring(0, func.indexOf("\n")).trim(); + } + calls.push(new CallInfo(name, func, position)); } public static synchronized void exit() { @@ -25,10 +33,14 @@ public final class CallStack { return calls; } - public record CallInfo(String name, String function) { + public record CallInfo(String name, String function, String position) { @Override public String toString() { - return String.format("%s: %s", name, function); + if (position == null) { + return String.format("%s: %s", name, function); + } else { + return String.format("%s: %s %s", name, function, position); + } } } } diff --git a/ownlang-parser/src/main/java/com/annimon/ownlang/parser/Pos.java b/ownlang-core/src/main/java/com/annimon/ownlang/util/Pos.java similarity index 90% rename from ownlang-parser/src/main/java/com/annimon/ownlang/parser/Pos.java rename to ownlang-core/src/main/java/com/annimon/ownlang/util/Pos.java index f5a1217..6c72e52 100644 --- a/ownlang-parser/src/main/java/com/annimon/ownlang/parser/Pos.java +++ b/ownlang-core/src/main/java/com/annimon/ownlang/util/Pos.java @@ -1,4 +1,4 @@ -package com.annimon.ownlang.parser; +package com.annimon.ownlang.util; public record Pos(int row, int col) { public static final Pos UNKNOWN = new Pos(-1, -1); diff --git a/ownlang-parser/src/main/java/com/annimon/ownlang/parser/Range.java b/ownlang-core/src/main/java/com/annimon/ownlang/util/Range.java similarity index 75% rename from ownlang-parser/src/main/java/com/annimon/ownlang/parser/Range.java rename to ownlang-core/src/main/java/com/annimon/ownlang/util/Range.java index 6902d48..b753d9d 100644 --- a/ownlang-parser/src/main/java/com/annimon/ownlang/parser/Range.java +++ b/ownlang-core/src/main/java/com/annimon/ownlang/util/Range.java @@ -1,4 +1,4 @@ -package com.annimon.ownlang.parser; +package com.annimon.ownlang.util; import java.util.Objects; @@ -18,8 +18,10 @@ public record Range(Pos start, Pos end) { } public String format() { - if (isOnSameLine()) { + if (isEqualPosition()) return start.format(); + else if (isOnSameLine()) { + return "[%d:%d~%d]".formatted(start.row(), start.col(), end.col()); } else { return start.format() + "..." + end.format(); } diff --git a/ownlang-core/src/main/java/com/annimon/ownlang/util/SourceLocation.java b/ownlang-core/src/main/java/com/annimon/ownlang/util/SourceLocation.java new file mode 100644 index 0000000..f380314 --- /dev/null +++ b/ownlang-core/src/main/java/com/annimon/ownlang/util/SourceLocation.java @@ -0,0 +1,13 @@ +package com.annimon.ownlang.util; + +public interface SourceLocation { + + default Range getRange() { + return null; + } + + default String formatRange() { + final var range = getRange(); + return range == null ? "" : range.format(); + } +} diff --git a/ownlang-parser/src/main/java/com/annimon/ownlang/exceptions/BaseParserException.java b/ownlang-parser/src/main/java/com/annimon/ownlang/exceptions/BaseParserException.java index 1d59a0c..c323a11 100644 --- a/ownlang-parser/src/main/java/com/annimon/ownlang/exceptions/BaseParserException.java +++ b/ownlang-parser/src/main/java/com/annimon/ownlang/exceptions/BaseParserException.java @@ -1,6 +1,6 @@ package com.annimon.ownlang.exceptions; -import com.annimon.ownlang.parser.Range; +import com.annimon.ownlang.util.Range; /** * Base type for all lexer and parser exceptions diff --git a/ownlang-parser/src/main/java/com/annimon/ownlang/exceptions/ParseException.java b/ownlang-parser/src/main/java/com/annimon/ownlang/exceptions/ParseException.java index 2113cbc..c4adc1d 100644 --- a/ownlang-parser/src/main/java/com/annimon/ownlang/exceptions/ParseException.java +++ b/ownlang-parser/src/main/java/com/annimon/ownlang/exceptions/ParseException.java @@ -1,6 +1,6 @@ package com.annimon.ownlang.exceptions; -import com.annimon.ownlang.parser.Range; +import com.annimon.ownlang.util.Range; /** * diff --git a/ownlang-parser/src/main/java/com/annimon/ownlang/lib/UserDefinedFunction.java b/ownlang-parser/src/main/java/com/annimon/ownlang/lib/UserDefinedFunction.java index b0a92be..ce5b15e 100644 --- a/ownlang-parser/src/main/java/com/annimon/ownlang/lib/UserDefinedFunction.java +++ b/ownlang-parser/src/main/java/com/annimon/ownlang/lib/UserDefinedFunction.java @@ -31,7 +31,7 @@ public class UserDefinedFunction implements Function { } @Override - public Value execute(Value... values) { + public Value execute(Value[] values) { final int size = values.length; final int requiredArgsCount = arguments.getRequiredArgumentsCount(); if (size < requiredArgsCount) { diff --git a/ownlang-parser/src/main/java/com/annimon/ownlang/parser/Lexer.java b/ownlang-parser/src/main/java/com/annimon/ownlang/parser/Lexer.java index 7ba7fc5..72663ef 100644 --- a/ownlang-parser/src/main/java/com/annimon/ownlang/parser/Lexer.java +++ b/ownlang-parser/src/main/java/com/annimon/ownlang/parser/Lexer.java @@ -2,6 +2,8 @@ package com.annimon.ownlang.parser; import com.annimon.ownlang.exceptions.OwnLangParserException; import com.annimon.ownlang.parser.error.ParseError; +import com.annimon.ownlang.util.Pos; +import com.annimon.ownlang.util.Range; import java.util.*; /** diff --git a/ownlang-parser/src/main/java/com/annimon/ownlang/parser/Parser.java b/ownlang-parser/src/main/java/com/annimon/ownlang/parser/Parser.java index 53950bb..149c3b7 100644 --- a/ownlang-parser/src/main/java/com/annimon/ownlang/parser/Parser.java +++ b/ownlang-parser/src/main/java/com/annimon/ownlang/parser/Parser.java @@ -8,6 +8,8 @@ import com.annimon.ownlang.lib.UserDefinedFunction; import com.annimon.ownlang.parser.ast.*; import com.annimon.ownlang.parser.error.ParseError; import com.annimon.ownlang.parser.error.ParseErrors; +import com.annimon.ownlang.util.Pos; +import com.annimon.ownlang.util.Range; import java.util.*; import java.util.function.Function; import java.util.stream.Collectors; @@ -351,12 +353,14 @@ public final class Parser { private FunctionalExpression function(Expression qualifiedNameExpr) { // function(arg1, arg2, ...) + final var startTokenIndex = index - 1; consume(TokenType.LPAREN); final FunctionalExpression function = new FunctionalExpression(qualifiedNameExpr); while (!match(TokenType.RPAREN)) { function.addArgument(expression()); match(TokenType.COMMA); } + function.setRange(getRange(startTokenIndex, index - 1)); return function; } diff --git a/ownlang-parser/src/main/java/com/annimon/ownlang/parser/Token.java b/ownlang-parser/src/main/java/com/annimon/ownlang/parser/Token.java index 8d151cd..134681d 100644 --- a/ownlang-parser/src/main/java/com/annimon/ownlang/parser/Token.java +++ b/ownlang-parser/src/main/java/com/annimon/ownlang/parser/Token.java @@ -1,5 +1,7 @@ package com.annimon.ownlang.parser; +import com.annimon.ownlang.util.Pos; + /** * @author aNNiMON */ diff --git a/ownlang-parser/src/main/java/com/annimon/ownlang/parser/ast/FunctionalExpression.java b/ownlang-parser/src/main/java/com/annimon/ownlang/parser/ast/FunctionalExpression.java index b84985e..59d538e 100644 --- a/ownlang-parser/src/main/java/com/annimon/ownlang/parser/ast/FunctionalExpression.java +++ b/ownlang-parser/src/main/java/com/annimon/ownlang/parser/ast/FunctionalExpression.java @@ -2,6 +2,8 @@ package com.annimon.ownlang.parser.ast; import com.annimon.ownlang.exceptions.*; import com.annimon.ownlang.lib.*; +import com.annimon.ownlang.util.Range; +import com.annimon.ownlang.util.SourceLocation; import java.util.ArrayList; import java.util.Iterator; import java.util.List; @@ -10,10 +12,12 @@ import java.util.List; * * @author aNNiMON */ -public final class FunctionalExpression extends InterruptableNode implements Expression, Statement { +public final class FunctionalExpression extends InterruptableNode + implements Expression, Statement, SourceLocation { public final Expression functionExpr; public final List arguments; + private Range range; public FunctionalExpression(Expression functionExpr) { this.functionExpr = functionExpr; @@ -23,7 +27,16 @@ public final class FunctionalExpression extends InterruptableNode implements Exp public void addArgument(Expression arg) { arguments.add(arg); } - + + public void setRange(Range range) { + this.range = range; + } + + @Override + public Range getRange() { + return range; + } + @Override public void execute() { eval(); @@ -38,7 +51,7 @@ public final class FunctionalExpression extends InterruptableNode implements Exp values[i] = arguments.get(i).eval(); } final Function f = consumeFunction(functionExpr); - CallStack.enter(functionExpr.toString(), f); + CallStack.enter(functionExpr.toString(), f, formatRange()); final Value result = f.execute(values); CallStack.exit(); return result; diff --git a/ownlang-parser/src/main/java/com/annimon/ownlang/parser/error/ParseError.java b/ownlang-parser/src/main/java/com/annimon/ownlang/parser/error/ParseError.java index 8fba8ef..d4dd19d 100644 --- a/ownlang-parser/src/main/java/com/annimon/ownlang/parser/error/ParseError.java +++ b/ownlang-parser/src/main/java/com/annimon/ownlang/parser/error/ParseError.java @@ -1,6 +1,6 @@ package com.annimon.ownlang.parser.error; -import com.annimon.ownlang.parser.Range; +import com.annimon.ownlang.util.Range; import java.util.Collections; import java.util.List; diff --git a/ownlang-parser/src/main/java/com/annimon/ownlang/parser/error/ParseErrorsFormatterStage.java b/ownlang-parser/src/main/java/com/annimon/ownlang/parser/error/ParseErrorsFormatterStage.java index 4a305bd..cafc52f 100644 --- a/ownlang-parser/src/main/java/com/annimon/ownlang/parser/error/ParseErrorsFormatterStage.java +++ b/ownlang-parser/src/main/java/com/annimon/ownlang/parser/error/ParseErrorsFormatterStage.java @@ -1,8 +1,8 @@ package com.annimon.ownlang.parser.error; import com.annimon.ownlang.Console; -import com.annimon.ownlang.parser.Pos; -import com.annimon.ownlang.parser.Range; +import com.annimon.ownlang.util.Pos; +import com.annimon.ownlang.util.Range; import com.annimon.ownlang.stages.SourceLoaderStage; import com.annimon.ownlang.stages.Stage; import com.annimon.ownlang.stages.StagesData; diff --git a/ownlang-utils/src/main/java/com/annimon/ownlang/utils/Repl.java b/ownlang-utils/src/main/java/com/annimon/ownlang/utils/Repl.java index 8d1bf06..3f3f959 100644 --- a/ownlang-utils/src/main/java/com/annimon/ownlang/utils/Repl.java +++ b/ownlang-utils/src/main/java/com/annimon/ownlang/utils/Repl.java @@ -8,6 +8,7 @@ import com.annimon.ownlang.lib.*; import com.annimon.ownlang.parser.*; import com.annimon.ownlang.parser.ast.BlockStatement; import com.annimon.ownlang.parser.ast.Statement; +import com.annimon.ownlang.util.Pos; import com.annimon.ownlang.parser.visitors.PrintVisitor; import com.annimon.ownlang.utils.repl.JLineConsole; import com.annimon.ownlang.utils.repl.OwnLangCompleter;