diff --git a/ownlang-core/src/main/java/com/annimon/ownlang/exceptions/ArgumentsMismatchException.java b/ownlang-core/src/main/java/com/annimon/ownlang/exceptions/ArgumentsMismatchException.java index 082e9b3..24c05ff 100644 --- a/ownlang-core/src/main/java/com/annimon/ownlang/exceptions/ArgumentsMismatchException.java +++ b/ownlang-core/src/main/java/com/annimon/ownlang/exceptions/ArgumentsMismatchException.java @@ -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); + } } diff --git a/ownlang-parser/src/main/java/com/annimon/ownlang/lib/ClassMethod.java b/ownlang-parser/src/main/java/com/annimon/ownlang/lib/ClassMethod.java index 6155a64..5ad723e 100644 --- a/ownlang-parser/src/main/java/com/annimon/ownlang/lib/ClassMethod.java +++ b/ownlang-parser/src/main/java/com/annimon/ownlang/lib/ClassMethod.java @@ -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; } 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 ce5b15e..f6015c0 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 @@ -5,21 +5,30 @@ 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; - - public UserDefinedFunction(Arguments arguments, Statement body) { + private final Range range; + + public UserDefinedFunction(Arguments arguments, Statement body, Range range) { this.arguments = arguments; this.body = body; + this.range = range; } - + + @Override + public Range getRange() { + return range; + } + @Override public int getArgsCount() { return arguments.size(); @@ -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 { 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 cf63114..0f52743 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 @@ -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(); } diff --git a/ownlang-parser/src/main/java/com/annimon/ownlang/parser/ast/Arguments.java b/ownlang-parser/src/main/java/com/annimon/ownlang/parser/ast/Arguments.java index e2cb0d5..7dc068f 100644 --- a/ownlang-parser/src/main/java/com/annimon/ownlang/parser/ast/Arguments.java +++ b/ownlang-parser/src/main/java/com/annimon/ownlang/parser/ast/Arguments.java @@ -1,19 +1,22 @@ 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 { +public final class Arguments implements Iterable, SourceLocation { private final List arguments; + private Range range; private int requiredArgumentsCount; public Arguments() { arguments = new ArrayList<>(); requiredArgumentsCount = 0; } - + public void addRequired(String name) { arguments.add(new Argument(name)); requiredArgumentsCount++; @@ -35,6 +38,15 @@ public final class Arguments implements Iterable { return arguments.size(); } + public void setRange(Range range) { + this.range = range; + } + + @Override + public Range getRange() { + return range; + } + @Override public Iterator iterator() { return arguments.iterator(); diff --git a/ownlang-parser/src/main/java/com/annimon/ownlang/parser/ast/FunctionDefineStatement.java b/ownlang-parser/src/main/java/com/annimon/ownlang/parser/ast/FunctionDefineStatement.java index 80e64c7..9664e1b 100644 --- a/ownlang-parser/src/main/java/com/annimon/ownlang/parser/ast/FunctionDefineStatement.java +++ b/ownlang-parser/src/main/java/com/annimon/ownlang/parser/ast/FunctionDefineStatement.java @@ -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 diff --git a/ownlang-parser/src/main/java/com/annimon/ownlang/parser/ast/ObjectCreationExpression.java b/ownlang-parser/src/main/java/com/annimon/ownlang/parser/ast/ObjectCreationExpression.java index 03476e1..5286327 100644 --- a/ownlang-parser/src/main/java/com/annimon/ownlang/parser/ast/ObjectCreationExpression.java +++ b/ownlang-parser/src/main/java/com/annimon/ownlang/parser/ast/ObjectCreationExpression.java @@ -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 diff --git a/ownlang-parser/src/main/java/com/annimon/ownlang/parser/optimization/OptimizationVisitor.java b/ownlang-parser/src/main/java/com/annimon/ownlang/parser/optimization/OptimizationVisitor.java index e3b28d8..1ba0d84 100644 --- a/ownlang-parser/src/main/java/com/annimon/ownlang/parser/optimization/OptimizationVisitor.java +++ b/ownlang-parser/src/main/java/com/annimon/ownlang/parser/optimization/OptimizationVisitor.java @@ -174,7 +174,7 @@ public abstract class OptimizationVisitor implements ResultVisitor { 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 implements ResultVisitor { 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 implements ResultVisitor { 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) { diff --git a/ownlang-parser/src/test/java/com/annimon/ownlang/parser/ProgramsTest.java b/ownlang-parser/src/test/java/com/annimon/ownlang/parser/ProgramsTest.java index 4bf86c4..951b50a 100644 --- a/ownlang-parser/src/test/java/com/annimon/ownlang/parser/ProgramsTest.java +++ b/ownlang-parser/src/test/java/com/annimon/ownlang/parser/ProgramsTest.java @@ -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); } }