OILS / frontend / builtin_def.py View on Github | oils.pub

171 lines, 72 significant
1#!/usr/bin/env python2
2"""frontend/builtin_def.py.
3
4Metadata:
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
13NOTE: bash has help -d -m -s. Default is -s, like a man page.
14"""
15from __future__ import print_function
16
17from 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
69class _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
82class _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
102def _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
160BUILTIN_NAMES = [b.name for b in _BUILTIN_DEF.builtins if b.kind != 'private']
161
162
163def All():
164 # type: () -> List[_Builtin]
165 return _BUILTIN_DEF.builtins
166
167
168def 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)