mirror of
https://github.com/aNNiMON/Own-Programming-Language-Tutorial.git
synced 2024-09-20 00:34:20 +03:00
Source located function, class and arguments
This commit is contained in:
parent
2bb5e45517
commit
d3dd8feb10
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user