Skip to content

Commit 3065270

Browse files
dmuir-gsparkprime
authored andcommitted
Rework de-sugaring such that native stdlib functions override jsonnet implementations.
1 parent 6a7b086 commit 3065270

11 files changed

+125
-32
lines changed

core/desugarer.cpp

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ limitations under the License.
1616

1717
#include <cassert>
1818

19+
#include <algorithm>
20+
1921
#include "ast.h"
2022
#include "desugarer.h"
2123
#include "lexer.h"
@@ -919,9 +921,17 @@ class Desugarer {
919921
Identifiers params;
920922
for (const auto &p : decl.params)
921923
params.push_back(id(p));
922-
fields.emplace_back(ObjectField::HIDDEN,
923-
str(decl.name),
924-
make<BuiltinFunction>(E, encode_utf8(decl.name), params));
924+
auto name = str(decl.name);
925+
auto fn = make<BuiltinFunction>(E, encode_utf8(decl.name), params);
926+
auto field = std::find_if(fields.begin(), fields.end(),
927+
[=](const DesugaredObject::Field& f) {
928+
return static_cast<LiteralString*>(f.name)->value == decl.name;
929+
});
930+
if (field != fields.end()) {
931+
field->body = fn;
932+
} else {
933+
fields.emplace_back(ObjectField::HIDDEN, name, fn);
934+
}
925935
}
926936
fields.emplace_back(
927937
ObjectField::HIDDEN, str(U"thisFile"), str(decode_utf8(ast->location.file)));

stdlib/std.jsonnet

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,18 @@ limitations under the License.
3535
toString(a)::
3636
if std.type(a) == 'string' then a else '' + a,
3737

38+
substr(str, from, len)::
39+
if std.type(str) != 'string' then
40+
error 'substr first parameter should be a string, got ' + std.type(str)
41+
else if std.type(from) != 'number' then
42+
error 'substr second parameter should be a number, got ' + std.type(from)
43+
else if std.type(len) != 'number' then
44+
error 'substr third parameter should be a number, got ' + std.type(len)
45+
else if len < 0 then
46+
error 'substr third parameter should be greater than zero, got ' + len
47+
else
48+
std.join('', std.makeArray(len, function(i) str[i + from])),
49+
3850
startsWith(a, b)::
3951
if std.length(a) < std.length(b) then
4052
false
@@ -96,6 +108,77 @@ limitations under the License.
96108
else
97109
std.splitLimit(str, c, -1),
98110

111+
splitLimit(str, c, maxsplits)::
112+
if std.type(str) != 'string' then
113+
error 'std.splitLimit first parameter should be a string, got ' + std.type(str)
114+
else if std.type(c) != 'string' then
115+
error 'std.splitLimit second parameter should be a string, got ' + std.type(c)
116+
else if std.length(c) != 1 then
117+
error 'std.splitLimit second parameter should have length 1, got ' + std.length(c)
118+
else if std.type(maxsplits) != 'number' then
119+
error 'std.splitLimit third parameter should be a number, got ' + std.type(maxsplits)
120+
else
121+
local aux(str, delim, i, arr, v) =
122+
local c = str[i];
123+
local i2 = i + 1;
124+
if i >= std.length(str) then
125+
arr + [v]
126+
else if c == delim && (maxsplits == -1 || std.length(arr) < maxsplits) then
127+
aux(str, delim, i2, arr + [v], '') tailstrict
128+
else
129+
aux(str, delim, i2, arr, v + c) tailstrict;
130+
aux(str, c, 0, [], ''),
131+
132+
strReplace(str, from, to)::
133+
assert std.type(str) == 'string';
134+
assert std.type(from) == 'string';
135+
assert std.type(to) == 'string';
136+
assert from != '' : "'from' string must not be zero length.";
137+
138+
// Cache for performance.
139+
local str_len = std.length(str);
140+
local from_len = std.length(from);
141+
142+
// True if from is at str[i].
143+
local found_at(i) = str[i:i + from_len] == from;
144+
145+
// Return the remainder of 'str' starting with 'start_index' where
146+
// all occurrences of 'from' after 'curr_index' are replaced with 'to'.
147+
local replace_after(start_index, curr_index, acc) =
148+
if curr_index > str_len then
149+
acc + str[start_index:curr_index]
150+
else if found_at(curr_index) then
151+
local new_index = curr_index + std.length(from);
152+
replace_after(new_index, new_index, acc + str[start_index:curr_index] + to) tailstrict
153+
else
154+
replace_after(start_index, curr_index + 1, acc) tailstrict;
155+
156+
// if from_len==1, then we replace by splitting and rejoining the
157+
// string which is much faster than recursing on replace_after
158+
if from_len == 1 then
159+
std.join(to, std.split(str, from))
160+
else
161+
replace_after(0, 0, ''),
162+
163+
asciiUpper(x)::
164+
local cp = std.codepoint;
165+
local up_letter(c) = if cp(c) >= 97 && cp(c) < 123 then
166+
std.char(cp(c) - 32)
167+
else
168+
c;
169+
std.join('', std.map(up_letter, std.stringChars(x))),
170+
171+
asciiLower(x)::
172+
local cp = std.codepoint;
173+
local down_letter(c) = if cp(c) >= 65 && cp(c) < 91 then
174+
std.char(cp(c) + 32)
175+
else
176+
c;
177+
std.join('', std.map(down_letter, std.stringChars(x))),
178+
179+
180+
range(from, to)::
181+
std.makeArray(to - from + 1, function(i) i + from),
99182

100183
slice(indexable, index, end, step)::
101184
local invar =
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
RUNTIME ERROR: cannot test equality of functions
2-
std.jsonnet:1140:9-34 function <anonymous>
2+
std.jsonnet:1223:9-34 function <anonymous>
33
error.equality_function.jsonnet:17:1-33
Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
RUNTIME ERROR: foobar
22
error.inside_equals_array.jsonnet:18:18-32 thunk <array_element>
3-
std.jsonnet:1120:29-33 thunk <b>
4-
std.jsonnet:1120:21-33 function <anonymous>
5-
std.jsonnet:1120:21-33 function <aux>
6-
std.jsonnet:1123:15-31 function <anonymous>
7-
std.jsonnet:1124:11-23
3+
std.jsonnet:1203:29-33 thunk <b>
4+
std.jsonnet:1203:21-33 function <anonymous>
5+
std.jsonnet:1203:21-33 function <aux>
6+
std.jsonnet:1206:15-31 function <anonymous>
7+
std.jsonnet:1207:11-23
Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
RUNTIME ERROR: foobar
22
error.inside_equals_object.jsonnet:18:22-36 object <b>
3-
std.jsonnet:1134:50-54 thunk <b>
4-
std.jsonnet:1134:42-54 function <anonymous>
5-
std.jsonnet:1134:42-54 function <aux>
6-
std.jsonnet:1137:15-31 function <anonymous>
7-
std.jsonnet:1138:11-23
3+
std.jsonnet:1217:50-54 thunk <b>
4+
std.jsonnet:1217:42-54 function <anonymous>
5+
std.jsonnet:1217:42-54 function <aux>
6+
std.jsonnet:1220:15-31 function <anonymous>
7+
std.jsonnet:1221:11-23
Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
RUNTIME ERROR: Object assertion failed.
22
error.invariant.equality.jsonnet:17:10-15 thunk <object_assert>
3-
std.jsonnet:1134:42-46 thunk <a>
4-
std.jsonnet:1134:42-54 function <anonymous>
5-
std.jsonnet:1134:42-54 function <anonymous>
6-
std.jsonnet:1138:11-23
3+
std.jsonnet:1217:42-46 thunk <a>
4+
std.jsonnet:1217:42-54 function <anonymous>
5+
std.jsonnet:1217:42-54 function <anonymous>
6+
std.jsonnet:1221:11-23
Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
RUNTIME ERROR: Object assertion failed.
22
error.obj_assert.fail1.jsonnet:20:23-29 thunk <object_assert>
3-
std.jsonnet:1134:42-46 thunk <a>
4-
std.jsonnet:1134:42-54 function <anonymous>
5-
std.jsonnet:1134:42-54 function <anonymous>
6-
std.jsonnet:1138:11-23
3+
std.jsonnet:1217:42-46 thunk <a>
4+
std.jsonnet:1217:42-54 function <anonymous>
5+
std.jsonnet:1217:42-54 function <anonymous>
6+
std.jsonnet:1221:11-23
Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
RUNTIME ERROR: foo was not equal to bar
22
error.obj_assert.fail2.jsonnet:20:32-65 thunk <object_assert>
3-
std.jsonnet:1134:42-46 thunk <a>
4-
std.jsonnet:1134:42-54 function <anonymous>
5-
std.jsonnet:1134:42-54 function <anonymous>
6-
std.jsonnet:1138:11-23
3+
std.jsonnet:1217:42-46 thunk <a>
4+
std.jsonnet:1217:42-54 function <anonymous>
5+
std.jsonnet:1217:42-54 function <anonymous>
6+
std.jsonnet:1221:11-23
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
RUNTIME ERROR: Assertion failed. 1 != 2
2-
std.jsonnet:699:7-50 function <anonymous>
2+
std.jsonnet:782:7-50 function <anonymous>
33
error.sanity.jsonnet:17:1-22
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
RUNTIME ERROR: expected string but arr[1] was array
2-
std.jsonnet:179:9-87 function <aux>
3-
std.jsonnet:181:9-49 function <aux>
4-
std.jsonnet:187:7-28 function <anonymous>
2+
std.jsonnet:262:9-87 function <aux>
3+
std.jsonnet:264:9-49 function <aux>
4+
std.jsonnet:270:7-28 function <anonymous>
55
error.std_join_types1.jsonnet:17:1-26

0 commit comments

Comments
 (0)