Добавлен foreach

This commit is contained in:
Victor 2016-01-09 13:13:04 +02:00
parent fa2295ad18
commit a17bef18c5
6 changed files with 168 additions and 2 deletions

View File

@ -101,3 +101,13 @@ print arr1
print "\n"
print arr1 << arr2
for op, func : map {
echo (4, op, 5, "=", func(4,5))
}
for v : arr1 print "" + v + ", "
print "\n"
for (v : arr1 << arr2) print "" + v + ", "
print "\n"
for v : [1,2,3,4,5,6,7,8,9] print "" + v + ", "

View File

@ -124,17 +124,50 @@ public final class Parser {
}
private Statement forStatement() {
match(TokenType.LPAREN); // необязательные скобки
int foreachIndex = lookMatch(0, TokenType.LPAREN) ? 1 : 0;
if (lookMatch(foreachIndex, TokenType.WORD) && lookMatch(foreachIndex + 1, TokenType.COLON)) {
// for v : arr || for (v : arr)
return foreachArrayStatement();
}
if (lookMatch(foreachIndex, TokenType.WORD) && lookMatch(foreachIndex + 1, TokenType.COMMA)
&& lookMatch(foreachIndex + 2, TokenType.WORD) && lookMatch(foreachIndex + 3, TokenType.COLON)) {
// for key, value : arr || for (key, value : arr)
return foreachMapStatement();
}
boolean openParen = match(TokenType.LPAREN); // необязательные скобки
final Statement initialization = assignmentStatement();
consume(TokenType.COMMA);
final Expression termination = expression();
consume(TokenType.COMMA);
final Statement increment = assignmentStatement();
match(TokenType.RPAREN); // необязательные скобки
if (openParen) consume(TokenType.RPAREN); // скобки
final Statement statement = statementOrBlock();
return new ForStatement(initialization, termination, increment, statement);
}
private ForeachArrayStatement foreachArrayStatement() {
boolean openParen = match(TokenType.LPAREN); // необязательные скобки
final String variable = consume(TokenType.WORD).getText();
consume(TokenType.COLON);
final Expression container = expression();
if (openParen) consume(TokenType.RPAREN); // скобки
final Statement statement = statementOrBlock();
return new ForeachArrayStatement(variable, container, statement);
}
private ForeachMapStatement foreachMapStatement() {
boolean openParen = match(TokenType.LPAREN); // необязательные скобки
final String key = consume(TokenType.WORD).getText();
consume(TokenType.COMMA);
final String value = consume(TokenType.WORD).getText();
consume(TokenType.COLON);
final Expression container = expression();
if (openParen) consume(TokenType.RPAREN); // скобки
final Statement statement = statementOrBlock();
return new ForeachMapStatement(key, value, container, statement);
}
private FunctionDefineStatement functionDefine() {
final String name = consume(TokenType.WORD).getText();
consume(TokenType.LPAREN);

View File

@ -0,0 +1,51 @@
package com.annimon.ownlang.parser.ast;
import com.annimon.ownlang.lib.Value;
import com.annimon.ownlang.lib.Variables;
/**
*
* @author aNNiMON
*/
public final class ForeachArrayStatement implements Statement {
public final String variable;
public final Expression container;
public final Statement body;
public ForeachArrayStatement(String variable, Expression container, Statement body) {
this.variable = variable;
this.container = container;
this.body = body;
}
@Override
public void execute() {
final Value previousVariableValue = Variables.isExists(variable) ? Variables.get(variable) : null;
final Iterable<Value> iterator = (Iterable<Value>) container.eval();
for (Value value : iterator) {
Variables.set(variable, value);
try {
body.execute();
} catch (BreakStatement bs) {
break;
} catch (ContinueStatement cs) {
// continue;
}
}
// Восстанавливаем переменную
if (previousVariableValue != null) {
Variables.set(variable, previousVariableValue);
}
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
@Override
public String toString() {
return String.format("for %s : %s %s", variable, container, body);
}
}

View File

@ -0,0 +1,58 @@
package com.annimon.ownlang.parser.ast;
import com.annimon.ownlang.lib.Value;
import com.annimon.ownlang.lib.Variables;
import java.util.Map;
/**
*
* @author aNNiMON
*/
public final class ForeachMapStatement implements Statement {
public final String key, value;
public final Expression container;
public final Statement body;
public ForeachMapStatement(String key, String value, Expression container, Statement body) {
this.key = key;
this.value = value;
this.container = container;
this.body = body;
}
@Override
public void execute() {
final Value previousVariableValue1 = Variables.isExists(key) ? Variables.get(key) : null;
final Value previousVariableValue2 = Variables.isExists(value) ? Variables.get(value) : null;
final Iterable<Map.Entry<Value, Value>> iterator = (Iterable<Map.Entry<Value, Value>>) container.eval();
for (Map.Entry<Value, Value> entry : iterator) {
Variables.set(key, entry.getKey());
Variables.set(value, entry.getValue());
try {
body.execute();
} catch (BreakStatement bs) {
break;
} catch (ContinueStatement cs) {
// continue;
}
}
// Восстанавливаем переменные
if (previousVariableValue1 != null) {
Variables.set(key, previousVariableValue1);
}
if (previousVariableValue2 != null) {
Variables.set(value, previousVariableValue2);
}
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
@Override
public String toString() {
return String.format("for %s, %s : %s %s", key, value, container, body);
}
}

View File

@ -17,6 +17,8 @@ public interface Visitor {
void visit(ContinueStatement s);
void visit(DoWhileStatement s);
void visit(ForStatement s);
void visit(ForeachArrayStatement s);
void visit(ForeachMapStatement s);
void visit(FunctionDefineStatement s);
void visit(FunctionReferenceExpression e);
void visit(FunctionStatement s);

View File

@ -76,6 +76,18 @@ public abstract class AbstractVisitor implements Visitor {
s.statement.accept(this);
}
@Override
public void visit(ForeachArrayStatement s) {
s.container.accept(this);
s.body.accept(this);
}
@Override
public void visit(ForeachMapStatement s) {
s.container.accept(this);
s.body.accept(this);
}
@Override
public void visit(FunctionDefineStatement s) {
s.body.accept(this);