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;
|
||||
|
||||
/**
|
||||
*
|
||||
* Represents array type.
|
||||
*
|
||||
* @author aNNiMON
|
||||
*/
|
||||
public final class ArrayValue implements Value, Iterable<Value> {
|
||||
public class ArrayValue implements Value, Iterable<Value> {
|
||||
|
||||
public static ArrayValue of(byte[] array) {
|
||||
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("arrayKeys", new std_arrayKeys());
|
||||
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