1 /** 
2  * Copyright: Enalye
3  * License: Zlib
4  * Authors: Enalye
5  */
6 module grimoire.stdlib.range;
7 
8 import std.range;
9 import grimoire.assembly, grimoire.compiler, grimoire.runtime;
10 
11 package(grimoire.stdlib) void grLoadStdLibRange(GrLibrary library) {
12     library.addForeign("RangeIter", ["T"]);
13     GrType rangeIterIntType = grGetForeignType("RangeIter", [grInt]);
14     GrType rangeIterFloatType = grGetForeignType("RangeIter", [grFloat]);
15 
16     library.addPrimitive(&_range_next_i, "next", [rangeIterIntType], [
17             grBool, grInt
18             ]);
19     library.addPrimitive(&_range_i, "range", [grInt, grInt], [rangeIterIntType]);
20     library.addPrimitive(&_range_step_i, "range", [grInt, grInt, grInt], [
21             rangeIterIntType
22             ]);
23 
24     library.addPrimitive(&_range_next_f, "next", [rangeIterFloatType], [
25             grBool, grFloat
26             ]);
27     library.addPrimitive(&_range_f, "range", [grFloat, grFloat], [
28             rangeIterFloatType
29             ]);
30     library.addPrimitive(&_range_step_f, "range", [grFloat, grFloat, grFloat],
31             [rangeIterFloatType]);
32 }
33 
34 private final class RangeIter(T) {
35     T value, end, step;
36 }
37 
38 private void _range_next_i(GrCall call) {
39     RangeIter!GrInt iter = call.getForeign!(RangeIter!GrInt)(0);
40     if (!iter) {
41         call.raise("NullError");
42         return;
43     }
44     if ((iter.step < 0 && iter.value < iter.end) || (iter.step > 0 && iter.value > iter.end)) {
45         call.setBool(false);
46         call.setInt(0);
47         return;
48     }
49     call.setBool(true);
50     call.setInt(iter.value);
51     iter.value += iter.step;
52 }
53 
54 private void _range_i(GrCall call) {
55     RangeIter!GrInt iter = new RangeIter!GrInt;
56     iter.value = call.getInt(0);
57     iter.end = call.getInt(1);
58     iter.step = iter.value > iter.end ? -1 : 1;
59     call.setForeign(iter);
60 }
61 
62 private void _range_step_i(GrCall call) {
63     RangeIter!GrInt iter = new RangeIter!GrInt;
64     iter.value = call.getInt(0);
65     iter.end = call.getInt(1);
66     iter.step = call.getInt(2);
67     if ((iter.value > iter.end && iter.step > 0) || (iter.value < iter.end && iter.step < 0)) {
68         iter.step = -iter.step;
69     }
70     call.setForeign(iter);
71 }
72 
73 private void _range_next_f(GrCall call) {
74     RangeIter!GrFloat iter = call.getForeign!(RangeIter!GrFloat)(0);
75     if (!iter) {
76         call.raise("NullError");
77         return;
78     }
79     if ((iter.step < 0f && iter.value < iter.end) || (iter.step > 0f && iter.value > iter.end)) {
80         call.setBool(false);
81         call.setFloat(0f);
82         return;
83     }
84     call.setBool(true);
85     call.setFloat(iter.value);
86     iter.value += iter.step;
87 }
88 
89 private void _range_f(GrCall call) {
90     RangeIter!GrFloat iter = new RangeIter!GrFloat;
91     iter.value = call.getFloat(0);
92     iter.end = call.getFloat(1);
93     iter.step = iter.value > iter.end ? -1f : 1f;
94     call.setForeign(iter);
95 }
96 
97 private void _range_step_f(GrCall call) {
98     RangeIter!GrFloat iter = new RangeIter!GrFloat;
99     iter.value = call.getFloat(0);
100     iter.end = call.getFloat(1);
101     iter.step = call.getFloat(2);
102     if ((iter.value > iter.end && iter.step > 0f) || (iter.value < iter.end && iter.step < 0f)) {
103         iter.step = -iter.step;
104     }
105     call.setForeign(iter);
106 }