Show function call position in call stack

This commit is contained in:
aNNiMON 2023-10-04 15:09:44 +03:00 committed by Victor Melnik
parent 39b94a0113
commit 1fb9c8b3c5
14 changed files with 65 additions and 16 deletions

View File

@ -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() {
if (position == null) {
return String.format("%s: %s", name, function);
} else {
return String.format("%s: %s %s", name, function, position);
}
}
}
}

View File

@ -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);

View File

@ -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();
}

View File

@ -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();
}
}

View File

@ -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

View File

@ -1,6 +1,6 @@
package com.annimon.ownlang.exceptions;
import com.annimon.ownlang.parser.Range;
import com.annimon.ownlang.util.Range;
/**
*

View File

@ -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) {

View File

@ -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.*;
/**

View File

@ -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;
}

View File

@ -1,5 +1,7 @@
package com.annimon.ownlang.parser;
import com.annimon.ownlang.util.Pos;
/**
* @author aNNiMON
*/

View File

@ -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<Expression> arguments;
private Range range;
public FunctionalExpression(Expression functionExpr) {
this.functionExpr = functionExpr;
@ -24,6 +28,15 @@ public final class FunctionalExpression extends InterruptableNode implements Exp
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;

View File

@ -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;

View File

@ -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;

View File

@ -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;