OILS
/
frontend
/
builtin_def.py
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 |
Links on special builtins:
|
16 |
http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_14
|
17 |
"""
|
18 |
from __future__ import print_function
|
19 |
|
20 |
from 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', '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', 'j8', '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 |
|
64 |
'runproc',
|
65 |
'boolstatus',
|
66 |
]
|
67 |
# yapf: enable
|
68 |
|
69 |
|
70 |
class _Builtin(object):
|
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
|
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 |
|
109 |
b.Add(':', enum_name='colon', kind='special')
|
110 |
b.Add('.', enum_name='dot', kind='special')
|
111 |
# Python keyword
|
112 |
b.Add('exec', enum_name='exec_', kind='special')
|
113 |
for name in ['eval', 'set', 'shift', 'times', 'trap', 'unset', 'builtin']:
|
114 |
b.Add(name, kind='special')
|
115 |
|
116 |
#
|
117 |
# Assignment builtins.
|
118 |
# Note: control flow aren't builtins in OSH: break continue return
|
119 |
#
|
120 |
|
121 |
for name in ["readonly", "local", "declare", "typeset"]:
|
122 |
b.Add(name, kind='assign')
|
123 |
b.Add('export', enum_name='export_', kind='assign') # C++ keyword conflict
|
124 |
|
125 |
b.Add('true', enum_name='true_') # C++ Keywords
|
126 |
b.Add('false', enum_name='false_')
|
127 |
b.Add('try', enum_name='try_')
|
128 |
|
129 |
for name in _NORMAL_BUILTINS:
|
130 |
b.Add(name)
|
131 |
|
132 |
# Slight variants
|
133 |
b.Add('test')
|
134 |
b.Add('[', enum_name='bracket')
|
135 |
|
136 |
b.Add('push-registers', enum_name='push_registers')
|
137 |
b.Add('is-main', enum_name='is_main')
|
138 |
|
139 |
# Implementation detail of $(<file)
|
140 |
# TODO: change to 'internal cat' (issue 1013)
|
141 |
b.Add('__cat', enum_name='cat')
|
142 |
|
143 |
|
144 |
_BUILTIN_DEF = _BuiltinDef()
|
145 |
|
146 |
_Init(_BUILTIN_DEF)
|
147 |
|
148 |
# Exposed in consts.py for completion
|
149 |
BUILTIN_NAMES = [b.name for b in _BUILTIN_DEF.builtins]
|
150 |
|
151 |
|
152 |
def All():
|
153 |
# type: () -> List[_Builtin]
|
154 |
return _BUILTIN_DEF.builtins
|
155 |
|
156 |
|
157 |
def BuiltinDict():
|
158 |
# type: () -> Dict[str, _Builtin]
|
159 |
"""For the slow path in frontend/match.py."""
|
160 |
return dict((b.name, b) for b in _BUILTIN_DEF.builtins)
|