Skip to content

Commit cb07629

Browse files
committed
Аргументы функций по умолчанию
1 parent f5c19e0 commit cb07629

File tree

6 files changed

+144
-37
lines changed

6 files changed

+144
-37
lines changed

program.own

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,4 +211,10 @@ def arrayRecursive(arr) = match arr {
211211
case [head :: tail]: "[" + head + ", " + arrayRecursive(tail) + "]"
212212
case []: "[]"
213213
case last: "[" + last + ", []]"
214-
}
214+
}
215+
216+
def funcWithOptionalArgs(str, count = 5, prefix = "<", suffix = ">") = prefix + (str * count) + suffix
217+
218+
println funcWithOptionalArgs("*")
219+
println funcWithOptionalArgs("+", 2)
220+
println funcWithOptionalArgs("*", 10, "<!")
Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,56 @@
11
package com.annimon.ownlang.lib;
22

33
import com.annimon.ownlang.exceptions.ArgumentsMismatchException;
4+
import com.annimon.ownlang.parser.ast.Argument;
5+
import com.annimon.ownlang.parser.ast.Arguments;
46
import com.annimon.ownlang.parser.ast.ReturnStatement;
57
import com.annimon.ownlang.parser.ast.Statement;
6-
import java.util.List;
78

89
/**
910
*
1011
* @author aNNiMON
1112
*/
1213
public final class UserDefinedFunction implements Function {
1314

14-
private final List<String> argNames;
15+
private final Arguments arguments;
1516
private final Statement body;
1617

17-
public UserDefinedFunction(List<String> argNames, Statement body) {
18-
this.argNames = argNames;
18+
public UserDefinedFunction(Arguments arguments, Statement body) {
19+
this.arguments = arguments;
1920
this.body = body;
2021
}
2122

2223
public int getArgsCount() {
23-
return argNames.size();
24+
return arguments.size();
2425
}
2526

2627
public String getArgsName(int index) {
2728
if (index < 0 || index >= getArgsCount()) return "";
28-
return argNames.get(index);
29+
return arguments.get(index).getName();
2930
}
3031

3132
@Override
3233
public Value execute(Value... values) {
3334
final int size = values.length;
34-
if (size != getArgsCount()) throw new ArgumentsMismatchException("Arguments count mismatch");
35+
final int requiredArgsCount = arguments.getRequiredArgumentsCount();
36+
if (size < requiredArgsCount) {
37+
throw new ArgumentsMismatchException(String.format("Arguments count mismatch. %d < %d", size, requiredArgsCount));
38+
}
39+
final int totalArgsCount = getArgsCount();
40+
if (size > totalArgsCount) {
41+
throw new ArgumentsMismatchException(String.format("Arguments count mismatch. %d > %d", size, totalArgsCount));
42+
}
3543

3644
try {
3745
Variables.push();
3846
for (int i = 0; i < size; i++) {
3947
Variables.set(getArgsName(i), values[i]);
4048
}
49+
// Optional args if exists
50+
for (int i = size; i < totalArgsCount; i++) {
51+
final Argument arg = arguments.get(i);
52+
Variables.set(arg.getName(), arg.getValueExpr().eval());
53+
}
4154
body.execute();
4255
return NumberValue.ZERO;
4356
} catch (ReturnStatement rt) {
@@ -49,6 +62,6 @@ public Value execute(Value... values) {
4962

5063
@Override
5164
public String toString() {
52-
return String.format("function %s %s", argNames.toString(), body.toString());
65+
return String.format("function %s %s", arguments.toString(), body.toString());
5366
}
5467
}

src/com/annimon/ownlang/parser/Parser.java

Lines changed: 29 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -199,20 +199,38 @@ private ForeachMapStatement foreachMapStatement() {
199199
}
200200

201201
private FunctionDefineStatement functionDefine() {
202-
// def name(arg1, arg2) { ... } || def name(args) = expr
202+
// def name(arg1, arg2 = value) { ... } || def name(args) = expr
203203
final String name = consume(TokenType.WORD).getText();
204+
final Arguments arguments = arguments();
205+
final Statement body = statementBody();
206+
return new FunctionDefineStatement(name, arguments, body);
207+
}
208+
209+
private Arguments arguments() {
210+
// (arg1, arg2, arg3 = expr1, arg4 = expr2)
211+
final Arguments arguments = new Arguments();
212+
boolean startsOptionalArgs = false;
204213
consume(TokenType.LPAREN);
205-
final List<String> argNames = new ArrayList<>();
206214
while (!match(TokenType.RPAREN)) {
207-
argNames.add(consume(TokenType.WORD).getText());
215+
final String name = consume(TokenType.WORD).getText();
216+
if (match(TokenType.EQ)) {
217+
startsOptionalArgs = true;
218+
arguments.addOptional(name, variable());
219+
} else if (!startsOptionalArgs) {
220+
arguments.addRequired(name);
221+
} else {
222+
throw new ParseException("Required argument cannot be after optional");
223+
}
208224
match(TokenType.COMMA);
209225
}
210-
if (lookMatch(0, TokenType.EQ)) {
211-
match(TokenType.EQ);
212-
return new FunctionDefineStatement(name, argNames, new ReturnStatement(expression()));
226+
return arguments;
227+
}
228+
229+
private Statement statementBody() {
230+
if (match(TokenType.EQ)) {
231+
return new ReturnStatement(expression());
213232
}
214-
final Statement body = statementOrBlock();
215-
return new FunctionDefineStatement(name, argNames, body);
233+
return statementOrBlock();
216234
}
217235

218236
private FunctionalExpression function(Expression qualifiedNameExpr) {
@@ -534,20 +552,9 @@ private Expression primary() {
534552
return match();
535553
}
536554
if (match(TokenType.DEF)) {
537-
consume(TokenType.LPAREN);
538-
final List<String> argNames = new ArrayList<>();
539-
while (!match(TokenType.RPAREN)) {
540-
argNames.add(consume(TokenType.WORD).getText());
541-
match(TokenType.COMMA);
542-
}
543-
Statement statement;
544-
if (lookMatch(0, TokenType.EQ)) {
545-
match(TokenType.EQ);
546-
statement = new ReturnStatement(expression());
547-
} else {
548-
statement = statementOrBlock();
549-
}
550-
return new ValueExpression(new UserDefinedFunction(argNames, statement));
555+
final Arguments arguments = arguments();
556+
final Statement statement = statementBody();
557+
return new ValueExpression(new UserDefinedFunction(arguments, statement));
551558
}
552559
return variable();
553560
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package com.annimon.ownlang.parser.ast;
2+
3+
public final class Argument {
4+
5+
private final String name;
6+
private final Expression valueExpr;
7+
8+
public Argument(String name) {
9+
this(name, null);
10+
}
11+
12+
public Argument(String name, Expression valueExpr) {
13+
this.name = name;
14+
this.valueExpr = valueExpr;
15+
}
16+
17+
public String getName() {
18+
return name;
19+
}
20+
21+
public Expression getValueExpr() {
22+
return valueExpr;
23+
}
24+
25+
@Override
26+
public String toString() {
27+
return name + (valueExpr == null ? "" : " = " + valueExpr);
28+
}
29+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package com.annimon.ownlang.parser.ast;
2+
3+
import java.util.ArrayList;
4+
import java.util.Iterator;
5+
import java.util.List;
6+
7+
public final class Arguments implements Iterable<Argument> {
8+
9+
private final List<Argument> arguments;
10+
private int requiredArgumentsCount;
11+
12+
public Arguments() {
13+
arguments = new ArrayList<>();
14+
requiredArgumentsCount = 0;
15+
}
16+
17+
public void addRequired(String name) {
18+
arguments.add(new Argument(name));
19+
requiredArgumentsCount++;
20+
}
21+
22+
public void addOptional(String name, Expression expr) {
23+
arguments.add(new Argument(name, expr));
24+
}
25+
26+
public Argument get(int index) {
27+
return arguments.get(index);
28+
}
29+
30+
public int getRequiredArgumentsCount() {
31+
return requiredArgumentsCount;
32+
}
33+
34+
public int size() {
35+
return arguments.size();
36+
}
37+
38+
@Override
39+
public Iterator<Argument> iterator() {
40+
return arguments.iterator();
41+
}
42+
43+
@Override
44+
public String toString() {
45+
final StringBuilder result = new StringBuilder();
46+
result.append('(');
47+
for (Argument arg : arguments) {
48+
result.append(arg).append(", ");
49+
}
50+
result.append(')');
51+
return result.toString();
52+
}
53+
}

src/com/annimon/ownlang/parser/ast/FunctionDefineStatement.java

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import com.annimon.ownlang.lib.Functions;
44
import com.annimon.ownlang.lib.UserDefinedFunction;
5-
import java.util.List;
65

76
/**
87
*
@@ -11,18 +10,18 @@
1110
public final class FunctionDefineStatement implements Statement {
1211

1312
public final String name;
14-
public final List<String> argNames;
13+
public final Arguments arguments;
1514
public final Statement body;
1615

17-
public FunctionDefineStatement(String name, List<String> argNames, Statement body) {
16+
public FunctionDefineStatement(String name, Arguments arguments, Statement body) {
1817
this.name = name;
19-
this.argNames = argNames;
18+
this.arguments = arguments;
2019
this.body = body;
2120
}
2221

2322
@Override
2423
public void execute() {
25-
Functions.set(name, new UserDefinedFunction(argNames, body));
24+
Functions.set(name, new UserDefinedFunction(arguments, body));
2625
}
2726

2827
@Override
@@ -32,6 +31,6 @@ public void accept(Visitor visitor) {
3231

3332
@Override
3433
public String toString() {
35-
return String.format("def %s(%s) %s", name, argNames, body);
34+
return String.format("def %s%s %s", name, arguments, body);
3635
}
3736
}

0 commit comments

Comments
 (0)