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

162 lines, 64 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
44 '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 'module', 'use',
56 'error',
57
58 # take a block
59 # push-registers added below
60 'fork', 'forkwait',
61 'fopen',
62 'shvar',
63 'ctx',
64
65 'runproc',
66 'boolstatus',
67]
68# yapf: enable
69
70
71class _Builtin(object):
72
73 def __init__(self, index, name, enum_name=None, kind='normal'):
74 # type: (int, str, Optional[str], str) -> None
75 """
76 kind: normal, special, assign
77 """
78 self.index = index
79 self.name = name # e.g. : or [
80 self.enum_name = enum_name or name # e.g. builtin_num::colon
81 self.kind = kind
82
83
84class _BuiltinDef(object):
85 """
86 NOTE: This isn't used anywhere! We're registering nothing.
87
88 We want to complete the flags to builtins. So this is a mapping from name
89 to arg spec. There might not be any flags.
90 """
91
92 def __init__(self):
93 # type: () -> None
94 self.builtins = [] # type: List[_Builtin]
95 self.index = 1 # start with 1
96
97 def Add(self, *posargs, **kwargs):
98 # type: (Any, Any) -> None
99 # NOTE: *posargs works around flake8/pyflakes bug!
100 self.builtins.append(_Builtin(self.index, *posargs, **kwargs))
101 self.index += 1
102
103
104def _Init(b):
105 # type: (_BuiltinDef) -> None
106
107 #
108 # Special builtins
109 #
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', 'builtin']:
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('true', enum_name='true_') # C++ Keywords
128 b.Add('false', enum_name='false_')
129 b.Add('try', enum_name='try_')
130
131 for name in _NORMAL_BUILTINS:
132 b.Add(name)
133
134 # Slight variants
135 b.Add('test')
136 b.Add('[', enum_name='bracket')
137
138 b.Add('push-registers', enum_name='push_registers')
139 b.Add('is-main', enum_name='is_main')
140
141 # Implementation detail of $(<file)
142 # TODO: change to 'internal cat' (issue 1013)
143 b.Add('__cat', enum_name='cat')
144
145
146_BUILTIN_DEF = _BuiltinDef()
147
148_Init(_BUILTIN_DEF)
149
150# Exposed in consts.py for completion
151BUILTIN_NAMES = [b.name for b in _BUILTIN_DEF.builtins]
152
153
154def All():
155 # type: () -> List[_Builtin]
156 return _BUILTIN_DEF.builtins
157
158
159def BuiltinDict():
160 # type: () -> Dict[str, _Builtin]
161 """For the slow path in frontend/match.py."""
162 return dict((b.name, b) for b in _BUILTIN_DEF.builtins)