mirror of
https://github.com/aNNiMON/Own-Programming-Language-Tutorial.git
synced 2024-09-20 08:44:20 +03:00
Добавлена функция std::range
This commit is contained in:
parent
66bf40bfbc
commit
6156c507d8
@ -6,10 +6,11 @@ import java.util.Iterator;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* Represents array type.
|
||||||
|
*
|
||||||
* @author aNNiMON
|
* @author aNNiMON
|
||||||
*/
|
*/
|
||||||
public final class ArrayValue implements Value, Iterable<Value> {
|
public class ArrayValue implements Value, Iterable<Value> {
|
||||||
|
|
||||||
public static ArrayValue of(byte[] array) {
|
public static ArrayValue of(byte[] array) {
|
||||||
final int size = array.length;
|
final int size = array.length;
|
||||||
|
218
src/com/annimon/ownlang/lib/modules/functions/std_range.java
Normal file
218
src/com/annimon/ownlang/lib/modules/functions/std_range.java
Normal file
@ -0,0 +1,218 @@
|
|||||||
|
package com.annimon.ownlang.lib.modules.functions;
|
||||||
|
|
||||||
|
import com.annimon.ownlang.lib.*;
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
public final class std_range implements Function {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Value execute(Value... args) {
|
||||||
|
Arguments.checkRange(1, 3, args.length);
|
||||||
|
|
||||||
|
final long from, to, step;
|
||||||
|
switch (args.length) {
|
||||||
|
default:
|
||||||
|
case 1:
|
||||||
|
from = 0;
|
||||||
|
to = getLong(args[0]);
|
||||||
|
step = 1;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
from = getLong(args[0]);
|
||||||
|
to = getLong(args[1]);
|
||||||
|
step = 1;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
from = getLong(args[0]);
|
||||||
|
to = getLong(args[1]);
|
||||||
|
step = getLong(args[2]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return RangeValue.of(from, to, step);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static long getLong(Value v) {
|
||||||
|
if (v.type() == Types.NUMBER) {
|
||||||
|
return ((NumberValue) v).asLong();
|
||||||
|
}
|
||||||
|
return v.asInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class RangeValue extends ArrayValue {
|
||||||
|
|
||||||
|
public static ArrayValue of(long from, long to, long step) {
|
||||||
|
boolean isInvalid = false;
|
||||||
|
isInvalid = isInvalid || (step == 0);
|
||||||
|
isInvalid = isInvalid || ((step > 0) && (from >= to));
|
||||||
|
isInvalid = isInvalid || ((step < 0) && (to >= from));
|
||||||
|
if (isInvalid) return new ArrayValue(0);
|
||||||
|
return new RangeValue(from, to, step);
|
||||||
|
}
|
||||||
|
|
||||||
|
private final long from, to, step;
|
||||||
|
private final int size;
|
||||||
|
|
||||||
|
public RangeValue(long from, long to, long step) {
|
||||||
|
super(new Value[0]);
|
||||||
|
this.from = from;
|
||||||
|
this.to = to;
|
||||||
|
this.step = step;
|
||||||
|
// x = range(0, 10, 2)
|
||||||
|
// 0, 2, 4, 6, 8 | 0..10 step 2
|
||||||
|
// 0, 3, 6, 9 | 0..10 step 3
|
||||||
|
// 0, 4, 8 | 0..10 step 4
|
||||||
|
final long base = (from < to) ? (to - from) : (from - to);
|
||||||
|
final long absStep = (step < 0) ? -step : step;
|
||||||
|
this.size = (int) (base / absStep + (base % absStep == 0 ? 0 : 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Value[] getCopyElements() {
|
||||||
|
final Value[] result = new Value[size];
|
||||||
|
int i = 0;
|
||||||
|
if (isIntegerRange()) {
|
||||||
|
final int toInt = (int) to;
|
||||||
|
final int stepInt = (int) step;
|
||||||
|
for (int value = (int) from; value < toInt; value += stepInt) {
|
||||||
|
result[i++] = NumberValue.of(value);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (long value = from; value < to; value += step) {
|
||||||
|
result[i++] = NumberValue.of(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isIntegerRange() {
|
||||||
|
if (to > 0) {
|
||||||
|
return (to < Integer.MAX_VALUE) && (from > Integer.MIN_VALUE && to < Integer.MAX_VALUE);
|
||||||
|
}
|
||||||
|
return (to > Integer.MIN_VALUE) && (to > Integer.MIN_VALUE && from < Integer.MAX_VALUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int size() {
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Value get(int index) {
|
||||||
|
if (isIntegerRange()) {
|
||||||
|
return NumberValue.of((int) (from + index * step));
|
||||||
|
}
|
||||||
|
return NumberValue.of(from + (long) index * step);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void set(int index, Value value) {
|
||||||
|
// not implemented
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object raw() {
|
||||||
|
return getCopyElements();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String asString() {
|
||||||
|
if (size == 0) return "[]";
|
||||||
|
|
||||||
|
final StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append('[').append(from);
|
||||||
|
for (long value = from + step; value < to; value += step) {
|
||||||
|
sb.append(", ").append(value);
|
||||||
|
}
|
||||||
|
sb.append(']');
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iterator<Value> iterator() {
|
||||||
|
if (isIntegerRange()) {
|
||||||
|
final int toInt = (int) to;
|
||||||
|
final int stepInt = (int) step;
|
||||||
|
return new Iterator<Value>() {
|
||||||
|
|
||||||
|
int value = (int) from;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasNext() {
|
||||||
|
return value < toInt;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Value next() {
|
||||||
|
final int result = value;
|
||||||
|
value += stepInt;
|
||||||
|
return NumberValue.of(result);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return new Iterator<Value>() {
|
||||||
|
|
||||||
|
long value = from;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasNext() {
|
||||||
|
return value < to;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Value next() {
|
||||||
|
final long result = value;
|
||||||
|
value += step;
|
||||||
|
return NumberValue.of(result);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
int hash = 5;
|
||||||
|
hash = 59 * hash + (int) (this.from ^ (this.from >>> 32));
|
||||||
|
hash = 59 * hash + (int) (this.to ^ (this.to >>> 32));
|
||||||
|
hash = 59 * hash + (int) (this.step ^ (this.step >>> 32));
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj) return true;
|
||||||
|
if (obj == null) return false;
|
||||||
|
if (getClass() != obj.getClass())
|
||||||
|
return false;
|
||||||
|
final RangeValue other = (RangeValue) obj;
|
||||||
|
if (this.from != other.from) return false;
|
||||||
|
if (this.to != other.to) return false;
|
||||||
|
if (this.step != other.step) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(Value o) {
|
||||||
|
if (o.type() == Types.ARRAY) {
|
||||||
|
final int lengthCompare = Integer.compare(size(), ((ArrayValue) o).size());
|
||||||
|
if (lengthCompare != 0) return lengthCompare;
|
||||||
|
|
||||||
|
if (o instanceof RangeValue) {
|
||||||
|
final RangeValue o2 = ((RangeValue) o);
|
||||||
|
int compareResult;
|
||||||
|
compareResult = Long.compare(this.from, o2.from);
|
||||||
|
if (compareResult != 0) return compareResult;
|
||||||
|
compareResult = Long.compare(this.to, o2.to);
|
||||||
|
if (compareResult != 0) return compareResult;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return asString().compareTo(o.asString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
if (step == 1) {
|
||||||
|
return String.format("range(%d, %d)", from, to);
|
||||||
|
}
|
||||||
|
return String.format("range(%d, %d, %d)", from, to, step);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -47,5 +47,6 @@ public final class std implements Module {
|
|||||||
Functions.set("arrayKeyExists", new std_arrayKeyExists());
|
Functions.set("arrayKeyExists", new std_arrayKeyExists());
|
||||||
Functions.set("arrayKeys", new std_arrayKeys());
|
Functions.set("arrayKeys", new std_arrayKeys());
|
||||||
Functions.set("arrayValues", new std_arrayValues());
|
Functions.set("arrayValues", new std_arrayValues());
|
||||||
|
Functions.set("range", new std_range());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
94
test/resources/modules/std/range.own
Normal file
94
test/resources/modules/std/range.own
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
use "std"
|
||||||
|
use "types"
|
||||||
|
use "functional"
|
||||||
|
|
||||||
|
def testRangeParams() {
|
||||||
|
x = range(10)
|
||||||
|
assertEquals(10, length(x))
|
||||||
|
assertEquals(0, x[0])
|
||||||
|
assertEquals(9, x[9])
|
||||||
|
}
|
||||||
|
|
||||||
|
def testRangeParamsFromTo() {
|
||||||
|
x = range(4, 10)
|
||||||
|
assertEquals(6, length(x))
|
||||||
|
assertEquals(4, x[0])
|
||||||
|
assertEquals(9, x[5])
|
||||||
|
}
|
||||||
|
|
||||||
|
def testRangeParamsWithStep() {
|
||||||
|
x = range(4, 10, 2)
|
||||||
|
assertEquals(3, length(x))
|
||||||
|
assertEquals(4, x[0])
|
||||||
|
assertEquals(8, x[2])
|
||||||
|
}
|
||||||
|
|
||||||
|
def testRangeParamsReversed() {
|
||||||
|
x = range(10, 4, -1)
|
||||||
|
assertEquals(6, length(x))
|
||||||
|
assertEquals(10, x[0])
|
||||||
|
assertEquals(5, x[5])
|
||||||
|
}
|
||||||
|
|
||||||
|
def testRangeLength() {
|
||||||
|
assertEquals(10, length(range(0, 10, 1)))
|
||||||
|
assertEquals(5, length(range(0, 10, 2)))
|
||||||
|
assertEquals(4, length(range(0, 10, 3)))
|
||||||
|
assertEquals(3, length(range(0, 10, 4)))
|
||||||
|
assertEquals(2, length(range(0, 10, 5)))
|
||||||
|
assertEquals(1, length(range(0, 10, 15)))
|
||||||
|
}
|
||||||
|
|
||||||
|
def testRangeReversedLength() {
|
||||||
|
assertEquals(10, length(range(10, 0, -1)))
|
||||||
|
assertEquals(5, length(range(10, 0, -2)))
|
||||||
|
assertEquals(4, length(range(10, 0, -3)))
|
||||||
|
assertEquals(3, length(range(10, 0, -4)))
|
||||||
|
assertEquals(2, length(range(10, 0, -5)))
|
||||||
|
assertEquals(1, length(range(10, 0, -15)))
|
||||||
|
}
|
||||||
|
|
||||||
|
def testRangeHuge() {
|
||||||
|
x = range(-1002003004005006007, 1002003004005006007)
|
||||||
|
assertEquals(-1002003004005006000, x[7])
|
||||||
|
|
||||||
|
x = range(-1002003004005006007, 1002003004005006007, 100000000000)
|
||||||
|
assertEquals(20040061, length(x))
|
||||||
|
|
||||||
|
x = range(-10000000, 20000000)
|
||||||
|
assertEquals(30000000, length(x))
|
||||||
|
assertEquals(0, x[10000000])
|
||||||
|
}
|
||||||
|
|
||||||
|
def testRangeAsString() {
|
||||||
|
x = range(1, 6)
|
||||||
|
assertEquals("[1, 2, 3, 4, 5]", string(x))
|
||||||
|
|
||||||
|
x = range(1, 6, 2)
|
||||||
|
assertEquals("[1, 3, 5]", string(x))
|
||||||
|
assertEquals(string([1,3,5]), string(x))
|
||||||
|
}
|
||||||
|
|
||||||
|
def testRangeIterate() {
|
||||||
|
sum = 0
|
||||||
|
for x : range(5) {
|
||||||
|
sum += x
|
||||||
|
}
|
||||||
|
assertEquals(10, sum)
|
||||||
|
}
|
||||||
|
|
||||||
|
def testRangeFunctionalForeach() {
|
||||||
|
i = 0
|
||||||
|
foreach(range(5), def(x) = assertEquals(i++, x))
|
||||||
|
}
|
||||||
|
|
||||||
|
def testRangeFunctionalReduce() {
|
||||||
|
sum = reduce(range(5), 0, def(x, y) = x + y)
|
||||||
|
assertEquals(10, sum)
|
||||||
|
}
|
||||||
|
|
||||||
|
def testRangeInvalid() {
|
||||||
|
assertEquals(0, length(range(-100)))
|
||||||
|
assertEquals(0, length(range(0, -100, 1)))
|
||||||
|
assertEquals(0, length(range(0, 100, 0)))
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user