2015-11-21 18:01:12 +00:00
|
|
|
# Some useful helpers for dealing with text (arrays of characters)
|
2015-04-17 18:22:59 +00:00
|
|
|
|
2016-09-17 17:30:24 +00:00
|
|
|
def equal a:text, b:text -> result:bool [
|
2015-07-14 05:43:16 +00:00
|
|
|
local-scope
|
2015-11-19 05:36:36 +00:00
|
|
|
load-ingredients
|
2016-11-23 22:01:07 +00:00
|
|
|
an:num, bn:num <- copy a, b
|
|
|
|
address-equal?:boolean <- equal an, bn
|
2017-03-12 08:08:41 +00:00
|
|
|
return-if address-equal?, 1/true
|
|
|
|
return-unless a, 0/false
|
|
|
|
return-unless b, 0/false
|
2016-09-17 17:28:25 +00:00
|
|
|
a-len:num <- length *a
|
|
|
|
b-len:num <- length *b
|
2015-04-03 19:53:33 +00:00
|
|
|
# compare lengths
|
2017-09-24 01:31:26 +00:00
|
|
|
trace 99, [text-equal], [comparing lengths]
|
|
|
|
length-equal?:bool <- equal a-len, b-len
|
|
|
|
return-unless length-equal?, 0/false
|
2015-04-03 19:53:33 +00:00
|
|
|
# compare each corresponding character
|
2015-11-21 18:01:12 +00:00
|
|
|
trace 99, [text-equal], [comparing characters]
|
2016-09-17 17:28:25 +00:00
|
|
|
i:num <- copy 0
|
2015-04-03 19:53:33 +00:00
|
|
|
{
|
2016-09-17 17:30:24 +00:00
|
|
|
done?:bool <- greater-or-equal i, a-len
|
2015-07-29 21:37:57 +00:00
|
|
|
break-if done?
|
2016-09-17 07:31:55 +00:00
|
|
|
a2:char <- index *a, i
|
|
|
|
b2:char <- index *b, i
|
2017-09-24 01:31:26 +00:00
|
|
|
chars-match?:bool <- equal a2, b2
|
|
|
|
return-unless chars-match?, 0/false
|
2015-07-29 21:37:57 +00:00
|
|
|
i <- add i, 1
|
2015-04-03 19:53:33 +00:00
|
|
|
loop
|
|
|
|
}
|
2017-09-24 03:39:19 +00:00
|
|
|
return 1/true
|
2015-04-03 19:53:33 +00:00
|
|
|
]
|
2015-04-06 19:02:38 +00:00
|
|
|
|
2015-11-21 18:01:12 +00:00
|
|
|
scenario text-equal-reflexive [
|
2016-09-29 02:48:56 +00:00
|
|
|
local-scope
|
|
|
|
x:text <- new [abc]
|
2015-04-06 19:02:38 +00:00
|
|
|
run [
|
2016-09-17 17:30:24 +00:00
|
|
|
10:bool/raw <- equal x, x
|
2015-04-06 19:02:38 +00:00
|
|
|
]
|
2015-05-02 22:52:22 +00:00
|
|
|
memory-should-contain [
|
2016-05-26 17:24:47 +00:00
|
|
|
10 <- 1 # x == x for all x
|
2015-04-06 19:02:38 +00:00
|
|
|
]
|
|
|
|
]
|
|
|
|
|
2015-11-21 18:01:12 +00:00
|
|
|
scenario text-equal-identical [
|
2016-09-29 02:48:56 +00:00
|
|
|
local-scope
|
|
|
|
x:text <- new [abc]
|
|
|
|
y:text <- new [abc]
|
2015-04-06 19:02:38 +00:00
|
|
|
run [
|
2016-09-17 17:30:24 +00:00
|
|
|
10:bool/raw <- equal x, y
|
2015-04-06 19:02:38 +00:00
|
|
|
]
|
2015-05-02 22:52:22 +00:00
|
|
|
memory-should-contain [
|
2016-05-26 17:24:47 +00:00
|
|
|
10 <- 1 # abc == abc
|
2015-04-06 19:02:38 +00:00
|
|
|
]
|
|
|
|
]
|
|
|
|
|
2015-11-21 18:01:12 +00:00
|
|
|
scenario text-equal-distinct-lengths [
|
2016-09-29 02:48:56 +00:00
|
|
|
local-scope
|
|
|
|
x:text <- new [abc]
|
|
|
|
y:text <- new [abcd]
|
2015-04-06 19:02:38 +00:00
|
|
|
run [
|
2016-09-17 17:30:24 +00:00
|
|
|
10:bool/raw <- equal x, y
|
2015-04-06 19:02:38 +00:00
|
|
|
]
|
2015-05-02 22:52:22 +00:00
|
|
|
memory-should-contain [
|
2016-05-26 17:24:47 +00:00
|
|
|
10 <- 0 # abc != abcd
|
2015-04-08 07:47:04 +00:00
|
|
|
]
|
2015-05-02 22:52:22 +00:00
|
|
|
trace-should-contain [
|
2015-11-21 18:01:12 +00:00
|
|
|
text-equal: comparing lengths
|
2015-04-13 17:09:46 +00:00
|
|
|
]
|
2015-05-02 22:52:22 +00:00
|
|
|
trace-should-not-contain [
|
2015-11-21 18:01:12 +00:00
|
|
|
text-equal: comparing characters
|
2015-04-13 17:09:46 +00:00
|
|
|
]
|
2015-04-08 07:47:04 +00:00
|
|
|
]
|
|
|
|
|
2015-11-21 18:01:12 +00:00
|
|
|
scenario text-equal-with-empty [
|
2016-09-29 02:48:56 +00:00
|
|
|
local-scope
|
|
|
|
x:text <- new []
|
|
|
|
y:text <- new [abcd]
|
2015-04-08 07:47:04 +00:00
|
|
|
run [
|
2016-09-17 17:30:24 +00:00
|
|
|
10:bool/raw <- equal x, y
|
2015-04-08 07:47:04 +00:00
|
|
|
]
|
2015-05-02 22:52:22 +00:00
|
|
|
memory-should-contain [
|
2016-05-26 17:24:47 +00:00
|
|
|
10 <- 0 # "" != abcd
|
2015-04-08 07:47:04 +00:00
|
|
|
]
|
|
|
|
]
|
|
|
|
|
2016-11-23 22:01:07 +00:00
|
|
|
scenario text-equal-with-null [
|
|
|
|
local-scope
|
|
|
|
x:text <- new [abcd]
|
|
|
|
y:text <- copy 0
|
|
|
|
run [
|
|
|
|
10:bool/raw <- equal x, 0
|
|
|
|
11:bool/raw <- equal 0, x
|
|
|
|
12:bool/raw <- equal x, y
|
|
|
|
13:bool/raw <- equal y, x
|
|
|
|
14:bool/raw <- equal y, y
|
|
|
|
]
|
|
|
|
memory-should-contain [
|
|
|
|
10 <- 0
|
|
|
|
11 <- 0
|
|
|
|
12 <- 0
|
|
|
|
13 <- 0
|
|
|
|
14 <- 1
|
|
|
|
]
|
|
|
|
check-trace-count-for-label 0, [error]
|
|
|
|
]
|
|
|
|
|
2015-11-21 18:01:12 +00:00
|
|
|
scenario text-equal-common-lengths-but-distinct [
|
2016-09-29 02:48:56 +00:00
|
|
|
local-scope
|
|
|
|
x:text <- new [abc]
|
|
|
|
y:text <- new [abd]
|
2015-04-08 07:47:04 +00:00
|
|
|
run [
|
2016-09-17 17:30:24 +00:00
|
|
|
10:bool/raw <- equal x, y
|
2015-04-08 07:47:04 +00:00
|
|
|
]
|
2015-05-02 22:52:22 +00:00
|
|
|
memory-should-contain [
|
2016-05-26 17:24:47 +00:00
|
|
|
10 <- 0 # abc != abd
|
2015-04-06 19:02:38 +00:00
|
|
|
]
|
|
|
|
]
|
2015-04-18 03:36:25 +00:00
|
|
|
|
2015-11-21 18:01:12 +00:00
|
|
|
# A new type to help incrementally construct texts.
|
2017-04-18 17:47:35 +00:00
|
|
|
container buffer:_elem [
|
2016-09-17 17:28:25 +00:00
|
|
|
length:num
|
2017-04-18 17:47:35 +00:00
|
|
|
data:&:@:_elem
|
2015-04-18 03:36:25 +00:00
|
|
|
]
|
|
|
|
|
2017-04-18 17:47:35 +00:00
|
|
|
def new-buffer capacity:num -> result:&:buffer:_elem [
|
2015-07-14 05:43:16 +00:00
|
|
|
local-scope
|
2015-11-19 05:36:36 +00:00
|
|
|
load-ingredients
|
2017-04-18 17:47:35 +00:00
|
|
|
result <- new {(buffer _elem): type}
|
2016-04-11 03:47:44 +00:00
|
|
|
*result <- put *result, length:offset, 0
|
2016-08-14 12:24:04 +00:00
|
|
|
{
|
|
|
|
break-if capacity
|
|
|
|
# capacity not provided
|
|
|
|
capacity <- copy 10
|
|
|
|
}
|
2017-04-18 17:47:35 +00:00
|
|
|
data:&:@:_elem <- new _elem:type, capacity
|
2016-04-11 03:47:44 +00:00
|
|
|
*result <- put *result, data:offset, data
|
2016-03-08 09:30:14 +00:00
|
|
|
return result
|
2015-04-18 03:36:25 +00:00
|
|
|
]
|
2015-04-18 04:51:13 +00:00
|
|
|
|
2017-04-18 17:47:35 +00:00
|
|
|
def grow-buffer buf:&:buffer:_elem -> buf:&:buffer:_elem [
|
2015-07-14 05:43:16 +00:00
|
|
|
local-scope
|
2015-11-19 05:36:36 +00:00
|
|
|
load-ingredients
|
2015-04-18 04:51:13 +00:00
|
|
|
# double buffer size
|
2017-04-19 01:02:07 +00:00
|
|
|
olddata:&:@:_elem <- get *buf, data:offset
|
2016-09-17 17:28:25 +00:00
|
|
|
oldlen:num <- length *olddata
|
|
|
|
newlen:num <- multiply oldlen, 2
|
2017-04-19 01:02:07 +00:00
|
|
|
newdata:&:@:_elem <- new _elem:type, newlen
|
2016-09-15 16:25:52 +00:00
|
|
|
*buf <- put *buf, data:offset, newdata
|
2015-04-18 04:51:13 +00:00
|
|
|
# copy old contents
|
2016-09-17 17:28:25 +00:00
|
|
|
i:num <- copy 0
|
2015-04-18 04:51:13 +00:00
|
|
|
{
|
2016-09-17 17:30:24 +00:00
|
|
|
done?:bool <- greater-or-equal i, oldlen
|
2015-07-29 21:37:57 +00:00
|
|
|
break-if done?
|
2017-04-19 01:02:07 +00:00
|
|
|
src:_elem <- index *olddata, i
|
2016-04-23 21:51:20 +00:00
|
|
|
*newdata <- put-index *newdata, i, src
|
2015-07-29 21:37:57 +00:00
|
|
|
i <- add i, 1
|
2015-04-18 04:51:13 +00:00
|
|
|
loop
|
|
|
|
}
|
|
|
|
]
|
|
|
|
|
2017-04-18 17:47:35 +00:00
|
|
|
def buffer-full? in:&:buffer:_elem -> result:bool [
|
2015-07-14 05:43:16 +00:00
|
|
|
local-scope
|
2015-11-19 05:36:36 +00:00
|
|
|
load-ingredients
|
2016-09-17 17:28:25 +00:00
|
|
|
len:num <- get *in, length:offset
|
2017-04-19 01:02:07 +00:00
|
|
|
s:&:@:_elem <- get *in, data:offset
|
2016-09-17 17:28:25 +00:00
|
|
|
capacity:num <- length *s
|
2015-11-19 05:36:36 +00:00
|
|
|
result <- greater-or-equal len, capacity
|
2015-04-18 04:51:13 +00:00
|
|
|
]
|
|
|
|
|
2017-04-19 01:02:07 +00:00
|
|
|
# most broadly applicable definition of append to a buffer
|
|
|
|
def append buf:&:buffer:_elem, x:_elem -> buf:&:buffer:_elem [
|
|
|
|
local-scope
|
|
|
|
load-ingredients
|
|
|
|
len:num <- get *buf, length:offset
|
|
|
|
{
|
|
|
|
# grow buffer if necessary
|
|
|
|
full?:bool <- buffer-full? buf
|
|
|
|
break-unless full?
|
|
|
|
buf <- grow-buffer buf
|
|
|
|
}
|
|
|
|
s:&:@:_elem <- get *buf, data:offset
|
|
|
|
*s <- put-index *s, len, x
|
|
|
|
len <- add len, 1
|
|
|
|
*buf <- put *buf, length:offset, len
|
|
|
|
]
|
|
|
|
|
|
|
|
# most broadly applicable definition of append to a buffer of characters: just
|
|
|
|
# call to-text
|
2017-04-18 17:47:35 +00:00
|
|
|
def append buf:&:buffer:char, x:_elem -> buf:&:buffer:char [
|
2015-11-28 05:38:09 +00:00
|
|
|
local-scope
|
|
|
|
load-ingredients
|
2016-09-12 17:00:43 +00:00
|
|
|
text:text <- to-text x
|
2017-06-09 07:13:39 +00:00
|
|
|
buf <- append buf, text
|
2015-11-28 05:38:09 +00:00
|
|
|
]
|
|
|
|
|
2017-04-19 01:02:07 +00:00
|
|
|
# specialization for characters that is backspace-aware
|
2017-04-18 17:47:35 +00:00
|
|
|
def append buf:&:buffer:char, c:char -> buf:&:buffer:char [
|
2015-07-14 05:43:16 +00:00
|
|
|
local-scope
|
2015-11-19 05:36:36 +00:00
|
|
|
load-ingredients
|
2016-09-17 17:28:25 +00:00
|
|
|
len:num <- get *buf, length:offset
|
2015-06-01 06:44:52 +00:00
|
|
|
{
|
|
|
|
# backspace? just drop last character if it exists and return
|
2016-09-17 17:30:24 +00:00
|
|
|
backspace?:bool <- equal c, 8/backspace
|
2015-07-29 21:37:57 +00:00
|
|
|
break-unless backspace?
|
2016-09-17 17:30:24 +00:00
|
|
|
empty?:bool <- lesser-or-equal len, 0
|
2016-03-08 09:30:14 +00:00
|
|
|
return-if empty?
|
2016-04-11 03:47:44 +00:00
|
|
|
len <- subtract len, 1
|
2016-09-15 16:25:52 +00:00
|
|
|
*buf <- put *buf, length:offset, len
|
2016-03-08 09:30:14 +00:00
|
|
|
return
|
2015-06-01 06:44:52 +00:00
|
|
|
}
|
2015-04-18 04:51:13 +00:00
|
|
|
{
|
|
|
|
# grow buffer if necessary
|
2016-09-17 17:30:24 +00:00
|
|
|
full?:bool <- buffer-full? buf
|
2015-07-29 21:37:57 +00:00
|
|
|
break-unless full?
|
2016-09-15 16:25:52 +00:00
|
|
|
buf <- grow-buffer buf
|
2015-04-18 04:51:13 +00:00
|
|
|
}
|
2016-09-15 16:25:52 +00:00
|
|
|
s:text <- get *buf, data:offset
|
2016-04-23 21:51:20 +00:00
|
|
|
*s <- put-index *s, len, c
|
2016-04-11 03:47:44 +00:00
|
|
|
len <- add len, 1
|
2016-09-15 16:25:52 +00:00
|
|
|
*buf <- put *buf, length:offset, len
|
2015-04-18 04:51:13 +00:00
|
|
|
]
|
|
|
|
|
2017-10-30 20:45:17 +00:00
|
|
|
def append buf:&:buffer:_elem, t:&:@:_elem -> buf:&:buffer:_elem [
|
2016-09-15 16:55:14 +00:00
|
|
|
local-scope
|
|
|
|
load-ingredients
|
2016-09-17 17:28:25 +00:00
|
|
|
len:num <- length *t
|
|
|
|
i:num <- copy 0
|
2016-09-15 16:55:14 +00:00
|
|
|
{
|
2016-09-17 17:30:24 +00:00
|
|
|
done?:bool <- greater-or-equal i, len
|
2016-09-15 16:55:14 +00:00
|
|
|
break-if done?
|
2017-10-30 20:45:17 +00:00
|
|
|
x:_elem <- index *t, i
|
|
|
|
buf <- append buf, x
|
2016-09-15 16:55:14 +00:00
|
|
|
i <- add i, 1
|
|
|
|
loop
|
|
|
|
}
|
|
|
|
]
|
|
|
|
|
2016-09-29 02:48:56 +00:00
|
|
|
scenario append-to-empty-buffer [
|
|
|
|
local-scope
|
2017-04-18 17:47:35 +00:00
|
|
|
x:&:buffer:char <- new-buffer
|
2015-04-18 04:51:13 +00:00
|
|
|
run [
|
2016-09-17 07:31:55 +00:00
|
|
|
c:char <- copy 97/a
|
2016-02-09 00:20:53 +00:00
|
|
|
x <- append x, c
|
2016-09-29 02:48:56 +00:00
|
|
|
10:num/raw <- get *x, length:offset
|
|
|
|
s:text <- get *x, data:offset
|
|
|
|
11:char/raw <- index *s, 0
|
|
|
|
12:char/raw <- index *s, 1
|
|
|
|
]
|
|
|
|
memory-should-contain [
|
|
|
|
10 <- 1 # buffer length
|
|
|
|
11 <- 97 # a
|
|
|
|
12 <- 0 # rest of buffer is empty
|
|
|
|
]
|
|
|
|
]
|
|
|
|
|
|
|
|
scenario append-to-buffer [
|
|
|
|
local-scope
|
2017-04-18 17:47:35 +00:00
|
|
|
x:&:buffer:char <- new-buffer
|
2016-09-29 02:48:56 +00:00
|
|
|
c:char <- copy 97/a
|
|
|
|
x <- append x, c
|
|
|
|
run [
|
|
|
|
c <- copy 98/b
|
2016-02-09 00:20:53 +00:00
|
|
|
x <- append x, c
|
2016-09-29 02:48:56 +00:00
|
|
|
10:num/raw <- get *x, length:offset
|
|
|
|
s:text <- get *x, data:offset
|
|
|
|
11:char/raw <- index *s, 0
|
|
|
|
12:char/raw <- index *s, 1
|
|
|
|
13:char/raw <- index *s, 2
|
|
|
|
]
|
|
|
|
memory-should-contain [
|
|
|
|
10 <- 2 # buffer length
|
|
|
|
11 <- 97 # a
|
|
|
|
12 <- 98 # b
|
|
|
|
13 <- 0 # rest of buffer is empty
|
|
|
|
]
|
|
|
|
]
|
|
|
|
|
|
|
|
scenario append-grows-buffer [
|
|
|
|
local-scope
|
2017-04-18 17:47:35 +00:00
|
|
|
x:&:buffer:char <- new-buffer 3
|
2016-09-29 02:48:56 +00:00
|
|
|
s1:text <- get *x, data:offset
|
|
|
|
x <- append x, [abc] # buffer is now full
|
|
|
|
s2:text <- get *x, data:offset
|
|
|
|
run [
|
2016-09-17 17:30:24 +00:00
|
|
|
10:bool/raw <- equal s1, s2
|
2016-09-17 20:00:39 +00:00
|
|
|
11:@:char/raw <- copy *s2
|
2015-04-18 15:34:48 +00:00
|
|
|
+buffer-filled
|
2016-09-17 07:31:55 +00:00
|
|
|
c:char <- copy 100/d
|
2016-02-09 00:20:53 +00:00
|
|
|
x <- append x, c
|
2016-09-12 07:06:40 +00:00
|
|
|
s3:text <- get *x, data:offset
|
2016-09-17 17:30:24 +00:00
|
|
|
20:bool/raw <- equal s1, s3
|
2016-09-17 17:28:25 +00:00
|
|
|
21:num/raw <- get *x, length:offset
|
2016-09-17 20:00:39 +00:00
|
|
|
30:@:char/raw <- copy *s3
|
2015-04-18 04:51:13 +00:00
|
|
|
]
|
2015-05-02 22:52:22 +00:00
|
|
|
memory-should-contain [
|
2015-04-18 15:34:48 +00:00
|
|
|
# before +buffer-filled
|
2016-09-29 02:48:56 +00:00
|
|
|
10 <- 1 # no change in data pointer after original append
|
2016-05-26 17:24:47 +00:00
|
|
|
11 <- 3 # size of data
|
|
|
|
12 <- 97 # data
|
|
|
|
13 <- 98
|
|
|
|
14 <- 99
|
2015-04-18 15:34:48 +00:00
|
|
|
# in the end
|
2016-09-29 02:48:56 +00:00
|
|
|
20 <- 0 # data pointer has grown after second append
|
2016-05-26 17:24:47 +00:00
|
|
|
21 <- 4 # final length
|
|
|
|
30 <- 6 # but data's capacity has doubled
|
|
|
|
31 <- 97 # data
|
|
|
|
32 <- 98
|
|
|
|
33 <- 99
|
|
|
|
34 <- 100
|
|
|
|
35 <- 0
|
|
|
|
36 <- 0
|
2015-04-18 04:51:13 +00:00
|
|
|
]
|
|
|
|
]
|
2015-04-19 03:11:59 +00:00
|
|
|
|
2015-06-06 17:15:43 +00:00
|
|
|
scenario buffer-append-handles-backspace [
|
2016-09-29 02:48:56 +00:00
|
|
|
local-scope
|
2017-04-18 17:47:35 +00:00
|
|
|
x:&:buffer:char <- new-buffer
|
2016-09-29 02:48:56 +00:00
|
|
|
x <- append x, [ab]
|
2015-06-06 17:15:43 +00:00
|
|
|
run [
|
2016-09-17 07:31:55 +00:00
|
|
|
c:char <- copy 8/backspace
|
2016-02-09 00:20:53 +00:00
|
|
|
x <- append x, c
|
2016-09-12 07:06:40 +00:00
|
|
|
s:text <- buffer-to-array x
|
2016-09-17 20:00:39 +00:00
|
|
|
10:@:char/raw <- copy *s
|
2015-06-06 17:15:43 +00:00
|
|
|
]
|
|
|
|
memory-should-contain [
|
2016-05-26 17:24:47 +00:00
|
|
|
10 <- 1 # length
|
|
|
|
11 <- 97 # contents
|
|
|
|
12 <- 0
|
2015-06-06 17:15:43 +00:00
|
|
|
]
|
|
|
|
]
|
|
|
|
|
2017-04-19 01:04:50 +00:00
|
|
|
scenario append-to-buffer-of-non-characters [
|
|
|
|
local-scope
|
|
|
|
x:&:buffer:text <- new-buffer 1/capacity
|
|
|
|
# no errors
|
|
|
|
]
|
|
|
|
|
2017-04-18 17:47:35 +00:00
|
|
|
def buffer-to-array in:&:buffer:_elem -> result:&:@:_elem [
|
2015-07-14 05:43:16 +00:00
|
|
|
local-scope
|
2015-11-19 05:36:36 +00:00
|
|
|
load-ingredients
|
2017-09-24 01:31:26 +00:00
|
|
|
# propagate null buffer
|
|
|
|
return-unless in, 0
|
2016-09-17 17:28:25 +00:00
|
|
|
len:num <- get *in, length:offset
|
2017-04-19 01:02:07 +00:00
|
|
|
s:&:@:_elem <- get *in, data:offset
|
2015-05-27 21:56:01 +00:00
|
|
|
# we can't just return s because it is usually the wrong length
|
2017-04-19 01:02:07 +00:00
|
|
|
result <- new _elem:type, len
|
2016-09-17 17:28:25 +00:00
|
|
|
i:num <- copy 0
|
2015-05-27 21:56:01 +00:00
|
|
|
{
|
2016-09-17 17:30:24 +00:00
|
|
|
done?:bool <- greater-or-equal i, len
|
2015-07-29 21:37:57 +00:00
|
|
|
break-if done?
|
2017-04-19 01:02:07 +00:00
|
|
|
src:_elem <- index *s, i
|
2016-04-23 21:51:20 +00:00
|
|
|
*result <- put-index *result, i, src
|
2015-07-29 21:37:57 +00:00
|
|
|
i <- add i, 1
|
2015-05-27 21:56:01 +00:00
|
|
|
loop
|
|
|
|
}
|
|
|
|
]
|
|
|
|
|
2016-09-15 20:46:13 +00:00
|
|
|
# Append any number of texts together.
|
|
|
|
# A later layer also translates calls to this to implicitly call to-text, so
|
|
|
|
# append to string becomes effectively dynamically typed.
|
|
|
|
#
|
|
|
|
# Beware though: this hack restricts how much 'append' can be overridden. Any
|
|
|
|
# new variants that match:
|
|
|
|
# append _:text, ___
|
|
|
|
# will never ever get used.
|
|
|
|
def append first:text -> result:text [
|
2015-07-14 05:43:16 +00:00
|
|
|
local-scope
|
2015-11-19 05:36:36 +00:00
|
|
|
load-ingredients
|
2017-04-18 17:47:35 +00:00
|
|
|
buf:&:buffer:char <- new-buffer 30
|
2016-09-15 20:46:13 +00:00
|
|
|
# append first ingredient
|
|
|
|
{
|
|
|
|
break-unless first
|
|
|
|
buf <- append buf, first
|
|
|
|
}
|
|
|
|
# append remaining ingredients
|
2015-04-19 07:13:08 +00:00
|
|
|
{
|
2016-09-17 17:30:24 +00:00
|
|
|
arg:text, arg-found?:bool <- next-ingredient
|
2016-09-15 16:55:14 +00:00
|
|
|
break-unless arg-found?
|
|
|
|
loop-unless arg
|
|
|
|
buf <- append buf, arg
|
2015-04-19 07:13:08 +00:00
|
|
|
loop
|
|
|
|
}
|
2016-09-15 16:55:14 +00:00
|
|
|
result <- buffer-to-array buf
|
2015-04-19 07:13:08 +00:00
|
|
|
]
|
|
|
|
|
2015-11-21 18:01:12 +00:00
|
|
|
scenario text-append-1 [
|
2016-09-29 02:48:56 +00:00
|
|
|
local-scope
|
|
|
|
x:text <- new [hello,]
|
|
|
|
y:text <- new [ world!]
|
2015-04-19 07:13:08 +00:00
|
|
|
run [
|
2016-09-12 07:06:40 +00:00
|
|
|
z:text <- append x, y
|
2016-09-17 20:00:39 +00:00
|
|
|
10:@:char/raw <- copy *z
|
2015-04-19 07:13:08 +00:00
|
|
|
]
|
2015-05-02 22:52:22 +00:00
|
|
|
memory-should-contain [
|
2016-05-26 17:24:47 +00:00
|
|
|
10:array:character <- [hello, world!]
|
2015-04-19 07:13:08 +00:00
|
|
|
]
|
|
|
|
]
|
2015-04-20 17:25:02 +00:00
|
|
|
|
2016-05-25 02:20:35 +00:00
|
|
|
scenario text-append-null [
|
2016-09-29 02:48:56 +00:00
|
|
|
local-scope
|
|
|
|
x:text <- copy 0
|
|
|
|
y:text <- new [ world!]
|
2016-05-25 02:20:35 +00:00
|
|
|
run [
|
2016-09-12 07:06:40 +00:00
|
|
|
z:text <- append x, y
|
2016-09-17 20:00:39 +00:00
|
|
|
10:@:char/raw <- copy *z
|
2016-05-25 02:20:35 +00:00
|
|
|
]
|
|
|
|
memory-should-contain [
|
2016-05-26 17:24:47 +00:00
|
|
|
10:array:character <- [ world!]
|
2016-05-25 02:20:35 +00:00
|
|
|
]
|
|
|
|
]
|
|
|
|
|
|
|
|
scenario text-append-null-2 [
|
2016-09-29 02:48:56 +00:00
|
|
|
local-scope
|
|
|
|
x:text <- new [hello,]
|
|
|
|
y:text <- copy 0
|
2016-05-25 02:20:35 +00:00
|
|
|
run [
|
2016-09-12 07:06:40 +00:00
|
|
|
z:text <- append x, y
|
2016-09-17 20:00:39 +00:00
|
|
|
10:@:char/raw <- copy *z
|
2016-05-25 02:20:35 +00:00
|
|
|
]
|
|
|
|
memory-should-contain [
|
2016-05-26 17:24:47 +00:00
|
|
|
10:array:character <- [hello,]
|
2016-05-25 02:20:35 +00:00
|
|
|
]
|
|
|
|
]
|
|
|
|
|
2016-09-15 16:55:14 +00:00
|
|
|
scenario text-append-multiary [
|
2016-09-29 02:48:56 +00:00
|
|
|
local-scope
|
|
|
|
x:text <- new [hello, ]
|
|
|
|
y:text <- new [world]
|
|
|
|
z:text <- new [!]
|
2016-09-15 16:55:14 +00:00
|
|
|
run [
|
|
|
|
z:text <- append x, y, z
|
2016-09-17 20:00:39 +00:00
|
|
|
10:@:char/raw <- copy *z
|
2016-09-15 16:55:14 +00:00
|
|
|
]
|
|
|
|
memory-should-contain [
|
|
|
|
10:array:character <- [hello, world!]
|
|
|
|
]
|
|
|
|
]
|
|
|
|
|
2015-11-21 18:01:12 +00:00
|
|
|
scenario replace-character-in-text [
|
2016-09-29 02:48:56 +00:00
|
|
|
local-scope
|
|
|
|
x:text <- new [abc]
|
2015-08-20 05:13:15 +00:00
|
|
|
run [
|
2016-05-26 17:08:25 +00:00
|
|
|
x <- replace x, 98/b, 122/z
|
2016-09-17 20:00:39 +00:00
|
|
|
10:@:char/raw <- copy *x
|
2015-08-20 05:13:15 +00:00
|
|
|
]
|
|
|
|
memory-should-contain [
|
2016-05-26 17:24:47 +00:00
|
|
|
10:array:character <- [azc]
|
2015-08-20 05:13:15 +00:00
|
|
|
]
|
|
|
|
]
|
|
|
|
|
2016-09-17 17:28:25 +00:00
|
|
|
def replace s:text, oldc:char, newc:char, from:num/optional -> s:text [
|
2015-08-20 05:13:15 +00:00
|
|
|
local-scope
|
2015-11-19 05:36:36 +00:00
|
|
|
load-ingredients
|
2016-09-17 17:28:25 +00:00
|
|
|
len:num <- length *s
|
|
|
|
i:num <- find-next s, oldc, from
|
2016-09-17 17:30:24 +00:00
|
|
|
done?:bool <- greater-or-equal i, len
|
2016-11-28 08:42:24 +00:00
|
|
|
return-if done?
|
2016-04-23 21:51:20 +00:00
|
|
|
*s <- put-index *s, i, newc
|
2015-08-20 05:13:15 +00:00
|
|
|
i <- add i, 1
|
2015-11-21 18:01:12 +00:00
|
|
|
s <- replace s, oldc, newc, i
|
2015-08-20 05:13:15 +00:00
|
|
|
]
|
|
|
|
|
|
|
|
scenario replace-character-at-start [
|
2016-09-29 02:48:56 +00:00
|
|
|
local-scope
|
|
|
|
x:text <- new [abc]
|
2015-08-20 05:13:15 +00:00
|
|
|
run [
|
2016-05-26 17:08:25 +00:00
|
|
|
x <- replace x, 97/a, 122/z
|
2016-09-17 20:00:39 +00:00
|
|
|
10:@:char/raw <- copy *x
|
2015-08-20 05:13:15 +00:00
|
|
|
]
|
|
|
|
memory-should-contain [
|
2016-05-26 17:24:47 +00:00
|
|
|
10:array:character <- [zbc]
|
2015-08-20 05:13:15 +00:00
|
|
|
]
|
|
|
|
]
|
|
|
|
|
|
|
|
scenario replace-character-at-end [
|
2016-09-29 02:48:56 +00:00
|
|
|
local-scope
|
|
|
|
x:text <- new [abc]
|
2015-08-20 05:13:15 +00:00
|
|
|
run [
|
2016-05-26 17:08:25 +00:00
|
|
|
x <- replace x, 99/c, 122/z
|
2016-09-17 20:00:39 +00:00
|
|
|
10:@:char/raw <- copy *x
|
2015-08-20 05:13:15 +00:00
|
|
|
]
|
|
|
|
memory-should-contain [
|
2016-05-26 17:24:47 +00:00
|
|
|
10:array:character <- [abz]
|
2015-08-20 05:13:15 +00:00
|
|
|
]
|
|
|
|
]
|
|
|
|
|
|
|
|
scenario replace-character-missing [
|
2016-09-29 02:48:56 +00:00
|
|
|
local-scope
|
|
|
|
x:text <- new [abc]
|
2015-08-20 05:13:15 +00:00
|
|
|
run [
|
2016-05-26 17:08:25 +00:00
|
|
|
x <- replace x, 100/d, 122/z
|
2016-09-17 20:00:39 +00:00
|
|
|
10:@:char/raw <- copy *x
|
2015-08-20 05:13:15 +00:00
|
|
|
]
|
|
|
|
memory-should-contain [
|
2016-05-26 17:24:47 +00:00
|
|
|
10:array:character <- [abc]
|
2015-08-20 05:13:15 +00:00
|
|
|
]
|
|
|
|
]
|
|
|
|
|
|
|
|
scenario replace-all-characters [
|
2016-09-29 02:48:56 +00:00
|
|
|
local-scope
|
|
|
|
x:text <- new [banana]
|
2015-08-20 05:13:15 +00:00
|
|
|
run [
|
2016-05-26 17:08:25 +00:00
|
|
|
x <- replace x, 97/a, 122/z
|
2016-09-17 20:00:39 +00:00
|
|
|
10:@:char/raw <- copy *x
|
2015-08-20 05:13:15 +00:00
|
|
|
]
|
|
|
|
memory-should-contain [
|
2016-05-26 17:24:47 +00:00
|
|
|
10:array:character <- [bznznz]
|
2015-08-20 05:13:15 +00:00
|
|
|
]
|
|
|
|
]
|
|
|
|
|
2015-04-20 17:25:02 +00:00
|
|
|
# replace underscores in first with remaining args
|
2016-09-12 17:00:43 +00:00
|
|
|
def interpolate template:text -> result:text [
|
2015-07-14 05:43:16 +00:00
|
|
|
local-scope
|
2015-11-19 05:36:36 +00:00
|
|
|
load-ingredients # consume just the template
|
2015-04-20 17:25:02 +00:00
|
|
|
# compute result-len, space to allocate for result
|
2016-09-17 17:28:25 +00:00
|
|
|
tem-len:num <- length *template
|
|
|
|
result-len:num <- copy tem-len
|
2015-04-20 17:25:02 +00:00
|
|
|
{
|
2015-11-19 05:36:36 +00:00
|
|
|
# while ingredients remain
|
2016-09-17 17:30:24 +00:00
|
|
|
a:text, arg-received?:bool <- next-ingredient
|
2015-07-29 21:37:57 +00:00
|
|
|
break-unless arg-received?
|
|
|
|
# result-len = result-len + arg.length - 1 (for the 'underscore' being replaced)
|
2016-09-17 17:28:25 +00:00
|
|
|
a-len:num <- length *a
|
2015-07-29 21:37:57 +00:00
|
|
|
result-len <- add result-len, a-len
|
|
|
|
result-len <- subtract result-len, 1
|
2015-04-20 17:25:02 +00:00
|
|
|
loop
|
|
|
|
}
|
|
|
|
rewind-ingredients
|
|
|
|
_ <- next-ingredient # skip template
|
2016-01-20 07:18:03 +00:00
|
|
|
result <- new character:type, result-len
|
2015-04-20 17:25:02 +00:00
|
|
|
# repeatedly copy sections of template and 'holes' into result
|
2016-09-17 17:28:25 +00:00
|
|
|
result-idx:num <- copy 0
|
|
|
|
i:num <- copy 0
|
2015-04-20 17:25:02 +00:00
|
|
|
{
|
|
|
|
# while arg received
|
2016-09-17 17:30:24 +00:00
|
|
|
a:text, arg-received?:bool <- next-ingredient
|
2015-07-29 21:37:57 +00:00
|
|
|
break-unless arg-received?
|
2015-04-20 17:25:02 +00:00
|
|
|
# copy template into result until '_'
|
|
|
|
{
|
|
|
|
# while i < template.length
|
2016-09-17 17:30:24 +00:00
|
|
|
tem-done?:bool <- greater-or-equal i, tem-len
|
2016-10-22 19:08:10 +00:00
|
|
|
break-if tem-done?, +done
|
2015-04-20 17:25:02 +00:00
|
|
|
# while template[i] != '_'
|
2016-09-17 07:31:55 +00:00
|
|
|
in:char <- index *template, i
|
2016-09-17 17:30:24 +00:00
|
|
|
underscore?:bool <- equal in, 95/_
|
2015-07-29 21:37:57 +00:00
|
|
|
break-if underscore?
|
2015-04-20 17:25:02 +00:00
|
|
|
# result[result-idx] = template[i]
|
2016-04-23 21:51:20 +00:00
|
|
|
*result <- put-index *result, result-idx, in
|
2015-07-29 21:37:57 +00:00
|
|
|
i <- add i, 1
|
|
|
|
result-idx <- add result-idx, 1
|
2015-04-20 17:25:02 +00:00
|
|
|
loop
|
|
|
|
}
|
|
|
|
# copy 'a' into result
|
2016-09-17 17:28:25 +00:00
|
|
|
j:num <- copy 0
|
2015-04-20 17:25:02 +00:00
|
|
|
{
|
|
|
|
# while j < a.length
|
2016-09-17 17:30:24 +00:00
|
|
|
arg-done?:bool <- greater-or-equal j, a-len
|
2015-07-29 21:37:57 +00:00
|
|
|
break-if arg-done?
|
2015-04-20 17:25:02 +00:00
|
|
|
# result[result-idx] = a[j]
|
2016-09-17 07:31:55 +00:00
|
|
|
in:char <- index *a, j
|
2016-04-23 21:51:20 +00:00
|
|
|
*result <- put-index *result, result-idx, in
|
2015-07-29 21:37:57 +00:00
|
|
|
j <- add j, 1
|
|
|
|
result-idx <- add result-idx, 1
|
2015-04-20 17:25:02 +00:00
|
|
|
loop
|
|
|
|
}
|
|
|
|
# skip '_' in template
|
2015-07-29 21:37:57 +00:00
|
|
|
i <- add i, 1
|
2015-04-20 17:25:02 +00:00
|
|
|
loop # interpolate next arg
|
|
|
|
}
|
2015-05-16 20:17:36 +00:00
|
|
|
+done
|
2015-04-20 17:25:02 +00:00
|
|
|
# done with holes; copy rest of template directly into result
|
|
|
|
{
|
|
|
|
# while i < template.length
|
2016-09-17 17:30:24 +00:00
|
|
|
tem-done?:bool <- greater-or-equal i, tem-len
|
2015-07-29 21:37:57 +00:00
|
|
|
break-if tem-done?
|
2015-04-20 17:25:02 +00:00
|
|
|
# result[result-idx] = template[i]
|
2016-09-17 07:31:55 +00:00
|
|
|
in:char <- index *template, i
|
2016-04-23 21:51:20 +00:00
|
|
|
*result <- put-index *result, result-idx, in
|
2015-07-29 21:37:57 +00:00
|
|
|
i <- add i, 1
|
|
|
|
result-idx <- add result-idx, 1
|
2015-04-20 17:25:02 +00:00
|
|
|
loop
|
|
|
|
}
|
|
|
|
]
|
|
|
|
|
|
|
|
scenario interpolate-works [
|
2016-09-29 02:48:56 +00:00
|
|
|
local-scope
|
|
|
|
x:text <- new [abc_ghi]
|
|
|
|
y:text <- new [def]
|
2015-04-20 17:25:02 +00:00
|
|
|
run [
|
2016-09-12 07:06:40 +00:00
|
|
|
z:text <- interpolate x, y
|
2016-09-17 20:00:39 +00:00
|
|
|
10:@:char/raw <- copy *z
|
2015-04-20 17:25:02 +00:00
|
|
|
]
|
2015-05-02 22:52:22 +00:00
|
|
|
memory-should-contain [
|
2016-05-27 01:50:33 +00:00
|
|
|
10:array:character <- [abcdefghi]
|
2015-04-20 17:25:02 +00:00
|
|
|
]
|
|
|
|
]
|
|
|
|
|
|
|
|
scenario interpolate-at-start [
|
2016-09-29 02:48:56 +00:00
|
|
|
local-scope
|
|
|
|
x:text <- new [_, hello!]
|
|
|
|
y:text <- new [abc]
|
2015-04-20 17:25:02 +00:00
|
|
|
run [
|
2016-09-12 07:06:40 +00:00
|
|
|
z:text <- interpolate x, y
|
2016-09-17 20:00:39 +00:00
|
|
|
10:@:char/raw <- copy *z
|
2015-04-20 17:25:02 +00:00
|
|
|
]
|
2015-05-02 22:52:22 +00:00
|
|
|
memory-should-contain [
|
2016-05-26 17:24:47 +00:00
|
|
|
10:array:character <- [abc, hello!]
|
|
|
|
22 <- 0 # out of bounds
|
2015-04-20 17:25:02 +00:00
|
|
|
]
|
|
|
|
]
|
|
|
|
|
|
|
|
scenario interpolate-at-end [
|
2016-09-29 02:48:56 +00:00
|
|
|
local-scope
|
|
|
|
x:text <- new [hello, _]
|
|
|
|
y:text <- new [abc]
|
2015-04-20 17:25:02 +00:00
|
|
|
run [
|
2016-09-12 07:06:40 +00:00
|
|
|
z:text <- interpolate x, y
|
2016-09-17 20:00:39 +00:00
|
|
|
10:@:char/raw <- copy *z
|
2015-04-20 17:25:02 +00:00
|
|
|
]
|
2015-05-02 22:52:22 +00:00
|
|
|
memory-should-contain [
|
2016-05-26 17:24:47 +00:00
|
|
|
10:array:character <- [hello, abc]
|
2015-04-20 17:25:02 +00:00
|
|
|
]
|
|
|
|
]
|
2015-05-23 18:37:44 +00:00
|
|
|
|
2016-09-17 17:30:24 +00:00
|
|
|
# result:bool <- space? c:char
|
|
|
|
def space? c:char -> result:bool [
|
2015-07-14 05:43:16 +00:00
|
|
|
local-scope
|
2015-11-19 05:36:36 +00:00
|
|
|
load-ingredients
|
2015-05-23 19:35:10 +00:00
|
|
|
# most common case first
|
2015-11-19 05:36:36 +00:00
|
|
|
result <- equal c, 32/space
|
2016-03-08 09:30:14 +00:00
|
|
|
return-if result
|
2015-07-29 21:37:57 +00:00
|
|
|
result <- equal c, 10/newline
|
2016-03-08 09:30:14 +00:00
|
|
|
return-if result
|
2015-07-29 21:37:57 +00:00
|
|
|
result <- equal c, 9/tab
|
2016-03-08 09:30:14 +00:00
|
|
|
return-if result
|
2015-07-29 21:37:57 +00:00
|
|
|
result <- equal c, 13/carriage-return
|
2016-03-08 09:30:14 +00:00
|
|
|
return-if result
|
2015-05-23 19:30:58 +00:00
|
|
|
# remaining uncommon cases in sorted order
|
|
|
|
# http://unicode.org code-points in unicode-set Z and Pattern_White_Space
|
2015-07-29 21:37:57 +00:00
|
|
|
result <- equal c, 11/ctrl-k
|
2016-03-08 09:30:14 +00:00
|
|
|
return-if result
|
2015-07-29 21:37:57 +00:00
|
|
|
result <- equal c, 12/ctrl-l
|
2016-03-08 09:30:14 +00:00
|
|
|
return-if result
|
2015-07-29 21:37:57 +00:00
|
|
|
result <- equal c, 133/ctrl-0085
|
2016-03-08 09:30:14 +00:00
|
|
|
return-if result
|
2015-07-29 21:37:57 +00:00
|
|
|
result <- equal c, 160/no-break-space
|
2016-03-08 09:30:14 +00:00
|
|
|
return-if result
|
2015-07-29 21:37:57 +00:00
|
|
|
result <- equal c, 5760/ogham-space-mark
|
2016-03-08 09:30:14 +00:00
|
|
|
return-if result
|
2015-07-29 21:37:57 +00:00
|
|
|
result <- equal c, 8192/en-quad
|
2016-03-08 09:30:14 +00:00
|
|
|
return-if result
|
2015-07-29 21:37:57 +00:00
|
|
|
result <- equal c, 8193/em-quad
|
2016-03-08 09:30:14 +00:00
|
|
|
return-if result
|
2015-07-29 21:37:57 +00:00
|
|
|
result <- equal c, 8194/en-space
|
2016-03-08 09:30:14 +00:00
|
|
|
return-if result
|
2015-07-29 21:37:57 +00:00
|
|
|
result <- equal c, 8195/em-space
|
2016-03-08 09:30:14 +00:00
|
|
|
return-if result
|
2015-07-29 21:37:57 +00:00
|
|
|
result <- equal c, 8196/three-per-em-space
|
2016-03-08 09:30:14 +00:00
|
|
|
return-if result
|
2015-07-29 21:37:57 +00:00
|
|
|
result <- equal c, 8197/four-per-em-space
|
2016-03-08 09:30:14 +00:00
|
|
|
return-if result
|
2015-07-29 21:37:57 +00:00
|
|
|
result <- equal c, 8198/six-per-em-space
|
2016-03-08 09:30:14 +00:00
|
|
|
return-if result
|
2015-07-29 21:37:57 +00:00
|
|
|
result <- equal c, 8199/figure-space
|
2016-03-08 09:30:14 +00:00
|
|
|
return-if result
|
2015-07-29 21:37:57 +00:00
|
|
|
result <- equal c, 8200/punctuation-space
|
2016-03-08 09:30:14 +00:00
|
|
|
return-if result
|
2015-07-29 21:37:57 +00:00
|
|
|
result <- equal c, 8201/thin-space
|
2016-03-08 09:30:14 +00:00
|
|
|
return-if result
|
2015-07-29 21:37:57 +00:00
|
|
|
result <- equal c, 8202/hair-space
|
2016-03-08 09:30:14 +00:00
|
|
|
return-if result
|
2015-07-29 21:37:57 +00:00
|
|
|
result <- equal c, 8206/left-to-right
|
2016-03-08 09:30:14 +00:00
|
|
|
return-if result
|
2015-07-29 21:37:57 +00:00
|
|
|
result <- equal c, 8207/right-to-left
|
2016-03-08 09:30:14 +00:00
|
|
|
return-if result
|
2015-07-29 21:37:57 +00:00
|
|
|
result <- equal c, 8232/line-separator
|
2016-03-08 09:30:14 +00:00
|
|
|
return-if result
|
2015-07-29 21:37:57 +00:00
|
|
|
result <- equal c, 8233/paragraph-separator
|
2016-03-08 09:30:14 +00:00
|
|
|
return-if result
|
2015-07-29 21:37:57 +00:00
|
|
|
result <- equal c, 8239/narrow-no-break-space
|
2016-03-08 09:30:14 +00:00
|
|
|
return-if result
|
2015-07-29 21:37:57 +00:00
|
|
|
result <- equal c, 8287/medium-mathematical-space
|
2016-03-08 09:30:14 +00:00
|
|
|
return-if result
|
2015-07-29 21:37:57 +00:00
|
|
|
result <- equal c, 12288/ideographic-space
|
2015-05-23 19:30:58 +00:00
|
|
|
]
|
|
|
|
|
2016-09-12 17:00:43 +00:00
|
|
|
def trim s:text -> result:text [
|
2015-07-14 05:43:16 +00:00
|
|
|
local-scope
|
2015-11-19 05:36:36 +00:00
|
|
|
load-ingredients
|
2016-09-17 17:28:25 +00:00
|
|
|
len:num <- length *s
|
2015-05-23 18:37:44 +00:00
|
|
|
# left trim: compute start
|
2016-09-17 17:28:25 +00:00
|
|
|
start:num <- copy 0
|
2015-05-23 18:37:44 +00:00
|
|
|
{
|
|
|
|
{
|
2016-09-17 17:30:24 +00:00
|
|
|
at-end?:bool <- greater-or-equal start, len
|
2015-07-29 21:37:57 +00:00
|
|
|
break-unless at-end?
|
2015-11-19 05:36:36 +00:00
|
|
|
result <- new character:type, 0
|
2016-03-08 09:30:14 +00:00
|
|
|
return
|
2015-05-23 18:37:44 +00:00
|
|
|
}
|
2016-09-17 07:31:55 +00:00
|
|
|
curr:char <- index *s, start
|
2016-09-17 17:30:24 +00:00
|
|
|
whitespace?:bool <- space? curr
|
2015-07-29 21:37:57 +00:00
|
|
|
break-unless whitespace?
|
|
|
|
start <- add start, 1
|
2015-05-23 18:37:44 +00:00
|
|
|
loop
|
|
|
|
}
|
|
|
|
# right trim: compute end
|
2016-09-17 17:28:25 +00:00
|
|
|
end:num <- subtract len, 1
|
2015-05-23 18:37:44 +00:00
|
|
|
{
|
2016-09-17 17:30:24 +00:00
|
|
|
not-at-start?:bool <- greater-than end, start
|
2015-07-29 21:37:57 +00:00
|
|
|
assert not-at-start?, [end ran up against start]
|
2016-09-17 07:31:55 +00:00
|
|
|
curr:char <- index *s, end
|
2016-09-17 17:30:24 +00:00
|
|
|
whitespace?:bool <- space? curr
|
2015-07-29 21:37:57 +00:00
|
|
|
break-unless whitespace?
|
|
|
|
end <- subtract end, 1
|
2015-05-23 18:37:44 +00:00
|
|
|
loop
|
|
|
|
}
|
2015-05-23 19:35:10 +00:00
|
|
|
# result = new character[end+1 - start]
|
2016-09-17 17:28:25 +00:00
|
|
|
new-len:num <- subtract end, start, -1
|
2016-09-12 07:06:40 +00:00
|
|
|
result:text <- new character:type, new-len
|
2015-08-03 17:09:59 +00:00
|
|
|
# copy the untrimmed parts between start and end
|
2016-09-17 17:28:25 +00:00
|
|
|
i:num <- copy start
|
|
|
|
j:num <- copy 0
|
2015-05-23 18:37:44 +00:00
|
|
|
{
|
|
|
|
# while i <= end
|
2016-09-17 17:30:24 +00:00
|
|
|
done?:bool <- greater-than i, end
|
2015-07-29 21:37:57 +00:00
|
|
|
break-if done?
|
2015-05-23 18:37:44 +00:00
|
|
|
# result[j] = s[i]
|
2016-09-17 07:31:55 +00:00
|
|
|
src:char <- index *s, i
|
2016-04-23 21:51:20 +00:00
|
|
|
*result <- put-index *result, j, src
|
2015-07-29 21:37:57 +00:00
|
|
|
i <- add i, 1
|
|
|
|
j <- add j, 1
|
2015-05-23 18:37:44 +00:00
|
|
|
loop
|
|
|
|
}
|
|
|
|
]
|
|
|
|
|
|
|
|
scenario trim-unmodified [
|
2016-09-29 02:48:56 +00:00
|
|
|
local-scope
|
|
|
|
x:text <- new [abc]
|
2015-05-23 18:37:44 +00:00
|
|
|
run [
|
2016-09-12 07:06:40 +00:00
|
|
|
y:text <- trim x
|
2016-09-17 20:00:39 +00:00
|
|
|
1:@:char/raw <- copy *y
|
2015-05-23 18:37:44 +00:00
|
|
|
]
|
|
|
|
memory-should-contain [
|
2016-05-26 17:08:25 +00:00
|
|
|
1:array:character <- [abc]
|
2015-05-23 18:37:44 +00:00
|
|
|
]
|
|
|
|
]
|
|
|
|
|
|
|
|
scenario trim-left [
|
2016-09-29 02:48:56 +00:00
|
|
|
local-scope
|
|
|
|
x:text <- new [ abc]
|
2015-05-23 18:37:44 +00:00
|
|
|
run [
|
2016-09-12 07:06:40 +00:00
|
|
|
y:text <- trim x
|
2016-09-17 20:00:39 +00:00
|
|
|
1:@:char/raw <- copy *y
|
2015-05-23 18:37:44 +00:00
|
|
|
]
|
|
|
|
memory-should-contain [
|
2016-05-26 17:08:25 +00:00
|
|
|
1:array:character <- [abc]
|
2015-05-23 18:37:44 +00:00
|
|
|
]
|
|
|
|
]
|
|
|
|
|
|
|
|
scenario trim-right [
|
2016-09-29 02:48:56 +00:00
|
|
|
local-scope
|
|
|
|
x:text <- new [abc ]
|
2015-05-23 18:37:44 +00:00
|
|
|
run [
|
2016-09-12 07:06:40 +00:00
|
|
|
y:text <- trim x
|
2016-09-17 20:00:39 +00:00
|
|
|
1:@:char/raw <- copy *y
|
2015-05-23 18:37:44 +00:00
|
|
|
]
|
|
|
|
memory-should-contain [
|
2016-05-26 17:08:25 +00:00
|
|
|
1:array:character <- [abc]
|
2015-05-23 18:37:44 +00:00
|
|
|
]
|
|
|
|
]
|
|
|
|
|
|
|
|
scenario trim-left-right [
|
2016-09-29 02:48:56 +00:00
|
|
|
local-scope
|
|
|
|
x:text <- new [ abc ]
|
2015-05-23 18:37:44 +00:00
|
|
|
run [
|
2016-09-12 07:06:40 +00:00
|
|
|
y:text <- trim x
|
2016-09-17 20:00:39 +00:00
|
|
|
1:@:char/raw <- copy *y
|
2015-05-23 18:37:44 +00:00
|
|
|
]
|
|
|
|
memory-should-contain [
|
2016-05-26 17:08:25 +00:00
|
|
|
1:array:character <- [abc]
|
2015-05-23 18:37:44 +00:00
|
|
|
]
|
|
|
|
]
|
2015-05-23 19:30:58 +00:00
|
|
|
|
|
|
|
scenario trim-newline-tab [
|
2016-09-29 02:48:56 +00:00
|
|
|
local-scope
|
|
|
|
x:text <- new [ abc
|
2015-05-23 19:30:58 +00:00
|
|
|
]
|
2016-09-29 02:48:56 +00:00
|
|
|
run [
|
2016-09-12 07:06:40 +00:00
|
|
|
y:text <- trim x
|
2016-09-17 20:00:39 +00:00
|
|
|
1:@:char/raw <- copy *y
|
2015-05-23 19:30:58 +00:00
|
|
|
]
|
|
|
|
memory-should-contain [
|
2016-05-26 17:08:25 +00:00
|
|
|
1:array:character <- [abc]
|
2015-05-23 19:30:58 +00:00
|
|
|
]
|
|
|
|
]
|
2015-06-19 19:28:36 +00:00
|
|
|
|
2016-09-17 17:28:25 +00:00
|
|
|
def find-next text:text, pattern:char, idx:num -> next-index:num [
|
2015-07-14 05:43:16 +00:00
|
|
|
local-scope
|
2016-01-13 06:10:38 +00:00
|
|
|
load-ingredients
|
2016-09-17 17:28:25 +00:00
|
|
|
len:num <- length *text
|
2015-06-19 19:28:36 +00:00
|
|
|
{
|
2016-09-17 17:30:24 +00:00
|
|
|
eof?:bool <- greater-or-equal idx, len
|
2015-07-29 21:37:57 +00:00
|
|
|
break-if eof?
|
2016-09-17 07:31:55 +00:00
|
|
|
curr:char <- index *text, idx
|
2016-09-17 17:30:24 +00:00
|
|
|
found?:bool <- equal curr, pattern
|
2015-07-29 21:37:57 +00:00
|
|
|
break-if found?
|
|
|
|
idx <- add idx, 1
|
2015-06-19 19:28:36 +00:00
|
|
|
loop
|
|
|
|
}
|
2016-03-08 09:30:14 +00:00
|
|
|
return idx
|
2015-06-19 19:28:36 +00:00
|
|
|
]
|
|
|
|
|
2015-11-21 18:01:12 +00:00
|
|
|
scenario text-find-next [
|
2016-09-29 02:48:56 +00:00
|
|
|
local-scope
|
|
|
|
x:text <- new [a/b]
|
2015-06-19 19:28:36 +00:00
|
|
|
run [
|
2016-09-17 17:28:25 +00:00
|
|
|
10:num/raw <- find-next x, 47/slash, 0/start-index
|
2015-06-19 19:28:36 +00:00
|
|
|
]
|
|
|
|
memory-should-contain [
|
2016-05-26 17:24:47 +00:00
|
|
|
10 <- 1
|
2015-06-19 19:28:36 +00:00
|
|
|
]
|
|
|
|
]
|
|
|
|
|
2015-11-21 18:01:12 +00:00
|
|
|
scenario text-find-next-empty [
|
2016-09-29 02:48:56 +00:00
|
|
|
local-scope
|
|
|
|
x:text <- new []
|
2015-06-19 19:28:36 +00:00
|
|
|
run [
|
2016-09-17 17:28:25 +00:00
|
|
|
10:num/raw <- find-next x, 47/slash, 0/start-index
|
2015-06-19 19:28:36 +00:00
|
|
|
]
|
|
|
|
memory-should-contain [
|
2016-05-26 17:24:47 +00:00
|
|
|
10 <- 0
|
2015-06-19 19:28:36 +00:00
|
|
|
]
|
|
|
|
]
|
|
|
|
|
2015-11-21 18:01:12 +00:00
|
|
|
scenario text-find-next-initial [
|
2016-09-29 02:48:56 +00:00
|
|
|
local-scope
|
|
|
|
x:text <- new [/abc]
|
2015-06-19 19:28:36 +00:00
|
|
|
run [
|
2016-09-17 17:28:25 +00:00
|
|
|
10:num/raw <- find-next x, 47/slash, 0/start-index
|
2015-06-19 19:28:36 +00:00
|
|
|
]
|
|
|
|
memory-should-contain [
|
2016-05-26 17:24:47 +00:00
|
|
|
10 <- 0 # prefix match
|
2015-06-19 19:28:36 +00:00
|
|
|
]
|
|
|
|
]
|
|
|
|
|
2015-11-21 18:01:12 +00:00
|
|
|
scenario text-find-next-final [
|
2016-09-29 02:48:56 +00:00
|
|
|
local-scope
|
|
|
|
x:text <- new [abc/]
|
2015-06-19 19:28:36 +00:00
|
|
|
run [
|
2016-09-17 17:28:25 +00:00
|
|
|
10:num/raw <- find-next x, 47/slash, 0/start-index
|
2015-06-19 19:28:36 +00:00
|
|
|
]
|
|
|
|
memory-should-contain [
|
2016-05-26 17:24:47 +00:00
|
|
|
10 <- 3 # suffix match
|
2015-06-19 19:28:36 +00:00
|
|
|
]
|
|
|
|
]
|
|
|
|
|
2015-11-21 18:01:12 +00:00
|
|
|
scenario text-find-next-missing [
|
2016-09-29 02:48:56 +00:00
|
|
|
local-scope
|
|
|
|
x:text <- new [abcd]
|
2015-06-19 19:28:36 +00:00
|
|
|
run [
|
2016-09-17 17:28:25 +00:00
|
|
|
10:num/raw <- find-next x, 47/slash, 0/start-index
|
2015-06-19 19:28:36 +00:00
|
|
|
]
|
|
|
|
memory-should-contain [
|
2016-05-26 17:24:47 +00:00
|
|
|
10 <- 4 # no match
|
2015-06-19 19:28:36 +00:00
|
|
|
]
|
|
|
|
]
|
|
|
|
|
2015-11-21 18:01:12 +00:00
|
|
|
scenario text-find-next-invalid-index [
|
2016-09-29 02:48:56 +00:00
|
|
|
local-scope
|
|
|
|
x:text <- new [abc]
|
2015-06-19 19:28:36 +00:00
|
|
|
run [
|
2016-09-17 17:28:25 +00:00
|
|
|
10:num/raw <- find-next x, 47/slash, 4/start-index
|
2015-06-19 19:28:36 +00:00
|
|
|
]
|
|
|
|
memory-should-contain [
|
2016-05-26 17:24:47 +00:00
|
|
|
10 <- 4 # no change
|
2015-06-19 19:28:36 +00:00
|
|
|
]
|
|
|
|
]
|
|
|
|
|
2015-11-21 18:01:12 +00:00
|
|
|
scenario text-find-next-first [
|
2016-09-29 02:48:56 +00:00
|
|
|
local-scope
|
|
|
|
x:text <- new [ab/c/]
|
2015-06-19 19:28:36 +00:00
|
|
|
run [
|
2016-09-17 17:28:25 +00:00
|
|
|
10:num/raw <- find-next x, 47/slash, 0/start-index
|
2015-06-19 19:28:36 +00:00
|
|
|
]
|
|
|
|
memory-should-contain [
|
2016-05-26 17:24:47 +00:00
|
|
|
10 <- 2 # first '/' of multiple
|
2015-06-19 19:28:36 +00:00
|
|
|
]
|
|
|
|
]
|
|
|
|
|
2015-11-21 18:01:12 +00:00
|
|
|
scenario text-find-next-second [
|
2016-09-29 02:48:56 +00:00
|
|
|
local-scope
|
|
|
|
x:text <- new [ab/c/]
|
2015-06-19 19:28:36 +00:00
|
|
|
run [
|
2016-09-17 17:28:25 +00:00
|
|
|
10:num/raw <- find-next x, 47/slash, 3/start-index
|
2015-06-19 19:28:36 +00:00
|
|
|
]
|
|
|
|
memory-should-contain [
|
2016-05-26 17:24:47 +00:00
|
|
|
10 <- 4 # second '/' of multiple
|
2015-06-19 19:28:36 +00:00
|
|
|
]
|
|
|
|
]
|
|
|
|
|
2015-11-21 18:01:12 +00:00
|
|
|
# search for a pattern of multiple characters
|
2015-06-19 19:28:36 +00:00
|
|
|
# fairly dumb algorithm
|
2016-09-17 17:28:25 +00:00
|
|
|
def find-next text:text, pattern:text, idx:num -> next-index:num [
|
2015-07-14 05:43:16 +00:00
|
|
|
local-scope
|
2015-11-19 05:36:36 +00:00
|
|
|
load-ingredients
|
2016-09-17 07:31:55 +00:00
|
|
|
first:char <- index *pattern, 0
|
2015-06-19 19:28:36 +00:00
|
|
|
# repeatedly check for match at current idx
|
2016-09-17 17:28:25 +00:00
|
|
|
len:num <- length *text
|
2015-06-19 19:28:36 +00:00
|
|
|
{
|
2015-11-21 18:01:12 +00:00
|
|
|
# does some unnecessary work checking even when there isn't enough of text left
|
2016-09-17 17:30:24 +00:00
|
|
|
done?:bool <- greater-or-equal idx, len
|
2015-07-29 21:37:57 +00:00
|
|
|
break-if done?
|
2016-09-17 17:30:24 +00:00
|
|
|
found?:bool <- match-at text, pattern, idx
|
2015-07-29 21:37:57 +00:00
|
|
|
break-if found?
|
|
|
|
idx <- add idx, 1
|
2015-06-19 19:28:36 +00:00
|
|
|
# optimization: skip past indices that definitely won't match
|
2015-07-29 21:37:57 +00:00
|
|
|
idx <- find-next text, first, idx
|
2015-06-19 19:28:36 +00:00
|
|
|
loop
|
|
|
|
}
|
2016-03-08 09:30:14 +00:00
|
|
|
return idx
|
2015-06-19 19:28:36 +00:00
|
|
|
]
|
|
|
|
|
2015-11-21 18:01:12 +00:00
|
|
|
scenario find-next-text-1 [
|
2016-09-29 02:48:56 +00:00
|
|
|
local-scope
|
|
|
|
x:text <- new [abc]
|
|
|
|
y:text <- new [bc]
|
2015-06-19 19:28:36 +00:00
|
|
|
run [
|
2016-09-17 17:28:25 +00:00
|
|
|
10:num/raw <- find-next x, y, 0
|
2015-06-19 19:28:36 +00:00
|
|
|
]
|
|
|
|
memory-should-contain [
|
2016-05-26 17:08:25 +00:00
|
|
|
10 <- 1
|
2015-06-19 19:28:36 +00:00
|
|
|
]
|
|
|
|
]
|
|
|
|
|
2015-11-21 18:01:12 +00:00
|
|
|
scenario find-next-text-2 [
|
2016-09-29 02:48:56 +00:00
|
|
|
local-scope
|
|
|
|
x:text <- new [abcd]
|
|
|
|
y:text <- new [bc]
|
2015-06-19 19:28:36 +00:00
|
|
|
run [
|
2016-09-17 17:28:25 +00:00
|
|
|
10:num/raw <- find-next x, y, 1
|
2015-06-19 19:28:36 +00:00
|
|
|
]
|
|
|
|
memory-should-contain [
|
2016-05-26 17:08:25 +00:00
|
|
|
10 <- 1
|
2015-06-19 19:28:36 +00:00
|
|
|
]
|
|
|
|
]
|
|
|
|
|
2015-11-21 18:01:12 +00:00
|
|
|
scenario find-next-no-match [
|
2016-09-29 02:48:56 +00:00
|
|
|
local-scope
|
|
|
|
x:text <- new [abc]
|
|
|
|
y:text <- new [bd]
|
2015-06-19 19:28:36 +00:00
|
|
|
run [
|
2016-09-17 17:28:25 +00:00
|
|
|
10:num/raw <- find-next x, y, 0
|
2015-06-19 19:28:36 +00:00
|
|
|
]
|
|
|
|
memory-should-contain [
|
2016-05-26 17:24:47 +00:00
|
|
|
10 <- 3 # not found
|
2015-06-19 19:28:36 +00:00
|
|
|
]
|
|
|
|
]
|
|
|
|
|
2015-11-21 18:01:12 +00:00
|
|
|
scenario find-next-suffix-match [
|
2016-09-29 02:48:56 +00:00
|
|
|
local-scope
|
|
|
|
x:text <- new [abcd]
|
|
|
|
y:text <- new [cd]
|
2015-06-19 19:28:36 +00:00
|
|
|
run [
|
2016-09-17 17:28:25 +00:00
|
|
|
10:num/raw <- find-next x, y, 0
|
2015-06-19 19:28:36 +00:00
|
|
|
]
|
|
|
|
memory-should-contain [
|
2016-05-26 17:24:47 +00:00
|
|
|
10 <- 2
|
2015-06-19 19:28:36 +00:00
|
|
|
]
|
|
|
|
]
|
|
|
|
|
2015-11-21 18:01:12 +00:00
|
|
|
scenario find-next-suffix-match-2 [
|
2016-09-29 02:48:56 +00:00
|
|
|
local-scope
|
|
|
|
x:text <- new [abcd]
|
|
|
|
y:text <- new [cde]
|
2015-06-19 19:28:36 +00:00
|
|
|
run [
|
2016-09-17 17:28:25 +00:00
|
|
|
10:num/raw <- find-next x, y, 0
|
2015-06-19 19:28:36 +00:00
|
|
|
]
|
|
|
|
memory-should-contain [
|
2016-05-26 17:24:47 +00:00
|
|
|
10 <- 4 # not found
|
2015-06-19 19:28:36 +00:00
|
|
|
]
|
|
|
|
]
|
|
|
|
|
2015-11-21 18:01:12 +00:00
|
|
|
# checks if pattern matches at index 'idx'
|
2016-09-17 17:30:24 +00:00
|
|
|
def match-at text:text, pattern:text, idx:num -> result:bool [
|
2015-07-14 05:43:16 +00:00
|
|
|
local-scope
|
2015-11-19 05:36:36 +00:00
|
|
|
load-ingredients
|
2016-09-17 17:28:25 +00:00
|
|
|
pattern-len:num <- length *pattern
|
2015-06-19 19:28:36 +00:00
|
|
|
# check that there's space left for the pattern
|
2017-09-24 01:31:26 +00:00
|
|
|
x:num <- length *text
|
|
|
|
x <- subtract x, pattern-len
|
|
|
|
enough-room?:bool <- lesser-or-equal idx, x
|
|
|
|
return-unless enough-room?, 0/not-found
|
2015-06-19 19:28:36 +00:00
|
|
|
# check each character of pattern
|
2016-09-17 17:28:25 +00:00
|
|
|
pattern-idx:num <- copy 0
|
2015-06-19 19:28:36 +00:00
|
|
|
{
|
2016-09-17 17:30:24 +00:00
|
|
|
done?:bool <- greater-or-equal pattern-idx, pattern-len
|
2015-07-29 21:37:57 +00:00
|
|
|
break-if done?
|
2016-09-17 07:31:55 +00:00
|
|
|
c:char <- index *text, idx
|
|
|
|
exp:char <- index *pattern, pattern-idx
|
2017-09-24 01:31:26 +00:00
|
|
|
match?:bool <- equal c, exp
|
|
|
|
return-unless match?, 0/not-found
|
2015-07-29 21:37:57 +00:00
|
|
|
idx <- add idx, 1
|
|
|
|
pattern-idx <- add pattern-idx, 1
|
2015-06-19 19:28:36 +00:00
|
|
|
loop
|
|
|
|
}
|
2016-03-08 09:30:14 +00:00
|
|
|
return 1/found
|
2015-06-19 19:28:36 +00:00
|
|
|
]
|
|
|
|
|
2015-11-21 18:01:12 +00:00
|
|
|
scenario match-at-checks-pattern-at-index [
|
2016-09-29 02:48:56 +00:00
|
|
|
local-scope
|
|
|
|
x:text <- new [abc]
|
|
|
|
y:text <- new [ab]
|
2015-06-19 19:28:36 +00:00
|
|
|
run [
|
2016-09-17 17:30:24 +00:00
|
|
|
10:bool/raw <- match-at x, y, 0
|
2015-06-19 19:28:36 +00:00
|
|
|
]
|
|
|
|
memory-should-contain [
|
2016-05-26 17:24:47 +00:00
|
|
|
10 <- 1 # match found
|
2015-06-19 19:28:36 +00:00
|
|
|
]
|
|
|
|
]
|
|
|
|
|
|
|
|
scenario match-at-reflexive [
|
2016-09-29 02:48:56 +00:00
|
|
|
local-scope
|
|
|
|
x:text <- new [abc]
|
2015-06-19 19:28:36 +00:00
|
|
|
run [
|
2016-09-17 17:30:24 +00:00
|
|
|
10:bool/raw <- match-at x, x, 0
|
2015-06-19 19:28:36 +00:00
|
|
|
]
|
|
|
|
memory-should-contain [
|
2016-05-26 17:24:47 +00:00
|
|
|
10 <- 1 # match found
|
2015-06-19 19:28:36 +00:00
|
|
|
]
|
|
|
|
]
|
|
|
|
|
|
|
|
scenario match-at-outside-bounds [
|
2016-09-29 02:48:56 +00:00
|
|
|
local-scope
|
|
|
|
x:text <- new [abc]
|
|
|
|
y:text <- new [a]
|
2015-06-19 19:28:36 +00:00
|
|
|
run [
|
2016-09-17 17:30:24 +00:00
|
|
|
10:bool/raw <- match-at x, y, 4
|
2015-06-19 19:28:36 +00:00
|
|
|
]
|
|
|
|
memory-should-contain [
|
2016-05-26 17:24:47 +00:00
|
|
|
10 <- 0 # never matches
|
2015-06-19 19:28:36 +00:00
|
|
|
]
|
|
|
|
]
|
|
|
|
|
|
|
|
scenario match-at-empty-pattern [
|
2016-09-29 02:48:56 +00:00
|
|
|
local-scope
|
|
|
|
x:text <- new [abc]
|
|
|
|
y:text <- new []
|
2015-06-19 19:28:36 +00:00
|
|
|
run [
|
2016-09-17 17:30:24 +00:00
|
|
|
10:bool/raw <- match-at x, y, 0
|
2015-06-19 19:28:36 +00:00
|
|
|
]
|
|
|
|
memory-should-contain [
|
2016-05-26 17:24:47 +00:00
|
|
|
10 <- 1 # always matches empty pattern given a valid index
|
2015-06-19 19:28:36 +00:00
|
|
|
]
|
|
|
|
]
|
|
|
|
|
|
|
|
scenario match-at-empty-pattern-outside-bound [
|
2016-09-29 02:48:56 +00:00
|
|
|
local-scope
|
|
|
|
x:text <- new [abc]
|
|
|
|
y:text <- new []
|
2015-06-19 19:28:36 +00:00
|
|
|
run [
|
2016-09-17 17:30:24 +00:00
|
|
|
10:bool/raw <- match-at x, y, 4
|
2015-06-19 19:28:36 +00:00
|
|
|
]
|
|
|
|
memory-should-contain [
|
2016-05-26 17:24:47 +00:00
|
|
|
10 <- 0 # no match
|
2015-06-19 19:28:36 +00:00
|
|
|
]
|
|
|
|
]
|
|
|
|
|
|
|
|
scenario match-at-empty-text [
|
2016-09-29 02:48:56 +00:00
|
|
|
local-scope
|
|
|
|
x:text <- new []
|
|
|
|
y:text <- new [abc]
|
2015-06-19 19:28:36 +00:00
|
|
|
run [
|
2016-09-17 17:30:24 +00:00
|
|
|
10:bool/raw <- match-at x, y, 0
|
2015-06-19 19:28:36 +00:00
|
|
|
]
|
|
|
|
memory-should-contain [
|
2016-05-26 17:24:47 +00:00
|
|
|
10 <- 0 # no match
|
2015-06-19 19:28:36 +00:00
|
|
|
]
|
|
|
|
]
|
|
|
|
|
|
|
|
scenario match-at-empty-against-empty [
|
2016-09-29 02:48:56 +00:00
|
|
|
local-scope
|
|
|
|
x:text <- new []
|
2015-06-19 19:28:36 +00:00
|
|
|
run [
|
2016-09-17 17:30:24 +00:00
|
|
|
10:bool/raw <- match-at x, x, 0
|
2015-06-19 19:28:36 +00:00
|
|
|
]
|
|
|
|
memory-should-contain [
|
2016-05-26 17:24:47 +00:00
|
|
|
10 <- 1 # matches because pattern is also empty
|
2015-06-19 19:28:36 +00:00
|
|
|
]
|
|
|
|
]
|
|
|
|
|
|
|
|
scenario match-at-inside-bounds [
|
2016-09-29 02:48:56 +00:00
|
|
|
local-scope
|
|
|
|
x:text <- new [abc]
|
|
|
|
y:text <- new [bc]
|
2015-06-19 19:28:36 +00:00
|
|
|
run [
|
2016-09-17 17:30:24 +00:00
|
|
|
10:bool/raw <- match-at x, y, 1
|
2015-06-19 19:28:36 +00:00
|
|
|
]
|
|
|
|
memory-should-contain [
|
2016-05-26 17:24:47 +00:00
|
|
|
10 <- 1 # match
|
2015-06-19 19:28:36 +00:00
|
|
|
]
|
|
|
|
]
|
|
|
|
|
|
|
|
scenario match-at-inside-bounds-2 [
|
2016-09-29 02:48:56 +00:00
|
|
|
local-scope
|
|
|
|
x:text <- new [abc]
|
|
|
|
y:text <- new [bc]
|
2015-06-19 19:28:36 +00:00
|
|
|
run [
|
2016-09-17 17:30:24 +00:00
|
|
|
10:bool/raw <- match-at x, y, 0
|
2015-06-19 19:28:36 +00:00
|
|
|
]
|
|
|
|
memory-should-contain [
|
2016-05-26 17:24:47 +00:00
|
|
|
10 <- 0 # no match
|
2015-06-19 19:28:36 +00:00
|
|
|
]
|
|
|
|
]
|
|
|
|
|
2016-09-17 20:00:39 +00:00
|
|
|
def split s:text, delim:char -> result:&:@:text [
|
2015-07-14 05:43:16 +00:00
|
|
|
local-scope
|
2015-11-19 05:36:36 +00:00
|
|
|
load-ingredients
|
2015-11-21 18:01:12 +00:00
|
|
|
# empty text? return empty array
|
2016-09-17 17:28:25 +00:00
|
|
|
len:num <- length *s
|
2015-06-19 19:28:36 +00:00
|
|
|
{
|
2016-09-17 17:30:24 +00:00
|
|
|
empty?:bool <- equal len, 0
|
2015-07-29 21:37:57 +00:00
|
|
|
break-unless empty?
|
2016-04-24 18:54:30 +00:00
|
|
|
result <- new {(address array character): type}, 0
|
2016-03-08 09:30:14 +00:00
|
|
|
return
|
2015-06-19 19:28:36 +00:00
|
|
|
}
|
|
|
|
# count #pieces we need room for
|
2016-09-17 17:28:25 +00:00
|
|
|
count:num <- copy 1 # n delimiters = n+1 pieces
|
|
|
|
idx:num <- copy 0
|
2015-06-19 19:28:36 +00:00
|
|
|
{
|
2015-07-29 21:37:57 +00:00
|
|
|
idx <- find-next s, delim, idx
|
2016-09-17 17:30:24 +00:00
|
|
|
done?:bool <- greater-or-equal idx, len
|
2015-07-29 21:37:57 +00:00
|
|
|
break-if done?
|
|
|
|
idx <- add idx, 1
|
|
|
|
count <- add count, 1
|
2015-06-19 19:28:36 +00:00
|
|
|
loop
|
|
|
|
}
|
|
|
|
# allocate space
|
2016-04-24 18:54:30 +00:00
|
|
|
result <- new {(address array character): type}, count
|
2015-06-19 19:28:36 +00:00
|
|
|
# repeatedly copy slices start..end until delimiter into result[curr-result]
|
2016-09-17 17:28:25 +00:00
|
|
|
curr-result:num <- copy 0
|
|
|
|
start:num <- copy 0
|
2015-06-19 19:28:36 +00:00
|
|
|
{
|
|
|
|
# while next delim exists
|
2016-09-17 17:30:24 +00:00
|
|
|
done?:bool <- greater-or-equal start, len
|
2015-07-29 21:37:57 +00:00
|
|
|
break-if done?
|
2016-09-17 17:28:25 +00:00
|
|
|
end:num <- find-next s, delim, start
|
2015-06-19 19:28:36 +00:00
|
|
|
# copy start..end into result[curr-result]
|
2016-09-12 07:06:40 +00:00
|
|
|
dest:text <- copy-range s, start, end
|
2016-04-23 21:51:20 +00:00
|
|
|
*result <- put-index *result, curr-result, dest
|
2015-06-19 19:28:36 +00:00
|
|
|
# slide over to next slice
|
2015-07-29 21:37:57 +00:00
|
|
|
start <- add end, 1
|
|
|
|
curr-result <- add curr-result, 1
|
2015-06-19 19:28:36 +00:00
|
|
|
loop
|
|
|
|
}
|
|
|
|
]
|
|
|
|
|
2015-11-21 18:01:12 +00:00
|
|
|
scenario text-split-1 [
|
2016-09-29 02:48:56 +00:00
|
|
|
local-scope
|
|
|
|
x:text <- new [a/b]
|
2015-06-19 19:28:36 +00:00
|
|
|
run [
|
2016-09-17 20:00:39 +00:00
|
|
|
y:&:@:text <- split x, 47/slash
|
2016-09-17 17:28:25 +00:00
|
|
|
10:num/raw <- length *y
|
2016-09-12 07:06:40 +00:00
|
|
|
a:text <- index *y, 0
|
|
|
|
b:text <- index *y, 1
|
2016-09-17 20:00:39 +00:00
|
|
|
20:@:char/raw <- copy *a
|
|
|
|
30:@:char/raw <- copy *b
|
2015-06-19 19:28:36 +00:00
|
|
|
]
|
|
|
|
memory-should-contain [
|
2016-05-26 17:24:47 +00:00
|
|
|
10 <- 2 # length of result
|
|
|
|
20:array:character <- [a]
|
|
|
|
30:array:character <- [b]
|
2015-06-19 19:28:36 +00:00
|
|
|
]
|
|
|
|
]
|
|
|
|
|
2015-11-21 18:01:12 +00:00
|
|
|
scenario text-split-2 [
|
2016-09-29 02:48:56 +00:00
|
|
|
local-scope
|
|
|
|
x:text <- new [a/b/c]
|
2015-06-19 19:28:36 +00:00
|
|
|
run [
|
2016-09-17 20:00:39 +00:00
|
|
|
y:&:@:text <- split x, 47/slash
|
2016-09-17 17:28:25 +00:00
|
|
|
10:num/raw <- length *y
|
2016-09-12 07:06:40 +00:00
|
|
|
a:text <- index *y, 0
|
|
|
|
b:text <- index *y, 1
|
|
|
|
c:text <- index *y, 2
|
2016-09-17 20:00:39 +00:00
|
|
|
20:@:char/raw <- copy *a
|
|
|
|
30:@:char/raw <- copy *b
|
|
|
|
40:@:char/raw <- copy *c
|
2015-06-19 19:28:36 +00:00
|
|
|
]
|
|
|
|
memory-should-contain [
|
2016-05-26 17:24:47 +00:00
|
|
|
10 <- 3 # length of result
|
|
|
|
20:array:character <- [a]
|
|
|
|
30:array:character <- [b]
|
|
|
|
40:array:character <- [c]
|
2015-06-19 19:28:36 +00:00
|
|
|
]
|
|
|
|
]
|
|
|
|
|
2015-11-21 18:01:12 +00:00
|
|
|
scenario text-split-missing [
|
2016-09-29 02:48:56 +00:00
|
|
|
local-scope
|
|
|
|
x:text <- new [abc]
|
2015-06-19 19:28:36 +00:00
|
|
|
run [
|
2016-09-17 20:00:39 +00:00
|
|
|
y:&:@:text <- split x, 47/slash
|
2016-09-17 17:28:25 +00:00
|
|
|
10:num/raw <- length *y
|
2016-09-12 07:06:40 +00:00
|
|
|
a:text <- index *y, 0
|
2016-09-17 20:00:39 +00:00
|
|
|
20:@:char/raw <- copy *a
|
2015-06-19 19:28:36 +00:00
|
|
|
]
|
|
|
|
memory-should-contain [
|
2016-05-26 17:24:47 +00:00
|
|
|
10 <- 1 # length of result
|
|
|
|
20:array:character <- [abc]
|
2015-06-19 19:28:36 +00:00
|
|
|
]
|
|
|
|
]
|
|
|
|
|
2015-11-21 18:01:12 +00:00
|
|
|
scenario text-split-empty [
|
2016-09-29 02:48:56 +00:00
|
|
|
local-scope
|
|
|
|
x:text <- new []
|
2015-06-19 19:28:36 +00:00
|
|
|
run [
|
2016-09-17 20:00:39 +00:00
|
|
|
y:&:@:text <- split x, 47/slash
|
2016-09-17 17:28:25 +00:00
|
|
|
10:num/raw <- length *y
|
2015-06-19 19:28:36 +00:00
|
|
|
]
|
|
|
|
memory-should-contain [
|
2016-05-26 17:24:47 +00:00
|
|
|
10 <- 0 # empty result
|
2015-06-19 19:28:36 +00:00
|
|
|
]
|
|
|
|
]
|
|
|
|
|
2015-11-21 18:01:12 +00:00
|
|
|
scenario text-split-empty-piece [
|
2016-09-29 02:48:56 +00:00
|
|
|
local-scope
|
|
|
|
x:text <- new [a/b//c]
|
2015-06-19 19:28:36 +00:00
|
|
|
run [
|
2016-09-17 20:00:39 +00:00
|
|
|
y:&:@:text <- split x:text, 47/slash
|
2016-09-17 17:28:25 +00:00
|
|
|
10:num/raw <- length *y
|
2016-09-12 07:06:40 +00:00
|
|
|
a:text <- index *y, 0
|
|
|
|
b:text <- index *y, 1
|
|
|
|
c:text <- index *y, 2
|
|
|
|
d:text <- index *y, 3
|
2016-09-17 20:00:39 +00:00
|
|
|
20:@:char/raw <- copy *a
|
|
|
|
30:@:char/raw <- copy *b
|
|
|
|
40:@:char/raw <- copy *c
|
|
|
|
50:@:char/raw <- copy *d
|
2015-06-19 19:28:36 +00:00
|
|
|
]
|
|
|
|
memory-should-contain [
|
2016-05-26 17:24:47 +00:00
|
|
|
10 <- 4 # length of result
|
|
|
|
20:array:character <- [a]
|
|
|
|
30:array:character <- [b]
|
|
|
|
40:array:character <- []
|
|
|
|
50:array:character <- [c]
|
2015-06-19 19:28:36 +00:00
|
|
|
]
|
|
|
|
]
|
|
|
|
|
2016-09-17 07:31:55 +00:00
|
|
|
def split-first text:text, delim:char -> x:text, y:text [
|
2015-07-14 05:43:16 +00:00
|
|
|
local-scope
|
2015-11-19 05:36:36 +00:00
|
|
|
load-ingredients
|
2015-11-21 18:01:12 +00:00
|
|
|
# empty text? return empty texts
|
2016-09-17 17:28:25 +00:00
|
|
|
len:num <- length *text
|
2015-06-19 19:28:36 +00:00
|
|
|
{
|
2016-09-17 17:30:24 +00:00
|
|
|
empty?:bool <- equal len, 0
|
2015-07-29 21:37:57 +00:00
|
|
|
break-unless empty?
|
2016-09-12 07:06:40 +00:00
|
|
|
x:text <- new []
|
|
|
|
y:text <- new []
|
2016-03-08 09:30:14 +00:00
|
|
|
return
|
2015-06-19 19:28:36 +00:00
|
|
|
}
|
2016-09-17 17:28:25 +00:00
|
|
|
idx:num <- find-next text, delim, 0
|
2016-09-12 07:06:40 +00:00
|
|
|
x:text <- copy-range text, 0, idx
|
2015-07-29 21:37:57 +00:00
|
|
|
idx <- add idx, 1
|
2016-09-12 07:06:40 +00:00
|
|
|
y:text <- copy-range text, idx, len
|
2015-06-19 19:28:36 +00:00
|
|
|
]
|
|
|
|
|
2015-11-21 18:01:12 +00:00
|
|
|
scenario text-split-first [
|
2016-09-29 02:48:56 +00:00
|
|
|
local-scope
|
|
|
|
x:text <- new [a/b]
|
2015-06-19 19:28:36 +00:00
|
|
|
run [
|
2016-09-12 07:06:40 +00:00
|
|
|
y:text, z:text <- split-first x, 47/slash
|
2016-09-17 20:00:39 +00:00
|
|
|
10:@:char/raw <- copy *y
|
|
|
|
20:@:char/raw <- copy *z
|
2015-06-19 19:28:36 +00:00
|
|
|
]
|
|
|
|
memory-should-contain [
|
2015-11-21 17:26:30 +00:00
|
|
|
10:array:character <- [a]
|
|
|
|
20:array:character <- [b]
|
2015-06-19 19:28:36 +00:00
|
|
|
]
|
|
|
|
]
|
|
|
|
|
2016-09-17 17:28:25 +00:00
|
|
|
def copy-range buf:text, start:num, end:num -> result:text [
|
2015-07-14 05:43:16 +00:00
|
|
|
local-scope
|
2015-11-19 05:36:36 +00:00
|
|
|
load-ingredients
|
2015-06-19 19:28:36 +00:00
|
|
|
# if end is out of bounds, trim it
|
2016-09-17 17:28:25 +00:00
|
|
|
len:num <- length *buf
|
|
|
|
end:num <- min len, end
|
2015-06-19 19:28:36 +00:00
|
|
|
# allocate space for result
|
2015-07-29 21:37:57 +00:00
|
|
|
len <- subtract end, start
|
2016-09-12 07:06:40 +00:00
|
|
|
result:text <- new character:type, len
|
2015-06-19 19:28:36 +00:00
|
|
|
# copy start..end into result[curr-result]
|
2016-09-17 17:28:25 +00:00
|
|
|
src-idx:num <- copy start
|
|
|
|
dest-idx:num <- copy 0
|
2015-06-19 19:28:36 +00:00
|
|
|
{
|
2016-09-17 17:30:24 +00:00
|
|
|
done?:bool <- greater-or-equal src-idx, end
|
2015-07-29 21:37:57 +00:00
|
|
|
break-if done?
|
2016-09-17 07:31:55 +00:00
|
|
|
src:char <- index *buf, src-idx
|
2016-04-23 21:51:20 +00:00
|
|
|
*result <- put-index *result, dest-idx, src
|
2015-07-29 21:37:57 +00:00
|
|
|
src-idx <- add src-idx, 1
|
|
|
|
dest-idx <- add dest-idx, 1
|
2015-06-19 19:28:36 +00:00
|
|
|
loop
|
|
|
|
}
|
|
|
|
]
|
|
|
|
|
2016-09-29 02:48:56 +00:00
|
|
|
scenario copy-range-works [
|
|
|
|
local-scope
|
|
|
|
x:text <- new [abc]
|
2015-06-19 19:28:36 +00:00
|
|
|
run [
|
2016-09-12 07:06:40 +00:00
|
|
|
y:text <- copy-range x, 1, 3
|
2016-09-17 20:00:39 +00:00
|
|
|
1:@:char/raw <- copy *y
|
2015-06-19 19:28:36 +00:00
|
|
|
]
|
|
|
|
memory-should-contain [
|
2016-05-26 17:08:25 +00:00
|
|
|
1:array:character <- [bc]
|
2015-06-19 19:28:36 +00:00
|
|
|
]
|
|
|
|
]
|
|
|
|
|
2016-09-29 02:48:56 +00:00
|
|
|
scenario copy-range-out-of-bounds [
|
|
|
|
local-scope
|
|
|
|
x:text <- new [abc]
|
2015-06-19 19:28:36 +00:00
|
|
|
run [
|
2016-09-12 07:06:40 +00:00
|
|
|
y:text <- copy-range x, 2, 4
|
2016-09-17 20:00:39 +00:00
|
|
|
1:@:char/raw <- copy *y
|
2015-06-19 19:28:36 +00:00
|
|
|
]
|
|
|
|
memory-should-contain [
|
2016-05-26 17:08:25 +00:00
|
|
|
1:array:character <- [c]
|
2015-06-19 19:28:36 +00:00
|
|
|
]
|
|
|
|
]
|
|
|
|
|
2016-09-29 02:48:56 +00:00
|
|
|
scenario copy-range-out-of-bounds-2 [
|
|
|
|
local-scope
|
|
|
|
x:text <- new [abc]
|
2015-06-19 19:28:36 +00:00
|
|
|
run [
|
2016-09-12 07:06:40 +00:00
|
|
|
y:text <- copy-range x, 3, 3
|
2016-09-17 20:00:39 +00:00
|
|
|
1:@:char/raw <- copy *y
|
2015-06-19 19:28:36 +00:00
|
|
|
]
|
|
|
|
memory-should-contain [
|
2016-05-26 17:08:25 +00:00
|
|
|
1:array:character <- []
|
2015-06-19 19:28:36 +00:00
|
|
|
]
|
|
|
|
]
|
2016-11-12 07:34:50 +00:00
|
|
|
|
|
|
|
def parse-whole-number in:text -> out:num, error?:bool [
|
|
|
|
local-scope
|
|
|
|
load-ingredients
|
2016-11-14 03:27:12 +00:00
|
|
|
out <- copy 0
|
2016-11-12 07:34:50 +00:00
|
|
|
result:num <- copy 0 # temporary location
|
|
|
|
i:num <- copy 0
|
|
|
|
len:num <- length *in
|
|
|
|
{
|
|
|
|
done?:bool <- greater-or-equal i, len
|
|
|
|
break-if done?
|
|
|
|
c:char <- index *in, i
|
|
|
|
x:num <- character-to-code c
|
|
|
|
digit:num, error?:bool <- character-code-to-digit x
|
2017-03-12 08:08:41 +00:00
|
|
|
return-if error?
|
2016-11-12 07:34:50 +00:00
|
|
|
result <- multiply result, 10
|
|
|
|
result <- add result, digit
|
|
|
|
i <- add i, 1
|
|
|
|
loop
|
|
|
|
}
|
|
|
|
# no error; all digits were valid
|
|
|
|
out <- copy result
|
|
|
|
]
|
|
|
|
|
|
|
|
# (contributed by Ella Couch)
|
2016-11-13 17:28:00 +00:00
|
|
|
recipe character-code-to-digit character-code:number -> result:number, error?:boolean [
|
2016-11-12 07:34:50 +00:00
|
|
|
local-scope
|
|
|
|
load-ingredients
|
|
|
|
result <- copy 0
|
2016-11-13 17:28:00 +00:00
|
|
|
error? <- lesser-than character-code, 48 # '0'
|
2017-03-12 08:08:41 +00:00
|
|
|
return-if error?
|
2016-11-13 17:28:00 +00:00
|
|
|
error? <- greater-than character-code, 57 # '9'
|
2017-03-12 08:08:41 +00:00
|
|
|
return-if error?
|
2016-11-12 07:34:50 +00:00
|
|
|
result <- subtract character-code, 48
|
|
|
|
]
|
|
|
|
|
|
|
|
scenario character-code-to-digit-contain-only-digit [
|
|
|
|
local-scope
|
|
|
|
a:number <- copy 48 # character code for '0'
|
|
|
|
run [
|
|
|
|
10:number/raw, 11:boolean/raw <- character-code-to-digit a
|
|
|
|
]
|
|
|
|
memory-should-contain [
|
|
|
|
10 <- 0
|
|
|
|
11 <- 0 # no error
|
|
|
|
]
|
|
|
|
]
|
|
|
|
|
|
|
|
scenario character-code-to-digit-contain-only-digit-2 [
|
|
|
|
local-scope
|
|
|
|
a:number <- copy 57 # character code for '9'
|
|
|
|
run [
|
|
|
|
1:number/raw, 2:boolean/raw <- character-code-to-digit a
|
|
|
|
]
|
|
|
|
memory-should-contain [
|
|
|
|
1 <- 9
|
|
|
|
2 <- 0 # no error
|
|
|
|
]
|
|
|
|
]
|
|
|
|
|
|
|
|
scenario character-code-to-digit-handles-codes-lower-than-zero [
|
|
|
|
local-scope
|
|
|
|
a:number <- copy 47
|
|
|
|
run [
|
|
|
|
10:number/raw, 11:boolean/raw <- character-code-to-digit a
|
|
|
|
]
|
|
|
|
memory-should-contain [
|
|
|
|
10 <- 0
|
|
|
|
11 <- 1 # error
|
|
|
|
]
|
|
|
|
]
|
|
|
|
|
|
|
|
scenario character-code-to-digit-handles-codes-larger-than-nine [
|
|
|
|
local-scope
|
|
|
|
a:number <- copy 58
|
|
|
|
run [
|
|
|
|
10:number/raw, 11:boolean/raw <- character-code-to-digit a
|
|
|
|
]
|
|
|
|
memory-should-contain [
|
|
|
|
10 <- 0
|
|
|
|
11 <- 1 # error
|
|
|
|
]
|
|
|
|
]
|