1 | #!/usr/bin/env python2
|
2 | """frontend/builtin_def.py.
|
3 |
|
4 | Metadata:
|
5 |
|
6 | - Is used for lookup in cmd_eval.py
|
7 | - Should be used for completion
|
8 | - complete names of builtins
|
9 | - complete flags they take
|
10 | - handle aliases : . and source, [ and test
|
11 | - Should be reflected in the contents of the 'help' builtin
|
12 |
|
13 | NOTE: bash has help -d -m -s. Default is -s, like a man page.
|
14 | """
|
15 | from __future__ import print_function
|
16 |
|
17 | from typing import Dict, List, Optional, Any
|
18 |
|
19 | # Special builtins can't be redefined by functions. On the other hand, 'cd'
|
20 | # CAN be redefined.
|
21 | #
|
22 | # http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_14
|
23 | # https://www.gnu.org/software/bash/manual/html_node/Special-Builtins.html
|
24 |
|
25 | # yapf: disable
|
26 | _NORMAL_BUILTINS = [
|
27 | 'read', 'echo', 'printf', 'mapfile', 'readarray',
|
28 |
|
29 | 'cd', 'pushd', 'popd', 'dirs', 'pwd',
|
30 |
|
31 | 'source', # note that . alias is special
|
32 |
|
33 | 'umask', 'ulimit', 'wait', 'jobs', 'fg', 'bg',
|
34 |
|
35 | 'shopt',
|
36 | 'complete', 'compgen', 'compopt', 'compadjust', 'compexport',
|
37 |
|
38 | 'getopts',
|
39 |
|
40 | # introspection / meta
|
41 | 'builtin', 'command', 'type', 'hash', 'help', 'history',
|
42 |
|
43 | 'alias', 'unalias',
|
44 | 'bind',
|
45 |
|
46 | #
|
47 | # YSH
|
48 | #
|
49 | 'append',
|
50 | 'write', 'json', 'json8', 'pp',
|
51 | 'hay', 'haynode',
|
52 | 'use',
|
53 | 'error', 'failed',
|
54 |
|
55 | # take a block
|
56 | # push-registers added below
|
57 | 'fork', 'forkwait',
|
58 | 'redir', 'fopen', # fopen is for backward compat
|
59 | 'shvar',
|
60 | 'ctx',
|
61 |
|
62 | 'invoke',
|
63 | 'runproc',
|
64 | 'boolstatus',
|
65 | ]
|
66 | # yapf: enable
|
67 |
|
68 |
|
69 | class _Builtin(object):
|
70 |
|
71 | def __init__(self, index, name, enum_name=None, kind='normal'):
|
72 | # type: (int, str, Optional[str], str) -> None
|
73 | """
|
74 | kind: normal, special, assign, intern
|
75 | """
|
76 | self.index = index
|
77 | self.name = name # e.g. : or [
|
78 | self.enum_name = enum_name or name # e.g. builtin_num::colon
|
79 | self.kind = kind
|
80 |
|
81 |
|
82 | class _BuiltinDef(object):
|
83 | """
|
84 | NOTE: This isn't used anywhere! We're registering nothing.
|
85 |
|
86 | We want to complete the flags to builtins. So this is a mapping from name
|
87 | to arg spec. There might not be any flags.
|
88 | """
|
89 |
|
90 | def __init__(self):
|
91 | # type: () -> None
|
92 | self.builtins = [] # type: List[_Builtin]
|
93 | self.index = 1 # start with 1
|
94 |
|
95 | def Add(self, *posargs, **kwargs):
|
96 | # type: (Any, Any) -> None
|
97 | # NOTE: *posargs works around flake8/pyflakes bug!
|
98 | self.builtins.append(_Builtin(self.index, *posargs, **kwargs))
|
99 | self.index += 1
|
100 |
|
101 |
|
102 | def _Init(b):
|
103 | # type: (_BuiltinDef) -> None
|
104 |
|
105 | #
|
106 | # Special builtins
|
107 | #
|
108 | # List:
|
109 | # http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_14
|
110 |
|
111 | b.Add(':', enum_name='colon', kind='special')
|
112 | b.Add('.', enum_name='dot', kind='special')
|
113 | # Python keyword
|
114 | b.Add('exec', enum_name='exec_', kind='special')
|
115 | for name in ['eval', 'set', 'shift', 'times', 'trap', 'unset']:
|
116 | b.Add(name, kind='special')
|
117 |
|
118 | #
|
119 | # Assignment builtins.
|
120 | # Note: control flow aren't builtins in OSH: break continue return
|
121 | #
|
122 |
|
123 | for name in ["readonly", "local", "declare", "typeset"]:
|
124 | b.Add(name, kind='assign')
|
125 | b.Add('export', enum_name='export_', kind='assign') # C++ keyword conflict
|
126 |
|
127 | #b.Add('extern', enum_name='extern_')
|
128 | b.Add('true', enum_name='true_') # C++ Keywords
|
129 | b.Add('false', enum_name='false_')
|
130 | b.Add('try', enum_name='try_')
|
131 | b.Add('assert', enum_name='assert_') # avoid Python keyword
|
132 |
|
133 | # Control flow
|
134 | b.Add('break', enum_name='break_')
|
135 | b.Add('continue', enum_name='continue_')
|
136 | b.Add('return', enum_name='return_')
|
137 | b.Add('exit')
|
138 |
|
139 | for name in _NORMAL_BUILTINS:
|
140 | b.Add(name)
|
141 |
|
142 | # Slight variants
|
143 | b.Add('test')
|
144 | b.Add('[', enum_name='bracket')
|
145 |
|
146 | b.Add('push-registers', enum_name='push_registers')
|
147 | b.Add('source-guard', enum_name='source_guard')
|
148 | b.Add('is-main', enum_name='is_main')
|
149 |
|
150 | # Private builtins
|
151 | for name in ['cat', 'rm', 'sleep']:
|
152 | b.Add(name, kind='private')
|
153 |
|
154 |
|
155 | _BUILTIN_DEF = _BuiltinDef()
|
156 |
|
157 | _Init(_BUILTIN_DEF)
|
158 |
|
159 | # Exposed in consts.py for completion
|
160 | BUILTIN_NAMES = [b.name for b in _BUILTIN_DEF.builtins if b.kind != 'private']
|
161 |
|
162 |
|
163 | def All():
|
164 | # type: () -> List[_Builtin]
|
165 | return _BUILTIN_DEF.builtins
|
166 |
|
167 |
|
168 | def BuiltinDict():
|
169 | # type: () -> Dict[str, _Builtin]
|
170 | """For the slow path in frontend/match.py."""
|
171 | return dict((b.name, b) for b in _BUILTIN_DEF.builtins)
|