Skip to content

Commit

Permalink
#234 Added new func to std_seq.go. (#240)
Browse files Browse the repository at this point in the history
1. Updated `seq` library to add functions that are used for manipulating sequenced data structures including string and array. These functions are: `contains`, `has_prefix`, `has_suffix`, `sub`, `split` and `join`.
2. Changed some APIs signature, like changed `//seq.sub(subject, old, new)` to `//seq.sub(old, new, subject)`. It can help to support following code:
```
let rmspace = //seq.sub(" ", "");
rmspace("hello world"), rmspace("a b c")]
```
  • Loading branch information
ericzhang6222 authored May 25, 2020
1 parent c9f4306 commit 8cbfbb2
Show file tree
Hide file tree
Showing 22 changed files with 962 additions and 177 deletions.
2 changes: 1 addition & 1 deletion docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -432,7 +432,7 @@ External libraries may be accessed via package references.
1. **`//math`:** math functions and constants such as `//math.sin`
and `//math.pi`.
2. **`//str`:** string functions such as `//str.upper` and
`//str.join`.
`//str.lower`.
3. **`//fn`:** higher order functions such as `//fn.fix` and `//fn.fixt`.
See the [standard library reference](std.md) for full documentation on all packages.
2. **`//{./path}`** provides access to other arrai files relative to the current
Expand Down
86 changes: 83 additions & 3 deletions docs/std-seq.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,101 @@
# seq

The `seq` library contains functions that are used for string manipulations.
The `seq` library contains functions that are used for manipulating sequenced data structures including string and array.

## `//seq.concat(seqs <: array) <: array` <br/> `concat(seqs <: string) <: string`
## `//seq.concat(seqs <: array) <: array` <br/> `//seq.concat(seqs <: string) <: string`

`concat` takes an array of sequences `seqs` and returns a sequence that is
the concatenation of the sequences in the array.

Usage:
| example | equals |
|:-|:-|
| `//seq.concat(["ba", "na", "na"])` | `"banana"` |
| `//seq.concat([[1, 2], [3, 4, 5]])` | `[1, 2, 3, 4, 5]` |

## `//seq.repeat(n <: number, seq <: array) <: array` <br/> `repeat(n <: number, seq <: string) <: string`
## `//seq.contains(sub <: array, subject <: array) <: bool` <br/> `//seq.contains(sub <: string, subject <: string) <: bool`

`contains` checks whether sequence `sub` is contained in sequence `subject` and returns true if it is, or false otherwise.

Usage:
| example | equals |
|:-|:-|
| `//seq.contains("substring", "the full string which has substring")` | `true` |
| `//seq.contains("microwave", "just some random sentence")` | `false` |
| `//seq.contains([1,2,3,4,5], [1,2,3,4,5])` | `true` |
| `//seq.contains([['B','C']],[['A', 'B'], ['B','C'],['D','E']])` | `true` |

## `//seq.has_prefix(prefix <: array, subject <: array) <: bool` <br/> `//seq.has_prefix(prefix <: string, subject <: string) <: bool`

`has_prefix` checks whether the sequence `subject` is prefixed by sequence `prefix` and returns true if it is, or false otherwise.

Usage:
| example | equals |
|:-|:-|
| `//seq.has_prefix("I'm", "I'm running out of stuff to write")` | `true` |
| `//seq.has_prefix("to write", "I'm running out of stuff to write")` | `false` |
| `//seq.has_prefix(['A'],['A','B','C'])` | `true` |
| `//seq.has_prefix([1, 2],[1, 2, 3])` | `true` |
| `//seq.has_prefix([[1, 2]],[[1, 2], [3]])` | `true` |


## `//seq.has_suffix(suffix <: array, subject <: array) <: bool` <br/> `//seq.has_suffix(suffix <: string, subject <: string) <: bool`

`has_suffix` checks whether the sequence `subject` is suffixed by sequence `suffix` and returns true if it is, or false otherwise.

Usage:
| example | equals |
|:-|:-|
| `//seq.has_suffix("I'm", "I'm running out of stuff to write")` | `false` |
| `//seq.has_suffix("to write", "I'm running out of stuff to write")` | `true` |
| `//seq.has_suffix(['E'],['A','B','C','D','E'])` | `true` |
| `//seq.has_suffix([[3, 4]],[[1 ,2], [3, 4]])` | `true` |

## `//seq.join(joiner <: array, subject <: array) <: array` <br/> `//seq.join(joiner <: string, subject <: array_of_string) <: string`

`join` returns a concatenated sequence with each member of sequence `subject` delimited by sequence `joiner`

Usage:
| example | equals |
|:-|:-|
| `//seq.join(", ", ["pew", "another pew", "and more pews"])` | `"pew, another pew, and more pews"` |
| `//seq.join(" ", ["this", "is", "a", "sentence"])` | `"this is a sentence"` |
| `//seq.join(["", "this", "is", "a", "sentence"])` | `"thisisasentence"` |
| `//seq.join([0], [[1, 2], [3, 4], [5, 6]]` | `[1, 2, 0, 3, 4, 0, 5, 6]`
| `//seq.join([0], [[2, [3, 4]], [5, 6]])` | `[2, [3, 4], 0, 5, 6]` |
| `//seq.join([[0],[1]], [[[1, 2], [3, 4]],[[5, 6],[7, 8]]])` | `[[1, 2], [3, 4], [0], [1], [5, 6], [7, 8]]` |

## `//seq.split(delimiter <: array, subject <: array) <: array` <br/> `//seq.split(delimiter <: string, subject <: string) <: array of string`

`split` splits sequence `subject` based on the provided sequence `delimiter`. It returns an array of sequence which are split from the sequence `subject`.

Usage:
| example | equals |
|:-|:-|
| `//seq.split(" ", "deliberately adding spaces to demonstrate the split function")` | `["deliberately", "adding", "spaces", "to", "demonstrate", "the", "split", "function"]` |
| `//seq.split("random stuff", "this is just a random sentence")` | `["this is just a random sentence"]` |
| `//seq.split([1],[1, 2, 3])` | `[[],[2,3]]` |
| `//seq.split([3],[1, 2, 3])` | `[[1,2],[]]` |
| `//seq.split(['A'],['B', 'A', 'C', 'A', 'D', 'E'])` | `[['B'],['C'], ['D', 'E']]` |
| `//seq.split([['C','D'],['E','F']],[['A','B'], ['C','D'], ['E','F'], ['G']])`) | `[[['A','B']], [['G']]]` |

## `//seq.sub(old <: array, new <: array, subject <: array) <: array` <br/> `//seq.sub(old <: string, new <: string, subject <: string) <: string`

`sub` replaces occurrences of sequence `old` in sequence `subject` with sequence `new`. It returns the modified sequence.

Usage:
| example | equals |
|:-|:-|
| `//seq.sub("old string", "new sentence", "this is the old string")` | `"this is the new sentence"` |
| `//seq.sub("string", "stuff", "just another sentence")` | `"just another sentence"` |
| `//seq.sub([1], [2], [1, 2, 3])` | `[2, 2, 3]` |
| `//seq.sub([[2,2]], [[4,4]], [[1,1], [2,2], [3,3]])`| `[[1,1], [4,4], [3,3]]` |

## `//seq.repeat(n <: number, seq <: array) <: array` <br/> `//seq.repeat(n <: number, seq <: string) <: string`

`repeat` returns a sequence that contains `seq` repeated `n` times.

Usage:
| example | equals |
|:-|:-|
| `//seq.repeat(2, "hots")` | `"hotshots"` |
69 changes: 0 additions & 69 deletions docs/std-str.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,41 +2,6 @@

The `str` library contains functions that are used for string manipulations.

## `//str.contains(str <: string, substr <: string) <: bool`

`contains` checks whether `substr` is contained in `str`. It returns a
boolean.

Usage:

| example | equals |
|:-|:-|
| `//str.contains("the full string which has substring", "substring")` | `true` |
| `//str.contains("just some random sentence", "microwave")` | `{}` which is equal to `false` |

## `//str.sub(s <: string, old <: string, new <: string) <: string`

`sub` replaces occurrences of `old` in `s` with `new`. It returns the modified string.

Usage:

| example | equals |
|:-|:-|
| `//str.sub("this is the old string", "old string", "new sentence")` | `"this is the new sentence"` |
| `//str.sub("just another sentence", "string", "stuff")` | `"just another sentence"` |

## `//str.split(s <: string, delimiter <: string) <: array of string`

`split` splits the string `s` based on the provided `delimiter`. It returns an array of strings
which are split from the string `s`.

Usage:

| example | equals |
|:-|:-|
| `//str.split("deliberately adding spaces to demonstrate the split function", " ")` | `["deliberately", "adding", "spaces", "to", "demonstrate", "the", "split", "function"]` |
| `//str.split("this is just a random sentence", "random stuff")` | `["this is just a random sentence"]` |

## `//str.lower(s <: string) <: string`

`lower` returns the string `s` with all of the character converted to lowercase.
Expand Down Expand Up @@ -72,37 +37,3 @@ Usage:
|:-|:-|
| `//str.title("laser noises pew pew pew")` | `"Laser Noises Pew Pew Pew"` |
| `//str.title("pew")` | `"Pew"` |

## `//str.has_prefix(s <: string, prefix <: string) <: bool`

`has_prefix` checks whether the string `s` is prefixed by `prefix`. It returns a boolean.

Usage:

| example | equals |
|:-|:-|
| `//str.has_prefix("I'm running out of stuff to write", "I'm")` | `true` |
| `//str.has_prefix("I'm running out of stuff to write", "to write")` | `{}` which is equal to `false` |

## `//str.has_suffix(s <: string, suffix <: string) <: bool`

`has_suffix` checks whether the string `s` is suffixed by `suffix`. It returns a boolean.

Usage:

| example | equals |
|:-|:-|
| `//str.has_suffix("I'm running out of stuff to write", "I'm")` | `{}` which is equal to `false` |
| `//str.has_suffix("I'm running out of stuff to write", "to write")` | `true` |

## `//str.join(s <: array_of_string, delimiter <: string) <: string`

`join` returns a concatenated string with each member of `s` delimited by `delimiter`

Usage:

| example | equals |
|:-|:-|
| `//str.join(["pew", "another pew", "and more pews"], ", ")` | `"pew, another pew, and more pews"` |
| `//str.join(["this", "is", "a", "sentence"], " ")` | `"this is a sentence"` |
| `//str.join(["this", "is", "a", "sentence"], "")` | `"thisisasentence"` |
12 changes: 6 additions & 6 deletions examples/grpc/grpc-proto.arrai
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
let grpc = //{./grpc};
let wrap = "wrap" <: app.attrs.patterns;
let proto = //{./proto-util}(wrap);
let endpoints = app.endpoints where !//str.has_prefix(.@item.name, "enum ");
let endpoints = app.endpoints where !//seq.has_prefix("enum ", .@item.name);
//archive.tar.tar({
app.name + ".proto": $`
// THIS IS AUTOGENERATED BY sysl //
Expand All @@ -24,8 +24,8 @@ let endpoints = app.endpoints where !//str.has_prefix(.@item.name, "enum ");
${cond (app.endpoints: $`
${//rel.union((endpoints >> (.params >>
cond (
//str.contains(grpc.type(.), "google.protobuf"): $`
import "${//str.sub(grpc.type(.), ".", "/")}.proto";`,
//seq.contains("google.protobuf", grpc.type(.)): $`
import "${//seq.sub(".", "/", grpc.type(.))}.proto";`,
) => .@item
)) => .@item)::\i:\n}
service ${app.name} {
Expand All @@ -37,14 +37,14 @@ let endpoints = app.endpoints where !//str.has_prefix(.@item.name, "enum ");
}`:::\n}
${endpoints >> proto.wrapSequence(.).grpcType::\i}
${cond (wrap: endpoints) >>
let retTokens = //str.split(ep.ret("ok"), " ");
let retName = //str.sub(//seq.concat(retTokens -- {"sequence", "of"}), ".", "");
let retTokens = //seq.split(" ", ep.ret("ok"));
let retName = //seq.sub(".", "", //seq.concat(retTokens -- {"sequence", "of"}));
let attr = ep.attrs(retName + "_rpcId");
let epi = proto.endpointInfo(ep);
$`
message ${epi.paramName} {
${ep.params >>
let name = //str.sub(.name, "-", "");
let name = //seq.sub("-", "", .name);
$`${grpc.type(.)} req${name} = ${.attrs(name + "_rpcId")};`
::\i}
}
Expand Down
2 changes: 1 addition & 1 deletion examples/grpc/grpc.arrai
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
),
'sequence': 'repeated ' + type(t.sequence)
*: cond (
//str.contains(t.type_ref, "google-protobuf"): //str.sub(t.type_ref, "-", "."),
//seq.contains("google-protobuf", t.type_ref): //seq.sub("-", ".", t.type_ref),
*: t.type_ref,
),
),
Expand Down
14 changes: 7 additions & 7 deletions examples/grpc/proto-util.arrai
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
let grpc = //{./grpc};

\wrap (
field: \. $`${grpc.type(.)} ${//str.sub(.key, "-", "")} = ${.attrs.rpcId};`,
field: \. $`${grpc.type(.)} ${//seq.sub("-", "", .key)} = ${.attrs.rpcId};`,

imports: \fields
fields where(//str.contains(grpc.type(.@item), "google.protobuf")) >>
$`import "${//str.sub(grpc.type(.), ".", "/")}.proto";`,
fields where(//seq.contains("google.protobuf", grpc.type(.@item))) >>
$`import "${//seq.sub(".", "/", grpc.type(.))}.proto";`,

endpointInfo: \ep
let method = //str.sub(//str.title(//str.lower(ep.name)), "-", "");
let method = //seq.sub("-", "", //str.title(//str.lower(ep.name)));
let paramName = cond (
wrap: method + "Request",
*: $"${ep.params >> grpc.type(.)::, }",
);
let streamRes = cond (
ep.attrs.stream: //str.sub(ep.ret("ok"), "sequence of", "stream"),
*: //str.sub(ep.ret("ok"), "sequence of ", "") + "s",
ep.attrs.stream: //seq.sub("sequence of", "stream", ep.ret("ok")),
*: //seq.sub("sequence of ", "", ep.ret("ok")) + "s",
);
let responseName = cond (wrap: method + "Response", *: streamRes);
(
Expand All @@ -26,7 +26,7 @@ let grpc = //{./grpc};
),

wrapSequence: \ep
let type = //str.sub(ep.ret("ok"), "sequence of ", "");
let type = //seq.sub("sequence of ", "", ep.ret("ok"));
let wrapType = type + "s";
let name = //str.lower(type) + "s";
(
Expand Down
2 changes: 1 addition & 1 deletion internal/shell/shell_cmd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ func TestIsCommand(t *testing.T) {
t.Parallel()

assert.True(t, isCommand("/hi"))
assert.False(t, isCommand("//str.join"))
assert.False(t, isCommand("//seq.join"))
}

func TestTryRunCommand(t *testing.T) {
Expand Down
12 changes: 6 additions & 6 deletions internal/shell/shell_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,12 +151,12 @@ func TestGetLastToken(t *testing.T) {
assert.Equal(t, "//str", getLastToken([]rune("//str")))
assert.Equal(t, "//", getLastToken([]rune("//")))
assert.Equal(t, "///", getLastToken([]rune("///")))
assert.Equal(t, "//", getLastToken([]rune("//str.contains(//")))
assert.Equal(t, "//arch", getLastToken([]rune("//str.contains(//arch")))
assert.Equal(t, "tuple.", getLastToken([]rune("//str.contains(tuple.")))
assert.Equal(t, "//", getLastToken([]rune("//seq.contains(//")))
assert.Equal(t, "//arch", getLastToken([]rune("//seq.contains(//arch")))
assert.Equal(t, "tuple.", getLastToken([]rune("//seq.contains(tuple.")))
assert.Equal(t, "x.", getLastToken([]rune("x.")))
assert.Equal(t, "x", getLastToken([]rune("x")))
assert.Equal(t, "", getLastToken([]rune("//str.contains(")))
assert.Equal(t, "", getLastToken([]rune("//seq.contains(")))
assert.Equal(t, "", getLastToken([]rune("")))
}

Expand All @@ -166,14 +166,14 @@ func TestTabCompletionStdlib(t *testing.T) {
stdlibNames := stdlib.Names().OrderedNames()

assertTabCompletion(t, append(stdlibNames, "{"), 0, "//\t", nil)
assertTabCompletion(t, append(stdlibNames, "{"), 0, "//str.contains(//\t", nil)
assertTabCompletion(t, append(stdlibNames, "{"), 0, "//seq.contains(//\t", nil)
prefix := "s"

assertTabCompletionWithPrefix(t, prefix, stdlibNames, "//%s\t", nil)
assertTabCompletionWithPrefix(t, prefix, stdlibNames, "x(//%s\t", nil)
assertTabCompletionWithPrefix(t, prefix, stdlibNames, "x(//%s\t + random)", nil)

lib := "str"
lib := "seq"
strlib := stdlib.MustGet(lib).(rel.Tuple).Names().OrderedNames()
assertTabCompletionWithPrefix(t, prefix, strlib, "//"+lib+".%s\t", nil)
for i := 0; i < len(strlib); i++ {
Expand Down
2 changes: 1 addition & 1 deletion rel/value_set_array.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ func (a Array) Kind() int {
return arrayKind
}

// Bool returns true iff the tuple has attributes.
// IsTrue returns true if the tuple has attributes.
func (a Array) IsTrue() bool {
return a.count > 0
}
Expand Down
Loading

0 comments on commit 8cbfbb2

Please sign in to comment.