OILS / frontend / builtin_def.py View on Github | oilshell.org

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