mirror of
https://github.com/aNNiMON/Own-Programming-Language-Tutorial.git
synced 2024-09-20 08:44:20 +03:00
Возможность итерирования строк, массивов с индексом в for, и functional::foreach
This commit is contained in:
parent
2d93c8b9a7
commit
589fdbf0d5
@ -48,13 +48,13 @@ public final class Variables {
|
|||||||
scope.variables.put("false", NumberValue.ZERO);
|
scope.variables.put("false", NumberValue.ZERO);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void push() {
|
public static void push() {
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
scope = new Scope(scope);
|
scope = new Scope(scope);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pop() {
|
public static void pop() {
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
if (scope.parent != null) {
|
if (scope.parent != null) {
|
||||||
scope = scope.parent;
|
scope = scope.parent;
|
||||||
|
@ -1,36 +1,62 @@
|
|||||||
package com.annimon.ownlang.modules.functional;
|
package com.annimon.ownlang.modules.functional;
|
||||||
|
|
||||||
import com.annimon.ownlang.exceptions.TypeException;
|
import com.annimon.ownlang.exceptions.TypeException;
|
||||||
import com.annimon.ownlang.lib.Arguments;
|
import com.annimon.ownlang.lib.*;
|
||||||
import com.annimon.ownlang.lib.ArrayValue;
|
|
||||||
import com.annimon.ownlang.lib.Function;
|
|
||||||
import com.annimon.ownlang.lib.MapValue;
|
|
||||||
import com.annimon.ownlang.lib.Types;
|
|
||||||
import com.annimon.ownlang.lib.Value;
|
|
||||||
import com.annimon.ownlang.lib.ValueUtils;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public final class functional_foreach implements Function {
|
public final class functional_foreach implements Function {
|
||||||
|
|
||||||
|
private static final int UNKNOWN = -1;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Value execute(Value... args) {
|
public Value execute(Value... args) {
|
||||||
Arguments.check(2, args.length);
|
Arguments.check(2, args.length);
|
||||||
final Value container = args[0];
|
final Value container = args[0];
|
||||||
final Function consumer = ValueUtils.consumeFunction(args[1], 1);
|
final Function consumer = ValueUtils.consumeFunction(args[1], 1);
|
||||||
if (container.type() == Types.ARRAY) {
|
final int argsCount;
|
||||||
final ArrayValue array = (ArrayValue) container;
|
if (consumer instanceof UserDefinedFunction) {
|
||||||
for (Value element : array) {
|
argsCount = ((UserDefinedFunction) consumer).getArgsCount();
|
||||||
consumer.execute(element);
|
} else {
|
||||||
}
|
argsCount = UNKNOWN;
|
||||||
return array;
|
|
||||||
}
|
}
|
||||||
if (container.type() == Types.MAP) {
|
|
||||||
final MapValue map = (MapValue) container;
|
switch (container.type()) {
|
||||||
for (Map.Entry<Value, Value> element : map) {
|
case Types.STRING:
|
||||||
consumer.execute(element.getKey(), element.getValue());
|
final StringValue string = (StringValue) container;
|
||||||
}
|
if (argsCount == 2) {
|
||||||
return map;
|
for (char ch : string.asString().toCharArray()) {
|
||||||
|
consumer.execute(new StringValue(String.valueOf(ch)), NumberValue.of(ch));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (char ch : string.asString().toCharArray()) {
|
||||||
|
consumer.execute(new StringValue(String.valueOf(ch)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return string;
|
||||||
|
|
||||||
|
case Types.ARRAY:
|
||||||
|
final ArrayValue array = (ArrayValue) container;
|
||||||
|
if (argsCount == 2) {
|
||||||
|
int index = 0;
|
||||||
|
for (Value element : array) {
|
||||||
|
consumer.execute(element, NumberValue.of(index++));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (Value element : array) {
|
||||||
|
consumer.execute(element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return array;
|
||||||
|
|
||||||
|
case Types.MAP:
|
||||||
|
final MapValue map = (MapValue) container;
|
||||||
|
for (Map.Entry<Value, Value> element : map) {
|
||||||
|
consumer.execute(element.getKey(), element.getValue());
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new TypeException("Cannot iterate " + Types.typeToString(container.type()));
|
||||||
}
|
}
|
||||||
throw new TypeException("Invalid first argument. Array or map expected");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
package com.annimon.ownlang.parser.ast;
|
package com.annimon.ownlang.parser.ast;
|
||||||
|
|
||||||
import com.annimon.ownlang.lib.Value;
|
import com.annimon.ownlang.exceptions.TypeException;
|
||||||
import com.annimon.ownlang.lib.Variables;
|
import com.annimon.ownlang.lib.*;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@ -23,8 +24,45 @@ public final class ForeachArrayStatement extends InterruptableNode implements St
|
|||||||
public void execute() {
|
public void execute() {
|
||||||
super.interruptionCheck();
|
super.interruptionCheck();
|
||||||
final Value previousVariableValue = Variables.isExists(variable) ? Variables.get(variable) : null;
|
final Value previousVariableValue = Variables.isExists(variable) ? Variables.get(variable) : null;
|
||||||
final Iterable<Value> iterator = (Iterable<Value>) container.eval();
|
|
||||||
for (Value value : iterator) {
|
final Value containerValue = container.eval();
|
||||||
|
switch (containerValue.type()) {
|
||||||
|
case Types.STRING:
|
||||||
|
iterateString(containerValue.asString());
|
||||||
|
break;
|
||||||
|
case Types.ARRAY:
|
||||||
|
iterateArray((ArrayValue) containerValue);
|
||||||
|
break;
|
||||||
|
case Types.MAP:
|
||||||
|
iterateMap((MapValue) containerValue);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new TypeException("Cannot iterate " + Types.typeToString(containerValue.type()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore variables
|
||||||
|
if (previousVariableValue != null) {
|
||||||
|
Variables.set(variable, previousVariableValue);
|
||||||
|
} else {
|
||||||
|
Variables.remove(variable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void iterateString(String str) {
|
||||||
|
for (char ch : str.toCharArray()) {
|
||||||
|
Variables.set(variable, new StringValue(String.valueOf(ch)));
|
||||||
|
try {
|
||||||
|
body.execute();
|
||||||
|
} catch (BreakStatement bs) {
|
||||||
|
break;
|
||||||
|
} catch (ContinueStatement cs) {
|
||||||
|
// continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void iterateArray(ArrayValue containerValue) {
|
||||||
|
for (Value value : containerValue) {
|
||||||
Variables.set(variable, value);
|
Variables.set(variable, value);
|
||||||
try {
|
try {
|
||||||
body.execute();
|
body.execute();
|
||||||
@ -34,9 +72,21 @@ public final class ForeachArrayStatement extends InterruptableNode implements St
|
|||||||
// continue;
|
// continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Восстанавливаем переменную
|
}
|
||||||
if (previousVariableValue != null) {
|
|
||||||
Variables.set(variable, previousVariableValue);
|
private void iterateMap(MapValue containerValue) {
|
||||||
|
for (Map.Entry<Value, Value> entry : containerValue) {
|
||||||
|
Variables.set(variable, new ArrayValue(new Value[] {
|
||||||
|
entry.getKey(),
|
||||||
|
entry.getValue()
|
||||||
|
}));
|
||||||
|
try {
|
||||||
|
body.execute();
|
||||||
|
} catch (BreakStatement bs) {
|
||||||
|
break;
|
||||||
|
} catch (ContinueStatement cs) {
|
||||||
|
// continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package com.annimon.ownlang.parser.ast;
|
package com.annimon.ownlang.parser.ast;
|
||||||
|
|
||||||
import com.annimon.ownlang.lib.Value;
|
import com.annimon.ownlang.exceptions.TypeException;
|
||||||
import com.annimon.ownlang.lib.Variables;
|
import com.annimon.ownlang.lib.*;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -26,8 +26,66 @@ public final class ForeachMapStatement extends InterruptableNode implements Stat
|
|||||||
super.interruptionCheck();
|
super.interruptionCheck();
|
||||||
final Value previousVariableValue1 = Variables.isExists(key) ? Variables.get(key) : null;
|
final Value previousVariableValue1 = Variables.isExists(key) ? Variables.get(key) : null;
|
||||||
final Value previousVariableValue2 = Variables.isExists(value) ? Variables.get(value) : 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) {
|
final Value containerValue = container.eval();
|
||||||
|
switch (containerValue.type()) {
|
||||||
|
case Types.STRING:
|
||||||
|
iterateString(containerValue.asString());
|
||||||
|
break;
|
||||||
|
case Types.ARRAY:
|
||||||
|
iterateArray((ArrayValue) containerValue);
|
||||||
|
break;
|
||||||
|
case Types.MAP:
|
||||||
|
iterateMap((MapValue) containerValue);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new TypeException("Cannot iterate " + Types.typeToString(containerValue.type()) + " as key, value pair");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore variables
|
||||||
|
if (previousVariableValue1 != null) {
|
||||||
|
Variables.set(key, previousVariableValue1);
|
||||||
|
} else {
|
||||||
|
Variables.remove(key);
|
||||||
|
}
|
||||||
|
if (previousVariableValue2 != null) {
|
||||||
|
Variables.set(value, previousVariableValue2);
|
||||||
|
} else {
|
||||||
|
Variables.remove(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void iterateString(String str) {
|
||||||
|
for (char ch : str.toCharArray()) {
|
||||||
|
Variables.set(key, new StringValue(String.valueOf(ch)));
|
||||||
|
Variables.set(value, NumberValue.of(ch));
|
||||||
|
try {
|
||||||
|
body.execute();
|
||||||
|
} catch (BreakStatement bs) {
|
||||||
|
break;
|
||||||
|
} catch (ContinueStatement cs) {
|
||||||
|
// continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void iterateArray(ArrayValue containerValue) {
|
||||||
|
int index = 0;
|
||||||
|
for (Value v : containerValue) {
|
||||||
|
Variables.set(key, v);
|
||||||
|
Variables.set(value, NumberValue.of(index++));
|
||||||
|
try {
|
||||||
|
body.execute();
|
||||||
|
} catch (BreakStatement bs) {
|
||||||
|
break;
|
||||||
|
} catch (ContinueStatement cs) {
|
||||||
|
// continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void iterateMap(MapValue containerValue) {
|
||||||
|
for (Map.Entry<Value, Value> entry : containerValue) {
|
||||||
Variables.set(key, entry.getKey());
|
Variables.set(key, entry.getKey());
|
||||||
Variables.set(value, entry.getValue());
|
Variables.set(value, entry.getValue());
|
||||||
try {
|
try {
|
||||||
@ -38,13 +96,6 @@ public final class ForeachMapStatement extends InterruptableNode implements Stat
|
|||||||
// continue;
|
// continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Восстанавливаем переменные
|
|
||||||
if (previousVariableValue1 != null) {
|
|
||||||
Variables.set(key, previousVariableValue1);
|
|
||||||
}
|
|
||||||
if (previousVariableValue2 != null) {
|
|
||||||
Variables.set(value, previousVariableValue2);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
30
src/test/resources/expressions/foreachKeyValue.own
Normal file
30
src/test/resources/expressions/foreachKeyValue.own
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
def testArrayIterate() {
|
||||||
|
sum = 0
|
||||||
|
for v, i : [1, 2, 3] {
|
||||||
|
sum += v * i
|
||||||
|
}
|
||||||
|
assertEquals(1 * 0 + 2 * 1 + 3 * 2, sum)
|
||||||
|
}
|
||||||
|
|
||||||
|
def testMapIterate() {
|
||||||
|
map = {12: 1, 13: 2, 14: 3}
|
||||||
|
sumKey = 0
|
||||||
|
sumValue = 0
|
||||||
|
for key, value : map {
|
||||||
|
sumKey += key
|
||||||
|
sumValue += value
|
||||||
|
}
|
||||||
|
assertEquals(39, sumKey)
|
||||||
|
assertEquals(6, sumValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
def testStringIterate() {
|
||||||
|
str = ""
|
||||||
|
sum = 0
|
||||||
|
for s, code : "abcd" {
|
||||||
|
str += s.upper
|
||||||
|
sum += code
|
||||||
|
}
|
||||||
|
assertEquals("ABCD", str)
|
||||||
|
assertEquals(394/*97 + 98 + 99 + 100*/, sum)
|
||||||
|
}
|
41
src/test/resources/expressions/foreachValue.own
Normal file
41
src/test/resources/expressions/foreachValue.own
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
use "std"
|
||||||
|
|
||||||
|
def testArrayIterate() {
|
||||||
|
sum = 0
|
||||||
|
for v : [1, 2, 3] {
|
||||||
|
sum += v
|
||||||
|
}
|
||||||
|
assertEquals(6, sum)
|
||||||
|
}
|
||||||
|
|
||||||
|
def testMapIterate() {
|
||||||
|
map = {12: 1, 13: 2, 14: 3}
|
||||||
|
sumKey = 0
|
||||||
|
sumValue = 0
|
||||||
|
for pair : map {
|
||||||
|
extract(key, value) = pair
|
||||||
|
sumKey += key
|
||||||
|
sumValue += value
|
||||||
|
}
|
||||||
|
assertEquals(39, sumKey)
|
||||||
|
assertEquals(6, sumValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
def testStringIterate() {
|
||||||
|
sum = 0
|
||||||
|
for s : "abcd" {
|
||||||
|
sum += s.charAt(0)
|
||||||
|
}
|
||||||
|
assertEquals(394/*97 + 98 + 99 + 100*/, sum)
|
||||||
|
}
|
||||||
|
|
||||||
|
def testScope() {
|
||||||
|
v = 45
|
||||||
|
sum = 0
|
||||||
|
for v : [1, 2, 3] {
|
||||||
|
sum += v
|
||||||
|
}
|
||||||
|
assertEquals(6, sum)
|
||||||
|
assertEquals(45, v)
|
||||||
|
}
|
||||||
|
|
36
src/test/resources/modules/functional/foreach.own
Normal file
36
src/test/resources/modules/functional/foreach.own
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
use ["std", "functional"]
|
||||||
|
|
||||||
|
def testArrayForeach1Arg() {
|
||||||
|
sum = 0
|
||||||
|
foreach([1, 2, 3], def(v) {
|
||||||
|
sum += v
|
||||||
|
})
|
||||||
|
assertEquals(6, sum)
|
||||||
|
}
|
||||||
|
|
||||||
|
def testArrayForeach2Args() {
|
||||||
|
sum = 0
|
||||||
|
foreach([1, 2, 3], def(v, index) {
|
||||||
|
sum += v * index
|
||||||
|
})
|
||||||
|
assertEquals(1 * 0 + 2 * 1 + 3 * 2, sum)
|
||||||
|
}
|
||||||
|
|
||||||
|
def testStringForeach1Arg() {
|
||||||
|
sum = 0
|
||||||
|
foreach("abcd", def(s) {
|
||||||
|
sum += s.charAt(0)
|
||||||
|
})
|
||||||
|
assertEquals(394/*97 + 98 + 99 + 100*/, sum)
|
||||||
|
}
|
||||||
|
|
||||||
|
def testStringForeach2Args() {
|
||||||
|
str = ""
|
||||||
|
sum = 0
|
||||||
|
foreach("abcd", def(s, code) {
|
||||||
|
str += s.upper
|
||||||
|
sum += code
|
||||||
|
})
|
||||||
|
assertEquals("ABCD", str)
|
||||||
|
assertEquals(97 + 98 + 99 + 100, sum)
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user