mirror of
https://github.com/aNNiMON/Own-Programming-Language-Tutorial.git
synced 2024-09-20 00:34:20 +03:00
Аргументы функций по умолчанию
This commit is contained in:
parent
f5c19e06d1
commit
cb07629f06
@ -211,4 +211,10 @@ def arrayRecursive(arr) = match arr {
|
|||||||
case [head :: tail]: "[" + head + ", " + arrayRecursive(tail) + "]"
|
case [head :: tail]: "[" + head + ", " + arrayRecursive(tail) + "]"
|
||||||
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, "<!")
|
@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
29
src/com/annimon/ownlang/parser/ast/Argument.java
Normal file
29
src/com/annimon/ownlang/parser/ast/Argument.java
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
53
src/com/annimon/ownlang/parser/ast/Arguments.java
Normal file
53
src/com/annimon/ownlang/parser/ast/Arguments.java
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user