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

2798 lines, 1400 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, Obj, 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 var_frame 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_FrontFrame(object):
1131 """
1132 For use by io->evalToDict(), which is a primitive used for Hay and the Dict
1133 proc
1134
1135 var mutated = 'm'
1136 var shadowed = 's'
1137
1138 Dict (&d) {
1139 shadowed = 42
1140 mutated = 'new' # this is equivalent to var mutated
1141
1142 setvar mutated = 'new'
1143 }
1144 echo $shadowed # restored to 's'
1145 echo $mutated # new
1146
1147 Or maybe we disallow the setvar lookup?
1148 """
1149
1150 def __init__(self, mem, out_dict):
1151 # type: (Mem, Dict[str, value_t]) -> None
1152 self.rear_frame = mem.var_stack[-1]
1153
1154 # __rear__ gets a lookup rule
1155 self.front_frame = NewDict() # type: Dict[str, Cell]
1156 self.front_frame['__rear__'] = Cell(False, False, False,
1157 value.Frame(self.rear_frame))
1158
1159 mem.var_stack[-1] = self.front_frame
1160
1161 self.mem = mem
1162 self.out_dict = out_dict
1163
1164 def __enter__(self):
1165 # type: () -> None
1166 pass
1167
1168 def __exit__(self, type, value, traceback):
1169 # type: (Any, Any, Any) -> None
1170
1171 for name, cell in iteritems(self.front_frame):
1172 #log('name %r', name)
1173 #log('cell %r', cell)
1174
1175 # User can hide variables with _ suffix
1176 # e.g. for i_ in foo bar { echo $i_ }
1177 if name.endswith('_'):
1178 continue
1179
1180 self.out_dict[name] = cell.val
1181
1182 # Restore
1183 self.mem.var_stack[-1] = self.rear_frame
1184
1185
1186class ctx_Eval(object):
1187 """Push temporary set of variables, $0, $1, $2, etc."""
1188
1189 def __init__(self, mem, dollar0, pos_args, vars):
1190 # type: (Mem, Optional[str], Optional[List[str]], Optional[Dict[str, value_t]]) -> None
1191 self.mem = mem
1192 self.dollar0 = dollar0
1193 self.pos_args = pos_args
1194 self.vars = vars
1195
1196 # $0 needs to have lexical scoping. So we store it with other locals.
1197 # As "0" cannot be parsed as an lvalue, we can safely store dollar0 there.
1198 if dollar0 is not None:
1199 assert mem.GetValue("0", scope_e.LocalOnly).tag() == value_e.Undef
1200 self.dollar0_lval = LeftName("0", loc.Missing)
1201 mem.SetLocalName(self.dollar0_lval, value.Str(dollar0))
1202
1203 if pos_args is not None:
1204 mem.argv_stack.append(_ArgFrame(pos_args))
1205
1206 if vars is not None:
1207 self.restore = [] # type: List[Tuple[LeftName, value_t]]
1208 self._Push(vars)
1209
1210 def __enter__(self):
1211 # type: () -> None
1212 pass
1213
1214 def __exit__(self, type, value_, traceback):
1215 # type: (Any, Any, Any) -> None
1216 if self.vars is not None:
1217 self._Pop()
1218
1219 if self.pos_args is not None:
1220 self.mem.argv_stack.pop()
1221
1222 if self.dollar0 is not None:
1223 self.mem.SetLocalName(self.dollar0_lval, value.Undef)
1224
1225 # Note: _Push and _Pop are separate methods because the C++ translation
1226 # doesn't like when they are inline in __init__ and __exit__.
1227 def _Push(self, vars):
1228 # type: (Dict[str, value_t]) -> None
1229 for name in vars:
1230 lval = location.LName(name)
1231 # LocalOnly because we are only overwriting the current scope
1232 old_val = self.mem.GetValue(name, scope_e.LocalOnly)
1233 self.restore.append((lval, old_val))
1234 self.mem.SetNamed(lval, vars[name], scope_e.LocalOnly)
1235
1236 def _Pop(self):
1237 # type: () -> None
1238 for lval, old_val in self.restore:
1239 if old_val.tag() == value_e.Undef:
1240 self.mem.Unset(lval, scope_e.LocalOnly)
1241 else:
1242 self.mem.SetNamed(lval, old_val, scope_e.LocalOnly)
1243
1244
1245def _FrameLookup(frame, name):
1246 # type: (Dict[str, Cell], str) -> Tuple[Optional[Cell], Dict[str, Cell]]
1247 """
1248 Look in the frame itself, then the __rear__ frame if it exists
1249 """
1250 cell = frame.get(name)
1251 if cell:
1252 return cell, frame
1253
1254 rear_cell = frame.get('__rear__') # ctx_FrontFrame() sets this
1255 if rear_cell:
1256 rear_val = rear_cell.val
1257 if rear_val and rear_val.tag() == value_e.Frame:
1258 frame = cast(value.Frame, rear_val).frame
1259 cell = frame.get(name)
1260 if cell:
1261 #return cell, frame
1262 return cell, None
1263
1264 return None, None
1265
1266
1267class Mem(object):
1268 """For storing variables.
1269
1270 Callers:
1271 User code: assigning and evaluating variables, in command context or
1272 arithmetic context.
1273 Completion engine: for COMP_WORDS, etc.
1274 Builtins call it implicitly: read, cd for $PWD, $OLDPWD, etc.
1275
1276 Modules: cmd_eval, word_eval, expr_eval, completion
1277 """
1278
1279 def __init__(self, dollar0, argv, arena, debug_stack):
1280 # type: (str, List[str], alloc.Arena, List[debug_frame_t]) -> None
1281 """
1282 Args:
1283 arena: currently unused
1284 """
1285 # circular dep initialized out of line
1286 self.exec_opts = None # type: optview.Exec
1287 self.unsafe_arith = None # type: sh_expr_eval.UnsafeArith
1288
1289 self.dollar0 = dollar0
1290 # If you only use YSH procs and funcs, this will remain at length 1.
1291 self.argv_stack = [_ArgFrame(argv)]
1292
1293 frame = NewDict() # type: Dict[str, Cell]
1294
1295 frame['ARGV'] = _MakeArgvCell(argv)
1296
1297 self.var_stack = [frame]
1298
1299 # The debug_stack isn't strictly necessary for execution. We use it
1300 # for crash dumps and for 3 parallel arrays: BASH_SOURCE, FUNCNAME, and
1301 # BASH_LINENO.
1302 self.debug_stack = debug_stack
1303
1304 self.pwd = None # type: Optional[str]
1305 self.seconds_start = time_.time()
1306
1307 self.token_for_line = None # type: Optional[Token]
1308 self.loc_for_expr = loc.Missing # type: loc_t
1309
1310 self.last_arg = '' # $_ is initially empty, NOT unset
1311 self.line_num = value.Str('')
1312
1313 # Done ONCE on initialization
1314 self.root_pid = posix.getpid()
1315
1316 # TODO:
1317 # - These are REGISTERS mutated by user code.
1318 # - Call it self.reg_stack? with ctx_Registers
1319 # - push-registers builtin
1320 self.last_status = [0] # type: List[int] # a stack
1321 self.try_status = [0] # type: List[int] # a stack
1322 self.try_error = [value.Dict({})] # type: List[value.Dict] # a stack
1323 self.pipe_status = [[]] # type: List[List[int]] # stack
1324 self.process_sub_status = [[]] # type: List[List[int]] # stack
1325
1326 # A stack but NOT a register?
1327 self.this_dir = [] # type: List[str]
1328 self.regex_match = [regex_match.No] # type: List[regex_match_t]
1329
1330 self.last_bg_pid = -1 # Uninitialized value mutable public variable
1331
1332 self.running_debug_trap = False # set by ctx_DebugTrap()
1333 self.running_err_trap = False # set by ctx_ErrTrap
1334 self.is_main = True # we start out in main
1335
1336 # For the ctx builtin
1337 self.ctx_stack = [] # type: List[Dict[str, value_t]]
1338
1339 self.builtins = NewDict() # type: Dict[str, value_t]
1340
1341 # Note: Python 2 and 3 have __builtins__
1342 # This is just for inspection
1343 builtins_module = Obj(None, self.builtins)
1344 frame['__builtins__'] = Cell(False, False, False, builtins_module)
1345
1346 def __repr__(self):
1347 # type: () -> str
1348 parts = [] # type: List[str]
1349 parts.append('<Mem')
1350 for i, frame in enumerate(self.var_stack):
1351 parts.append(' -- %d --' % i)
1352 for n, v in frame.iteritems():
1353 parts.append(' %s %s' % (n, v))
1354 parts.append('>')
1355 return '\n'.join(parts) + '\n'
1356
1357 def AddBuiltin(self, name, val):
1358 # type: (str, value_t) -> None
1359 self.builtins[name] = val
1360
1361 def SetPwd(self, pwd):
1362 # type: (str) -> None
1363 """Used by builtins."""
1364 self.pwd = pwd
1365
1366 def ParsingChangesAllowed(self):
1367 # type: () -> bool
1368 """For checking that syntax options are only used at the top level."""
1369
1370 # DISALLOW proc calls : they push argv_stack, var_stack, debug_stack
1371 # ALLOW source foo.sh arg1: pushes argv_stack, debug_stack
1372 # ALLOW FOO=bar : pushes var_stack
1373 return len(self.var_stack) == 1 or len(self.argv_stack) == 1
1374
1375 def Dump(self):
1376 # type: () -> Tuple[List[value_t], List[value_t], List[value_t]]
1377 """Copy state before unwinding the stack."""
1378 var_stack = [
1379 value.Dict(_DumpVarFrame(frame)) for frame in self.var_stack
1380 ] # type: List[value_t]
1381 argv_stack = [value.Dict(frame.Dump())
1382 for frame in self.argv_stack] # type: List[value_t]
1383
1384 debug_stack = [] # type: List[value_t]
1385
1386 # Reuse these immutable objects
1387 t_call = value.Str('Call')
1388 t_source = value.Str('Source')
1389 t_main = value.Str('Main')
1390
1391 for frame in reversed(self.debug_stack):
1392 UP_frame = frame
1393 with tagswitch(frame) as case:
1394 if case(debug_frame_e.Call):
1395 frame = cast(debug_frame.Call, UP_frame)
1396 d = {
1397 'type': t_call,
1398 'func_name': value.Str(frame.func_name)
1399 } # type: Dict[str, value_t]
1400
1401 _AddCallToken(d, frame.call_tok)
1402 # TODO: Add def_tok
1403
1404 elif case(debug_frame_e.Source):
1405 frame = cast(debug_frame.Source, UP_frame)
1406 d = {
1407 'type': t_source,
1408 'source_name': value.Str(frame.source_name)
1409 }
1410 _AddCallToken(d, frame.call_tok)
1411
1412 elif case(debug_frame_e.Main):
1413 frame = cast(debug_frame.Main, UP_frame)
1414 d = {'type': t_main, 'dollar0': value.Str(frame.dollar0)}
1415
1416 debug_stack.append(value.Dict(d))
1417 return var_stack, argv_stack, debug_stack
1418
1419 def SetLastArgument(self, s):
1420 # type: (str) -> None
1421 """For $_"""
1422 self.last_arg = s
1423
1424 def SetTokenForLine(self, tok):
1425 # type: (Token) -> None
1426 """Set a token to compute $LINENO
1427
1428 This means it should be set on SimpleCommand, ShAssignment, ((, [[,
1429 case, etc. -- anything that evaluates a word. Example: there was a bug
1430 with 'case $LINENO'
1431
1432 This token also used as a "least-specific" / fallback location for
1433 errors in ExecuteAndCatch().
1434
1435 Although most of that should be taken over by 'with ui.ctx_Location()`,
1436 for the errfmt.
1437 """
1438 if self.running_debug_trap or self.running_err_trap:
1439 return
1440
1441 #if tok.span_id == runtime.NO_SPID:
1442 # NOTE: This happened in the osh-runtime benchmark for yash.
1443 #log('Warning: span_id undefined in SetTokenForLine')
1444
1445 #import traceback
1446 #traceback.print_stack()
1447 #return
1448
1449 self.token_for_line = tok
1450
1451 def SetLocationForExpr(self, blame_loc):
1452 # type: (loc_t) -> None
1453 """
1454 A more specific fallback location, like the $[ in
1455
1456 echo $[len(42)]
1457 """
1458 self.loc_for_expr = blame_loc
1459
1460 def GetFallbackLocation(self):
1461 # type: () -> loc_t
1462
1463 if self.loc_for_expr != loc.Missing: # more specific
1464 return self.loc_for_expr
1465
1466 if self.token_for_line: # less specific
1467 return self.token_for_line
1468
1469 return loc.Missing
1470
1471 #
1472 # Status Variable Stack (for isolating $PS1 and $PS4)
1473 #
1474
1475 def LastStatus(self):
1476 # type: () -> int
1477 return self.last_status[-1]
1478
1479 def TryStatus(self):
1480 # type: () -> int
1481 return self.try_status[-1]
1482
1483 def TryError(self):
1484 # type: () -> value.Dict
1485 return self.try_error[-1]
1486
1487 def PipeStatus(self):
1488 # type: () -> List[int]
1489 return self.pipe_status[-1]
1490
1491 def SetLastStatus(self, x):
1492 # type: (int) -> None
1493 self.last_status[-1] = x
1494
1495 def SetTryStatus(self, x):
1496 # type: (int) -> None
1497 self.try_status[-1] = x
1498
1499 def SetTryError(self, x):
1500 # type: (value.Dict) -> None
1501 self.try_error[-1] = x
1502
1503 def SetPipeStatus(self, x):
1504 # type: (List[int]) -> None
1505 self.pipe_status[-1] = x
1506
1507 def SetSimplePipeStatus(self, status):
1508 # type: (int) -> None
1509
1510 # Optimization to avoid allocations
1511 top = self.pipe_status[-1]
1512 if len(top) == 1:
1513 top[0] = status
1514 else:
1515 self.pipe_status[-1] = [status]
1516
1517 def SetProcessSubStatus(self, x):
1518 # type: (List[int]) -> None
1519 self.process_sub_status[-1] = x
1520
1521 #
1522 # Call Stack
1523 #
1524
1525 def PushCall(self, func_name, def_tok):
1526 # type: (str, Token) -> None
1527 """Push argv, var, and debug stack frames.
1528
1529 Currently used for proc and func calls. TODO: New func evaluator may
1530 not use it.
1531
1532 Args:
1533 def_tok: Token where proc or func was defined, used to compute
1534 BASH_SOURCE.
1535 """
1536 # self.token_for_line can be None?
1537 self.debug_stack.append(
1538 debug_frame.Call(self.token_for_line, def_tok, func_name))
1539
1540 def PopCall(self):
1541 # type: () -> None
1542 """
1543 Args:
1544 should_pop_argv_stack: Pass False if PushCall was given None for argv
1545 True for proc, False for func
1546 """
1547 self.debug_stack.pop()
1548
1549 def ShouldRunDebugTrap(self):
1550 # type: () -> bool
1551
1552 # TODO: RunLastPart of pipeline can disable this
1553
1554 # Don't recursively run DEBUG trap
1555 if self.running_debug_trap:
1556 return False
1557
1558 # Don't run it inside functions
1559 if len(self.var_stack) > 1:
1560 return False
1561
1562 return True
1563
1564 def InsideFunction(self):
1565 # type: () -> bool
1566 """For the ERR trap"""
1567
1568 # Don't run it inside functions
1569 return len(self.var_stack) > 1
1570
1571 def PushSource(self, source_name, argv):
1572 # type: (str, List[str]) -> None
1573 """ For 'source foo.sh 1 2 3' """
1574 if len(argv):
1575 self.argv_stack.append(_ArgFrame(argv))
1576
1577 # self.token_for_line can be None?
1578 self.debug_stack.append(
1579 debug_frame.Source(self.token_for_line, source_name))
1580
1581 def PopSource(self, argv):
1582 # type: (List[str]) -> None
1583 self.debug_stack.pop()
1584
1585 if len(argv):
1586 self.argv_stack.pop()
1587
1588 def PushTemp(self):
1589 # type: () -> None
1590 """For the temporary scope in 'FOO=bar BAR=baz echo'.
1591
1592 Also for PS4 evaluation with more variables.
1593 """
1594 # We don't want the 'read' builtin to write to this frame!
1595 frame = NewDict() # type: Dict[str, Cell]
1596 self.var_stack.append(frame)
1597
1598 def PopTemp(self):
1599 # type: () -> None
1600 self.var_stack.pop()
1601
1602 def TopNamespace(self):
1603 # type: () -> Dict[str, Cell]
1604 """For eval_to_dict()."""
1605 return self.var_stack[-1]
1606
1607 #
1608 # Argv
1609 #
1610
1611 def Shift(self, n):
1612 # type: (int) -> int
1613 frame = self.argv_stack[-1]
1614 num_args = len(frame.argv)
1615
1616 if (frame.num_shifted + n) <= num_args:
1617 frame.num_shifted += n
1618 return 0 # success
1619 else:
1620 return 1 # silent error
1621
1622 def GetArg0(self):
1623 # type: () -> value.Str
1624 """Like GetArgNum(0) but with a more specific type."""
1625 return value.Str(self.dollar0)
1626
1627 def GetArgNum(self, arg_num):
1628 # type: (int) -> value_t
1629 if arg_num == 0:
1630 # $0 may be overriden, eg. by Str => replace()
1631 vars = self.var_stack[-1]
1632 if "0" in vars and vars["0"].val.tag() != value_e.Undef:
1633 return vars["0"].val
1634 return value.Str(self.dollar0)
1635
1636 return self.argv_stack[-1].GetArgNum(arg_num)
1637
1638 def GetArgv(self):
1639 # type: () -> List[str]
1640 """For $* and $@."""
1641 return self.argv_stack[-1].GetArgv()
1642
1643 def SetArgv(self, argv):
1644 # type: (List[str]) -> None
1645 """For set -- 1 2 3."""
1646 # from set -- 1 2 3
1647 self.argv_stack[-1].SetArgv(argv)
1648
1649 #
1650 # Special Vars
1651 #
1652
1653 def GetSpecialVar(self, op_id):
1654 # type: (int) -> value_t
1655 if op_id == Id.VSub_Bang: # $!
1656 n = self.last_bg_pid
1657 if n == -1:
1658 return value.Undef # could be an error
1659
1660 elif op_id == Id.VSub_QMark: # $?
1661 # External commands need WIFEXITED test. What about subshells?
1662 n = self.last_status[-1]
1663
1664 elif op_id == Id.VSub_Pound: # $#
1665 n = self.argv_stack[-1].GetNumArgs()
1666
1667 elif op_id == Id.VSub_Dollar: # $$
1668 n = self.root_pid
1669
1670 else:
1671 raise NotImplementedError(op_id)
1672
1673 return value.Str(str(n))
1674
1675 #
1676 # Named Vars
1677 #
1678
1679 def _ResolveNameOnly(self, name, which_scopes):
1680 # type: (str, scope_t) -> Tuple[Optional[Cell], Dict[str, Cell]]
1681 """Helper for getting and setting variable.
1682
1683 Returns:
1684 cell: The cell corresponding to looking up 'name' with the given mode, or
1685 None if it's not found.
1686 var_frame: The frame it should be set to or deleted from.
1687 """
1688 if which_scopes == scope_e.Dynamic:
1689 for i in xrange(len(self.var_stack) - 1, -1, -1):
1690 var_frame = self.var_stack[i]
1691 cell, result_frame = _FrameLookup(var_frame, name)
1692 if cell:
1693 return cell, result_frame
1694 return None, self.var_stack[0] # set in global var_frame
1695
1696 if which_scopes == scope_e.LocalOnly:
1697 var_frame = self.var_stack[-1]
1698 cell, result_frame = _FrameLookup(var_frame, name)
1699 if cell:
1700 return cell, result_frame
1701 return None, var_frame
1702
1703 if which_scopes == scope_e.GlobalOnly:
1704 var_frame = self.var_stack[0]
1705 cell, result_frame = _FrameLookup(var_frame, name)
1706 if cell:
1707 return cell, result_frame
1708
1709 return None, var_frame
1710
1711 if which_scopes == scope_e.LocalOrGlobal:
1712 # Local
1713 var_frame = self.var_stack[-1]
1714 cell, result_frame = _FrameLookup(var_frame, name)
1715 if cell:
1716 return cell, result_frame
1717
1718 # Global
1719 var_frame = self.var_stack[0]
1720 cell, result_frame = _FrameLookup(var_frame, name)
1721 if cell:
1722 return cell, result_frame
1723
1724 return None, var_frame
1725
1726 raise AssertionError()
1727
1728 def _ResolveNameOrRef(
1729 self,
1730 name, # type: str
1731 which_scopes, # type: scope_t
1732 ref_trail=None, # type: Optional[List[str]]
1733 ):
1734 # type: (...) -> Tuple[Optional[Cell], Dict[str, Cell], str]
1735 """Look up a cell and namespace, but respect the nameref flag.
1736
1737 Resolving namerefs does RECURSIVE calls.
1738 """
1739 cell, var_frame = self._ResolveNameOnly(name, which_scopes)
1740
1741 if cell is None or not cell.nameref:
1742 return cell, var_frame, name # not a nameref
1743
1744 val = cell.val
1745 UP_val = val
1746 with tagswitch(val) as case:
1747 if case(value_e.Undef):
1748 # This is 'local -n undef_ref', which is kind of useless, because the
1749 # more common idiom is 'local -n ref=$1'. Note that you can mutate
1750 # references themselves with local -n ref=new.
1751 if self.exec_opts.strict_nameref():
1752 e_die('nameref %r is undefined' % name)
1753 else:
1754 return cell, var_frame, name # fallback
1755
1756 elif case(value_e.Str):
1757 val = cast(value.Str, UP_val)
1758 new_name = val.s
1759
1760 else:
1761 # SetValue() protects the invariant that nameref is Undef or Str
1762 raise AssertionError(val.tag())
1763
1764 # TODO: Respect eval_unsafe_arith here (issue 881). See how it's done in
1765 # 'printf -v' with MakeArithParser
1766 if not match.IsValidVarName(new_name):
1767 # e.g. '#' or '1' or ''
1768 if self.exec_opts.strict_nameref():
1769 e_die('nameref %r contains invalid variable name %r' %
1770 (name, new_name))
1771 else:
1772 # Bash has this odd behavior of clearing the nameref bit when
1773 # ref=#invalid#. strict_nameref avoids it.
1774 cell.nameref = False
1775 return cell, var_frame, name # fallback
1776
1777 # Check for circular namerefs.
1778 if ref_trail is None:
1779 ref_trail = [name]
1780 else:
1781 if new_name in ref_trail:
1782 e_die('Circular nameref %s' % ' -> '.join(ref_trail))
1783 ref_trail.append(new_name)
1784
1785 # 'declare -n' uses dynamic scope.
1786 cell, var_frame, cell_name = self._ResolveNameOrRef(
1787 new_name, scope_e.Dynamic, ref_trail=ref_trail)
1788 return cell, var_frame, cell_name
1789
1790 def IsBashAssoc(self, name):
1791 # type: (str) -> bool
1792 """Returns whether a name resolve to a cell with an associative array.
1793
1794 We need to know this to evaluate the index expression properly
1795 -- should it be coerced to an integer or not?
1796 """
1797 cell, _, _ = self._ResolveNameOrRef(name, self.ScopesForReading())
1798 # foo=([key]=value)
1799 return cell is not None and cell.val.tag() == value_e.BashAssoc
1800
1801 def SetPlace(self, place, val, blame_loc):
1802 # type: (value.Place, value_t, loc_t) -> None
1803
1804 yval = place.lval
1805 UP_yval = yval
1806 with tagswitch(yval) as case:
1807 if case(y_lvalue_e.Local):
1808 yval = cast(LeftName, UP_yval)
1809
1810 # Check that the frame is still alive
1811 found = False
1812 for i in xrange(len(self.var_stack) - 1, -1, -1):
1813 frame = self.var_stack[i]
1814 if frame is place.frame:
1815 found = True
1816 #log('FOUND %s', found)
1817 break
1818 if not found:
1819 e_die(
1820 "Can't assign to place that's no longer on the call stack.",
1821 blame_loc)
1822
1823 cell = frame.get(yval.name)
1824 if cell is None:
1825 cell = Cell(False, False, False, val)
1826 frame[yval.name] = cell
1827 else:
1828 cell.val = val
1829
1830 elif case(y_lvalue_e.Container):
1831 e_die('Container place not implemented', blame_loc)
1832
1833 else:
1834 raise AssertionError()
1835
1836 def SetLocalName(self, lval, val):
1837 # type: (LeftName, value_t) -> None
1838 """
1839 Set a name in the local scope - used for func/proc param binding, etc.
1840 """
1841
1842 # Equivalent to
1843 # self._ResolveNameOnly(lval.name, scope_e.LocalOnly)
1844 var_frame = self.var_stack[-1]
1845 cell = var_frame.get(lval.name)
1846
1847 if cell:
1848 if cell.readonly:
1849 e_die("Can't assign to readonly value %r" % lval.name,
1850 lval.blame_loc)
1851 cell.val = val # Mutate value_t
1852 else:
1853 cell = Cell(False, False, False, val)
1854 var_frame[lval.name] = cell
1855
1856 def SetNamed(self, lval, val, which_scopes, flags=0):
1857 # type: (LeftName, value_t, scope_t, int) -> None
1858 if flags & SetNameref or flags & ClearNameref:
1859 # declare -n ref=x # refers to the ref itself
1860 cell, var_frame = self._ResolveNameOnly(lval.name, which_scopes)
1861 cell_name = lval.name
1862 else:
1863 # ref=x # mutates THROUGH the reference
1864
1865 # Note on how to implement declare -n ref='a[42]'
1866 # 1. Call _ResolveNameOnly()
1867 # 2. If cell.nameref, call self.unsafe_arith.ParseVarRef() ->
1868 # BracedVarSub
1869 # 3. Turn BracedVarSub into an sh_lvalue, and call
1870 # self.unsafe_arith.SetValue() wrapper with ref_trail
1871 cell, var_frame, cell_name = self._ResolveNameOrRef(
1872 lval.name, which_scopes)
1873
1874 if cell:
1875 # Clear before checking readonly bit.
1876 # NOTE: Could be cell.flags &= flag_clear_mask
1877 if flags & ClearExport:
1878 cell.exported = False
1879 if flags & ClearReadOnly:
1880 cell.readonly = False
1881 if flags & ClearNameref:
1882 cell.nameref = False
1883
1884 if val is not None: # e.g. declare -rx existing
1885 # Note: this DYNAMIC check means we can't have 'const' in a loop.
1886 # But that's true for 'readonly' too, and hoisting it makes more
1887 # sense anyway.
1888 if cell.readonly:
1889 e_die("Can't assign to readonly value %r" % lval.name,
1890 lval.blame_loc)
1891 cell.val = val # CHANGE VAL
1892
1893 # NOTE: Could be cell.flags |= flag_set_mask
1894 if flags & SetExport:
1895 cell.exported = True
1896 if flags & SetReadOnly:
1897 cell.readonly = True
1898 if flags & SetNameref:
1899 cell.nameref = True
1900
1901 else:
1902 if val is None: # declare -rx nonexistent
1903 # set -o nounset; local foo; echo $foo # It's still undefined!
1904 val = value.Undef # export foo, readonly foo
1905
1906 cell = Cell(bool(flags & SetExport), bool(flags & SetReadOnly),
1907 bool(flags & SetNameref), val)
1908 var_frame[cell_name] = cell
1909
1910 # Maintain invariant that only strings and undefined cells can be
1911 # exported.
1912 assert cell.val is not None, cell
1913
1914 if cell.val.tag() not in (value_e.Undef, value_e.Str):
1915 if cell.exported:
1916 if self.exec_opts.strict_array():
1917 e_die("Only strings can be exported (strict_array)",
1918 lval.blame_loc)
1919 if cell.nameref:
1920 e_die("nameref must be a string", lval.blame_loc)
1921
1922 def SetValue(self, lval, val, which_scopes, flags=0):
1923 # type: (sh_lvalue_t, value_t, scope_t, int) -> None
1924 """
1925 Args:
1926 lval: sh_lvalue
1927 val: value, or None if only changing flags
1928 which_scopes:
1929 Local | Global | Dynamic - for builtins, PWD, etc.
1930 flags: packed pair (keyword_id, bit mask of set/clear flags)
1931
1932 Note: in bash, PWD=/ changes the directory. But not in dash.
1933 """
1934 # STRICTNESS / SANENESS:
1935 #
1936 # 1) Don't create arrays automatically, e.g. a[1000]=x
1937 # 2) Never change types? yeah I think that's a good idea, at least for oil
1938 # (not sh, for compatibility). set -o strict_types or something. That
1939 # means arrays have to be initialized with let arr = [], which is fine.
1940 # This helps with stuff like IFS. It starts off as a string, and assigning
1941 # it to a list is an error. I guess you will have to turn this no for
1942 # bash?
1943 #
1944 # TODO:
1945 # - COMPUTED vars can't be set
1946 # - What about PWD / OLDPWD / UID / EUID ? You can simply make them
1947 # readonly.
1948 # - Maybe PARSE $PS1 and $PS4 when they're set, to avoid the error on use?
1949 # - Other validity: $HOME could be checked for existence
1950
1951 UP_lval = lval
1952 with tagswitch(lval) as case:
1953 if case(sh_lvalue_e.Var):
1954 lval = cast(LeftName, UP_lval)
1955
1956 self.SetNamed(lval, val, which_scopes, flags=flags)
1957
1958 elif case(sh_lvalue_e.Indexed):
1959 lval = cast(sh_lvalue.Indexed, UP_lval)
1960
1961 # There is no syntax 'declare a[x]'
1962 assert val is not None, val
1963
1964 # TODO: relax this for Oil
1965 assert val.tag() == value_e.Str, val
1966 rval = cast(value.Str, val)
1967
1968 # Note: location could be a[x]=1 or (( a[ x ] = 1 ))
1969 left_loc = lval.blame_loc
1970
1971 # bash/mksh have annoying behavior of letting you do LHS assignment to
1972 # Undef, which then turns into an INDEXED array. (Undef means that set
1973 # -o nounset fails.)
1974 cell, var_frame, _ = self._ResolveNameOrRef(
1975 lval.name, which_scopes)
1976 if not cell:
1977 self._BindNewArrayWithEntry(var_frame, lval, rval, flags)
1978 return
1979
1980 if cell.readonly:
1981 e_die("Can't assign to readonly array", left_loc)
1982
1983 UP_cell_val = cell.val
1984 # undef[0]=y is allowed
1985 with tagswitch(UP_cell_val) as case2:
1986 if case2(value_e.Undef):
1987 self._BindNewArrayWithEntry(var_frame, lval, rval,
1988 flags)
1989 return
1990
1991 elif case2(value_e.Str):
1992 # s=x
1993 # s[1]=y # invalid
1994 e_die("Can't assign to items in a string", left_loc)
1995
1996 elif case2(value_e.BashArray):
1997 cell_val = cast(value.BashArray, UP_cell_val)
1998 strs = cell_val.strs
1999
2000 n = len(strs)
2001 index = lval.index
2002 if index < 0: # a[-1]++ computes this twice; could we avoid it?
2003 index += n
2004
2005 if 0 <= index and index < n:
2006 strs[index] = rval.s
2007 else:
2008 # Fill it in with None. It could look like this:
2009 # ['1', 2, 3, None, None, '4', None]
2010 # Then ${#a[@]} counts the entries that are not None.
2011 #
2012 # TODO: strict_array for Oil arrays won't auto-fill.
2013 n = index - len(strs) + 1
2014 for i in xrange(n):
2015 strs.append(None)
2016 strs[lval.index] = rval.s
2017 return
2018
2019 # This could be an object, eggex object, etc. It won't be
2020 # BashAssoc shouldn because we query IsBashAssoc before evaluating
2021 # sh_lhs. Could conslidate with s[i] case above
2022 e_die(
2023 "Value of type %s can't be indexed" % ui.ValType(cell.val),
2024 left_loc)
2025
2026 elif case(sh_lvalue_e.Keyed):
2027 lval = cast(sh_lvalue.Keyed, UP_lval)
2028
2029 # There is no syntax 'declare A["x"]'
2030 assert val is not None, val
2031 assert val.tag() == value_e.Str, val
2032 rval = cast(value.Str, val)
2033
2034 left_loc = lval.blame_loc
2035
2036 cell, var_frame, _ = self._ResolveNameOrRef(
2037 lval.name, which_scopes)
2038 if cell.readonly:
2039 e_die("Can't assign to readonly associative array",
2040 left_loc)
2041
2042 # We already looked it up before making the sh_lvalue
2043 assert cell.val.tag() == value_e.BashAssoc, cell
2044 cell_val2 = cast(value.BashAssoc, cell.val)
2045
2046 cell_val2.d[lval.key] = rval.s
2047
2048 else:
2049 raise AssertionError(lval.tag())
2050
2051 def _BindNewArrayWithEntry(self, var_frame, lval, val, flags):
2052 # type: (Dict[str, Cell], sh_lvalue.Indexed, value.Str, int) -> None
2053 """Fill 'var_frame' with a new indexed array entry."""
2054 no_str = None # type: Optional[str]
2055 items = [no_str] * lval.index
2056 items.append(val.s)
2057 new_value = value.BashArray(items)
2058
2059 # arrays can't be exported; can't have BashAssoc flag
2060 readonly = bool(flags & SetReadOnly)
2061 var_frame[lval.name] = Cell(False, readonly, False, new_value)
2062
2063 def InternalSetGlobal(self, name, new_val):
2064 # type: (str, value_t) -> None
2065 """For setting read-only globals internally.
2066
2067 Args:
2068 name: string (not Lhs)
2069 new_val: value
2070
2071 The variable must already exist.
2072
2073 Use case: SHELLOPTS.
2074 """
2075 cell = self.var_stack[0][name]
2076 cell.val = new_val
2077
2078 def GetValue(self, name, which_scopes=scope_e.Shopt):
2079 # type: (str, scope_t) -> value_t
2080 """Used by the WordEvaluator, ArithEvaluator, ExprEvaluator, etc."""
2081 assert isinstance(name, str), name
2082
2083 if which_scopes == scope_e.Shopt:
2084 which_scopes = self.ScopesForReading()
2085
2086 with str_switch(name) as case:
2087 # "Registers"
2088 if case('_status'): # deprecated in favor of _error.code
2089 return num.ToBig(self.TryStatus())
2090
2091 elif case('_error'):
2092 return self.TryError()
2093
2094 elif case('_this_dir'):
2095 if len(self.this_dir) == 0:
2096 # e.g. osh -c '' doesn't have it set
2097 # Should we give a custom error here?
2098 # If you're at the interactive shell, 'source mymodule.oil' will still
2099 # work because 'source' sets it.
2100 return value.Undef
2101 else:
2102 return value.Str(self.this_dir[-1]) # top of stack
2103
2104 elif case('PIPESTATUS'):
2105 strs2 = [str(i)
2106 for i in self.pipe_status[-1]] # type: List[str]
2107 return value.BashArray(strs2)
2108
2109 elif case('_pipeline_status'):
2110 items = [num.ToBig(i)
2111 for i in self.pipe_status[-1]] # type: List[value_t]
2112 return value.List(items)
2113
2114 elif case('_process_sub_status'): # YSH naming convention
2115 items = [num.ToBig(i) for i in self.process_sub_status[-1]]
2116 return value.List(items)
2117
2118 elif case('BASH_REMATCH'):
2119 top_match = self.regex_match[-1]
2120 with tagswitch(top_match) as case2:
2121 if case2(regex_match_e.No):
2122 groups = [] # type: List[str]
2123 elif case2(regex_match_e.Yes):
2124 m = cast(RegexMatch, top_match)
2125 groups = util.RegexGroupStrings(m.s, m.indices)
2126 return value.BashArray(groups)
2127
2128 # Do lookup of system globals before looking at user variables. Note: we
2129 # could optimize this at compile-time like $?. That would break
2130 # ${!varref}, but it's already broken for $?.
2131
2132 elif case('FUNCNAME'):
2133 # bash wants it in reverse order. This is a little inefficient but we're
2134 # not depending on deque().
2135 strs = [] # type: List[str]
2136 for frame in reversed(self.debug_stack):
2137 UP_frame = frame
2138 with tagswitch(frame) as case2:
2139 if case2(debug_frame_e.Call):
2140 frame = cast(debug_frame.Call, UP_frame)
2141 strs.append(frame.func_name)
2142
2143 elif case2(debug_frame_e.Source):
2144 # bash doesn't tell you the filename sourced
2145 strs.append('source')
2146
2147 elif case2(debug_frame_e.Main):
2148 strs.append('main') # also bash behavior
2149
2150 return value.BashArray(strs) # TODO: Reuse this object too?
2151
2152 # $BASH_SOURCE and $BASH_LINENO have OFF BY ONE design bugs:
2153 #
2154 # ${BASH_LINENO[$i]} is the line number in the source file
2155 # (${BASH_SOURCE[$i+1]}) where ${FUNCNAME[$i]} was called (or
2156 # ${BASH_LINENO[$i-1]} if referenced within another shell function).
2157 #
2158 # https://www.gnu.org/software/bash/manual/html_node/Bash-Variables.html
2159
2160 elif case('BASH_SOURCE'):
2161 strs = []
2162 for frame in reversed(self.debug_stack):
2163 UP_frame = frame
2164 with tagswitch(frame) as case2:
2165 if case2(debug_frame_e.Call):
2166 frame = cast(debug_frame.Call, UP_frame)
2167
2168 # Weird bash behavior
2169 assert frame.def_tok.line is not None
2170 source_str = ui.GetLineSourceString(
2171 frame.def_tok.line)
2172 strs.append(source_str)
2173
2174 elif case2(debug_frame_e.Source):
2175 frame = cast(debug_frame.Source, UP_frame)
2176 # Is this right?
2177 strs.append(frame.source_name)
2178
2179 elif case2(debug_frame_e.Main):
2180 frame = cast(debug_frame.Main, UP_frame)
2181 strs.append(frame.dollar0)
2182
2183 return value.BashArray(strs) # TODO: Reuse this object too?
2184
2185 elif case('BASH_LINENO'):
2186 strs = []
2187 for frame in reversed(self.debug_stack):
2188 UP_frame = frame
2189 with tagswitch(frame) as case2:
2190 if case2(debug_frame_e.Call):
2191 frame = cast(debug_frame.Call, UP_frame)
2192 strs.append(_LineNumber(frame.call_tok))
2193
2194 elif case2(debug_frame_e.Source):
2195 frame = cast(debug_frame.Source, UP_frame)
2196 strs.append(_LineNumber(frame.call_tok))
2197
2198 elif case2(debug_frame_e.Main):
2199 # Bash does this to line up with 'main'
2200 strs.append('0')
2201
2202 return value.BashArray(strs) # TODO: Reuse this object too?
2203
2204 elif case('LINENO'):
2205 assert self.token_for_line is not None
2206 # Reuse object with mutation
2207 # TODO: maybe use interned GetLineNumStr?
2208 self.line_num.s = str(self.token_for_line.line.line_num)
2209 return self.line_num
2210
2211 elif case('BASHPID'): # TODO: YSH io->getpid()
2212 return value.Str(str(posix.getpid()))
2213
2214 elif case('_'):
2215 return value.Str(self.last_arg)
2216
2217 elif case('SECONDS'):
2218 f = time_.time() - self.seconds_start
2219 ok, big_int = mops.FromFloat(f)
2220 assert ok, f # should never be NAN or INFINITY
2221 return value.Int(big_int)
2222
2223 else:
2224 # In the case 'declare -n ref='a[42]', the result won't be a cell. Idea to
2225 # fix this:
2226 # 1. Call self.unsafe_arith.ParseVarRef() -> BracedVarSub
2227 # 2. Call self.unsafe_arith.GetNameref(bvs_part), and get a value_t
2228 # We still need a ref_trail to detect cycles.
2229 cell, _, _ = self._ResolveNameOrRef(name, which_scopes)
2230 if cell:
2231 return cell.val
2232
2233 builtin_val = self.builtins.get(name)
2234 if builtin_val:
2235 return builtin_val
2236
2237 # TODO: Can look in the builtins module, which is a value.Obj
2238 return value.Undef
2239
2240 def GetCell(self, name, which_scopes=scope_e.Shopt):
2241 # type: (str, scope_t) -> Cell
2242 """Get both the value and flags.
2243
2244 Usages:
2245 - the 'pp' builtin.
2246 - declare -p
2247 - ${x@a}
2248 - to test of 'TZ' is exported in printf? Why?
2249
2250 Note: consulting __builtins__ doesn't see necessary for any of these
2251 """
2252 if which_scopes == scope_e.Shopt:
2253 which_scopes = self.ScopesForReading()
2254
2255 cell, _ = self._ResolveNameOnly(name, which_scopes)
2256 return cell
2257
2258 def Unset(self, lval, which_scopes):
2259 # type: (sh_lvalue_t, scope_t) -> bool
2260 """
2261 Returns:
2262 Whether the cell was found.
2263 """
2264 # TODO: Refactor sh_lvalue type to avoid this
2265 UP_lval = lval
2266
2267 with tagswitch(lval) as case:
2268 if case(sh_lvalue_e.Var): # unset x
2269 lval = cast(LeftName, UP_lval)
2270 var_name = lval.name
2271 elif case(sh_lvalue_e.Indexed): # unset 'a[1]'
2272 lval = cast(sh_lvalue.Indexed, UP_lval)
2273 var_name = lval.name
2274 elif case(sh_lvalue_e.Keyed): # unset 'A["K"]'
2275 lval = cast(sh_lvalue.Keyed, UP_lval)
2276 var_name = lval.name
2277 else:
2278 raise AssertionError()
2279
2280 if which_scopes == scope_e.Shopt:
2281 which_scopes = self.ScopesForWriting()
2282
2283 cell, var_frame, cell_name = self._ResolveNameOrRef(
2284 var_name, which_scopes)
2285 if not cell:
2286 return False # 'unset' builtin falls back on functions
2287 if cell.readonly:
2288 raise error.Runtime("Can't unset readonly variable %r" % var_name)
2289
2290 with tagswitch(lval) as case:
2291 if case(sh_lvalue_e.Var): # unset x
2292 # Make variables in higher scopes visible.
2293 # example: test/spec.sh builtin-vars -r 24 (ble.sh)
2294 mylib.dict_erase(var_frame, cell_name)
2295
2296 # alternative that some shells use:
2297 # var_frame[cell_name].val = value.Undef
2298 # cell.exported = False
2299
2300 # This should never happen because we do recursive lookups of namerefs.
2301 assert not cell.nameref, cell
2302
2303 elif case(sh_lvalue_e.Indexed): # unset 'a[1]'
2304 lval = cast(sh_lvalue.Indexed, UP_lval)
2305 # Note: Setting an entry to None and shifting entries are pretty
2306 # much the same in shell.
2307
2308 val = cell.val
2309 UP_val = val
2310 if val.tag() != value_e.BashArray:
2311 raise error.Runtime("%r isn't an array" % var_name)
2312
2313 val = cast(value.BashArray, UP_val)
2314 strs = val.strs
2315
2316 n = len(strs)
2317 last_index = n - 1
2318 index = lval.index
2319 if index < 0:
2320 index += n
2321
2322 if index == last_index:
2323 # Special case: The array SHORTENS if you unset from the end. You
2324 # can tell with a+=(3 4)
2325 strs.pop()
2326 elif 0 <= index and index < last_index:
2327 strs[index] = None
2328 else:
2329 # If it's not found, it's not an error. In other words, 'unset'
2330 # ensures that a value doesn't exist, regardless of whether it
2331 # existed. It's idempotent.
2332 # (Ousterhout specifically argues that the strict behavior was a
2333 # mistake for Tcl!)
2334 pass
2335
2336 elif case(sh_lvalue_e.Keyed): # unset 'A["K"]'
2337 lval = cast(sh_lvalue.Keyed, UP_lval)
2338
2339 val = cell.val
2340 UP_val = val
2341
2342 # note: never happens because of mem.IsBashAssoc test for sh_lvalue.Keyed
2343 #if val.tag() != value_e.BashAssoc:
2344 # raise error.Runtime("%r isn't an associative array" % lval.name)
2345
2346 val = cast(value.BashAssoc, UP_val)
2347 mylib.dict_erase(val.d, lval.key)
2348
2349 else:
2350 raise AssertionError(lval)
2351
2352 return True
2353
2354 def ScopesForReading(self):
2355 # type: () -> scope_t
2356 """Read scope."""
2357 return (scope_e.Dynamic
2358 if self.exec_opts.dynamic_scope() else scope_e.LocalOrGlobal)
2359
2360 def ScopesForWriting(self):
2361 # type: () -> scope_t
2362 """Write scope."""
2363 return (scope_e.Dynamic
2364 if self.exec_opts.dynamic_scope() else scope_e.LocalOnly)
2365
2366 def ClearFlag(self, name, flag):
2367 # type: (str, int) -> bool
2368 """Used for export -n.
2369
2370 We don't use SetValue() because even if rval is None, it will make an
2371 Undef value in a scope.
2372 """
2373 cell, var_frame = self._ResolveNameOnly(name, self.ScopesForReading())
2374 if cell:
2375 if flag & ClearExport:
2376 cell.exported = False
2377 if flag & ClearNameref:
2378 cell.nameref = False
2379 return True
2380 else:
2381 return False
2382
2383 def GetExported(self):
2384 # type: () -> Dict[str, str]
2385 """Get all the variables that are marked exported."""
2386 # TODO: This is run on every SimpleCommand. Should we have a dirty flag?
2387 # We have to notice these things:
2388 # - If an exported variable is changed.
2389 # - If the set of exported variables changes.
2390
2391 exported = {} # type: Dict[str, str]
2392 # Search from globals up. Names higher on the stack will overwrite names
2393 # lower on the stack.
2394 for scope in self.var_stack:
2395 for name, cell in iteritems(scope):
2396 # TODO: Disallow exporting at assignment time. If an exported Str is
2397 # changed to BashArray, also clear its 'exported' flag.
2398 if cell.exported and cell.val.tag() == value_e.Str:
2399 val = cast(value.Str, cell.val)
2400 exported[name] = val.s
2401 return exported
2402
2403 def VarNames(self):
2404 # type: () -> List[str]
2405 """For internal OSH completion and compgen -A variable.
2406
2407 NOTE: We could also add $? $$ etc.?
2408 """
2409 ret = [] # type: List[str]
2410 # Look up the stack, yielding all variables. Bash seems to do this.
2411 for scope in self.var_stack:
2412 for name in scope:
2413 ret.append(name)
2414 return ret
2415
2416 def VarNamesStartingWith(self, prefix):
2417 # type: (str) -> List[str]
2418 """For ${!prefix@}"""
2419 # Look up the stack, yielding all variables. Bash seems to do this.
2420 names = [] # type: List[str]
2421 for scope in self.var_stack:
2422 for name in scope:
2423 if name.startswith(prefix):
2424 names.append(name)
2425 return names
2426
2427 def GetAllVars(self):
2428 # type: () -> Dict[str, str]
2429 """Get all variables and their values, for 'set' builtin."""
2430 result = {} # type: Dict[str, str]
2431 for scope in self.var_stack:
2432 for name, cell in iteritems(scope):
2433 # TODO: Show other types?
2434 val = cell.val
2435 if val.tag() == value_e.Str:
2436 str_val = cast(value.Str, val)
2437 result[name] = str_val.s
2438 return result
2439
2440 def GetAllCells(self, which_scopes):
2441 # type: (scope_t) -> Dict[str, Cell]
2442 """Get all variables and their values, for 'set' builtin."""
2443 result = {} # type: Dict[str, Cell]
2444
2445 if which_scopes == scope_e.Dynamic:
2446 scopes = self.var_stack
2447 elif which_scopes == scope_e.LocalOnly:
2448 scopes = self.var_stack[-1:]
2449 elif which_scopes == scope_e.GlobalOnly:
2450 scopes = self.var_stack[0:1]
2451 elif which_scopes == scope_e.LocalOrGlobal:
2452 scopes = [self.var_stack[0]]
2453 if len(self.var_stack) > 1:
2454 scopes.append(self.var_stack[-1])
2455 else:
2456 raise AssertionError()
2457
2458 for scope in scopes:
2459 for name, cell in iteritems(scope):
2460 result[name] = cell
2461 return result
2462
2463 def IsGlobalScope(self):
2464 # type: () -> bool
2465 return len(self.var_stack) == 1
2466
2467 def SetRegexMatch(self, match):
2468 # type: (regex_match_t) -> None
2469 self.regex_match[-1] = match
2470
2471 def GetRegexMatch(self):
2472 # type: () -> regex_match_t
2473 return self.regex_match[-1]
2474
2475 def PushContextStack(self, context):
2476 # type: (Dict[str, value_t]) -> None
2477 self.ctx_stack.append(context)
2478
2479 def GetContext(self):
2480 # type: () -> Optional[Dict[str, value_t]]
2481 if len(self.ctx_stack):
2482 return self.ctx_stack[-1]
2483 return None
2484
2485 def PopContextStack(self):
2486 # type: () -> Dict[str, value_t]
2487 assert self.ctx_stack, "Empty context stack"
2488 return self.ctx_stack.pop()
2489
2490
2491def _InvokableObj(val):
2492 # type: (value_t) -> Tuple[Optional[value.Proc], Optional[Obj]]
2493 """
2494 Returns:
2495 None if the value is not invokable
2496 (self Obj, __invoke__ Proc) if so
2497 """
2498 if val.tag() != value_e.Obj:
2499 return None, None
2500
2501 obj = cast(Obj, val)
2502 if not obj.prototype:
2503 return None, None
2504
2505 invoke_val = obj.prototype.d.get('__invoke__')
2506 if invoke_val is None:
2507 return None, None
2508
2509 # TODO: __invoke__ of wrong type could be fatal error?
2510 if invoke_val.tag() != value_e.Proc:
2511 return None, None
2512
2513 return cast(value.Proc, invoke_val), obj
2514
2515
2516def _AddNames(unique, frame):
2517 # type: (Dict[str, bool], Dict[str, Cell]) -> None
2518 for name in frame:
2519 val = frame[name].val
2520 if val.tag() == value_e.Proc:
2521 unique[name] = True
2522 proc, _ = _InvokableObj(val)
2523 if proc is not None:
2524 unique[name] = True
2525
2526
2527class Procs(object):
2528 """
2529 Terminology:
2530
2531 - invokable - these are INTERIOR
2532 - value.Proc - which can be shell function in __sh_funcs__ namespace, or
2533 YSH proc
2534 - value.Obj with __invoke__
2535 - exterior - external commands, extern builtin
2536
2537 Note: the YSH 'invoke' builtin can generalize YSH 'runproc' builtin, shell command/builtin,
2538 and also type / type -a
2539 """
2540
2541 def __init__(self, mem):
2542 # type: (Mem) -> None
2543 self.mem = mem
2544 self.sh_funcs = {} # type: Dict[str, value.Proc]
2545
2546 def DefineShellFunc(self, name, proc):
2547 # type: (str, value.Proc) -> None
2548 self.sh_funcs[name] = proc
2549
2550 def IsShellFunc(self, name):
2551 # type: (str) -> bool
2552 return name in self.sh_funcs
2553
2554 def GetShellFunc(self, name):
2555 # type: (str) -> Optional[value.Proc]
2556 return self.sh_funcs.get(name)
2557
2558 def EraseShellFunc(self, to_del):
2559 # type: (str) -> None
2560 """Undefine a sh-func with name `to_del`, if it exists."""
2561 mylib.dict_erase(self.sh_funcs, to_del)
2562
2563 def ShellFuncNames(self):
2564 # type: () -> List[str]
2565 """Returns a *sorted* list of all shell function names
2566
2567 Callers:
2568 declare -f -F
2569 """
2570 names = self.sh_funcs.keys()
2571 names.sort()
2572 return names
2573
2574 def DefineProc(self, name, proc):
2575 # type: (str, value.Proc) -> None
2576 """
2577 procs are defined in the local scope.
2578 """
2579 self.mem.var_stack[-1][name] = Cell(False, False, False, proc)
2580
2581 def IsProc(self, name):
2582 # type: (str) -> bool
2583
2584 maybe_proc = self.mem.GetValue(name)
2585 # Could be Undef
2586 return maybe_proc.tag() == value_e.Proc
2587
2588 def IsInvokableObj(self, name):
2589 # type: (str) -> bool
2590
2591 val = self.mem.GetValue(name)
2592 proc, self_val = _InvokableObj(val)
2593 return proc is not None
2594
2595 def InvokableNames(self):
2596 # type: () -> List[str]
2597 """Returns a *sorted* list of all invokable names
2598
2599 Callers:
2600 complete -A function
2601 pp proc - should deprecate this
2602 """
2603 unique = NewDict() # type: Dict[str, bool]
2604 for name in self.sh_funcs:
2605 unique[name] = True
2606
2607 top_frame = self.mem.var_stack[-1]
2608 _AddNames(unique, top_frame)
2609
2610 global_frame = self.mem.var_stack[0]
2611 #log('%d %d', id(top_frame), id(global_frame))
2612 if global_frame is not top_frame:
2613 _AddNames(unique, global_frame)
2614
2615 #log('%s', unique)
2616
2617 names = unique.keys()
2618 names.sort()
2619
2620 return names
2621
2622 def GetInvokable(self, name):
2623 # type: (str) -> Tuple[Optional[value.Proc], Optional[Obj]]
2624 """Try to find a proc/sh-func by `name`, or return None if not found.
2625
2626 First, we search for a proc, and then a sh-func. This means that procs
2627 can shadow the definition of sh-funcs.
2628
2629 Callers:
2630 executor.py: running
2631 meta_osh.py runproc lookup - this is not 'invoke', because it is
2632 INTERIOR shell functions, procs, invokable Obj
2633 cmd_eval: check for redefining proc or sh-func (remove)
2634 """
2635 val = self.mem.GetValue(name)
2636
2637 if val.tag() == value_e.Proc:
2638 return cast(value.Proc, val), None
2639
2640 proc, self_val = _InvokableObj(val)
2641 if proc:
2642 return proc, self_val
2643
2644 if name in self.sh_funcs:
2645 return self.sh_funcs[name], None
2646
2647 return None, None
2648
2649
2650#
2651# Wrappers to Set Variables
2652#
2653
2654
2655def OshLanguageSetValue(mem, lval, val, flags=0):
2656 # type: (Mem, sh_lvalue_t, value_t, int) -> None
2657 """Like 'setvar' (scope_e.LocalOnly), unless dynamic scope is on.
2658
2659 That is, it respects shopt --unset dynamic_scope.
2660
2661 Used for assignment builtins, (( a = b )), {fd}>out, ${x=}, etc.
2662 """
2663 which_scopes = mem.ScopesForWriting()
2664 mem.SetValue(lval, val, which_scopes, flags=flags)
2665
2666
2667def BuiltinSetValue(mem, lval, val):
2668 # type: (Mem, sh_lvalue_t, value_t) -> None
2669 """Equivalent of x=$y
2670
2671 Called by BuiltinSetString and BuiltinSetArray Used directly by
2672 printf -v because it can mutate an array
2673 """
2674 mem.SetValue(lval, val, mem.ScopesForWriting())
2675
2676
2677def BuiltinSetString(mem, name, s):
2678 # type: (Mem, str, str) -> None
2679 """Set a string by looking up the stack.
2680
2681 Used for 'read', 'getopts', completion builtins, etc.
2682 """
2683 assert isinstance(s, str)
2684 BuiltinSetValue(mem, location.LName(name), value.Str(s))
2685
2686
2687def BuiltinSetArray(mem, name, a):
2688 # type: (Mem, str, List[str]) -> None
2689 """Set an array by looking up the stack.
2690
2691 Used by compadjust, read -a, etc.
2692 """
2693 assert isinstance(a, list)
2694 BuiltinSetValue(mem, location.LName(name), value.BashArray(a))
2695
2696
2697def SetGlobalString(mem, name, s):
2698 # type: (Mem, str, str) -> None
2699 """Helper for completion, etc."""
2700 assert isinstance(s, str)
2701 val = value.Str(s)
2702 mem.SetNamed(location.LName(name), val, scope_e.GlobalOnly)
2703
2704
2705def SetGlobalArray(mem, name, a):
2706 # type: (Mem, str, List[str]) -> None
2707 """Used by completion, shell initialization, etc."""
2708 assert isinstance(a, list)
2709 mem.SetNamed(location.LName(name), value.BashArray(a), scope_e.GlobalOnly)
2710
2711
2712def _SetGlobalValue(mem, name, val):
2713 # type: (Mem, str, value_t) -> None
2714 """Helper for completion, etc."""
2715 mem.SetNamed(location.LName(name), val, scope_e.GlobalOnly)
2716
2717
2718def ExportGlobalString(mem, name, s):
2719 # type: (Mem, str, str) -> None
2720 """Helper for completion, $PWD, $OLDPWD, etc."""
2721 assert isinstance(s, str)
2722 val = value.Str(s)
2723 mem.SetNamed(location.LName(name),
2724 val,
2725 scope_e.GlobalOnly,
2726 flags=SetExport)
2727
2728
2729#
2730# Wrappers to Get Variables
2731#
2732
2733
2734def DynamicGetVar(mem, name, which_scopes):
2735 # type: (Mem, str, scope_t) -> value_t
2736 """
2737 For getVar() and shvarGet()
2738 """
2739 val = mem.GetValue(name, which_scopes=which_scopes)
2740
2741 # Undef is not a user-visible value!
2742 # There's no way to distinguish null from undefined.
2743 if val.tag() == value_e.Undef:
2744 return value.Null
2745
2746 return val
2747
2748
2749def GetString(mem, name):
2750 # type: (Mem, str) -> str
2751 """Wrapper around GetValue().
2752
2753 Check that HOME, PWD, OLDPWD, etc. are strings. bash doesn't have these
2754 errors because ${array} is ${array[0]}.
2755
2756 TODO: We could also check this when you're storing variables?
2757 """
2758 val = mem.GetValue(name)
2759 UP_val = val
2760 with tagswitch(val) as case:
2761 if case(value_e.Undef):
2762 raise error.Runtime("$%s isn't defined" % name)
2763 elif case(value_e.Str):
2764 return cast(value.Str, UP_val).s
2765 else:
2766 # User would have to 'unset HOME' to get rid of exported flag
2767 raise error.Runtime("$%s should be a string" % name)
2768
2769
2770def MaybeString(mem, name):
2771 # type: (Mem, str) -> Optional[str]
2772 """Like GetString(), but doesn't throw an exception."""
2773 try:
2774 return GetString(mem, name)
2775 except error.Runtime:
2776 return None
2777
2778
2779def GetInteger(mem, name):
2780 # type: (Mem, str) -> int
2781 """For OPTIND variable used in getopts builtin.
2782
2783 TODO: it could be value.Int() ?
2784 """
2785 val = mem.GetValue(name)
2786 if val.tag() != value_e.Str:
2787 raise error.Runtime('$%s should be a string, got %s' %
2788 (name, ui.ValType(val)))
2789 s = cast(value.Str, val).s
2790 try:
2791 i = int(s)
2792 except ValueError:
2793 raise error.Runtime("$%s doesn't look like an integer, got %r" %
2794 (name, s))
2795 return i
2796
2797
2798# vim: sw=4