1 | ---
|
2 | in_progress: yes
|
3 | css_files: ../../web/base.css ../../web/manual.css ../../web/toc.css
|
4 | ---
|
5 |
|
6 | List of Errors in the OSH Interpreter
|
7 | =====================================
|
8 |
|
9 | <div id="toc">
|
10 | </div>
|
11 |
|
12 | Parse Error:
|
13 | Can be determined statically
|
14 | spec/parse-errors.test.sh
|
15 |
|
16 |
|
17 |
|
18 | TODO: See test/runtime-errors.sh. Merge them here.
|
19 |
|
20 | ## Syntax Errors in Oil String Literals
|
21 |
|
22 | - `parse_backslash`
|
23 | - no octal
|
24 | - no `\z`
|
25 | - no `\u{invalid`
|
26 |
|
27 | - `parse_backticks`
|
28 | - use "$(echo hi)"` and not backticks
|
29 |
|
30 | ## Fatal vs. Non-Fatal
|
31 |
|
32 | Fatal Error:
|
33 | terminates the interpreter unconditionally, e.g. divide by zero does this in
|
34 | bash.
|
35 |
|
36 | Non-fatal error:
|
37 | terminates the current builtin and exits 1
|
38 |
|
39 | non-fatal errors can be turned into fatal errors.
|
40 |
|
41 | by Strict modes:
|
42 | set -o errexit
|
43 |
|
44 | strict modes can also things that are not errors at all into fatal errors
|
45 | set -o nounset
|
46 | set -o failglob
|
47 |
|
48 | Fatal errors can be turned into non-fatal ones!!!!
|
49 |
|
50 | by dparen:
|
51 |
|
52 | (( 1 / 0 ))
|
53 |
|
54 | by command sub -- although this involves another process so it's
|
55 | understandable!
|
56 |
|
57 | set -o errexit
|
58 | echo $(exit 1)
|
59 |
|
60 | ## Strict Modes
|
61 |
|
62 | strict_array
|
63 | strict_errexit
|
64 | strict_arith
|
65 |
|
66 | TODO: strict-word-eval?
|
67 | for unicode errors
|
68 | for subshell negative indices? I think this is most consistent right now.
|
69 |
|
70 |
|
71 | ## Parse Error API
|
72 |
|
73 | TODO:
|
74 |
|
75 | p_die() internally
|
76 |
|
77 |
|
78 | w = w_parser.ReadWord()
|
79 | if w is None:
|
80 | do something with w_parser.Error()
|
81 |
|
82 | Related to memory management API:
|
83 |
|
84 | # arena is the out param
|
85 | arena = pool.NewArena()
|
86 | c_parser = cmd_parse.CommandParser(w_parser, arena)
|
87 | bool ok = c_parser.Parse()
|
88 | if ok:
|
89 | arena.RootNode() # turns indexes into pointers?
|
90 | arena.Deallocate() # d
|
91 | else:
|
92 | c_parser.Error() # Is this still a stack?
|
93 |
|
94 | ## Runtime Error API: error codes + error contexts?
|
95 |
|
96 | Idea:
|
97 |
|
98 | - Should we have a table of errors for metaprogramming?
|
99 | - assign each one of these a code, and decide what to do based on a table?
|
100 | - then have an error CONTEXT
|
101 | - based on spec tests?
|
102 |
|
103 | - and error context takes an error code, looks it up in a table, and decides
|
104 | whether to catch or to reraise!
|
105 |
|
106 | List of contexts:
|
107 |
|
108 | - assignment a=$() exit code
|
109 | - command sub $()
|
110 | - subshell ()
|
111 | - pipeline? ls | { foo; exit 1; }
|
112 | - dparen (( )) vs. arith sub $(( ))
|
113 |
|
114 | ## Problem in bash: Context affects a lot
|
115 |
|
116 | echo $(( 1 / 0 ))
|
117 | echo 'after-$(())
|
118 | (( 1 / 0 ))
|
119 | echo 'after-$(())
|
120 |
|
121 |
|
122 | ## Arith Eval
|
123 |
|
124 | Divide by zero: $(( 1 / 0 ))
|
125 |
|
126 | ^
|
127 | Maybe: integer overflow. But we want big numbers.
|
128 |
|
129 | Type errors between integers and strings:
|
130 |
|
131 | x=foo
|
132 | $(( x * 2 )) # doesn't make sense, except in bash's crazy world.
|
133 |
|
134 | Invalid hex constant:
|
135 |
|
136 | x=0xabcg
|
137 | echo $(( x * 2 )) (fatal in bash)
|
138 |
|
139 | ## Bool Eval
|
140 |
|
141 | regcomp parse error:
|
142 |
|
143 | x=$(cat invalid-syntax.txt)
|
144 | [[ foo =~ $x ]]
|
145 |
|
146 | ## Word Eval
|
147 |
|
148 | IMPORTANT: Command sub error $(exit 1)
|
149 |
|
150 | User-requested error: ${undef?error}
|
151 |
|
152 | set -o nounset
|
153 |
|
154 | def _EmptyStrOrError(self, val, token=None):
|
155 | # calls `e_die()`
|
156 |
|
157 | Variants:
|
158 | nounset: index out of bounds ${a[3]}
|
159 | I guess same diagnostic?
|
160 |
|
161 | In bash you can set an index out of bounds, like
|
162 | b[2]=9
|
163 | Might want to have a mode for this?
|
164 |
|
165 | set -o failglob
|
166 | TODO: not implemented
|
167 | might need PWD diagnostic
|
168 |
|
169 |
|
170 |
|
171 | Redirects:
|
172 | Redirect to empty filename/descriptor ( or array)
|
173 |
|
174 | { break; }
|
175 | ^~~~~~ break only invalid inside loop, etc.
|
176 |
|
177 |
|
178 | NotImplementedError
|
179 | - e.g for var ref ${!a}
|
180 | - bash associative arrays? I think we want most of that
|
181 | - $"" ?
|
182 | - |& not yet done
|
183 | - ;;& for case -- although parsing it is all of the work I guess
|
184 | - some could be parse time errors too though?
|
185 |
|
186 |
|
187 | - String Slicing and String Length require valid utf-8 characters
|
188 |
|
189 | s=$(cat invalid.txt)
|
190 | echo ${#s} # code points
|
191 | echo ${s:1:3} # code points
|
192 |
|
193 | - Slicing: Index is negative. ${foo: -4} and ${foo: 1 : -4} aren't supported
|
194 | right now, unlike bash and zsh.
|
195 |
|
196 | ## Command Exec
|
197 |
|
198 | IMPORTANT: subshell error ( exit 1 )
|
199 |
|
200 | set -o errexit -- turns NON-FATAL error into FATAL error.
|
201 |
|
202 | set -o pipefail
|
203 | pipefail might need some fanciness for ${PIPESTATUS}
|
204 |
|
205 | Trying to set readonly variable:
|
206 | readonly foo=bar
|
207 | foo=x
|
208 | (could any of this be done at compile time?)
|
209 |
|
210 | - this needs two locations: where the assignment was, and where it was
|
211 | declared readonly.
|
212 |
|
213 | Trying to redeclare a variable? That can also be parse time.
|
214 | local x=1
|
215 | local x=2
|
216 |
|
217 | Type errors between Str and StrArray: -- strict-array controls this
|
218 | EvalWordToString calls e_die()`
|
219 |
|
220 | echo foo > "$@"
|
221 | ^-- # Should have what it evaluated to? # This could be static too
|
222 |
|
223 | case "$@" in
|
224 | "$@") echo bad;;
|
225 | esac
|
226 |
|
227 | ${undef:-"$@"} is OK, but ${var%"$@"} doesn't make sense really.
|
228 | ${v/"$@"/"$@"}
|
229 |
|
230 |
|
231 | LHS evaluation:
|
232 | s='abc'
|
233 | s[1]=X # invalid because it's a string, not an array
|
234 |
|
235 |
|
236 | Invalid descriptor:
|
237 |
|
238 |
|
239 | fd=$(cat invalid.txt)
|
240 | echo foo 2>& $fd
|
241 |
|
242 | ### Builtins
|
243 |
|
244 | In core/builtins.py:
|
245 |
|
246 | util.usage('...')
|
247 | return 1
|
248 |
|
249 | A usage error is a runtime error that results in the builtin returning 1.
|
250 |
|
251 | Builtin has too many arguments -- but this falls under the errexit rule
|
252 | cd foo bar baz
|
253 | continue "$@"
|
254 | (Parse error: continue 1 2 3)
|
255 |
|
256 | Although we might want to highlight the extra args.
|
257 |
|
258 |
|
259 |
|
260 | ## Syscall Failures
|
261 |
|
262 | Fatal error from system calls:
|
263 | fork() could fail in theory
|
264 |
|
265 | Some are not failures:
|
266 |
|
267 | stat() [[ -f /tmp/foo ]]
|
268 | cd /ff chdir() # exit code 1
|
269 | cat <nonexistent # This is just exit code 1
|
270 |
|
271 | ## Interpreter Failures
|
272 |
|
273 | Runtime: Stack Too Deep (catch infinite recursion)
|
274 | Out of memory: should not happen with OSH, but maybe with Oil
|
275 |
|
276 | Runtime Parse Errors
|
277 | --------------------
|
278 |
|
279 | The way bash works 0x$var can be a hex literal.
|
280 | so var=xx makes this invalid. hex/octal/decimal have this problem.
|
281 |
|
282 |
|
283 | Parse Time Errors
|
284 | -----------------
|
285 |
|
286 | regcomp() errors (sometimes at parse time; other times at runtime)
|
287 |
|
288 | Need to show stack trace for "source" like Python. Prototype this.
|
289 |
|
290 | Also might show which token thing caused you to be in arith parse state, like:
|
291 |
|
292 | $((echo hi))
|
293 | ^~ ^~
|
294 | Arith Invalid token
|
295 |
|
296 |
|