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(); calls.clear();
} }
public static synchronized void enter(String name, Function function) { public static synchronized void enter(String name, Function function, String position) {
calls.push(new CallInfo(name, function.toString())); 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() { public static synchronized void exit() {
@ -25,10 +33,14 @@ public final class CallStack {
return calls; return calls;
} }
public record CallInfo(String name, String function) { public record CallInfo(String name, String function, String position) {
@Override @Override
public String toString() { public String toString() {
if (position == null) {
return String.format("%s: %s", name, function); 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 record Pos(int row, int col) {
public static final Pos UNKNOWN = new Pos(-1, -1); 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; import java.util.Objects;
@ -18,8 +18,10 @@ public record Range(Pos start, Pos end) {
} }
public String format() { public String format() {
if (isOnSameLine()) { if (isEqualPosition())
return start.format(); return start.format();
else if (isOnSameLine()) {
return "[%d:%d~%d]".formatted(start.row(), start.col(), end.col());
} else { } else {
return start.format() + "..." + end.format(); 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; 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 * Base type for all lexer and parser exceptions

View File

@ -1,6 +1,6 @@
package com.annimon.ownlang.exceptions; 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 @Override
public Value execute(Value... values) { public Value execute(Value[] values) {
final int size = values.length; final int size = values.length;
final int requiredArgsCount = arguments.getRequiredArgumentsCount(); final int requiredArgsCount = arguments.getRequiredArgumentsCount();
if (size < requiredArgsCount) { if (size < requiredArgsCount) {

View File

@ -2,6 +2,8 @@ package com.annimon.ownlang.parser;
import com.annimon.ownlang.exceptions.OwnLangParserException; import com.annimon.ownlang.exceptions.OwnLangParserException;
import com.annimon.ownlang.parser.error.ParseError; import com.annimon.ownlang.parser.error.ParseError;
import com.annimon.ownlang.util.Pos;
import com.annimon.ownlang.util.Range;
import java.util.*; 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.ast.*;
import com.annimon.ownlang.parser.error.ParseError; import com.annimon.ownlang.parser.error.ParseError;
import com.annimon.ownlang.parser.error.ParseErrors; 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.*;
import java.util.function.Function; import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -351,12 +353,14 @@ public final class Parser {
private FunctionalExpression function(Expression qualifiedNameExpr) { private FunctionalExpression function(Expression qualifiedNameExpr) {
// function(arg1, arg2, ...) // function(arg1, arg2, ...)
final var startTokenIndex = index - 1;
consume(TokenType.LPAREN); consume(TokenType.LPAREN);
final FunctionalExpression function = new FunctionalExpression(qualifiedNameExpr); final FunctionalExpression function = new FunctionalExpression(qualifiedNameExpr);
while (!match(TokenType.RPAREN)) { while (!match(TokenType.RPAREN)) {
function.addArgument(expression()); function.addArgument(expression());
match(TokenType.COMMA); match(TokenType.COMMA);
} }
function.setRange(getRange(startTokenIndex, index - 1));
return function; return function;
} }

View File

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

View File

@ -2,6 +2,8 @@ package com.annimon.ownlang.parser.ast;
import com.annimon.ownlang.exceptions.*; import com.annimon.ownlang.exceptions.*;
import com.annimon.ownlang.lib.*; import com.annimon.ownlang.lib.*;
import com.annimon.ownlang.util.Range;
import com.annimon.ownlang.util.SourceLocation;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
@ -10,10 +12,12 @@ import java.util.List;
* *
* @author aNNiMON * @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 Expression functionExpr;
public final List<Expression> arguments; public final List<Expression> arguments;
private Range range;
public FunctionalExpression(Expression functionExpr) { public FunctionalExpression(Expression functionExpr) {
this.functionExpr = functionExpr; this.functionExpr = functionExpr;
@ -24,6 +28,15 @@ public final class FunctionalExpression extends InterruptableNode implements Exp
arguments.add(arg); arguments.add(arg);
} }
public void setRange(Range range) {
this.range = range;
}
@Override
public Range getRange() {
return range;
}
@Override @Override
public void execute() { public void execute() {
eval(); eval();
@ -38,7 +51,7 @@ public final class FunctionalExpression extends InterruptableNode implements Exp
values[i] = arguments.get(i).eval(); values[i] = arguments.get(i).eval();
} }
final Function f = consumeFunction(functionExpr); final Function f = consumeFunction(functionExpr);
CallStack.enter(functionExpr.toString(), f); CallStack.enter(functionExpr.toString(), f, formatRange());
final Value result = f.execute(values); final Value result = f.execute(values);
CallStack.exit(); CallStack.exit();
return result; return result;

View File

@ -1,6 +1,6 @@
package com.annimon.ownlang.parser.error; 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.Collections;
import java.util.List; import java.util.List;

View File

@ -1,8 +1,8 @@
package com.annimon.ownlang.parser.error; package com.annimon.ownlang.parser.error;
import com.annimon.ownlang.Console; import com.annimon.ownlang.Console;
import com.annimon.ownlang.parser.Pos; import com.annimon.ownlang.util.Pos;
import com.annimon.ownlang.parser.Range; import com.annimon.ownlang.util.Range;
import com.annimon.ownlang.stages.SourceLoaderStage; import com.annimon.ownlang.stages.SourceLoaderStage;
import com.annimon.ownlang.stages.Stage; import com.annimon.ownlang.stages.Stage;
import com.annimon.ownlang.stages.StagesData; 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.*;
import com.annimon.ownlang.parser.ast.BlockStatement; import com.annimon.ownlang.parser.ast.BlockStatement;
import com.annimon.ownlang.parser.ast.Statement; import com.annimon.ownlang.parser.ast.Statement;
import com.annimon.ownlang.util.Pos;
import com.annimon.ownlang.parser.visitors.PrintVisitor; import com.annimon.ownlang.parser.visitors.PrintVisitor;
import com.annimon.ownlang.utils.repl.JLineConsole; import com.annimon.ownlang.utils.repl.JLineConsole;
import com.annimon.ownlang.utils.repl.OwnLangCompleter; import com.annimon.ownlang.utils.repl.OwnLangCompleter;