Аргументы функций по умолчанию

This commit is contained in:
Victor 2016-02-13 18:08:36 +02:00
parent f5c19e06d1
commit cb07629f06
6 changed files with 144 additions and 37 deletions

View File

@ -212,3 +212,9 @@ def arrayRecursive(arr) = match arr {
case []: "[]" case []: "[]"
case last: "[" + last + ", []]" case last: "[" + last + ", []]"
} }
def funcWithOptionalArgs(str, count = 5, prefix = "<", suffix = ">") = prefix + (str * count) + suffix
println funcWithOptionalArgs("*")
println funcWithOptionalArgs("+", 2)
println funcWithOptionalArgs("*", 10, "<!")

View File

@ -1,9 +1,10 @@
package com.annimon.ownlang.lib; package com.annimon.ownlang.lib;
import com.annimon.ownlang.exceptions.ArgumentsMismatchException; import com.annimon.ownlang.exceptions.ArgumentsMismatchException;
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.ReturnStatement;
import com.annimon.ownlang.parser.ast.Statement; import com.annimon.ownlang.parser.ast.Statement;
import java.util.List;
/** /**
* *
@ -11,33 +12,45 @@ import java.util.List;
*/ */
public final class UserDefinedFunction implements Function { public final class UserDefinedFunction implements Function {
private final List<String> argNames; private final Arguments arguments;
private final Statement body; private final Statement body;
public UserDefinedFunction(List<String> argNames, Statement body) { public UserDefinedFunction(Arguments arguments, Statement body) {
this.argNames = argNames; this.arguments = arguments;
this.body = body; this.body = body;
} }
public int getArgsCount() { public int getArgsCount() {
return argNames.size(); return arguments.size();
} }
public String getArgsName(int index) { public String getArgsName(int index) {
if (index < 0 || index >= getArgsCount()) return ""; if (index < 0 || index >= getArgsCount()) return "";
return argNames.get(index); return arguments.get(index).getName();
} }
@Override @Override
public Value execute(Value... values) { public Value execute(Value... values) {
final int size = values.length; final int size = values.length;
if (size != getArgsCount()) throw new ArgumentsMismatchException("Arguments count mismatch"); final int requiredArgsCount = arguments.getRequiredArgumentsCount();
if (size < requiredArgsCount) {
throw new ArgumentsMismatchException(String.format("Arguments count mismatch. %d < %d", size, requiredArgsCount));
}
final int totalArgsCount = getArgsCount();
if (size > totalArgsCount) {
throw new ArgumentsMismatchException(String.format("Arguments count mismatch. %d > %d", size, totalArgsCount));
}
try { try {
Variables.push(); Variables.push();
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
Variables.set(getArgsName(i), values[i]); Variables.set(getArgsName(i), values[i]);
} }
// Optional args if exists
for (int i = size; i < totalArgsCount; i++) {
final Argument arg = arguments.get(i);
Variables.set(arg.getName(), arg.getValueExpr().eval());
}
body.execute(); body.execute();
return NumberValue.ZERO; return NumberValue.ZERO;
} catch (ReturnStatement rt) { } catch (ReturnStatement rt) {
@ -49,6 +62,6 @@ public final class UserDefinedFunction implements Function {
@Override @Override
public String toString() { public String toString() {
return String.format("function %s %s", argNames.toString(), body.toString()); return String.format("function %s %s", arguments.toString(), body.toString());
} }
} }

View File

@ -199,20 +199,38 @@ public final class Parser {
} }
private FunctionDefineStatement functionDefine() { private FunctionDefineStatement functionDefine() {
// def name(arg1, arg2) { ... } || def name(args) = expr // def name(arg1, arg2 = value) { ... } || def name(args) = expr
final String name = consume(TokenType.WORD).getText(); final String name = consume(TokenType.WORD).getText();
final Arguments arguments = arguments();
final Statement body = statementBody();
return new FunctionDefineStatement(name, arguments, body);
}
private Arguments arguments() {
// (arg1, arg2, arg3 = expr1, arg4 = expr2)
final Arguments arguments = new Arguments();
boolean startsOptionalArgs = false;
consume(TokenType.LPAREN); consume(TokenType.LPAREN);
final List<String> argNames = new ArrayList<>();
while (!match(TokenType.RPAREN)) { while (!match(TokenType.RPAREN)) {
argNames.add(consume(TokenType.WORD).getText()); final String name = consume(TokenType.WORD).getText();
if (match(TokenType.EQ)) {
startsOptionalArgs = true;
arguments.addOptional(name, variable());
} else if (!startsOptionalArgs) {
arguments.addRequired(name);
} else {
throw new ParseException("Required argument cannot be after optional");
}
match(TokenType.COMMA); match(TokenType.COMMA);
} }
if (lookMatch(0, TokenType.EQ)) { return arguments;
match(TokenType.EQ); }
return new FunctionDefineStatement(name, argNames, new ReturnStatement(expression()));
private Statement statementBody() {
if (match(TokenType.EQ)) {
return new ReturnStatement(expression());
} }
final Statement body = statementOrBlock(); return statementOrBlock();
return new FunctionDefineStatement(name, argNames, body);
} }
private FunctionalExpression function(Expression qualifiedNameExpr) { private FunctionalExpression function(Expression qualifiedNameExpr) {
@ -534,20 +552,9 @@ public final class Parser {
return match(); return match();
} }
if (match(TokenType.DEF)) { if (match(TokenType.DEF)) {
consume(TokenType.LPAREN); final Arguments arguments = arguments();
final List<String> argNames = new ArrayList<>(); final Statement statement = statementBody();
while (!match(TokenType.RPAREN)) { return new ValueExpression(new UserDefinedFunction(arguments, statement));
argNames.add(consume(TokenType.WORD).getText());
match(TokenType.COMMA);
}
Statement statement;
if (lookMatch(0, TokenType.EQ)) {
match(TokenType.EQ);
statement = new ReturnStatement(expression());
} else {
statement = statementOrBlock();
}
return new ValueExpression(new UserDefinedFunction(argNames, statement));
} }
return variable(); return variable();
} }

View File

@ -0,0 +1,29 @@
package com.annimon.ownlang.parser.ast;
public final class Argument {
private final String name;
private final Expression valueExpr;
public Argument(String name) {
this(name, null);
}
public Argument(String name, Expression valueExpr) {
this.name = name;
this.valueExpr = valueExpr;
}
public String getName() {
return name;
}
public Expression getValueExpr() {
return valueExpr;
}
@Override
public String toString() {
return name + (valueExpr == null ? "" : " = " + valueExpr);
}
}

View File

@ -0,0 +1,53 @@
package com.annimon.ownlang.parser.ast;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public final class Arguments implements Iterable<Argument> {
private final List<Argument> arguments;
private int requiredArgumentsCount;
public Arguments() {
arguments = new ArrayList<>();
requiredArgumentsCount = 0;
}
public void addRequired(String name) {
arguments.add(new Argument(name));
requiredArgumentsCount++;
}
public void addOptional(String name, Expression expr) {
arguments.add(new Argument(name, expr));
}
public Argument get(int index) {
return arguments.get(index);
}
public int getRequiredArgumentsCount() {
return requiredArgumentsCount;
}
public int size() {
return arguments.size();
}
@Override
public Iterator<Argument> iterator() {
return arguments.iterator();
}
@Override
public String toString() {
final StringBuilder result = new StringBuilder();
result.append('(');
for (Argument arg : arguments) {
result.append(arg).append(", ");
}
result.append(')');
return result.toString();
}
}

View File

@ -2,7 +2,6 @@ package com.annimon.ownlang.parser.ast;
import com.annimon.ownlang.lib.Functions; import com.annimon.ownlang.lib.Functions;
import com.annimon.ownlang.lib.UserDefinedFunction; import com.annimon.ownlang.lib.UserDefinedFunction;
import java.util.List;
/** /**
* *
@ -11,18 +10,18 @@ import java.util.List;
public final class FunctionDefineStatement implements Statement { public final class FunctionDefineStatement implements Statement {
public final String name; public final String name;
public final List<String> argNames; public final Arguments arguments;
public final Statement body; public final Statement body;
public FunctionDefineStatement(String name, List<String> argNames, Statement body) { public FunctionDefineStatement(String name, Arguments arguments, Statement body) {
this.name = name; this.name = name;
this.argNames = argNames; this.arguments = arguments;
this.body = body; this.body = body;
} }
@Override @Override
public void execute() { public void execute() {
Functions.set(name, new UserDefinedFunction(argNames, body)); Functions.set(name, new UserDefinedFunction(arguments, body));
} }
@Override @Override
@ -32,6 +31,6 @@ public final class FunctionDefineStatement implements Statement {
@Override @Override
public String toString() { public String toString() {
return String.format("def %s(%s) %s", name, argNames, body); return String.format("def %s%s %s", name, arguments, body);
} }
} }