Source located function, class and arguments

This commit is contained in:
aNNiMON 2023-10-05 18:57:36 +03:00 committed by Victor Melnik
parent 2bb5e45517
commit d3dd8feb10
9 changed files with 66 additions and 22 deletions

View File

@ -1,5 +1,7 @@
package com.annimon.ownlang.exceptions;
import com.annimon.ownlang.util.Range;
public final class ArgumentsMismatchException extends OwnLangRuntimeException {
public ArgumentsMismatchException() {
@ -8,4 +10,8 @@ public final class ArgumentsMismatchException extends OwnLangRuntimeException {
public ArgumentsMismatchException(String message) {
super(message);
}
public ArgumentsMismatchException(String message, Range range) {
super(message, range);
}
}

View File

@ -2,13 +2,14 @@ package com.annimon.ownlang.lib;
import com.annimon.ownlang.parser.ast.Arguments;
import com.annimon.ownlang.parser.ast.Statement;
import com.annimon.ownlang.util.Range;
public class ClassMethod extends UserDefinedFunction {
public final ClassInstanceValue classInstance;
public ClassMethod(Arguments arguments, Statement body, ClassInstanceValue classInstance) {
super(arguments, body);
public ClassMethod(Arguments arguments, Statement body, ClassInstanceValue classInstance, Range range) {
super(arguments, body, range);
this.classInstance = classInstance;
}

View File

@ -5,19 +5,28 @@ import com.annimon.ownlang.parser.ast.Argument;
import com.annimon.ownlang.parser.ast.Arguments;
import com.annimon.ownlang.parser.ast.ReturnStatement;
import com.annimon.ownlang.parser.ast.Statement;
import com.annimon.ownlang.util.Range;
import com.annimon.ownlang.util.SourceLocation;
/**
*
* @author aNNiMON
*/
public class UserDefinedFunction implements Function {
public class UserDefinedFunction implements Function, SourceLocation {
public final Arguments arguments;
public final Statement body;
private final Range range;
public UserDefinedFunction(Arguments arguments, Statement body) {
public UserDefinedFunction(Arguments arguments, Statement body, Range range) {
this.arguments = arguments;
this.body = body;
this.range = range;
}
@Override
public Range getRange() {
return range;
}
@Override
@ -35,13 +44,15 @@ public class UserDefinedFunction implements Function {
final int size = values.length;
final int requiredArgsCount = arguments.getRequiredArgumentsCount();
if (size < requiredArgsCount) {
throw new ArgumentsMismatchException(String.format(
"Arguments count mismatch. Required %d, got %d", requiredArgsCount, size));
String error = String.format(
"Arguments count mismatch. Required %d, got %d", requiredArgsCount, size);
throw new ArgumentsMismatchException(error, arguments.getRange());
}
final int totalArgsCount = getArgsCount();
if (size > totalArgsCount) {
throw new ArgumentsMismatchException(String.format(
"Arguments count mismatch. Total %d, got %d", totalArgsCount, size));
String error = String.format(
"Arguments count mismatch. Total %d, got %d", totalArgsCount, size);
throw new ArgumentsMismatchException(error, arguments.getRange());
}
try {

View File

@ -290,16 +290,18 @@ public final class Parser {
private FunctionDefineStatement functionDefine() {
// def name(arg1, arg2 = value) { ... } || def name(args) = expr
final var startTokenIndex = index - 1;
final String name = consume(TokenType.WORD).text();
final Arguments arguments = arguments();
final Statement body = statementBody();
return new FunctionDefineStatement(name, arguments, body);
return new FunctionDefineStatement(name, arguments, body, getRange(startTokenIndex, index - 1));
}
private Arguments arguments() {
// (arg1, arg2, arg3 = expr1, arg4 = expr2)
final Arguments arguments = new Arguments();
boolean startsOptionalArgs = false;
final var startTokenIndex = index;
consume(TokenType.LPAREN);
while (!match(TokenType.RPAREN)) {
final String name = consume(TokenType.WORD).text();
@ -313,6 +315,7 @@ public final class Parser {
}
match(TokenType.COMMA);
}
arguments.setRange(getRange(startTokenIndex, index - 1));
return arguments;
}
@ -802,9 +805,10 @@ public final class Parser {
}
if (match(TokenType.DEF)) {
// anonymous function def(args) ...
final var startTokenIndex = index - 1;
final Arguments arguments = arguments();
final Statement statement = statementBody();
return new ValueExpression(new UserDefinedFunction(arguments, statement));
return new ValueExpression(new UserDefinedFunction(arguments, statement, getRange(startTokenIndex, index - 1)));
}
return variable();
}

View File

@ -1,12 +1,15 @@
package com.annimon.ownlang.parser.ast;
import com.annimon.ownlang.util.Range;
import com.annimon.ownlang.util.SourceLocation;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public final class Arguments implements Iterable<Argument> {
public final class Arguments implements Iterable<Argument>, SourceLocation {
private final List<Argument> arguments;
private Range range;
private int requiredArgumentsCount;
public Arguments() {
@ -35,6 +38,15 @@ public final class Arguments implements Iterable<Argument> {
return arguments.size();
}
public void setRange(Range range) {
this.range = range;
}
@Override
public Range getRange() {
return range;
}
@Override
public Iterator<Argument> iterator() {
return arguments.iterator();

View File

@ -2,26 +2,35 @@ package com.annimon.ownlang.parser.ast;
import com.annimon.ownlang.lib.ScopeHandler;
import com.annimon.ownlang.lib.UserDefinedFunction;
import com.annimon.ownlang.util.Range;
import com.annimon.ownlang.util.SourceLocation;
/**
*
* @author aNNiMON
*/
public final class FunctionDefineStatement implements Statement {
public final class FunctionDefineStatement implements Statement, SourceLocation {
public final String name;
public final Arguments arguments;
public final Statement body;
private final Range range;
public FunctionDefineStatement(String name, Arguments arguments, Statement body) {
public FunctionDefineStatement(String name, Arguments arguments, Statement body, Range range) {
this.name = name;
this.arguments = arguments;
this.body = body;
this.range = range;
}
@Override
public Range getRange() {
return range;
}
@Override
public void execute() {
ScopeHandler.setFunction(name, new UserDefinedFunction(arguments, body));
ScopeHandler.setFunction(name, new UserDefinedFunction(arguments, body, range));
}
@Override

View File

@ -38,7 +38,7 @@ public final class ObjectCreationExpression implements Expression, SourceLocatio
return instantiable.newInstance(ctorArgs());
}
}
throw new UnknownClassException(className, getRange());
throw new UnknownClassException(className, range);
}
// Create an instance and put evaluated fields with method declarations
@ -49,7 +49,7 @@ public final class ObjectCreationExpression implements Expression, SourceLocatio
instance.addField(fieldName, f.eval());
}
for (FunctionDefineStatement m : cd.methods) {
instance.addMethod(m.name, new ClassMethod(m.arguments, m.body, instance));
instance.addMethod(m.name, new ClassMethod(m.arguments, m.body, instance, m.getRange()));
}
// Call a constructor

View File

@ -174,7 +174,7 @@ public abstract class OptimizationVisitor<T> implements ResultVisitor<Node, T> {
final Node body = s.body.accept(this, t);
if (changed || body != s.body) {
return new FunctionDefineStatement(s.name, newArgs, consumeStatement(body));
return new FunctionDefineStatement(s.name, newArgs, consumeStatement(body), s.getRange());
}
return s;
}
@ -423,7 +423,7 @@ public abstract class OptimizationVisitor<T> implements ResultVisitor<Node, T> {
final Node body = s.body.accept(this, t);
if (changed || body != s.body) {
return new UserDefinedFunction(newArgs, consumeStatement(body));
return new UserDefinedFunction(newArgs, consumeStatement(body), s.getRange());
}
return s;
}
@ -432,6 +432,7 @@ public abstract class OptimizationVisitor<T> implements ResultVisitor<Node, T> {
protected boolean visit(final Arguments in, final Arguments out, T t) {
boolean changed = false;
out.setRange(in.getRange());
for (Argument argument : in) {
final Expression valueExpr = argument.valueExpr();
if (valueExpr == null) {

View File

@ -97,8 +97,8 @@ public class ProgramsTest {
.perform(stagesData, ex.getParseErrors());
fail(inputSource + "\n" + error, ex);
} catch (Exception oae) {
fail(inputSource.toString(), oae);
Console.handleException(stagesData, Thread.currentThread(), oae);
fail(inputSource.toString(), oae);
}
}