Skip to content

Commit ed2e2ac

Browse files
author
Andy C
committed
[doc] Document (( vs ( ( parsing issue
And clarify $(( vs $( ( as well
1 parent cd41783 commit ed2e2ac

File tree

2 files changed

+103
-10
lines changed

2 files changed

+103
-10
lines changed

doc/known-differences.md

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,12 +88,14 @@ Undecidable](https://www.oilshell.org/blog/2016/10/20.html) (2016).
8888
- [OILS-ERR-101](error-catalog.html#oils-err-101) explains more ways to fix
8989
this.
9090

91-
### Subshell in command sub
91+
### Subshell in command sub - `$((` versus `$( (`
9292

93-
You can have a subshell in a command sub, but it usually doesn't make sense.
93+
You can have a subshell `(` in a command sub `$(`, but it usually doesn't make
94+
sense.
9495

95-
In OSH you need a space after `$(`. The characters `$((` always start an
96-
arith sub.
96+
In OSH you need a space after `$(`, so it would be `$( (`.
97+
98+
characters `$((` always start an arith sub.
9799

98100
No:
99101

@@ -105,6 +107,40 @@ Yes:
105107
$({ cd / && ls; }) # Use {} for grouping, not (). Note trailing ;
106108
$(cd / && ls) # Even better
107109

110+
### Nested Subshells - `((` versus `( (`
111+
112+
You should never need nested subshells with `((` in Bourne shell or Oils.
113+
114+
If you do, you should add a space with `( (` instead of `((`, similar to the
115+
issue above.
116+
117+
In OSH, `((` always starts bash-style arithmetic.
118+
119+
---
120+
121+
The only place I see `((` arise is when shell users try to use `( )` to mean
122+
**grouping**, because they are used to C or Python.
123+
124+
But it means **subshell**, not grouping. In shell, `{ }` is the way to group
125+
commands.
126+
127+
No:
128+
129+
if ((test -f a || test -f b) && grep foo c); then
130+
echo ok
131+
fi
132+
133+
Allowed, but not what you want:
134+
135+
if ( (test -f a || test -f b) && grep foo c); then
136+
echo ok
137+
fi
138+
139+
Yes:
140+
141+
if { test -f a || test -f b; } && grep foo c; then
142+
echo ok
143+
fi
108144

109145
### Extended glob vs. Negation of boolean expression
110146

stdlib/ysh/stream.ysh

Lines changed: 63 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,30 @@ proc test-slurp-by {
3131
seq 8 | slurp-by (3)
3232
}
3333

34-
# Note:
35-
# - these are all the same algorithm
36-
# - also word, block, etc. are all optional
34+
### Awk
35+
36+
# Naming
37+
#
38+
# TEXT INPUT
39+
# each-word # this doesn't go by lines, it does a global regex split or something?
40+
#
41+
# LINE INPUT
42+
# each-line --j8 { echo "-- $_line" } # similar to @()
43+
# each-line --j8 (^"-- $_line") # is this superfluous?
44+
#
45+
# each-split name1 name2
46+
# (delim=' ')
47+
# (ifs=' ')
48+
# (pat=/d+/)
49+
# # also assign names for each part?
50+
#
51+
# each-match # regex match
52+
# must-match # assert that every line matches
53+
#
54+
# TABLE INPUT
55+
# each-row # TSV and TSV8 input?
56+
#
57+
# They all take templates or blocks?
3758

3859
proc each-line (...words; template=null; ; block=null) {
3960
# TODO:
@@ -112,7 +133,9 @@ proc must-split-by (; ; ifs=null; block) {
112133
echo TODO
113134
}
114135

115-
proc if-match (; pattern; ; block) {
136+
# Naming: each-match, each-split?
137+
138+
proc if-match (; pattern, template=null; ; block=null) {
116139
### like 'grep' but with submatches
117140

118141
for line in (io.stdin) {
@@ -122,7 +145,14 @@ proc if-match (; pattern; ; block) {
122145
#var groups = m.groups()
123146

124147
# Should we also pass _line?
125-
call io->eval(block, dollar0=m.group(0))
148+
149+
if (block) {
150+
call io->eval(block, dollar0=m.group(0))
151+
} elif (template) {
152+
echo TEMPLATE
153+
} else {
154+
echo TSV
155+
}
126156
}
127157
}
128158

@@ -144,6 +174,8 @@ proc line-data {
144174
/// 42 bar'''
145175
}
146176

177+
const pat = /<capture d+> s+ <capture w+>/
178+
147179
proc test-if-match {
148180
var z = 'z' # test out scoping
149181
var count = 0 # test out mutation
@@ -153,7 +185,6 @@ proc test-if-match {
153185
# sed: print a new line based on submatches
154186
# awk: re-arrange the cols, and also accumulate counters
155187

156-
var pat = /<capture d+> s+ <capture w+>/
157188
line-data | if-match (pat) {
158189
echo "$z $0 $z"
159190
# TODO: need pos_args
@@ -165,6 +196,32 @@ proc test-if-match {
165196
echo "count = $count"
166197
}
167198

199+
proc test-if-match-2 {
200+
# If there's no block or template, it should print out a TSV with:
201+
#
202+
# $0 ...
203+
# $1 $2
204+
# $_line maybe?
205+
206+
#line-data | if-match (pat)
207+
208+
var z = 'z' # scoping
209+
line-data | if-match (pat, ^"$z $0 $z")
210+
line-data | if-match (pat, ^"-- $0 --")
211+
}
212+
213+
# might be a nice way to write it, not sure if byo.sh can discover it
214+
if false {
215+
tests 'if-match' {
216+
proc case-block {
217+
echo TODO
218+
}
219+
proc case-template {
220+
echo TODO
221+
}
222+
}
223+
}
224+
168225
# Protocol:
169226
#
170227
# - The file lists its tests the "actions"

0 commit comments

Comments
 (0)