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

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