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; package com.annimon.ownlang.exceptions;
import com.annimon.ownlang.util.Range;
public final class ArgumentsMismatchException extends OwnLangRuntimeException { public final class ArgumentsMismatchException extends OwnLangRuntimeException {
public ArgumentsMismatchException() { public ArgumentsMismatchException() {
@ -8,4 +10,8 @@ public final class ArgumentsMismatchException extends OwnLangRuntimeException {
public ArgumentsMismatchException(String message) { public ArgumentsMismatchException(String message) {
super(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.Arguments;
import com.annimon.ownlang.parser.ast.Statement; import com.annimon.ownlang.parser.ast.Statement;
import com.annimon.ownlang.util.Range;
public class ClassMethod extends UserDefinedFunction { public class ClassMethod extends UserDefinedFunction {
public final ClassInstanceValue classInstance; public final ClassInstanceValue classInstance;
public ClassMethod(Arguments arguments, Statement body, ClassInstanceValue classInstance) { public ClassMethod(Arguments arguments, Statement body, ClassInstanceValue classInstance, Range range) {
super(arguments, body); super(arguments, body, range);
this.classInstance = classInstance; 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.Arguments;
import com.annimon.ownlang.parser.ast.ReturnStatement; import com.annimon.ownlang.parser.ast.ReturnStatement;
import com.annimon.ownlang.parser.ast.Statement; import com.annimon.ownlang.parser.ast.Statement;
import com.annimon.ownlang.util.Range;
import com.annimon.ownlang.util.SourceLocation;
/** /**
* *
* @author aNNiMON * @author aNNiMON
*/ */
public class UserDefinedFunction implements Function { public class UserDefinedFunction implements Function, SourceLocation {
public final Arguments arguments; public final Arguments arguments;
public final Statement body; 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.arguments = arguments;
this.body = body; this.body = body;
this.range = range;
}
@Override
public Range getRange() {
return range;
} }
@Override @Override
@ -35,13 +44,15 @@ public class UserDefinedFunction implements Function {
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) {
throw new ArgumentsMismatchException(String.format( String error = String.format(
"Arguments count mismatch. Required %d, got %d", requiredArgsCount, size)); "Arguments count mismatch. Required %d, got %d", requiredArgsCount, size);
throw new ArgumentsMismatchException(error, arguments.getRange());
} }
final int totalArgsCount = getArgsCount(); final int totalArgsCount = getArgsCount();
if (size > totalArgsCount) { if (size > totalArgsCount) {
throw new ArgumentsMismatchException(String.format( String error = String.format(
"Arguments count mismatch. Total %d, got %d", totalArgsCount, size)); "Arguments count mismatch. Total %d, got %d", totalArgsCount, size);
throw new ArgumentsMismatchException(error, arguments.getRange());
} }
try { try {

View File

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

View File

@ -1,12 +1,15 @@
package com.annimon.ownlang.parser.ast; 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.ArrayList;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; 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 final List<Argument> arguments;
private Range range;
private int requiredArgumentsCount; private int requiredArgumentsCount;
public Arguments() { public Arguments() {
@ -35,6 +38,15 @@ public final class Arguments implements Iterable<Argument> {
return arguments.size(); return arguments.size();
} }
public void setRange(Range range) {
this.range = range;
}
@Override
public Range getRange() {
return range;
}
@Override @Override
public Iterator<Argument> iterator() { public Iterator<Argument> iterator() {
return arguments.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.ScopeHandler;
import com.annimon.ownlang.lib.UserDefinedFunction; import com.annimon.ownlang.lib.UserDefinedFunction;
import com.annimon.ownlang.util.Range;
import com.annimon.ownlang.util.SourceLocation;
/** /**
* *
* @author aNNiMON * @author aNNiMON
*/ */
public final class FunctionDefineStatement implements Statement { public final class FunctionDefineStatement implements Statement, SourceLocation {
public final String name; public final String name;
public final Arguments arguments; public final Arguments arguments;
public final Statement body; 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.name = name;
this.arguments = arguments; this.arguments = arguments;
this.body = body; this.body = body;
this.range = range;
}
@Override
public Range getRange() {
return range;
} }
@Override @Override
public void execute() { public void execute() {
ScopeHandler.setFunction(name, new UserDefinedFunction(arguments, body)); ScopeHandler.setFunction(name, new UserDefinedFunction(arguments, body, range));
} }
@Override @Override

View File

@ -38,7 +38,7 @@ public final class ObjectCreationExpression implements Expression, SourceLocatio
return instantiable.newInstance(ctorArgs()); return instantiable.newInstance(ctorArgs());
} }
} }
throw new UnknownClassException(className, getRange()); throw new UnknownClassException(className, range);
} }
// Create an instance and put evaluated fields with method declarations // 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()); instance.addField(fieldName, f.eval());
} }
for (FunctionDefineStatement m : cd.methods) { 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 // 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); final Node body = s.body.accept(this, t);
if (changed || body != s.body) { 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; return s;
} }
@ -423,7 +423,7 @@ public abstract class OptimizationVisitor<T> implements ResultVisitor<Node, T> {
final Node body = s.body.accept(this, t); final Node body = s.body.accept(this, t);
if (changed || body != s.body) { if (changed || body != s.body) {
return new UserDefinedFunction(newArgs, consumeStatement(body)); return new UserDefinedFunction(newArgs, consumeStatement(body), s.getRange());
} }
return s; 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) { protected boolean visit(final Arguments in, final Arguments out, T t) {
boolean changed = false; boolean changed = false;
out.setRange(in.getRange());
for (Argument argument : in) { for (Argument argument : in) {
final Expression valueExpr = argument.valueExpr(); final Expression valueExpr = argument.valueExpr();
if (valueExpr == null) { if (valueExpr == null) {

View File

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