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;
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,21 +5,30 @@ 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
|
||||||
public int getArgsCount() {
|
public int getArgsCount() {
|
||||||
return arguments.size();
|
return arguments.size();
|
||||||
@ -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 {
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
@ -1,19 +1,22 @@
|
|||||||
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() {
|
||||||
arguments = new ArrayList<>();
|
arguments = new ArrayList<>();
|
||||||
requiredArgumentsCount = 0;
|
requiredArgumentsCount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addRequired(String name) {
|
public void addRequired(String name) {
|
||||||
arguments.add(new Argument(name));
|
arguments.add(new Argument(name));
|
||||||
requiredArgumentsCount++;
|
requiredArgumentsCount++;
|
||||||
@ -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();
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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) {
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user