OILS / core / state.py View on Github | oilshell.org

2564 lines, 1303 significant
1# Copyright 2016 Andy Chu. All rights reserved.
2# Licensed under the Apache License, Version 2.0 (the "License");
3# you may not use this file except in compliance with the License.
4# You may obtain a copy of the License at
5#
6# http://www.apache.org/licenses/LICENSE-2.0
7"""
8state.py - Interpreter state
9"""
10from __future__ import print_function
11import time as time_ # avoid name conflict
12
13from _devbuild.gen.id_kind_asdl import Id
14from _devbuild.gen.option_asdl import option_i
15from _devbuild.gen.runtime_asdl import (scope_e, scope_t, Cell)
16from _devbuild.gen.syntax_asdl import (loc, loc_t, Token, debug_frame,
17 debug_frame_e, debug_frame_t)
18from _devbuild.gen.types_asdl import opt_group_i
19from _devbuild.gen.value_asdl import (value, value_e, value_t, sh_lvalue,
20 sh_lvalue_e, sh_lvalue_t, LeftName,
21 y_lvalue_e, regex_match, regex_match_e,
22 regex_match_t, RegexMatch)
23from core import error
24from core.error import e_usage, e_die
25from core import num
26from core import pyos
27from core import pyutil
28from core import optview
29from display import ui
30from core import util
31from frontend import consts
32from frontend import location
33from frontend import match
34from mycpp import mops
35from mycpp import mylib
36from mycpp.mylib import (log, print_stderr, str_switch, tagswitch, iteritems,
37 NewDict)
38from osh import split
39from pylib import os_path
40from pylib import path_stat
41
42import libc
43import posix_ as posix
44from posix_ import X_OK # translated directly to C macro
45
46from typing import Tuple, List, Dict, Optional, Any, cast, TYPE_CHECKING
47
48if TYPE_CHECKING:
49 from _devbuild.gen.option_asdl import option_t
50 from core import alloc
51 from osh import sh_expr_eval
52
53_ = log
54
55# This was derived from bash --norc -c 'argv "$COMP_WORDBREAKS".
56# Python overwrites this to something Python-specific in Modules/readline.c, so
57# we have to set it back!
58# Used in both core/competion.py and osh/state.py
59_READLINE_DELIMS = ' \t\n"\'><=;|&(:'
60
61# flags for mem.SetValue()
62SetReadOnly = 1 << 0
63ClearReadOnly = 1 << 1
64SetExport = 1 << 2
65ClearExport = 1 << 3
66SetNameref = 1 << 4
67ClearNameref = 1 << 5
68
69
70def LookupExecutable(name, path_dirs, exec_required=True):
71 # type: (str, List[str], bool) -> Optional[str]
72 """
73 Returns either
74 - the name if it's a relative path that exists
75 - the executable name resolved against path_dirs
76 - None if not found
77 """
78 if len(name) == 0: # special case for "$(true)"
79 return None
80
81 if '/' in name:
82 return name if path_stat.exists(name) else None
83
84 for path_dir in path_dirs:
85 full_path = os_path.join(path_dir, name)
86 if exec_required:
87 found = posix.access(full_path, X_OK)
88 else:
89 found = path_stat.exists(full_path)
90
91 if found:
92 return full_path
93
94 return None
95
96
97class SearchPath(object):
98 """For looking up files in $PATH."""
99
100 def __init__(self, mem):
101 # type: (Mem) -> None
102 self.mem = mem
103 self.cache = {} # type: Dict[str, str]
104
105 def _GetPath(self):
106 # type: () -> List[str]
107
108 # TODO: Could cache this to avoid split() allocating all the time.
109 val = self.mem.GetValue('PATH')
110 UP_val = val
111 if val.tag() == value_e.Str:
112 val = cast(value.Str, UP_val)
113 return val.s.split(':')
114 else:
115 return [] # treat as empty path
116
117 def LookupOne(self, name, exec_required=True):
118 # type: (str, bool) -> Optional[str]
119 """
120 Returns the path itself (if relative path), the resolved path, or None.
121 """
122 return LookupExecutable(name,
123 self._GetPath(),
124 exec_required=exec_required)
125
126 def LookupReflect(self, name, do_all):
127 # type: (str, bool) -> List[str]
128 """
129 Like LookupOne(), with an option for 'type -a' to return all paths.
130 """
131 if len(name) == 0: # special case for "$(true)"
132 return []
133
134 if '/' in name:
135 if path_stat.exists(name):
136 return [name]
137 else:
138 return []
139
140 results = [] # type: List[str]
141 for path_dir in self._GetPath():
142 full_path = os_path.join(path_dir, name)
143 if path_stat.exists(full_path):
144 results.append(full_path)
145 if not do_all:
146 return results
147
148 return results
149
150 def CachedLookup(self, name):
151 # type: (str) -> Optional[str]
152 #log('name %r', name)
153 if name in self.cache:
154 return self.cache[name]
155
156 full_path = self.LookupOne(name)
157 if full_path is not None:
158 self.cache[name] = full_path
159 return full_path
160
161 def MaybeRemoveEntry(self, name):
162 # type: (str) -> None
163 """When the file system changes."""
164 mylib.dict_erase(self.cache, name)
165
166 def ClearCache(self):
167 # type: () -> None
168 """For hash -r."""
169 self.cache.clear()
170
171 def CachedCommands(self):
172 # type: () -> List[str]
173 return self.cache.values()
174
175
176class ctx_Source(object):
177 """For source builtin."""
178
179 def __init__(self, mem, source_name, argv):
180 # type: (Mem, str, List[str]) -> None
181 mem.PushSource(source_name, argv)
182 self.mem = mem
183 self.argv = argv
184
185 # Whenever we're sourcing, the 'is-main' builtin will return 1 (false)
186 self.to_restore = self.mem.is_main
187 self.mem.is_main = False
188
189 def __enter__(self):
190 # type: () -> None
191 pass
192
193 def __exit__(self, type, value, traceback):
194 # type: (Any, Any, Any) -> None
195 self.mem.PopSource(self.argv)
196
197 self.mem.is_main = self.to_restore
198
199
200class ctx_DebugTrap(object):
201 """For trap DEBUG."""
202
203 def __init__(self, mem):
204 # type: (Mem) -> None
205 mem.running_debug_trap = True
206 self.mem = mem
207
208 def __enter__(self):
209 # type: () -> None
210 pass
211
212 def __exit__(self, type, value, traceback):
213 # type: (Any, Any, Any) -> None
214 self.mem.running_debug_trap = False
215
216
217class ctx_ErrTrap(object):
218 """For trap ERR."""
219
220 def __init__(self, mem):
221 # type: (Mem) -> None
222 mem.running_err_trap = True
223 self.mem = mem
224
225 def __enter__(self):
226 # type: () -> None
227 pass
228
229 def __exit__(self, type, value, traceback):
230 # type: (Any, Any, Any) -> None
231 self.mem.running_err_trap = False
232
233
234class ctx_Option(object):
235 """Shopt --unset errexit { false }"""
236
237 def __init__(self, mutable_opts, opt_nums, b):
238 # type: (MutableOpts, List[int], bool) -> None
239 for opt_num in opt_nums:
240 mutable_opts.Push(opt_num, b)
241 if opt_num == option_i.errexit:
242 # it wasn't disabled
243 mutable_opts.errexit_disabled_tok.append(None)
244
245 self.mutable_opts = mutable_opts
246 self.opt_nums = opt_nums
247
248 def __enter__(self):
249 # type: () -> None
250 pass
251
252 def __exit__(self, type, value, traceback):
253 # type: (Any, Any, Any) -> None
254 for opt_num in self.opt_nums: # don't bother to do it in reverse order
255 if opt_num == option_i.errexit:
256 self.mutable_opts.errexit_disabled_tok.pop()
257 self.mutable_opts.Pop(opt_num)
258
259
260class ctx_AssignBuiltin(object):
261 """Local x=$(false) is disallowed."""
262
263 def __init__(self, mutable_opts):
264 # type: (MutableOpts) -> None
265 self.strict = False
266 if mutable_opts.Get(option_i.strict_errexit):
267 mutable_opts.Push(option_i._allow_command_sub, False)
268 mutable_opts.Push(option_i._allow_process_sub, False)
269 self.strict = True
270
271 self.mutable_opts = mutable_opts
272
273 def __enter__(self):
274 # type: () -> None
275 pass
276
277 def __exit__(self, type, value, traceback):
278 # type: (Any, Any, Any) -> None
279 if self.strict:
280 self.mutable_opts.Pop(option_i._allow_command_sub)
281 self.mutable_opts.Pop(option_i._allow_process_sub)
282
283
284class ctx_YshExpr(object):
285 """Command sub must fail in 'mystring' ++ $(false)"""
286
287 def __init__(self, mutable_opts):
288 # type: (MutableOpts) -> None
289
290 # Similar to $LIB_OSH/bash-strict.sh
291
292 # TODO: consider errexit:all group, or even ysh:all
293 # It would be nice if this were more efficient
294 mutable_opts.Push(option_i.command_sub_errexit, True)
295 mutable_opts.Push(option_i.errexit, True)
296 mutable_opts.Push(option_i.pipefail, True)
297 mutable_opts.Push(option_i.inherit_errexit, True)
298 mutable_opts.Push(option_i.strict_errexit, True)
299
300 # What about nounset? This has a similar pitfall -- it's not running
301 # like YSH.
302 # e.g. var x = $(echo $zz)
303
304 self.mutable_opts = mutable_opts
305
306 def __enter__(self):
307 # type: () -> None
308 pass
309
310 def __exit__(self, type, value, traceback):
311 # type: (Any, Any, Any) -> None
312 self.mutable_opts.Pop(option_i.command_sub_errexit)
313 self.mutable_opts.Pop(option_i.errexit)
314 self.mutable_opts.Pop(option_i.pipefail)
315 self.mutable_opts.Pop(option_i.inherit_errexit)
316 self.mutable_opts.Pop(option_i.strict_errexit)
317
318
319class ctx_ErrExit(object):
320 """Manages the errexit setting.
321
322 - The user can change it with builtin 'set' at any point in the code.
323 - These constructs implicitly disable 'errexit':
324 - if / while / until conditions
325 - ! (part of pipeline)
326 - && ||
327 """
328
329 def __init__(self, mutable_opts, b, disabled_tok):
330 # type: (MutableOpts, bool, Optional[Token]) -> None
331
332 # If we're disabling it, we need a span ID. If not, then we should NOT
333 # have one.
334 assert b == (disabled_tok is None)
335
336 mutable_opts.Push(option_i.errexit, b)
337 mutable_opts.errexit_disabled_tok.append(disabled_tok)
338
339 self.strict = False
340 if mutable_opts.Get(option_i.strict_errexit):
341 mutable_opts.Push(option_i._allow_command_sub, False)
342 mutable_opts.Push(option_i._allow_process_sub, False)
343 self.strict = True
344
345 self.mutable_opts = mutable_opts
346
347 def __enter__(self):
348 # type: () -> None
349 pass
350
351 def __exit__(self, type, value, traceback):
352 # type: (Any, Any, Any) -> None
353 self.mutable_opts.errexit_disabled_tok.pop()
354 self.mutable_opts.Pop(option_i.errexit)
355
356 if self.strict:
357 self.mutable_opts.Pop(option_i._allow_command_sub)
358 self.mutable_opts.Pop(option_i._allow_process_sub)
359
360
361class OptHook(object):
362 """Interface for option hooks."""
363
364 def __init__(self):
365 # type: () -> None
366 """Empty constructor for mycpp."""
367 pass
368
369 def OnChange(self, opt0_array, opt_name, b):
370 # type: (List[bool], str, bool) -> bool
371 """This method is called whenever an option is changed.
372
373 Returns success or failure.
374 """
375 return True
376
377
378def InitOpts():
379 # type: () -> List[bool]
380
381 opt0_array = [False] * option_i.ARRAY_SIZE
382 for opt_num in consts.DEFAULT_TRUE:
383 opt0_array[opt_num] = True
384 return opt0_array
385
386
387def MakeOpts(mem, opt_hook):
388 # type: (Mem, OptHook) -> Tuple[optview.Parse, optview.Exec, MutableOpts]
389
390 # Unusual representation: opt0_array + opt_stacks. For two features:
391 #
392 # - POSIX errexit disable semantics
393 # - Oil's shopt --set nullglob { ... }
394 #
395 # We could do it with a single List of stacks. But because shopt --set
396 # random_option { ... } is very uncommon, we optimize and store the ZERO
397 # element of the stack in a flat array opt0_array (default False), and then
398 # the rest in opt_stacks, where the value could be None. By allowing the
399 # None value, we save ~50 or so list objects in the common case.
400
401 opt0_array = InitOpts()
402 # Overrides, including errexit
403 no_stack = None # type: List[bool] # for mycpp
404 opt_stacks = [no_stack] * option_i.ARRAY_SIZE # type: List[List[bool]]
405
406 parse_opts = optview.Parse(opt0_array, opt_stacks)
407 exec_opts = optview.Exec(opt0_array, opt_stacks)
408 mutable_opts = MutableOpts(mem, opt0_array, opt_stacks, opt_hook)
409
410 return parse_opts, exec_opts, mutable_opts
411
412
413def _SetGroup(opt0_array, opt_nums, b):
414 # type: (List[bool], List[int], bool) -> None
415 for opt_num in opt_nums:
416 b2 = not b if opt_num in consts.DEFAULT_TRUE else b
417 opt0_array[opt_num] = b2
418
419
420def MakeOilOpts():
421 # type: () -> optview.Parse
422 opt0_array = InitOpts()
423 _SetGroup(opt0_array, consts.YSH_ALL, True)
424
425 no_stack = None # type: List[bool]
426 opt_stacks = [no_stack] * option_i.ARRAY_SIZE # type: List[List[bool]]
427
428 parse_opts = optview.Parse(opt0_array, opt_stacks)
429 return parse_opts
430
431
432def _AnyOptionNum(opt_name):
433 # type: (str) -> option_t
434 opt_num = consts.OptionNum(opt_name)
435 if opt_num == 0:
436 e_usage('got invalid option %r' % opt_name, loc.Missing)
437
438 # Note: we relaxed this for Oil so we can do 'shopt --unset errexit' consistently
439 #if opt_num not in consts.SHOPT_OPTION_NUMS:
440 # e_usage("doesn't own option %r (try 'set')" % opt_name)
441
442 return opt_num
443
444
445def _SetOptionNum(opt_name):
446 # type: (str) -> option_t
447 opt_num = consts.OptionNum(opt_name)
448 if opt_num == 0:
449 e_usage('got invalid option %r' % opt_name, loc.Missing)
450
451 if opt_num not in consts.SET_OPTION_NUMS:
452 e_usage("invalid option %r (try shopt)" % opt_name, loc.Missing)
453
454 return opt_num
455
456
457class MutableOpts(object):
458
459 def __init__(self, mem, opt0_array, opt_stacks, opt_hook):
460 # type: (Mem, List[bool], List[List[bool]], OptHook) -> None
461 self.mem = mem
462 self.opt0_array = opt0_array
463 self.opt_stacks = opt_stacks
464 self.errexit_disabled_tok = [] # type: List[Token]
465
466 # Used for 'set -o vi/emacs'
467 self.opt_hook = opt_hook
468
469 def Init(self):
470 # type: () -> None
471
472 # This comes after all the 'set' options.
473 UP_shellopts = self.mem.GetValue('SHELLOPTS')
474 # Always true in Oil, see Init above
475 if UP_shellopts.tag() == value_e.Str:
476 shellopts = cast(value.Str, UP_shellopts)
477 self._InitOptionsFromEnv(shellopts.s)
478
479 def _InitOptionsFromEnv(self, shellopts):
480 # type: (str) -> None
481 # e.g. errexit:nounset:pipefail
482 lookup = shellopts.split(':')
483 for opt_num in consts.SET_OPTION_NUMS:
484 name = consts.OptionName(opt_num)
485 if name in lookup:
486 self._SetOldOption(name, True)
487
488 def Push(self, opt_num, b):
489 # type: (int, bool) -> None
490 overlay = self.opt_stacks[opt_num]
491 if overlay is None or len(overlay) == 0:
492 self.opt_stacks[opt_num] = [b] # Allocate a new list
493 else:
494 overlay.append(b)
495
496 def Pop(self, opt_num):
497 # type: (int) -> bool
498 overlay = self.opt_stacks[opt_num]
499 assert overlay is not None
500 return overlay.pop()
501
502 def PushDynamicScope(self, b):
503 # type: (bool) -> None
504 """B: False if it's a proc, and True if it's a shell function."""
505 # If it's already disabled, keep it disabled
506 if not self.Get(option_i.dynamic_scope):
507 b = False
508 self.Push(option_i.dynamic_scope, b)
509
510 def PopDynamicScope(self):
511 # type: () -> None
512 self.Pop(option_i.dynamic_scope)
513
514 def Get(self, opt_num):
515 # type: (int) -> bool
516 # Like _Getter in core/optview.py
517 overlay = self.opt_stacks[opt_num]
518 if overlay is None or len(overlay) == 0:
519 return self.opt0_array[opt_num]
520 else:
521 return overlay[-1] # the top value
522
523 def _Set(self, opt_num, b):
524 # type: (int, bool) -> None
525 """Used to disable errexit.
526
527 For bash compatibility in command sub.
528 """
529
530 # Like _Getter in core/optview.py
531 overlay = self.opt_stacks[opt_num]
532 if overlay is None or len(overlay) == 0:
533 self.opt0_array[opt_num] = b
534 else:
535 overlay[-1] = b # The top value
536
537 def set_interactive(self):
538 # type: () -> None
539 self._Set(option_i.interactive, True)
540
541 def set_redefine_proc_func(self):
542 # type: () -> None
543 """For interactive shells."""
544 self._Set(option_i.redefine_proc_func, True)
545
546 def set_redefine_module(self):
547 # type: () -> None
548 """For interactive shells."""
549 self._Set(option_i.redefine_module, True)
550
551 def set_emacs(self):
552 # type: () -> None
553 self._Set(option_i.emacs, True)
554
555 def set_xtrace(self, b):
556 # type: (bool) -> None
557 self._Set(option_i.xtrace, b)
558
559 def _SetArrayByNum(self, opt_num, b):
560 # type: (int, bool) -> None
561 if (opt_num in consts.PARSE_OPTION_NUMS and
562 not self.mem.ParsingChangesAllowed()):
563 e_die('Syntax options must be set at the top level '
564 '(outside any function)')
565
566 self._Set(opt_num, b)
567
568 def SetDeferredErrExit(self, b):
569 # type: (bool) -> None
570 """Set the errexit flag, possibly deferring it.
571
572 Implements the unusual POSIX "defer" behavior. Callers: set -o
573 errexit, shopt -s oil:all, oil:upgrade
574 """
575 #log('Set %s', b)
576
577 # Defer it until we pop by setting the BOTTOM OF THE STACK.
578 self.opt0_array[option_i.errexit] = b
579
580 def DisableErrExit(self):
581 # type: () -> None
582 """Called by core/process.py to implement bash quirks."""
583 self._Set(option_i.errexit, False)
584
585 def ErrExitDisabledToken(self):
586 # type: () -> Optional[Token]
587 """If errexit is disabled by POSIX rules, return Token for construct.
588
589 e.g. the Token for 'if' or '&&' etc.
590 """
591 # Bug fix: The errexit disabling inherently follows a STACK DISCIPLINE.
592 # But we run trap handlers in the MAIN LOOP, which break this. So just
593 # declare that it's never disabled in a trap.
594 if self.Get(option_i._running_trap):
595 return None
596
597 if len(self.errexit_disabled_tok) == 0:
598 return None
599
600 return self.errexit_disabled_tok[-1]
601
602 def ErrExitIsDisabled(self):
603 # type: () -> bool
604 """
605 Similar to ErrExitDisabledToken, for ERR trap
606 """
607 if len(self.errexit_disabled_tok) == 0:
608 return False
609
610 return self.errexit_disabled_tok[-1] is not None
611
612 def _SetOldOption(self, opt_name, b):
613 # type: (str, bool) -> None
614 """Private version for synchronizing from SHELLOPTS."""
615 assert '_' not in opt_name
616 assert opt_name in consts.SET_OPTION_NAMES
617
618 opt_num = consts.OptionNum(opt_name)
619 assert opt_num != 0, opt_name
620
621 if opt_num == option_i.errexit:
622 self.SetDeferredErrExit(b)
623 else:
624 if opt_num == option_i.verbose and b:
625 print_stderr('Warning: set -o verbose not implemented')
626 self._SetArrayByNum(opt_num, b)
627
628 # note: may FAIL before we get here.
629
630 success = self.opt_hook.OnChange(self.opt0_array, opt_name, b)
631
632 def SetOldOption(self, opt_name, b):
633 # type: (str, bool) -> None
634 """For set -o, set +o, or shopt -s/-u -o."""
635 unused = _SetOptionNum(opt_name) # validate it
636 self._SetOldOption(opt_name, b)
637
638 UP_val = self.mem.GetValue('SHELLOPTS')
639 assert UP_val.tag() == value_e.Str, UP_val
640 val = cast(value.Str, UP_val)
641 shellopts = val.s
642
643 # Now check if SHELLOPTS needs to be updated. It may be exported.
644 #
645 # NOTE: It might be better to skip rewriting SEHLLOPTS in the common case
646 # where it is not used. We could do it lazily upon GET.
647
648 # Also, it would be slightly more efficient to update SHELLOPTS if
649 # settings were batched, Examples:
650 # - set -eu
651 # - shopt -s foo bar
652 if b:
653 if opt_name not in shellopts:
654 new_val = value.Str('%s:%s' % (shellopts, opt_name))
655 self.mem.InternalSetGlobal('SHELLOPTS', new_val)
656 else:
657 if opt_name in shellopts:
658 names = [n for n in shellopts.split(':') if n != opt_name]
659 new_val = value.Str(':'.join(names))
660 self.mem.InternalSetGlobal('SHELLOPTS', new_val)
661
662 def SetAnyOption(self, opt_name, b):
663 # type: (str, bool) -> None
664 """For shopt -s/-u and sh -O/+O."""
665
666 # shopt -s all:oil turns on all Oil options, which includes all strict #
667 # options
668 opt_group = consts.OptionGroupNum(opt_name)
669 if opt_group == opt_group_i.YshUpgrade:
670 _SetGroup(self.opt0_array, consts.YSH_UPGRADE, b)
671 self.SetDeferredErrExit(b) # Special case
672 return
673
674 if opt_group == opt_group_i.YshAll:
675 _SetGroup(self.opt0_array, consts.YSH_ALL, b)
676 self.SetDeferredErrExit(b) # Special case
677 return
678
679 if opt_group == opt_group_i.StrictAll:
680 _SetGroup(self.opt0_array, consts.STRICT_ALL, b)
681 return
682
683 opt_num = _AnyOptionNum(opt_name)
684
685 if opt_num == option_i.errexit:
686 self.SetDeferredErrExit(b)
687 return
688
689 self._SetArrayByNum(opt_num, b)
690
691 def ShowOptions(self, opt_names):
692 # type: (List[str]) -> None
693 """For 'set -o' and 'shopt -p -o'."""
694 # TODO: Maybe sort them differently?
695
696 if len(opt_names) == 0: # if none, supplied, show all
697 opt_names = [consts.OptionName(i) for i in consts.SET_OPTION_NUMS]
698
699 for opt_name in opt_names:
700 opt_num = _SetOptionNum(opt_name)
701 b = self.Get(opt_num)
702 print('set %so %s' % ('-' if b else '+', opt_name))
703
704 def ShowShoptOptions(self, opt_names):
705 # type: (List[str]) -> None
706 """For 'shopt -p'."""
707
708 # Respect option groups.
709 opt_nums = [] # type: List[int]
710 for opt_name in opt_names:
711 opt_group = consts.OptionGroupNum(opt_name)
712 if opt_group == opt_group_i.YshUpgrade:
713 opt_nums.extend(consts.YSH_UPGRADE)
714 elif opt_group == opt_group_i.YshAll:
715 opt_nums.extend(consts.YSH_ALL)
716 elif opt_group == opt_group_i.StrictAll:
717 opt_nums.extend(consts.STRICT_ALL)
718 else:
719 index = consts.OptionNum(opt_name)
720 # Minor incompatibility with bash: we validate everything before
721 # printing.
722 if index == 0:
723 e_usage('got invalid option %r' % opt_name, loc.Missing)
724 opt_nums.append(index)
725
726 if len(opt_names) == 0:
727 # If none supplied, show all>
728 # TODO: Should this show 'set' options too?
729 opt_nums.extend(consts.VISIBLE_SHOPT_NUMS)
730
731 for opt_num in opt_nums:
732 b = self.Get(opt_num)
733 print('shopt -%s %s' %
734 ('s' if b else 'u', consts.OptionName(opt_num)))
735
736
737class _ArgFrame(object):
738 """Stack frame for arguments array."""
739
740 def __init__(self, argv):
741 # type: (List[str]) -> None
742 self.argv = argv
743 self.num_shifted = 0
744
745 def __repr__(self):
746 # type: () -> str
747 return '<_ArgFrame %s %d at %x>' % (self.argv, self.num_shifted,
748 id(self))
749
750 def Dump(self):
751 # type: () -> Dict[str, value_t]
752 items = [value.Str(s) for s in self.argv] # type: List[value_t]
753 argv = value.List(items)
754 return {
755 'argv': argv,
756 'num_shifted': num.ToBig(self.num_shifted),
757 }
758
759 def GetArgNum(self, arg_num):
760 # type: (int) -> value_t
761 index = self.num_shifted + arg_num - 1
762 if index >= len(self.argv):
763 return value.Undef
764
765 return value.Str(self.argv[index])
766
767 def GetArgv(self):
768 # type: () -> List[str]
769 return self.argv[self.num_shifted:]
770
771 def GetNumArgs(self):
772 # type: () -> int
773 return len(self.argv) - self.num_shifted
774
775 def SetArgv(self, argv):
776 # type: (List[str]) -> None
777 self.argv = argv
778 self.num_shifted = 0
779
780
781def _DumpVarFrame(frame):
782 # type: (Dict[str, Cell]) -> Dict[str, value_t]
783 """Dump the stack frame as reasonably compact and readable JSON."""
784
785 vars_json = {} # type: Dict[str, value_t]
786 for name, cell in iteritems(frame):
787 cell_json = {} # type: Dict[str, value_t]
788
789 buf = mylib.BufWriter()
790 if cell.exported:
791 buf.write('x')
792 if cell.readonly:
793 buf.write('r')
794 flags = buf.getvalue()
795 if len(flags):
796 cell_json['flags'] = value.Str(flags)
797
798 # TODO:
799 # - Use packle for crash dumps! Then we can represent object cycles
800 # - Right now the JSON serializer will probably crash
801 # - although BashArray and BashAssoc may need 'type' tags
802 # - they don't round trip correctly
803 # - maybe add value.Tombstone here or something?
804 # - value.{Func,Eggex,...} may have value.Tombstone and
805 # vm.ValueIdString()?
806
807 with tagswitch(cell.val) as case:
808 if case(value_e.Undef):
809 cell_json['val'] = value.Null
810
811 elif case(value_e.Str, value_e.BashArray, value_e.BashAssoc):
812 cell_json['val'] = cell.val
813
814 else:
815 # TODO: should we show the object ID here?
816 pass
817
818 vars_json[name] = value.Dict(cell_json)
819
820 return vars_json
821
822
823def GetWorkingDir():
824 # type: () -> str
825 """Fallback for pwd and $PWD when there's no 'cd' and no inherited $PWD."""
826 try:
827 return posix.getcwd()
828 except (IOError, OSError) as e:
829 e_die("Can't determine working directory: %s" % pyutil.strerror(e))
830
831
832def _LineNumber(tok):
833 # type: (Optional[Token]) -> str
834 """ For $BASH_LINENO """
835 if tok is None:
836 return '-1'
837 return str(tok.line.line_num)
838
839
840def _AddCallToken(d, token):
841 # type: (Dict[str, value_t], Optional[Token]) -> None
842 if token is None:
843 return
844 d['call_source'] = value.Str(ui.GetLineSourceString(token.line))
845 d['call_line_num'] = num.ToBig(token.line.line_num)
846 d['call_line'] = value.Str(token.line.content)
847
848
849def _InitDefaults(mem):
850 # type: (Mem) -> None
851
852 # Default value; user may unset it.
853 # $ echo -n "$IFS" | python -c 'import sys;print repr(sys.stdin.read())'
854 # ' \t\n'
855 SetGlobalString(mem, 'IFS', split.DEFAULT_IFS)
856
857 # NOTE: Should we put these in a name_map for Oil?
858 SetGlobalString(mem, 'UID', str(posix.getuid()))
859 SetGlobalString(mem, 'EUID', str(posix.geteuid()))
860 SetGlobalString(mem, 'PPID', str(posix.getppid()))
861
862 SetGlobalString(mem, 'HOSTNAME', libc.gethostname())
863
864 # In bash, this looks like 'linux-gnu', 'linux-musl', etc. Scripts test
865 # for 'darwin' and 'freebsd' too. They generally don't like at 'gnu' or
866 # 'musl'. We don't have that info, so just make it 'linux'.
867 SetGlobalString(mem, 'OSTYPE', pyos.OsType())
868
869 # For getopts builtin
870 SetGlobalString(mem, 'OPTIND', '1')
871
872 # When xtrace_rich is off, this is just like '+ ', the shell default
873 SetGlobalString(mem, 'PS4', '${SHX_indent}${SHX_punct}${SHX_pid_str} ')
874
875 # bash-completion uses this. Value copied from bash. It doesn't integrate
876 # with 'readline' yet.
877 SetGlobalString(mem, 'COMP_WORDBREAKS', _READLINE_DELIMS)
878
879 # TODO on $HOME: bash sets it if it's a login shell and not in POSIX mode!
880 # if (login_shell == 1 && posixly_correct == 0)
881 # set_home_var ();
882
883
884def InitVarsFromEnv(mem, environ):
885 # type: (Mem, Dict[str, str]) -> None
886
887 # This is the way dash and bash work -- at startup, they turn everything in
888 # 'environ' variable into shell variables. Bash has an export_env
889 # variable. Dash has a loop through environ in init.c
890 for n, v in iteritems(environ):
891 mem.SetNamed(location.LName(n),
892 value.Str(v),
893 scope_e.GlobalOnly,
894 flags=SetExport)
895
896 # If it's not in the environment, initialize it. This makes it easier to
897 # update later in MutableOpts.
898
899 # TODO: IFS, etc. should follow this pattern. Maybe need a SysCall
900 # interface? self.syscall.getcwd() etc.
901
902 val = mem.GetValue('SHELLOPTS')
903 if val.tag() == value_e.Undef:
904 SetGlobalString(mem, 'SHELLOPTS', '')
905 # Now make it readonly
906 mem.SetNamed(location.LName('SHELLOPTS'),
907 None,
908 scope_e.GlobalOnly,
909 flags=SetReadOnly)
910
911 # Usually we inherit PWD from the parent shell. When it's not set, we may
912 # compute it.
913 val = mem.GetValue('PWD')
914 if val.tag() == value_e.Undef:
915 SetGlobalString(mem, 'PWD', GetWorkingDir())
916 # Now mark it exported, no matter what. This is one of few variables
917 # EXPORTED. bash and dash both do it. (e.g. env -i -- dash -c env)
918 mem.SetNamed(location.LName('PWD'),
919 None,
920 scope_e.GlobalOnly,
921 flags=SetExport)
922
923 val = mem.GetValue('PATH')
924 if val.tag() == value_e.Undef:
925 # Setting PATH to these two dirs match what zsh and mksh do. bash and dash
926 # add {,/usr/,/usr/local}/{bin,sbin}
927 SetGlobalString(mem, 'PATH', '/bin:/usr/bin')
928
929
930def InitMem(mem, environ, version_str):
931 # type: (Mem, Dict[str, str], str) -> None
932 """Initialize memory with shell defaults.
933
934 Other interpreters could have different builtin variables.
935 """
936 # TODO: REMOVE this legacy. ble.sh checks it!
937 SetGlobalString(mem, 'OIL_VERSION', version_str)
938
939 SetGlobalString(mem, 'OILS_VERSION', version_str)
940
941 # The source builtin understands '///' to mean "relative to embedded stdlib"
942 SetGlobalString(mem, 'LIB_OSH', '///osh')
943 SetGlobalString(mem, 'LIB_YSH', '///ysh')
944
945 # - C spells it NAN
946 # - JavaScript spells it NaN
947 # - Python 2 has float('nan'), while Python 3 has math.nan.
948 #
949 # - libc prints the strings 'nan' and 'inf'
950 # - Python 3 prints the strings 'nan' and 'inf'
951 # - JavaScript prints 'NaN' and 'Infinity', which is more stylized
952 _SetGlobalValue(mem, 'NAN', value.Float(pyutil.nan()))
953 _SetGlobalValue(mem, 'INFINITY', value.Float(pyutil.infinity()))
954
955 _InitDefaults(mem)
956
957
958def InitInteractive(mem):
959 # type: (Mem) -> None
960 """Initialization that's only done in the interactive/headless shell."""
961
962 # Same default PS1 as bash
963 if mem.GetValue('PS1').tag() == value_e.Undef:
964 SetGlobalString(mem, 'PS1', r'\s-\v\$ ')
965
966
967class ctx_FuncCall(object):
968 """For func calls."""
969
970 def __init__(self, mem, func):
971 # type: (Mem, value.Func) -> None
972
973 frame = NewDict() # type: Dict[str, Cell]
974 mem.var_stack.append(frame)
975
976 mem.PushCall(func.name, func.parsed.name)
977 self.mem = mem
978
979 def __enter__(self):
980 # type: () -> None
981 pass
982
983 def __exit__(self, type, value, traceback):
984 # type: (Any, Any, Any) -> None
985 self.mem.PopCall()
986 self.mem.var_stack.pop()
987
988
989class ctx_ProcCall(object):
990 """For proc calls, including shell functions."""
991
992 def __init__(self, mem, mutable_opts, proc, argv):
993 # type: (Mem, MutableOpts, value.Proc, List[str]) -> None
994
995 # TODO:
996 # - argv stack shouldn't be used for procs
997 # - we can bind a real variable @A if we want
998 # - procs should be in the var namespace
999 #
1000 # should we separate procs and shell functions?
1001 # - dynamic scope is one difference
1002 # - '$@" shift etc. are another difference
1003
1004 frame = NewDict() # type: Dict[str, Cell]
1005
1006 assert argv is not None
1007 if proc.sh_compat:
1008 # shell function
1009 mem.argv_stack.append(_ArgFrame(argv))
1010 else:
1011 # procs
1012 # - open: is equivalent to ...ARGV
1013 # - closed: ARGV is empty list
1014 frame['ARGV'] = _MakeArgvCell(argv)
1015
1016 mem.var_stack.append(frame)
1017
1018 mem.PushCall(proc.name, proc.name_tok)
1019
1020 # Dynamic scope is only for shell functions
1021 mutable_opts.PushDynamicScope(proc.sh_compat)
1022
1023 # It may have been disabled with ctx_ErrExit for 'if echo $(false)', but
1024 # 'if p' should be allowed.
1025 self.mem = mem
1026 self.mutable_opts = mutable_opts
1027 self.sh_compat = proc.sh_compat
1028
1029 def __enter__(self):
1030 # type: () -> None
1031 pass
1032
1033 def __exit__(self, type, value, traceback):
1034 # type: (Any, Any, Any) -> None
1035 self.mutable_opts.PopDynamicScope()
1036 self.mem.PopCall()
1037 self.mem.var_stack.pop()
1038
1039 if self.sh_compat:
1040 self.mem.argv_stack.pop()
1041
1042
1043class ctx_Temp(object):
1044 """For FOO=bar myfunc, etc."""
1045
1046 def __init__(self, mem):
1047 # type: (Mem) -> None
1048 mem.PushTemp()
1049 self.mem = mem
1050
1051 def __enter__(self):
1052 # type: () -> None
1053 pass
1054
1055 def __exit__(self, type, value, traceback):
1056 # type: (Any, Any, Any) -> None
1057 self.mem.PopTemp()
1058
1059
1060class ctx_Registers(object):
1061 """For $PS1, $PS4, $PROMPT_COMMAND, traps, and headless EVAL.
1062
1063 This is tightly coupled to state.Mem, so it's not in builtin/pure_ysh.
1064 """
1065
1066 def __init__(self, mem):
1067 # type: (Mem) -> None
1068
1069 # Because some prompts rely on the status leaking. See issue #853.
1070 # PS1 also does.
1071 last = mem.last_status[-1]
1072 mem.last_status.append(last)
1073 mem.try_status.append(0)
1074 mem.try_error.append(value.Dict({}))
1075
1076 # TODO: We should also copy these values! Turn the whole thing into a
1077 # frame.
1078 mem.pipe_status.append([])
1079 mem.process_sub_status.append([])
1080
1081 mem.regex_match.append(regex_match.No)
1082
1083 self.mem = mem
1084
1085 def __enter__(self):
1086 # type: () -> None
1087 pass
1088
1089 def __exit__(self, type, value, traceback):
1090 # type: (Any, Any, Any) -> None
1091 self.mem.regex_match.pop()
1092
1093 self.mem.process_sub_status.pop()
1094 self.mem.pipe_status.pop()
1095
1096 self.mem.try_error.pop()
1097 self.mem.try_status.pop()
1098 self.mem.last_status.pop()
1099
1100
1101class ctx_ThisDir(object):
1102 """For $_this_dir."""
1103
1104 def __init__(self, mem, filename):
1105 # type: (Mem, Optional[str]) -> None
1106 self.do_pop = False
1107 if filename is not None: # script_name in main() may be -c, etc.
1108 d = os_path.dirname(os_path.abspath(filename))
1109 mem.this_dir.append(d)
1110 self.do_pop = True
1111
1112 self.mem = mem
1113
1114 def __enter__(self):
1115 # type: () -> None
1116 pass
1117
1118 def __exit__(self, type, value, traceback):
1119 # type: (Any, Any, Any) -> None
1120 if self.do_pop:
1121 self.mem.this_dir.pop()
1122
1123
1124def _MakeArgvCell(argv):
1125 # type: (List[str]) -> Cell
1126 items = [value.Str(a) for a in argv] # type: List[value_t]
1127 return Cell(False, False, False, value.List(items))
1128
1129
1130class ctx_Eval(object):
1131 """Push temporary variable frame and override $0, $1, $2, etc."""
1132
1133 def __init__(self, mem, dollar0, pos_args, vars):
1134 # type: (Mem, Optional[str], Optional[List[str]], Optional[Dict[str, value_t]]) -> None
1135 self.mem = mem
1136 self.dollar0 = dollar0
1137 self.pos_args = pos_args
1138 self.vars = vars
1139
1140 # $0 needs to have lexical scoping. So we store it with other locals.
1141 # As "0" cannot be parsed as an lvalue, we can safely store dollar0 there.
1142 if dollar0 is not None:
1143 assert mem.GetValue("0", scope_e.LocalOnly).tag() == value_e.Undef
1144 self.dollar0_lval = LeftName("0", loc.Missing)
1145 mem.SetLocalName(self.dollar0_lval, value.Str(dollar0))
1146
1147 if pos_args is not None:
1148 mem.argv_stack.append(_ArgFrame(pos_args))
1149
1150 if vars is not None:
1151 frame = {} # type: Dict[str, Cell]
1152 for name in vars:
1153 frame[name] = Cell(False, False, False, vars[name])
1154
1155 mem.var_stack.append(frame)
1156
1157 def __enter__(self):
1158 # type: () -> None
1159 pass
1160
1161 def __exit__(self, type, value_, traceback):
1162 # type: (Any, Any, Any) -> None
1163 if self.vars is not None:
1164 self.mem.var_stack.pop()
1165
1166 if self.pos_args is not None:
1167 self.mem.argv_stack.pop()
1168
1169 if self.dollar0 is not None:
1170 self.mem.SetLocalName(self.dollar0_lval, value.Undef)
1171
1172
1173class Mem(object):
1174 """For storing variables.
1175
1176 Callers:
1177 User code: assigning and evaluating variables, in command context or
1178 arithmetic context.
1179 Completion engine: for COMP_WORDS, etc.
1180 Builtins call it implicitly: read, cd for $PWD, $OLDPWD, etc.
1181
1182 Modules: cmd_eval, word_eval, expr_eval, completion
1183 """
1184
1185 def __init__(self, dollar0, argv, arena, debug_stack):
1186 # type: (str, List[str], alloc.Arena, List[debug_frame_t]) -> None
1187 """
1188 Args:
1189 arena: currently unused
1190 """
1191 # circular dep initialized out of line
1192 self.exec_opts = None # type: optview.Exec
1193 self.unsafe_arith = None # type: sh_expr_eval.UnsafeArith
1194
1195 self.dollar0 = dollar0
1196 # If you only use YSH procs and funcs, this will remain at length 1.
1197 self.argv_stack = [_ArgFrame(argv)]
1198
1199 frame = NewDict() # type: Dict[str, Cell]
1200
1201 frame['ARGV'] = _MakeArgvCell(argv)
1202
1203 self.var_stack = [frame]
1204
1205 # The debug_stack isn't strictly necessary for execution. We use it
1206 # for crash dumps and for 3 parallel arrays: BASH_SOURCE, FUNCNAME, and
1207 # BASH_LINENO.
1208 self.debug_stack = debug_stack
1209
1210 self.pwd = None # type: Optional[str]
1211 self.seconds_start = time_.time()
1212
1213 self.token_for_line = None # type: Optional[Token]
1214 self.loc_for_expr = loc.Missing # type: loc_t
1215
1216 self.last_arg = '' # $_ is initially empty, NOT unset
1217 self.line_num = value.Str('')
1218
1219 # Done ONCE on initialization
1220 self.root_pid = posix.getpid()
1221
1222 # TODO:
1223 # - These are REGISTERS mutated by user code.
1224 # - Call it self.reg_stack? with ctx_Registers
1225 # - push-registers builtin
1226 self.last_status = [0] # type: List[int] # a stack
1227 self.try_status = [0] # type: List[int] # a stack
1228 self.try_error = [value.Dict({})] # type: List[value.Dict] # a stack
1229 self.pipe_status = [[]] # type: List[List[int]] # stack
1230 self.process_sub_status = [[]] # type: List[List[int]] # stack
1231
1232 # A stack but NOT a register?
1233 self.this_dir = [] # type: List[str]
1234 self.regex_match = [regex_match.No] # type: List[regex_match_t]
1235
1236 self.last_bg_pid = -1 # Uninitialized value mutable public variable
1237
1238 self.running_debug_trap = False # set by ctx_DebugTrap()
1239 self.running_err_trap = False # set by ctx_ErrTrap
1240 self.is_main = True # we start out in main
1241
1242 # For the ctx builtin
1243 self.ctx_stack = [] # type: List[Dict[str, value_t]]
1244
1245 def __repr__(self):
1246 # type: () -> str
1247 parts = [] # type: List[str]
1248 parts.append('<Mem')
1249 for i, frame in enumerate(self.var_stack):
1250 parts.append(' -- %d --' % i)
1251 for n, v in frame.iteritems():
1252 parts.append(' %s %s' % (n, v))
1253 parts.append('>')
1254 return '\n'.join(parts) + '\n'
1255
1256 def SetPwd(self, pwd):
1257 # type: (str) -> None
1258 """Used by builtins."""
1259 self.pwd = pwd
1260
1261 def ParsingChangesAllowed(self):
1262 # type: () -> bool
1263 """For checking that syntax options are only used at the top level."""
1264
1265 # DISALLOW proc calls : they push argv_stack, var_stack, debug_stack
1266 # ALLOW source foo.sh arg1: pushes argv_stack, debug_stack
1267 # ALLOW FOO=bar : pushes var_stack
1268 return len(self.var_stack) == 1 or len(self.argv_stack) == 1
1269
1270 def Dump(self):
1271 # type: () -> Tuple[List[value_t], List[value_t], List[value_t]]
1272 """Copy state before unwinding the stack."""
1273 var_stack = [
1274 value.Dict(_DumpVarFrame(frame)) for frame in self.var_stack
1275 ] # type: List[value_t]
1276 argv_stack = [value.Dict(frame.Dump())
1277 for frame in self.argv_stack] # type: List[value_t]
1278
1279 debug_stack = [] # type: List[value_t]
1280
1281 # Reuse these immutable objects
1282 t_call = value.Str('Call')
1283 t_source = value.Str('Source')
1284 t_main = value.Str('Main')
1285
1286 for frame in reversed(self.debug_stack):
1287 UP_frame = frame
1288 with tagswitch(frame) as case:
1289 if case(debug_frame_e.Call):
1290 frame = cast(debug_frame.Call, UP_frame)
1291 d = {
1292 'type': t_call,
1293 'func_name': value.Str(frame.func_name)
1294 } # type: Dict[str, value_t]
1295
1296 _AddCallToken(d, frame.call_tok)
1297 # TODO: Add def_tok
1298
1299 elif case(debug_frame_e.Source):
1300 frame = cast(debug_frame.Source, UP_frame)
1301 d = {
1302 'type': t_source,
1303 'source_name': value.Str(frame.source_name)
1304 }
1305 _AddCallToken(d, frame.call_tok)
1306
1307 elif case(debug_frame_e.Main):
1308 frame = cast(debug_frame.Main, UP_frame)
1309 d = {'type': t_main, 'dollar0': value.Str(frame.dollar0)}
1310
1311 debug_stack.append(value.Dict(d))
1312 return var_stack, argv_stack, debug_stack
1313
1314 def SetLastArgument(self, s):
1315 # type: (str) -> None
1316 """For $_"""
1317 self.last_arg = s
1318
1319 def SetTokenForLine(self, tok):
1320 # type: (Token) -> None
1321 """Set a token to compute $LINENO
1322
1323 This means it should be set on SimpleCommand, ShAssignment, ((, [[,
1324 case, etc. -- anything that evaluates a word. Example: there was a bug
1325 with 'case $LINENO'
1326
1327 This token also used as a "least-specific" / fallback location for
1328 errors in ExecuteAndCatch().
1329
1330 Although most of that should be taken over by 'with ui.ctx_Location()`,
1331 for the errfmt.
1332 """
1333 if self.running_debug_trap or self.running_err_trap:
1334 return
1335
1336 #if tok.span_id == runtime.NO_SPID:
1337 # NOTE: This happened in the osh-runtime benchmark for yash.
1338 #log('Warning: span_id undefined in SetTokenForLine')
1339
1340 #import traceback
1341 #traceback.print_stack()
1342 #return
1343
1344 self.token_for_line = tok
1345
1346 def SetLocationForExpr(self, blame_loc):
1347 # type: (loc_t) -> None
1348 """
1349 A more specific fallback location, like the $[ in
1350
1351 echo $[len(42)]
1352 """
1353 self.loc_for_expr = blame_loc
1354
1355 def GetFallbackLocation(self):
1356 # type: () -> loc_t
1357
1358 if self.loc_for_expr != loc.Missing: # more specific
1359 return self.loc_for_expr
1360
1361 if self.token_for_line: # less specific
1362 return self.token_for_line
1363
1364 return loc.Missing
1365
1366 #
1367 # Status Variable Stack (for isolating $PS1 and $PS4)
1368 #
1369
1370 def LastStatus(self):
1371 # type: () -> int
1372 return self.last_status[-1]
1373
1374 def TryStatus(self):
1375 # type: () -> int
1376 return self.try_status[-1]
1377
1378 def TryError(self):
1379 # type: () -> value.Dict
1380 return self.try_error[-1]
1381
1382 def PipeStatus(self):
1383 # type: () -> List[int]
1384 return self.pipe_status[-1]
1385
1386 def SetLastStatus(self, x):
1387 # type: (int) -> None
1388 self.last_status[-1] = x
1389
1390 def SetTryStatus(self, x):
1391 # type: (int) -> None
1392 self.try_status[-1] = x
1393
1394 def SetTryError(self, x):
1395 # type: (value.Dict) -> None
1396 self.try_error[-1] = x
1397
1398 def SetPipeStatus(self, x):
1399 # type: (List[int]) -> None
1400 self.pipe_status[-1] = x
1401
1402 def SetSimplePipeStatus(self, status):
1403 # type: (int) -> None
1404
1405 # Optimization to avoid allocations
1406 top = self.pipe_status[-1]
1407 if len(top) == 1:
1408 top[0] = status
1409 else:
1410 self.pipe_status[-1] = [status]
1411
1412 def SetProcessSubStatus(self, x):
1413 # type: (List[int]) -> None
1414 self.process_sub_status[-1] = x
1415
1416 #
1417 # Call Stack
1418 #
1419
1420 def PushCall(self, func_name, def_tok):
1421 # type: (str, Token) -> None
1422 """Push argv, var, and debug stack frames.
1423
1424 Currently used for proc and func calls. TODO: New func evaluator may
1425 not use it.
1426
1427 Args:
1428 def_tok: Token where proc or func was defined, used to compute
1429 BASH_SOURCE.
1430 """
1431 # self.token_for_line can be None?
1432 self.debug_stack.append(
1433 debug_frame.Call(self.token_for_line, def_tok, func_name))
1434
1435 def PopCall(self):
1436 # type: () -> None
1437 """
1438 Args:
1439 should_pop_argv_stack: Pass False if PushCall was given None for argv
1440 True for proc, False for func
1441 """
1442 self.debug_stack.pop()
1443
1444 def ShouldRunDebugTrap(self):
1445 # type: () -> bool
1446
1447 # TODO: RunLastPart of pipeline can disable this
1448
1449 # Don't recursively run DEBUG trap
1450 if self.running_debug_trap:
1451 return False
1452
1453 # Don't run it inside functions
1454 if len(self.var_stack) > 1:
1455 return False
1456
1457 return True
1458
1459 def InsideFunction(self):
1460 # type: () -> bool
1461 """For the ERR trap"""
1462
1463 # Don't run it inside functions
1464 return len(self.var_stack) > 1
1465
1466 def PushSource(self, source_name, argv):
1467 # type: (str, List[str]) -> None
1468 """ For 'source foo.sh 1 2 3' """
1469 if len(argv):
1470 self.argv_stack.append(_ArgFrame(argv))
1471
1472 # self.token_for_line can be None?
1473 self.debug_stack.append(
1474 debug_frame.Source(self.token_for_line, source_name))
1475
1476 def PopSource(self, argv):
1477 # type: (List[str]) -> None
1478 self.debug_stack.pop()
1479
1480 if len(argv):
1481 self.argv_stack.pop()
1482
1483 def PushTemp(self):
1484 # type: () -> None
1485 """For the temporary scope in 'FOO=bar BAR=baz echo'.
1486
1487 Also for PS4 evaluation with more variables.
1488 """
1489 # We don't want the 'read' builtin to write to this frame!
1490 frame = NewDict() # type: Dict[str, Cell]
1491 self.var_stack.append(frame)
1492
1493 def PopTemp(self):
1494 # type: () -> None
1495 self.var_stack.pop()
1496
1497 def TopNamespace(self):
1498 # type: () -> Dict[str, Cell]
1499 """For eval_to_dict()."""
1500 return self.var_stack[-1]
1501
1502 #
1503 # Argv
1504 #
1505
1506 def Shift(self, n):
1507 # type: (int) -> int
1508 frame = self.argv_stack[-1]
1509 num_args = len(frame.argv)
1510
1511 if (frame.num_shifted + n) <= num_args:
1512 frame.num_shifted += n
1513 return 0 # success
1514 else:
1515 return 1 # silent error
1516
1517 def GetArg0(self):
1518 # type: () -> value.Str
1519 """Like GetArgNum(0) but with a more specific type."""
1520 return value.Str(self.dollar0)
1521
1522 def GetArgNum(self, arg_num):
1523 # type: (int) -> value_t
1524 if arg_num == 0:
1525 # $0 may be overriden, eg. by Str => replace()
1526 vars = self.var_stack[-1]
1527 if "0" in vars and vars["0"].val.tag() != value_e.Undef:
1528 return vars["0"].val
1529 return value.Str(self.dollar0)
1530
1531 return self.argv_stack[-1].GetArgNum(arg_num)
1532
1533 def GetArgv(self):
1534 # type: () -> List[str]
1535 """For $* and $@."""
1536 return self.argv_stack[-1].GetArgv()
1537
1538 def SetArgv(self, argv):
1539 # type: (List[str]) -> None
1540 """For set -- 1 2 3."""
1541 # from set -- 1 2 3
1542 self.argv_stack[-1].SetArgv(argv)
1543
1544 #
1545 # Special Vars
1546 #
1547
1548 def GetSpecialVar(self, op_id):
1549 # type: (int) -> value_t
1550 if op_id == Id.VSub_Bang: # $!
1551 n = self.last_bg_pid
1552 if n == -1:
1553 return value.Undef # could be an error
1554
1555 elif op_id == Id.VSub_QMark: # $?
1556 # External commands need WIFEXITED test. What about subshells?
1557 n = self.last_status[-1]
1558
1559 elif op_id == Id.VSub_Pound: # $#
1560 n = self.argv_stack[-1].GetNumArgs()
1561
1562 elif op_id == Id.VSub_Dollar: # $$
1563 n = self.root_pid
1564
1565 else:
1566 raise NotImplementedError(op_id)
1567
1568 return value.Str(str(n))
1569
1570 #
1571 # Named Vars
1572 #
1573
1574 def _ResolveNameOnly(self, name, which_scopes):
1575 # type: (str, scope_t) -> Tuple[Optional[Cell], Dict[str, Cell]]
1576 """Helper for getting and setting variable.
1577
1578 Returns:
1579 cell: The cell corresponding to looking up 'name' with the given mode, or
1580 None if it's not found.
1581 name_map: The name_map it should be set to or deleted from.
1582 """
1583 if which_scopes == scope_e.Dynamic:
1584 for i in xrange(len(self.var_stack) - 1, -1, -1):
1585 name_map = self.var_stack[i]
1586 if name in name_map:
1587 cell = name_map[name]
1588 return cell, name_map
1589 no_cell = None # type: Optional[Cell]
1590 return no_cell, self.var_stack[0] # set in global name_map
1591
1592 if which_scopes == scope_e.LocalOnly:
1593 name_map = self.var_stack[-1]
1594 return name_map.get(name), name_map
1595
1596 if which_scopes == scope_e.GlobalOnly:
1597 name_map = self.var_stack[0]
1598 return name_map.get(name), name_map
1599
1600 if which_scopes == scope_e.LocalOrGlobal:
1601 # Local
1602 name_map = self.var_stack[-1]
1603 cell = name_map.get(name)
1604 if cell:
1605 return cell, name_map
1606
1607 # Global
1608 name_map = self.var_stack[0]
1609 return name_map.get(name), name_map
1610
1611 raise AssertionError()
1612
1613 def _ResolveNameOrRef(
1614 self,
1615 name, # type: str
1616 which_scopes, # type: scope_t
1617 ref_trail=None, # type: Optional[List[str]]
1618 ):
1619 # type: (...) -> Tuple[Optional[Cell], Dict[str, Cell], str]
1620 """Look up a cell and namespace, but respect the nameref flag.
1621
1622 Resolving namerefs does RECURSIVE calls.
1623 """
1624 cell, name_map = self._ResolveNameOnly(name, which_scopes)
1625
1626 if cell is None or not cell.nameref:
1627 return cell, name_map, name # not a nameref
1628
1629 val = cell.val
1630 UP_val = val
1631 with tagswitch(val) as case:
1632 if case(value_e.Undef):
1633 # This is 'local -n undef_ref', which is kind of useless, because the
1634 # more common idiom is 'local -n ref=$1'. Note that you can mutate
1635 # references themselves with local -n ref=new.
1636 if self.exec_opts.strict_nameref():
1637 e_die('nameref %r is undefined' % name)
1638 else:
1639 return cell, name_map, name # fallback
1640
1641 elif case(value_e.Str):
1642 val = cast(value.Str, UP_val)
1643 new_name = val.s
1644
1645 else:
1646 # SetValue() protects the invariant that nameref is Undef or Str
1647 raise AssertionError(val.tag())
1648
1649 # TODO: Respect eval_unsafe_arith here (issue 881). See how it's done in
1650 # 'printf -v' with MakeArithParser
1651 if not match.IsValidVarName(new_name):
1652 # e.g. '#' or '1' or ''
1653 if self.exec_opts.strict_nameref():
1654 e_die('nameref %r contains invalid variable name %r' %
1655 (name, new_name))
1656 else:
1657 # Bash has this odd behavior of clearing the nameref bit when
1658 # ref=#invalid#. strict_nameref avoids it.
1659 cell.nameref = False
1660 return cell, name_map, name # fallback
1661
1662 # Check for circular namerefs.
1663 if ref_trail is None:
1664 ref_trail = [name]
1665 else:
1666 if new_name in ref_trail:
1667 e_die('Circular nameref %s' % ' -> '.join(ref_trail))
1668 ref_trail.append(new_name)
1669
1670 # 'declare -n' uses dynamic scope.
1671 cell, name_map, cell_name = self._ResolveNameOrRef(new_name,
1672 scope_e.Dynamic,
1673 ref_trail=ref_trail)
1674 return cell, name_map, cell_name
1675
1676 def IsBashAssoc(self, name):
1677 # type: (str) -> bool
1678 """Returns whether a name resolve to a cell with an associative array.
1679
1680 We need to know this to evaluate the index expression properly
1681 -- should it be coerced to an integer or not?
1682 """
1683 cell, _, _ = self._ResolveNameOrRef(name, self.ScopesForReading())
1684 # foo=([key]=value)
1685 return cell is not None and cell.val.tag() == value_e.BashAssoc
1686
1687 def SetPlace(self, place, val, blame_loc):
1688 # type: (value.Place, value_t, loc_t) -> None
1689
1690 yval = place.lval
1691 UP_yval = yval
1692 with tagswitch(yval) as case:
1693 if case(y_lvalue_e.Local):
1694 yval = cast(LeftName, UP_yval)
1695
1696 # Check that the frame is still alive
1697 found = False
1698 for i in xrange(len(self.var_stack) - 1, -1, -1):
1699 frame = self.var_stack[i]
1700 if frame is place.frame:
1701 found = True
1702 #log('FOUND %s', found)
1703 break
1704 if not found:
1705 e_die(
1706 "Can't assign to place that's no longer on the call stack.",
1707 blame_loc)
1708
1709 cell = frame.get(yval.name)
1710 if cell is None:
1711 cell = Cell(False, False, False, val)
1712 frame[yval.name] = cell
1713 else:
1714 cell.val = val
1715
1716 elif case(y_lvalue_e.Container):
1717 e_die('Container place not implemented', blame_loc)
1718
1719 else:
1720 raise AssertionError()
1721
1722 def SetLocalName(self, lval, val):
1723 # type: (LeftName, value_t) -> None
1724
1725 # Equivalent to
1726 # self._ResolveNameOnly(lval.name, scope_e.LocalOnly)
1727 name_map = self.var_stack[-1]
1728 cell = name_map.get(lval.name)
1729
1730 if cell:
1731 if cell.readonly:
1732 e_die("Can't assign to readonly value %r" % lval.name,
1733 lval.blame_loc)
1734 cell.val = val # Mutate value_t
1735 else:
1736 cell = Cell(False, False, False, val)
1737 name_map[lval.name] = cell
1738
1739 def SetNamed(self, lval, val, which_scopes, flags=0):
1740 # type: (LeftName, value_t, scope_t, int) -> None
1741
1742 if flags & SetNameref or flags & ClearNameref:
1743 # declare -n ref=x # refers to the ref itself
1744 cell, name_map = self._ResolveNameOnly(lval.name, which_scopes)
1745 cell_name = lval.name
1746 else:
1747 # ref=x # mutates THROUGH the reference
1748
1749 # Note on how to implement declare -n ref='a[42]'
1750 # 1. Call _ResolveNameOnly()
1751 # 2. If cell.nameref, call self.unsafe_arith.ParseVarRef() ->
1752 # BracedVarSub
1753 # 3. Turn BracedVarSub into an sh_lvalue, and call
1754 # self.unsafe_arith.SetValue() wrapper with ref_trail
1755 cell, name_map, cell_name = self._ResolveNameOrRef(
1756 lval.name, which_scopes)
1757
1758 if cell:
1759 # Clear before checking readonly bit.
1760 # NOTE: Could be cell.flags &= flag_clear_mask
1761 if flags & ClearExport:
1762 cell.exported = False
1763 if flags & ClearReadOnly:
1764 cell.readonly = False
1765 if flags & ClearNameref:
1766 cell.nameref = False
1767
1768 if val is not None: # e.g. declare -rx existing
1769 # Note: this DYNAMIC check means we can't have 'const' in a loop.
1770 # But that's true for 'readonly' too, and hoisting it makes more
1771 # sense anyway.
1772 if cell.readonly:
1773 e_die("Can't assign to readonly value %r" % lval.name,
1774 lval.blame_loc)
1775 cell.val = val # CHANGE VAL
1776
1777 # NOTE: Could be cell.flags |= flag_set_mask
1778 if flags & SetExport:
1779 cell.exported = True
1780 if flags & SetReadOnly:
1781 cell.readonly = True
1782 if flags & SetNameref:
1783 cell.nameref = True
1784
1785 else:
1786 if val is None: # declare -rx nonexistent
1787 # set -o nounset; local foo; echo $foo # It's still undefined!
1788 val = value.Undef # export foo, readonly foo
1789
1790 cell = Cell(bool(flags & SetExport), bool(flags & SetReadOnly),
1791 bool(flags & SetNameref), val)
1792 name_map[cell_name] = cell
1793
1794 # Maintain invariant that only strings and undefined cells can be
1795 # exported.
1796 assert cell.val is not None, cell
1797
1798 if cell.val.tag() not in (value_e.Undef, value_e.Str):
1799 if cell.exported:
1800 if self.exec_opts.strict_array():
1801 e_die("Only strings can be exported (strict_array)",
1802 lval.blame_loc)
1803 if cell.nameref:
1804 e_die("nameref must be a string", lval.blame_loc)
1805
1806 def SetValue(self, lval, val, which_scopes, flags=0):
1807 # type: (sh_lvalue_t, value_t, scope_t, int) -> None
1808 """
1809 Args:
1810 lval: sh_lvalue
1811 val: value, or None if only changing flags
1812 which_scopes:
1813 Local | Global | Dynamic - for builtins, PWD, etc.
1814 flags: packed pair (keyword_id, bit mask of set/clear flags)
1815
1816 Note: in bash, PWD=/ changes the directory. But not in dash.
1817 """
1818 # STRICTNESS / SANENESS:
1819 #
1820 # 1) Don't create arrays automatically, e.g. a[1000]=x
1821 # 2) Never change types? yeah I think that's a good idea, at least for oil
1822 # (not sh, for compatibility). set -o strict_types or something. That
1823 # means arrays have to be initialized with let arr = [], which is fine.
1824 # This helps with stuff like IFS. It starts off as a string, and assigning
1825 # it to a list is an error. I guess you will have to turn this no for
1826 # bash?
1827 #
1828 # TODO:
1829 # - COMPUTED vars can't be set
1830 # - What about PWD / OLDPWD / UID / EUID ? You can simply make them
1831 # readonly.
1832 # - Maybe PARSE $PS1 and $PS4 when they're set, to avoid the error on use?
1833 # - Other validity: $HOME could be checked for existence
1834
1835 UP_lval = lval
1836 with tagswitch(lval) as case:
1837 if case(sh_lvalue_e.Var):
1838 lval = cast(LeftName, UP_lval)
1839
1840 self.SetNamed(lval, val, which_scopes, flags=flags)
1841
1842 elif case(sh_lvalue_e.Indexed):
1843 lval = cast(sh_lvalue.Indexed, UP_lval)
1844
1845 # There is no syntax 'declare a[x]'
1846 assert val is not None, val
1847
1848 # TODO: relax this for Oil
1849 assert val.tag() == value_e.Str, val
1850 rval = cast(value.Str, val)
1851
1852 # Note: location could be a[x]=1 or (( a[ x ] = 1 ))
1853 left_loc = lval.blame_loc
1854
1855 # bash/mksh have annoying behavior of letting you do LHS assignment to
1856 # Undef, which then turns into an INDEXED array. (Undef means that set
1857 # -o nounset fails.)
1858 cell, name_map, _ = self._ResolveNameOrRef(
1859 lval.name, which_scopes)
1860 if not cell:
1861 self._BindNewArrayWithEntry(name_map, lval, rval, flags)
1862 return
1863
1864 if cell.readonly:
1865 e_die("Can't assign to readonly array", left_loc)
1866
1867 UP_cell_val = cell.val
1868 # undef[0]=y is allowed
1869 with tagswitch(UP_cell_val) as case2:
1870 if case2(value_e.Undef):
1871 self._BindNewArrayWithEntry(name_map, lval, rval,
1872 flags)
1873 return
1874
1875 elif case2(value_e.Str):
1876 # s=x
1877 # s[1]=y # invalid
1878 e_die("Can't assign to items in a string", left_loc)
1879
1880 elif case2(value_e.BashArray):
1881 cell_val = cast(value.BashArray, UP_cell_val)
1882 strs = cell_val.strs
1883
1884 n = len(strs)
1885 index = lval.index
1886 if index < 0: # a[-1]++ computes this twice; could we avoid it?
1887 index += n
1888
1889 if 0 <= index and index < n:
1890 strs[index] = rval.s
1891 else:
1892 # Fill it in with None. It could look like this:
1893 # ['1', 2, 3, None, None, '4', None]
1894 # Then ${#a[@]} counts the entries that are not None.
1895 #
1896 # TODO: strict_array for Oil arrays won't auto-fill.
1897 n = index - len(strs) + 1
1898 for i in xrange(n):
1899 strs.append(None)
1900 strs[lval.index] = rval.s
1901 return
1902
1903 # This could be an object, eggex object, etc. It won't be
1904 # BashAssoc shouldn because we query IsBashAssoc before evaluating
1905 # sh_lhs. Could conslidate with s[i] case above
1906 e_die(
1907 "Value of type %s can't be indexed" % ui.ValType(cell.val),
1908 left_loc)
1909
1910 elif case(sh_lvalue_e.Keyed):
1911 lval = cast(sh_lvalue.Keyed, UP_lval)
1912
1913 # There is no syntax 'declare A["x"]'
1914 assert val is not None, val
1915 assert val.tag() == value_e.Str, val
1916 rval = cast(value.Str, val)
1917
1918 left_loc = lval.blame_loc
1919
1920 cell, name_map, _ = self._ResolveNameOrRef(
1921 lval.name, which_scopes)
1922 if cell.readonly:
1923 e_die("Can't assign to readonly associative array",
1924 left_loc)
1925
1926 # We already looked it up before making the sh_lvalue
1927 assert cell.val.tag() == value_e.BashAssoc, cell
1928 cell_val2 = cast(value.BashAssoc, cell.val)
1929
1930 cell_val2.d[lval.key] = rval.s
1931
1932 else:
1933 raise AssertionError(lval.tag())
1934
1935 def _BindNewArrayWithEntry(self, name_map, lval, val, flags):
1936 # type: (Dict[str, Cell], sh_lvalue.Indexed, value.Str, int) -> None
1937 """Fill 'name_map' with a new indexed array entry."""
1938 no_str = None # type: Optional[str]
1939 items = [no_str] * lval.index
1940 items.append(val.s)
1941 new_value = value.BashArray(items)
1942
1943 # arrays can't be exported; can't have BashAssoc flag
1944 readonly = bool(flags & SetReadOnly)
1945 name_map[lval.name] = Cell(False, readonly, False, new_value)
1946
1947 def InternalSetGlobal(self, name, new_val):
1948 # type: (str, value_t) -> None
1949 """For setting read-only globals internally.
1950
1951 Args:
1952 name: string (not Lhs)
1953 new_val: value
1954
1955 The variable must already exist.
1956
1957 Use case: SHELLOPTS.
1958 """
1959 cell = self.var_stack[0][name]
1960 cell.val = new_val
1961
1962 def GetValue(self, name, which_scopes=scope_e.Shopt):
1963 # type: (str, scope_t) -> value_t
1964 """Used by the WordEvaluator, ArithEvaluator, ExprEvaluator, etc."""
1965 assert isinstance(name, str), name
1966
1967 if which_scopes == scope_e.Shopt:
1968 which_scopes = self.ScopesForReading()
1969
1970 with str_switch(name) as case:
1971 # "Registers"
1972 if case('_status'):
1973 return num.ToBig(self.TryStatus())
1974
1975 elif case('_error'):
1976 return self.TryError()
1977
1978 elif case('_this_dir'):
1979 if len(self.this_dir) == 0:
1980 # e.g. osh -c '' doesn't have it set
1981 # Should we give a custom error here?
1982 # If you're at the interactive shell, 'source mymodule.oil' will still
1983 # work because 'source' sets it.
1984 return value.Undef
1985 else:
1986 return value.Str(self.this_dir[-1]) # top of stack
1987
1988 elif case('PIPESTATUS'):
1989 strs2 = [str(i)
1990 for i in self.pipe_status[-1]] # type: List[str]
1991 return value.BashArray(strs2)
1992
1993 elif case('_pipeline_status'):
1994 items = [num.ToBig(i)
1995 for i in self.pipe_status[-1]] # type: List[value_t]
1996 return value.List(items)
1997
1998 elif case('_process_sub_status'): # YSH naming convention
1999 items = [num.ToBig(i) for i in self.process_sub_status[-1]]
2000 return value.List(items)
2001
2002 elif case('BASH_REMATCH'):
2003 top_match = self.regex_match[-1]
2004 with tagswitch(top_match) as case2:
2005 if case2(regex_match_e.No):
2006 groups = [] # type: List[str]
2007 elif case2(regex_match_e.Yes):
2008 m = cast(RegexMatch, top_match)
2009 groups = util.RegexGroupStrings(m.s, m.indices)
2010 return value.BashArray(groups)
2011
2012 # Do lookup of system globals before looking at user variables. Note: we
2013 # could optimize this at compile-time like $?. That would break
2014 # ${!varref}, but it's already broken for $?.
2015
2016 elif case('FUNCNAME'):
2017 # bash wants it in reverse order. This is a little inefficient but we're
2018 # not depending on deque().
2019 strs = [] # type: List[str]
2020 for frame in reversed(self.debug_stack):
2021 UP_frame = frame
2022 with tagswitch(frame) as case2:
2023 if case2(debug_frame_e.Call):
2024 frame = cast(debug_frame.Call, UP_frame)
2025 strs.append(frame.func_name)
2026
2027 elif case2(debug_frame_e.Source):
2028 # bash doesn't tell you the filename sourced
2029 strs.append('source')
2030
2031 elif case2(debug_frame_e.Main):
2032 strs.append('main') # also bash behavior
2033
2034 return value.BashArray(strs) # TODO: Reuse this object too?
2035
2036 # $BASH_SOURCE and $BASH_LINENO have OFF BY ONE design bugs:
2037 #
2038 # ${BASH_LINENO[$i]} is the line number in the source file
2039 # (${BASH_SOURCE[$i+1]}) where ${FUNCNAME[$i]} was called (or
2040 # ${BASH_LINENO[$i-1]} if referenced within another shell function).
2041 #
2042 # https://www.gnu.org/software/bash/manual/html_node/Bash-Variables.html
2043
2044 elif case('BASH_SOURCE'):
2045 strs = []
2046 for frame in reversed(self.debug_stack):
2047 UP_frame = frame
2048 with tagswitch(frame) as case2:
2049 if case2(debug_frame_e.Call):
2050 frame = cast(debug_frame.Call, UP_frame)
2051
2052 # Weird bash behavior
2053 assert frame.def_tok.line is not None
2054 source_str = ui.GetLineSourceString(
2055 frame.def_tok.line)
2056 strs.append(source_str)
2057
2058 elif case2(debug_frame_e.Source):
2059 frame = cast(debug_frame.Source, UP_frame)
2060 # Is this right?
2061 strs.append(frame.source_name)
2062
2063 elif case2(debug_frame_e.Main):
2064 frame = cast(debug_frame.Main, UP_frame)
2065 strs.append(frame.dollar0)
2066
2067 return value.BashArray(strs) # TODO: Reuse this object too?
2068
2069 elif case('BASH_LINENO'):
2070 strs = []
2071 for frame in reversed(self.debug_stack):
2072 UP_frame = frame
2073 with tagswitch(frame) as case2:
2074 if case2(debug_frame_e.Call):
2075 frame = cast(debug_frame.Call, UP_frame)
2076 strs.append(_LineNumber(frame.call_tok))
2077
2078 elif case2(debug_frame_e.Source):
2079 frame = cast(debug_frame.Source, UP_frame)
2080 strs.append(_LineNumber(frame.call_tok))
2081
2082 elif case2(debug_frame_e.Main):
2083 # Bash does this to line up with 'main'
2084 strs.append('0')
2085
2086 return value.BashArray(strs) # TODO: Reuse this object too?
2087
2088 elif case('LINENO'):
2089 assert self.token_for_line is not None
2090 # Reuse object with mutation
2091 # TODO: maybe use interned GetLineNumStr?
2092 self.line_num.s = str(self.token_for_line.line.line_num)
2093 return self.line_num
2094
2095 elif case('BASHPID'): # TODO: YSH io->getpid()
2096 return value.Str(str(posix.getpid()))
2097
2098 elif case('_'):
2099 return value.Str(self.last_arg)
2100
2101 elif case('SECONDS'):
2102 f = time_.time() - self.seconds_start
2103 ok, big_int = mops.FromFloat(f)
2104 assert ok, f # should never be NAN or INFINITY
2105 return value.Int(big_int)
2106
2107 else:
2108 # In the case 'declare -n ref='a[42]', the result won't be a cell. Idea to
2109 # fix this:
2110 # 1. Call self.unsafe_arith.ParseVarRef() -> BracedVarSub
2111 # 2. Call self.unsafe_arith.GetNameref(bvs_part), and get a value_t
2112 # We still need a ref_trail to detect cycles.
2113 cell, _, _ = self._ResolveNameOrRef(name, which_scopes)
2114 if cell:
2115 return cell.val
2116
2117 return value.Undef
2118
2119 def GetCell(self, name, which_scopes=scope_e.Shopt):
2120 # type: (str, scope_t) -> Cell
2121 """Get both the value and flags.
2122
2123 Usages:
2124 - the 'pp' builtin.
2125 - declare -p
2126 - ${x@a}
2127 - to test of 'TZ' is exported in printf? Why?
2128 """
2129 if which_scopes == scope_e.Shopt:
2130 which_scopes = self.ScopesForReading()
2131
2132 cell, _ = self._ResolveNameOnly(name, which_scopes)
2133 return cell
2134
2135 def Unset(self, lval, which_scopes):
2136 # type: (sh_lvalue_t, scope_t) -> bool
2137 """
2138 Returns:
2139 Whether the cell was found.
2140 """
2141 # TODO: Refactor sh_lvalue type to avoid this
2142 UP_lval = lval
2143
2144 with tagswitch(lval) as case:
2145 if case(sh_lvalue_e.Var): # unset x
2146 lval = cast(LeftName, UP_lval)
2147 var_name = lval.name
2148 elif case(sh_lvalue_e.Indexed): # unset 'a[1]'
2149 lval = cast(sh_lvalue.Indexed, UP_lval)
2150 var_name = lval.name
2151 elif case(sh_lvalue_e.Keyed): # unset 'A["K"]'
2152 lval = cast(sh_lvalue.Keyed, UP_lval)
2153 var_name = lval.name
2154 else:
2155 raise AssertionError()
2156
2157 if which_scopes == scope_e.Shopt:
2158 which_scopes = self.ScopesForWriting()
2159
2160 cell, name_map, cell_name = self._ResolveNameOrRef(
2161 var_name, which_scopes)
2162 if not cell:
2163 return False # 'unset' builtin falls back on functions
2164 if cell.readonly:
2165 raise error.Runtime("Can't unset readonly variable %r" % var_name)
2166
2167 with tagswitch(lval) as case:
2168 if case(sh_lvalue_e.Var): # unset x
2169 # Make variables in higher scopes visible.
2170 # example: test/spec.sh builtin-vars -r 24 (ble.sh)
2171 mylib.dict_erase(name_map, cell_name)
2172
2173 # alternative that some shells use:
2174 # name_map[cell_name].val = value.Undef
2175 # cell.exported = False
2176
2177 # This should never happen because we do recursive lookups of namerefs.
2178 assert not cell.nameref, cell
2179
2180 elif case(sh_lvalue_e.Indexed): # unset 'a[1]'
2181 lval = cast(sh_lvalue.Indexed, UP_lval)
2182 # Note: Setting an entry to None and shifting entries are pretty
2183 # much the same in shell.
2184
2185 val = cell.val
2186 UP_val = val
2187 if val.tag() != value_e.BashArray:
2188 raise error.Runtime("%r isn't an array" % var_name)
2189
2190 val = cast(value.BashArray, UP_val)
2191 strs = val.strs
2192
2193 n = len(strs)
2194 last_index = n - 1
2195 index = lval.index
2196 if index < 0:
2197 index += n
2198
2199 if index == last_index:
2200 # Special case: The array SHORTENS if you unset from the end. You
2201 # can tell with a+=(3 4)
2202 strs.pop()
2203 elif 0 <= index and index < last_index:
2204 strs[index] = None
2205 else:
2206 # If it's not found, it's not an error. In other words, 'unset'
2207 # ensures that a value doesn't exist, regardless of whether it
2208 # existed. It's idempotent.
2209 # (Ousterhout specifically argues that the strict behavior was a
2210 # mistake for Tcl!)
2211 pass
2212
2213 elif case(sh_lvalue_e.Keyed): # unset 'A["K"]'
2214 lval = cast(sh_lvalue.Keyed, UP_lval)
2215
2216 val = cell.val
2217 UP_val = val
2218
2219 # note: never happens because of mem.IsBashAssoc test for sh_lvalue.Keyed
2220 #if val.tag() != value_e.BashAssoc:
2221 # raise error.Runtime("%r isn't an associative array" % lval.name)
2222
2223 val = cast(value.BashAssoc, UP_val)
2224 mylib.dict_erase(val.d, lval.key)
2225
2226 else:
2227 raise AssertionError(lval)
2228
2229 return True
2230
2231 def ScopesForReading(self):
2232 # type: () -> scope_t
2233 """Read scope."""
2234 return (scope_e.Dynamic
2235 if self.exec_opts.dynamic_scope() else scope_e.LocalOrGlobal)
2236
2237 def ScopesForWriting(self):
2238 # type: () -> scope_t
2239 """Write scope."""
2240 return (scope_e.Dynamic
2241 if self.exec_opts.dynamic_scope() else scope_e.LocalOnly)
2242
2243 def ClearFlag(self, name, flag):
2244 # type: (str, int) -> bool
2245 """Used for export -n.
2246
2247 We don't use SetValue() because even if rval is None, it will make an
2248 Undef value in a scope.
2249 """
2250 cell, name_map = self._ResolveNameOnly(name, self.ScopesForReading())
2251 if cell:
2252 if flag & ClearExport:
2253 cell.exported = False
2254 if flag & ClearNameref:
2255 cell.nameref = False
2256 return True
2257 else:
2258 return False
2259
2260 def GetExported(self):
2261 # type: () -> Dict[str, str]
2262 """Get all the variables that are marked exported."""
2263 # TODO: This is run on every SimpleCommand. Should we have a dirty flag?
2264 # We have to notice these things:
2265 # - If an exported variable is changed.
2266 # - If the set of exported variables changes.
2267
2268 exported = {} # type: Dict[str, str]
2269 # Search from globals up. Names higher on the stack will overwrite names
2270 # lower on the stack.
2271 for scope in self.var_stack:
2272 for name, cell in iteritems(scope):
2273 # TODO: Disallow exporting at assignment time. If an exported Str is
2274 # changed to BashArray, also clear its 'exported' flag.
2275 if cell.exported and cell.val.tag() == value_e.Str:
2276 val = cast(value.Str, cell.val)
2277 exported[name] = val.s
2278 return exported
2279
2280 def VarNames(self):
2281 # type: () -> List[str]
2282 """For internal OSH completion and compgen -A variable.
2283
2284 NOTE: We could also add $? $$ etc.?
2285 """
2286 ret = [] # type: List[str]
2287 # Look up the stack, yielding all variables. Bash seems to do this.
2288 for scope in self.var_stack:
2289 for name in scope:
2290 ret.append(name)
2291 return ret
2292
2293 def VarNamesStartingWith(self, prefix):
2294 # type: (str) -> List[str]
2295 """For ${!prefix@}"""
2296 # Look up the stack, yielding all variables. Bash seems to do this.
2297 names = [] # type: List[str]
2298 for scope in self.var_stack:
2299 for name in scope:
2300 if name.startswith(prefix):
2301 names.append(name)
2302 return names
2303
2304 def GetAllVars(self):
2305 # type: () -> Dict[str, str]
2306 """Get all variables and their values, for 'set' builtin."""
2307 result = {} # type: Dict[str, str]
2308 for scope in self.var_stack:
2309 for name, cell in iteritems(scope):
2310 # TODO: Show other types?
2311 val = cell.val
2312 if val.tag() == value_e.Str:
2313 str_val = cast(value.Str, val)
2314 result[name] = str_val.s
2315 return result
2316
2317 def GetAllCells(self, which_scopes):
2318 # type: (scope_t) -> Dict[str, Cell]
2319 """Get all variables and their values, for 'set' builtin."""
2320 result = {} # type: Dict[str, Cell]
2321
2322 if which_scopes == scope_e.Dynamic:
2323 scopes = self.var_stack
2324 elif which_scopes == scope_e.LocalOnly:
2325 scopes = self.var_stack[-1:]
2326 elif which_scopes == scope_e.GlobalOnly:
2327 scopes = self.var_stack[0:1]
2328 elif which_scopes == scope_e.LocalOrGlobal:
2329 scopes = [self.var_stack[0]]
2330 if len(self.var_stack) > 1:
2331 scopes.append(self.var_stack[-1])
2332 else:
2333 raise AssertionError()
2334
2335 for scope in scopes:
2336 for name, cell in iteritems(scope):
2337 result[name] = cell
2338 return result
2339
2340 def IsGlobalScope(self):
2341 # type: () -> bool
2342 return len(self.var_stack) == 1
2343
2344 def SetRegexMatch(self, match):
2345 # type: (regex_match_t) -> None
2346 self.regex_match[-1] = match
2347
2348 def GetRegexMatch(self):
2349 # type: () -> regex_match_t
2350 return self.regex_match[-1]
2351
2352 def PushContextStack(self, context):
2353 # type: (Dict[str, value_t]) -> None
2354 self.ctx_stack.append(context)
2355
2356 def GetContext(self):
2357 # type: () -> Optional[Dict[str, value_t]]
2358 if len(self.ctx_stack):
2359 return self.ctx_stack[-1]
2360 return None
2361
2362 def PopContextStack(self):
2363 # type: () -> Dict[str, value_t]
2364 assert self.ctx_stack, "Empty context stack"
2365 return self.ctx_stack.pop()
2366
2367
2368class Procs:
2369
2370 def __init__(self, mem):
2371 # type: (Mem) -> None
2372 self.mem = mem
2373 self.sh_funcs = {} # type: Dict[str, value.Proc]
2374
2375 def SetProc(self, name, proc):
2376 # type: (str, value.Proc) -> None
2377 self.mem.var_stack[0][name] = Cell(False, False, False, proc)
2378
2379 def SetShFunc(self, name, proc):
2380 # type: (str, value.Proc) -> None
2381 self.sh_funcs[name] = proc
2382
2383 def Get(self, name):
2384 # type: (str) -> value.Proc
2385 """Try to find a proc/sh-func by `name`, or return None if not found.
2386
2387 First, we search for a proc, and then a sh-func. This means that procs
2388 can shadow the definition of sh-funcs.
2389 """
2390 maybe_proc = self.mem.GetValue(name)
2391 if maybe_proc.tag() == value_e.Proc:
2392 return cast(value.Proc, maybe_proc)
2393
2394 if name in self.sh_funcs:
2395 return self.sh_funcs[name]
2396
2397 return None
2398
2399 def Del(self, to_del):
2400 # type: (str) -> None
2401 """Undefine a sh-func with name `to_del`, if it exists."""
2402 mylib.dict_erase(self.sh_funcs, to_del)
2403
2404 def GetNames(self):
2405 # type: () -> List[str]
2406 """Returns a *sorted* list of all proc names"""
2407 names = list(self.sh_funcs.keys())
2408
2409 vars = self.mem.var_stack[0]
2410 for name in vars:
2411 cell = vars[name]
2412 if cell.val.tag() == value_e.Proc:
2413 names.append(name)
2414
2415 return sorted(names)
2416
2417
2418#
2419# Wrappers to Set Variables
2420#
2421
2422
2423def OshLanguageSetValue(mem, lval, val, flags=0):
2424 # type: (Mem, sh_lvalue_t, value_t, int) -> None
2425 """Like 'setvar' (scope_e.LocalOnly), unless dynamic scope is on.
2426
2427 That is, it respects shopt --unset dynamic_scope.
2428
2429 Used for assignment builtins, (( a = b )), {fd}>out, ${x=}, etc.
2430 """
2431 which_scopes = mem.ScopesForWriting()
2432 mem.SetValue(lval, val, which_scopes, flags=flags)
2433
2434
2435def BuiltinSetValue(mem, lval, val):
2436 # type: (Mem, sh_lvalue_t, value_t) -> None
2437 """Equivalent of x=$y
2438
2439 Called by BuiltinSetString and BuiltinSetArray Used directly by
2440 printf -v because it can mutate an array
2441 """
2442 mem.SetValue(lval, val, mem.ScopesForWriting())
2443
2444
2445def BuiltinSetString(mem, name, s):
2446 # type: (Mem, str, str) -> None
2447 """Set a string by looking up the stack.
2448
2449 Used for 'read', 'getopts', completion builtins, etc.
2450 """
2451 assert isinstance(s, str)
2452 BuiltinSetValue(mem, location.LName(name), value.Str(s))
2453
2454
2455def BuiltinSetArray(mem, name, a):
2456 # type: (Mem, str, List[str]) -> None
2457 """Set an array by looking up the stack.
2458
2459 Used by compadjust, read -a, etc.
2460 """
2461 assert isinstance(a, list)
2462 BuiltinSetValue(mem, location.LName(name), value.BashArray(a))
2463
2464
2465def SetGlobalString(mem, name, s):
2466 # type: (Mem, str, str) -> None
2467 """Helper for completion, etc."""
2468 assert isinstance(s, str)
2469 val = value.Str(s)
2470 mem.SetNamed(location.LName(name), val, scope_e.GlobalOnly)
2471
2472
2473def SetGlobalArray(mem, name, a):
2474 # type: (Mem, str, List[str]) -> None
2475 """Used by completion, shell initialization, etc."""
2476 assert isinstance(a, list)
2477 mem.SetNamed(location.LName(name), value.BashArray(a), scope_e.GlobalOnly)
2478
2479
2480def _SetGlobalValue(mem, name, val):
2481 # type: (Mem, str, value_t) -> None
2482 """Helper for completion, etc."""
2483 mem.SetNamed(location.LName(name), val, scope_e.GlobalOnly)
2484
2485
2486def ExportGlobalString(mem, name, s):
2487 # type: (Mem, str, str) -> None
2488 """Helper for completion, $PWD, $OLDPWD, etc."""
2489 assert isinstance(s, str)
2490 val = value.Str(s)
2491 mem.SetNamed(location.LName(name),
2492 val,
2493 scope_e.GlobalOnly,
2494 flags=SetExport)
2495
2496
2497#
2498# Wrappers to Get Variables
2499#
2500
2501
2502def DynamicGetVar(mem, name, which_scopes):
2503 # type: (Mem, str, scope_t) -> value_t
2504 """
2505 For getVar() and shvarGet()
2506 """
2507 val = mem.GetValue(name, which_scopes=which_scopes)
2508
2509 # Undef is not a user-visible value!
2510 # There's no way to distinguish null from undefined.
2511 if val.tag() == value_e.Undef:
2512 return value.Null
2513
2514 return val
2515
2516
2517def GetString(mem, name):
2518 # type: (Mem, str) -> str
2519 """Wrapper around GetValue(). Check that HOME, PWD, OLDPWD, etc. are
2520 strings. bash doesn't have these errors because ${array} is ${array[0]}.
2521
2522 TODO: We could also check this when you're storing variables?
2523 """
2524 val = mem.GetValue(name)
2525 UP_val = val
2526 with tagswitch(val) as case:
2527 if case(value_e.Undef):
2528 raise error.Runtime("$%s isn't defined" % name)
2529 elif case(value_e.Str):
2530 return cast(value.Str, UP_val).s
2531 else:
2532 # User would have to 'unset HOME' to get rid of exported flag
2533 raise error.Runtime("$%s should be a string" % name)
2534
2535
2536def MaybeString(mem, name):
2537 # type: (Mem, str) -> Optional[str]
2538 """Like GetString(), but doesn't throw an exception."""
2539 try:
2540 return GetString(mem, name)
2541 except error.Runtime:
2542 return None
2543
2544
2545def GetInteger(mem, name):
2546 # type: (Mem, str) -> int
2547 """For OPTIND variable used in getopts builtin.
2548
2549 TODO: it could be value.Int() ?
2550 """
2551 val = mem.GetValue(name)
2552 if val.tag() != value_e.Str:
2553 raise error.Runtime('$%s should be a string, got %s' %
2554 (name, ui.ValType(val)))
2555 s = cast(value.Str, val).s
2556 try:
2557 i = int(s)
2558 except ValueError:
2559 raise error.Runtime("$%s doesn't look like an integer, got %r" %
2560 (name, s))
2561 return i
2562
2563
2564# vim: sw=4