Skip to content

Commit

Permalink
Merge pull request #1267 from arturo-lang/sanitize-chop-and-drop
Browse files Browse the repository at this point in the history
[Collections] Sanitize `chop` & `drop`
  • Loading branch information
drkameleon authored Aug 10, 2023
2 parents e10cf78 + 29fcea7 commit 80cbbbb
Show file tree
Hide file tree
Showing 10 changed files with 127 additions and 82 deletions.
2 changes: 1 addition & 1 deletion examples/rosetta/forward difference.art
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ vsub: function [u v][
differences: function [block][
order: attr "order"
if order = null -> order: 1
loop 1..order 'n -> block: vsub block drop block 1
loop 1..order 'n -> block: vsub block drop block
return block
]

Expand Down
2 changes: 1 addition & 1 deletion examples/rosetta/iccanobif primes.art
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
summarize: function [n :string][
;; description: « returns a summary of a numeric string
s: size n
if s > 20 -> n: ((take n 10)++"...")++drop n s-10
if s > 20 -> n: ((take n 10)++"...")++drop.times:s-10 n
n ++ ~" (|s| digits)"
]

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

primes: select range.step:2 3 1e6 => prime?

pair: couple primes drop primes 1
pair: couple primes drop primes
| maximum'p -> p\1 - p\0
| <=

Expand Down
2 changes: 1 addition & 1 deletion examples/rosetta/quaternion type.art
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ qnorm: $ => [sqrt fold & [x y] -> x + y*y]

qneg: $ => [map & => neg]

qconj: $[q] [@[q\0] ++ qneg drop q 1]
qconj: $[q] [@[q\0] ++ qneg drop q]

qaddr: function [q r][
[a b c d]: q
Expand Down
4 changes: 2 additions & 2 deletions examples/rosetta/substring - top and tail.art
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ knight: "knight"
socks: "socks"
brooms: "brooms"

print drop knight 1 ; strip first character
print drop knight ; strip first character
print slice knight 1 (size knight)-1 ; alternate way to strip first character

print chop socks ; strip last character
print take socks (size socks)-1 ; alternate way to strip last character
print slice socks 0 (size socks)-2 ; yet another way to strip last character

print chop drop brooms 1 ; strip both first and last characters
print chop drop brooms ; strip both first and last characters
print slice brooms 1 (size brooms)-2 ; alternate way to strip both first and last characters
2 changes: 1 addition & 1 deletion examples/rosetta/the name game.art
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
nameGame: function [Name][
L: take Name 1
name: lower Name
unless in? L "AEIOU" -> drop 'name 1
unless in? L "AEIOU" -> drop 'name
[B F M]: ["b" "f" "m"]

if L="B" -> B: ""
Expand Down
2 changes: 1 addition & 1 deletion examples/rosetta/wagstaff primes.art
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ wagstaff?: function [e][
summarize: function [n][
n: ~"|n|"
s: size n
if s > 20 -> n: ((take n 10)++"...")++drop n s-10
if s > 20 -> n: ((take n 10)++"...")++drop.times:s-10 n
n ++ ~" (|s| digits)"
]

Expand Down
111 changes: 78 additions & 33 deletions src/library/Collections.nim
Original file line number Diff line number Diff line change
Expand Up @@ -137,35 +137,65 @@ proc defineSymbols*() =
},
returns = {String, Block, Nothing},
example = """
print chop "books" ; book
print chop chop "books" ; boo
chop "hellox" ; => "hello"
chop chop "hellox" ; => "hell"
..........
str: "books"
chop 'str ; str: "book"
str: "some text"
chop.times:5 str ; => some
chop.times: neg 5 str ; => text
..........
arr: @1..10
chop.times:3 'arr
arr ; => [1 2 3 4 5 6 7]
..........
chop [1 2 3] ; => [1 2]
..........
chop [1 2 3 4] ; => [1 2 3]
chop.times:1 [1 2 3] ; => [1 2]
chop.times:2 [1 2 3] ; => [1]
chop.times:3 [1 2 3] ; => []
chop.times:4 [1 2 3] ; => []
..........
chop.times: 3 "Arturo" ; Art
chop.times: neg 1 [1 2 3] ; => [2 3]
chop.times: neg 2 [1 2 3] ; => [3]
""":
#=======================================================
var times = 1
var times = -1

if checkAttr("times"):
times = aTimes.i

if xKind == Literal:
times = -aTimes.i

template numberInRange(container: untyped): untyped =
container.len >= abs(times)

template drop(container: untyped): untyped =
if 0 < times:
container[times..^1]
else:
container[0.. container.high - abs(times)]

if x.kind == Literal:
ensureInPlace()
if InPlaced.kind == String:
InPlaced.s = InPlaced.s[0..^(times + 1)]
elif InPlaced.kind == Block:
if InPlaced.a.len > 0:
InPlaced.a = InPlaced.a[0..^(times + 1)]
case InPlaced.kind
of String:
if numberInRange(InPlaced.s):
InPlaced.s = InPlaced.s.drop()
else:
InPlaced.s = ""
of Block:
if numberInRange(InPlaced.a):
InPlaced.a = InPlaced.a.drop()
else:
InPlaced.a = newSeq[Value](0)
else: discard
else:
if xKind == String:
push(newString(x.s[0..^(times + 1)]))
elif xKind == Block:
if x.a.len == 0: push(newBlock())
else: push(newBlock(x.a[0..^(times + 1)]))
case x.kind
of String:
if numberInRange(x.s): push(newString(x.s.drop()))
else: push(newString(""))
of Block:
if numberInRange(x.a): push(newBlock(x.a.drop()))
else: push(newBlock())
else: discard


# TODO(Collections/combine) should also work with in-place Literals?
Expand Down Expand Up @@ -372,35 +402,50 @@ proc defineSymbols*() =
alias = unaliased,
op = opNop,
rule = PrefixPrecedence,
description = "drop first *number* of elements from given collection and return the remaining ones",
description = "remove first item from given collection",
args = {
"collection": {String, Block, Literal},
"number" : {Integer}
"collection": {String, Block, Literal}
},
attrs = {
"times" : ({Integer}, "remove multiple items")
},
attrs = NoAttrs,
returns = {String, Block, Nothing},
example = """
drop "xhello" ; => "hello"
drop drop "xhello" ; => "ello"
..........
str: "some text"
drop str 5 ; => text
drop str neg 5 ; => some
drop.times:5 str ; => text
drop.times: neg 5 str ; => some
..........
arr: @1..10
drop 'arr 3
drop.times:3 'arr
arr ; => [4 5 6 7 8 9 10]
..........
drop [1 2 3] 3 ; => []
drop [1 2 3] 4 ; => []
drop [1 2 3] ; => [2 3]
..........
drop.times:1 [1 2 3] ; => [2 3]
drop.times:2 [1 2 3] ; => [3]
drop.times:3 [1 2 3] ; => []
drop.times:4 [1 2 3] ; => []
..........
drop.times: neg 1 [1 2 3] ; => [1 2]
drop.times: neg 2 [1 2 3] ; => [1]
""":
#=======================================================
var times = 1

if checkAttr("times"):
times = aTimes.i

template numberInRange(container: untyped): untyped =
container.len >= abs(y.i)
container.len >= abs(times)

template drop(container: untyped): untyped =
if 0 < y.i:
container[y.i..^1]
if 0 < times:
container[times..^1]
else:
container[0.. container.high - abs(y.i)]
container[0.. container.high - abs(times)]

if x.kind == Literal:
ensureInPlace()
Expand Down
80 changes: 40 additions & 40 deletions tests/unittests/lib.collections.art
Original file line number Diff line number Diff line change
Expand Up @@ -481,62 +481,62 @@ do [
topic "drop - :string < :string :string"
do [

ensure -> "art" = drop "art" 0
ensure -> "art" = drop.times:0 "art"
passed

ensure -> "rt" = drop "art" 1
ensure -> "t" = drop "art" 2
ensure -> "rt" = drop "art"
ensure -> "t" = drop.times:2 "art"
passed

ensure -> "" = drop "art" 3
ensure -> "" = drop "art" 4
ensure -> "" = drop.times:3 "art"
ensure -> "" = drop.times:4 "art"
passed

ensure -> "art" = drop "art" neg 0
ensure -> "art" = drop.times: neg 0 "art"
passed

ensure -> "ar" = drop "art" neg 1
ensure -> "a" = drop "art" neg 2
ensure -> "ar" = drop.times: neg 1 "art"
ensure -> "a" = drop.times: neg 2 "art"
passed

ensure -> "" = drop "art" neg 3
ensure -> "" = drop "art" neg 4
ensure -> "" = drop.times: neg 3 "art"
ensure -> "" = drop.times: neg 4 "art"
passed

]

topic "drop - :string < :string (literal) :string"
do [

a: "art", drop 'a 0
a: "art", drop.times:0 'a
ensure -> "art" = a
passed

a: "art", drop 'a 1
a: "art", drop 'a
ensure -> "rt" = a
a: "art", drop 'a 2
a: "art", drop.times:2 'a
ensure -> "t" = a
passed

a: "art", drop 'a 3
a: "art", drop.times:3 'a
ensure -> "" = a
a: "art", drop 'a 4
a: "art", drop.times:4 'a
ensure -> "" = a
passed

a: "art", drop 'a neg 0
a: "art", drop.times: neg 0 'a
ensure -> "art" = a
passed

a: "art", drop 'a neg 1
a: "art", drop.times: neg 1 'a
ensure -> "ar" = a
a: "art", drop 'a neg 2
a: "art", drop.times: neg 2 'a
ensure -> "a" = a
passed

a: "art", drop 'a neg 3
a: "art", drop.times: neg 3 'a
ensure -> "" = a
a: "art", drop 'a neg 4
a: "art", drop.times: neg 4 'a
ensure -> "" = a
passed

Expand All @@ -545,62 +545,62 @@ do [
topic "drop - :block < :block :block"
do [

ensure -> [a b c] = drop [a b c] 0
ensure -> [a b c] = drop.times:0 [a b c]
passed

ensure -> [b c] = drop [a b c] 1
ensure -> [c] = drop [a b c] 2
ensure -> [b c] = drop [a b c]
ensure -> [c] = drop.times:2 [a b c]
passed

ensure -> [] = drop [a b c] 3
ensure -> [] = drop [a b c] 4
ensure -> [] = drop.times:3 [a b c]
ensure -> [] = drop.times:4 [a b c]
passed

ensure -> [a b c] = drop [a b c] neg 0
ensure -> [a b c] = drop.times: neg 0 [a b c]
passed

ensure -> [a b] = drop [a b c] neg 1
ensure -> [a] = drop [a b c] neg 2
ensure -> [a b] = drop.times: neg 1 [a b c]
ensure -> [a] = drop.times: neg 2 [a b c]
passed

ensure -> [] = drop [a b c] neg 3
ensure -> [] = drop [a b c] neg 4
ensure -> [] = drop.times: neg 3 [a b c]
ensure -> [] = drop.times: neg 4 [a b c]
passed

]

topic "drop - :block < :block (literal) :block"
do [

a: [a b c], drop 'a 0
a: [a b c], drop.times:0 'a
ensure -> [a b c] = a
passed

a: [a b c], drop 'a 1
a: [a b c], drop 'a
ensure -> [b c] = a
a: [a b c], drop 'a 2
a: [a b c], drop.times:2 'a
ensure -> [c] = a
passed

a: [a b c], drop 'a 3
a: [a b c], drop.times:3 'a
ensure -> [] = a
a: [a b c], drop 'a 4
a: [a b c], drop.times:4 'a
ensure -> [] = a
passed

a: [a b c], drop 'a neg 0
a: [a b c], drop.times: neg 0 'a
ensure -> [a b c] = a
passed

a: [a b c], drop 'a neg 1
a: [a b c], drop.times: neg 1 'a
ensure -> [a b] = a
a: [a b c], drop 'a neg 2
a: [a b c], drop.times: neg 2 'a
ensure -> [a] = a
passed

a: [a b c], drop 'a neg 3
a: [a b c], drop.times: neg 3 'a
ensure -> [] = a
a: [a b c], drop 'a neg 4
a: [a b c], drop.times: neg 4 'a
ensure -> [] = a
passed

Expand Down
2 changes: 1 addition & 1 deletion version/build
Original file line number Diff line number Diff line change
@@ -1 +1 @@
975
980

0 comments on commit 80cbbbb

Please sign in to comment.