Skip to content

Commit 6a28d24

Browse files
committed
Add native dot methods for arrays and hashes
New array methods: .contains(v), .index(v), .reverse(), .compact() New hash method: .clone() Fix: .keys() now returns keys in sorted order
1 parent e4fc06c commit 6a28d24

File tree

3 files changed

+204
-0
lines changed

3 files changed

+204
-0
lines changed

compiler/templates/runtime_core_post.go.tmpl

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,46 @@ func rugo_array_method(arr []interface{}, method string, args ...interface{}) (i
382382
result = append(result, interface{}(ch))
383383
}
384384
return interface{}(result), true
385+
386+
case "contains":
387+
if len(args) < 1 {
388+
panic(".contains() requires an argument")
389+
}
390+
target := args[0]
391+
for _, v := range arr {
392+
if reflect.DeepEqual(v, target) {
393+
return true, true
394+
}
395+
}
396+
return false, true
397+
398+
case "index":
399+
if len(args) < 1 {
400+
panic(".index() requires an argument")
401+
}
402+
target := args[0]
403+
for i, v := range arr {
404+
if reflect.DeepEqual(v, target) {
405+
return i, true
406+
}
407+
}
408+
return -1, true
409+
410+
case "reverse":
411+
result := make([]interface{}, len(arr))
412+
for i, v := range arr {
413+
result[len(arr)-1-i] = v
414+
}
415+
return interface{}(result), true
416+
417+
case "compact":
418+
result := make([]interface{}, 0, len(arr))
419+
for i, v := range arr {
420+
if i == 0 || !reflect.DeepEqual(v, arr[i-1]) {
421+
result = append(result, v)
422+
}
423+
}
424+
return interface{}(result), true
385425
}
386426
return nil, false
387427
}
@@ -478,6 +518,9 @@ func rugo_hash_method(m map[interface{}]interface{}, method string, args ...inte
478518
for k := range m {
479519
result = append(result, k)
480520
}
521+
sort.Slice(result, func(i, j int) bool {
522+
return rugo_compare(result[i], result[j]) < 0
523+
})
481524
return interface{}(result), true
482525

483526
case "values":
@@ -500,6 +543,13 @@ func rugo_hash_method(m map[interface{}]interface{}, method string, args ...inte
500543
result[k] = v
501544
}
502545
return interface{}(result), true
546+
547+
case "clone":
548+
result := make(map[interface{}]interface{}, len(m))
549+
for k, v := range m {
550+
result[k] = v
551+
}
552+
return interface{}(result), true
503553
}
504554
return nil, false
505555
}

rats/core/82_array_methods_test.rugo

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,3 +287,117 @@ rats "array map then reduce chain"
287287
result = [1, 2, 3].map(fn(x) x * x end).reduce(0, fn(acc, x) acc + x end)
288288
test.assert_eq(result, 14)
289289
end
290+
291+
# ============================================================
292+
# S. contains
293+
# ============================================================
294+
295+
rats "array.contains returns true when value is present"
296+
test.assert_true([1, 2, 3].contains(2))
297+
end
298+
299+
rats "array.contains returns false when value is absent"
300+
test.assert_false([1, 2, 3].contains(99))
301+
end
302+
303+
rats "array.contains works with strings"
304+
test.assert_true(["a", "b", "c"].contains("b"))
305+
test.assert_false(["a", "b", "c"].contains("z"))
306+
end
307+
308+
rats "array.contains on empty array returns false"
309+
test.assert_false([].contains(1))
310+
end
311+
312+
rats "array.contains uses deep equality"
313+
test.assert_true([[1, 2], [3, 4]].contains([3, 4]))
314+
test.assert_false([[1, 2], [3, 4]].contains([5, 6]))
315+
end
316+
317+
# ============================================================
318+
# T. index
319+
# ============================================================
320+
321+
rats "array.index returns index of first occurrence"
322+
test.assert_eq([10, 20, 30, 20].index(20), 1)
323+
end
324+
325+
rats "array.index returns -1 when not found"
326+
test.assert_eq([1, 2, 3].index(99), -1)
327+
end
328+
329+
rats "array.index on empty array returns -1"
330+
test.assert_eq([].index(1), -1)
331+
end
332+
333+
rats "array.index works with strings"
334+
test.assert_eq(["a", "b", "c"].index("c"), 2)
335+
end
336+
337+
rats "array.index uses deep equality"
338+
test.assert_eq([[1], [2], [3]].index([2]), 1)
339+
end
340+
341+
# ============================================================
342+
# U. reverse
343+
# ============================================================
344+
345+
rats "array.reverse returns new reversed array"
346+
result = [1, 2, 3].reverse()
347+
test.assert_eq(result[0], 3)
348+
test.assert_eq(result[1], 2)
349+
test.assert_eq(result[2], 1)
350+
end
351+
352+
rats "array.reverse on empty array returns empty"
353+
test.assert_eq(len([].reverse()), 0)
354+
end
355+
356+
rats "array.reverse does not mutate original"
357+
arr = [1, 2, 3]
358+
rev = arr.reverse()
359+
test.assert_eq(arr[0], 1)
360+
test.assert_eq(rev[0], 3)
361+
end
362+
363+
rats "array.reverse on single element"
364+
result = [42].reverse()
365+
test.assert_eq(len(result), 1)
366+
test.assert_eq(result[0], 42)
367+
end
368+
369+
# ============================================================
370+
# V. compact
371+
# ============================================================
372+
373+
rats "array.compact removes consecutive duplicates"
374+
result = [1, 1, 2, 2, 2, 3, 1, 1].compact()
375+
test.assert_eq(len(result), 4)
376+
test.assert_eq(result[0], 1)
377+
test.assert_eq(result[1], 2)
378+
test.assert_eq(result[2], 3)
379+
test.assert_eq(result[3], 1)
380+
end
381+
382+
rats "array.compact on empty array returns empty"
383+
test.assert_eq(len([].compact()), 0)
384+
end
385+
386+
rats "array.compact with no consecutive duplicates"
387+
result = [1, 2, 3].compact()
388+
test.assert_eq(len(result), 3)
389+
end
390+
391+
rats "array.compact on single element"
392+
result = [42].compact()
393+
test.assert_eq(len(result), 1)
394+
test.assert_eq(result[0], 42)
395+
end
396+
397+
rats "array.compact works with strings"
398+
result = ["a", "a", "b", "b", "a"].compact()
399+
test.assert_eq(len(result), 3)
400+
test.assert_eq(result[0], "a")
401+
test.assert_eq(result[1], "b")
402+
test.assert_eq(result[2], "a")
403+
end

rats/core/83_hash_methods_test.rugo

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,3 +175,43 @@ rats "built-in method takes priority over hash key"
175175
test.assert_eq(type_of(result), "Array")
176176
test.assert_eq(len(result), 2)
177177
end
178+
179+
# ============================================================
180+
# M. keys returns sorted keys
181+
# ============================================================
182+
183+
rats "hash.keys returns sorted keys"
184+
h = {c: 3, a: 1, b: 2}
185+
keys = h.keys()
186+
test.assert_eq(keys[0], "a")
187+
test.assert_eq(keys[1], "b")
188+
test.assert_eq(keys[2], "c")
189+
end
190+
191+
# ============================================================
192+
# N. clone
193+
# ============================================================
194+
195+
rats "hash.clone returns a shallow copy"
196+
h = {a: 1, b: 2, c: 3}
197+
copy = h.clone()
198+
test.assert_eq(len(copy), 3)
199+
test.assert_eq(copy["a"], 1)
200+
test.assert_eq(copy["b"], 2)
201+
test.assert_eq(copy["c"], 3)
202+
end
203+
204+
rats "hash.clone does not mutate original"
205+
h = {x: 10}
206+
copy = h.clone()
207+
copy["y"] = 20
208+
test.assert_eq(len(h), 1)
209+
test.assert_eq(len(copy), 2)
210+
end
211+
212+
rats "hash.clone of empty hash"
213+
h = {}
214+
copy = h.clone()
215+
test.assert_eq(len(copy), 0)
216+
test.assert_eq(type_of(copy), "Hash")
217+
end

0 commit comments

Comments
 (0)