/
consts.py
187 lines (148 loc) · 5.77 KB
/
consts.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
#!/usr/bin/env python2
"""
lookup.py
"""
from __future__ import print_function
from _devbuild.gen.types_asdl import (
redir_arg_type_e, redir_arg_type_t, bool_arg_type_t
)
from _devbuild.gen.id_kind_asdl import Id, Id_t, Kind_t
from frontend import option_def
# Used as consts::STRICT_ALL, etc. Do it explicitly to satisfy MyPy.
STRICT_ALL = option_def.STRICT_ALL
OIL_BASIC = option_def.OIL_BASIC
OIL_ALL = option_def.OIL_ALL
# TODO: These could be changed to numbers
SET_OPTION_NAMES = option_def.SET_OPTION_NAMES
SHOPT_OPTION_NAMES = option_def.SHOPT_OPTION_NAMES
VISIBLE_SHOPT_NAMES = option_def.VISIBLE_SHOPT_NAMES
PARSE_OPTION_NAMES = option_def.PARSE_OPTION_NAMES
def GetKind(id_):
# type: (Id_t) -> Kind_t
"""To make coarse-grained parsing decisions."""
from _devbuild.gen.id_kind import ID_TO_KIND # break circular dep
return ID_TO_KIND[id_]
def BoolArgType(id_):
# type: (Id_t) -> bool_arg_type_t
from _devbuild.gen.id_kind import BOOL_ARG_TYPES # break circular dep
return BOOL_ARG_TYPES[id_]
#
# Redirect Tables associated with IDs
#
REDIR_DEFAULT_FD = {
# filename
Id.Redir_Less: 0, # cat <input.txt means cat 0<input.txt
Id.Redir_Great: 1,
Id.Redir_DGreat: 1,
Id.Redir_Clobber: 1,
Id.Redir_LessGreat: 1, # TODO: What does echo <>foo do?
# bash &> and &>>
Id.Redir_AndGreat: 1,
Id.Redir_AndDGreat: 1,
# descriptor
Id.Redir_GreatAnd: 1, # echo >&2 means echo 1>&2
Id.Redir_LessAnd: 0, # echo <&3 means echo 0<&3, I think
Id.Redir_TLess: 0, # here word
# here docs included
Id.Redir_DLess: 0,
Id.Redir_DLessDash: 0,
}
REDIR_ARG_TYPES = {
# filename
Id.Redir_Less: redir_arg_type_e.Path,
Id.Redir_Great: redir_arg_type_e.Path,
Id.Redir_DGreat: redir_arg_type_e.Path,
Id.Redir_Clobber: redir_arg_type_e.Path,
Id.Redir_LessGreat: redir_arg_type_e.Path,
# bash &> and &>>
Id.Redir_AndGreat: redir_arg_type_e.Path,
Id.Redir_AndDGreat: redir_arg_type_e.Path,
# descriptor
Id.Redir_GreatAnd: redir_arg_type_e.Desc,
Id.Redir_LessAnd: redir_arg_type_e.Desc,
Id.Redir_TLess: redir_arg_type_e.Here, # here word
# note: here docs aren't included
}
def RedirArgType(id_):
# type: (Id_t) -> redir_arg_type_t
return REDIR_ARG_TYPES[id_]
def RedirDefaultFd(id_):
# type: (Id_t) -> int
return REDIR_DEFAULT_FD[id_]
#
# Constants used by osh/split.py
#
# IFS splitting is complicated in general. We handle it with three concepts:
#
# - CH.* - Kinds of characters (edge labels)
# - ST.* - States (node labels)
# - EMIT.* Actions
#
# The Split() loop below classifies characters, follows state transitions, and
# emits spans. A span is a (ignored Bool, end_index Int) pair.
# As an example, consider this string:
# 'a _ b'
#
# The character classes are:
#
# a ' ' _ ' ' b
# Black DE_White DE_Gray DE_White Black
#
# The states are:
#
# a ' ' _ ' ' b
# Black DE_White1 DE_Gray DE_White2 Black
#
# DE_White2 is whitespace that follows a "gray" non-whitespace IFS character.
#
# The spans emitted are:
#
# (part 'a', ignored ' _ ', part 'b')
# SplitForRead() will check if the last two spans are a \ and \\n. Easy.
# Shorter names for state machine enums
from _devbuild.gen.runtime_asdl import emit_e as EMIT
from _devbuild.gen.runtime_asdl import char_kind_e as CH
from _devbuild.gen.runtime_asdl import state_e as ST
TRANSITIONS = {
# Whitespace should have been stripped
(ST.Start, CH.DE_White): (ST.Invalid, EMIT.Nothing), # ' '
(ST.Start, CH.DE_Gray): (ST.DE_Gray, EMIT.Empty), # '_'
(ST.Start, CH.Black): (ST.Black, EMIT.Nothing), # 'a'
(ST.Start, CH.Backslash): (ST.Backslash, EMIT.Nothing), # '\'
(ST.DE_White1, CH.DE_White): (ST.DE_White1, EMIT.Nothing), # ' '
(ST.DE_White1, CH.DE_Gray): (ST.DE_Gray, EMIT.Nothing), # ' _'
(ST.DE_White1, CH.Black): (ST.Black, EMIT.Delim), # ' a'
(ST.DE_White1, CH.Backslash): (ST.Backslash, EMIT.Delim), # ' \'
(ST.DE_Gray, CH.DE_White): (ST.DE_White2, EMIT.Nothing), # '_ '
(ST.DE_Gray, CH.DE_Gray): (ST.DE_Gray, EMIT.Empty), # '__'
(ST.DE_Gray, CH.Black): (ST.Black, EMIT.Delim), # '_a'
(ST.DE_Gray, CH.Backslash): (ST.Black, EMIT.Delim), # '_\'
(ST.DE_White2, CH.DE_White): (ST.DE_White2, EMIT.Nothing), # '_ '
(ST.DE_White2, CH.DE_Gray): (ST.DE_Gray, EMIT.Empty), # '_ _'
(ST.DE_White2, CH.Black): (ST.Black, EMIT.Delim), # '_ a'
(ST.DE_White2, CH.Backslash): (ST.Backslash, EMIT.Delim), # '_ \'
(ST.Black, CH.DE_White): (ST.DE_White1, EMIT.Part), # 'a '
(ST.Black, CH.DE_Gray): (ST.DE_Gray, EMIT.Part), # 'a_'
(ST.Black, CH.Black): (ST.Black, EMIT.Nothing), # 'aa'
(ST.Black, CH.Backslash): (ST.Backslash, EMIT.Part), # 'a\'
# Here we emit an ignored \ and the second character as well.
# We're emitting TWO spans here; we don't wait until the subsequent
# character. That is OK.
#
# Problem: if '\ ' is the last one, we don't want to emit a trailing span?
# In all other cases we do.
(ST.Backslash, CH.DE_White): (ST.Black, EMIT.Escape), # '\ '
(ST.Backslash, CH.DE_Gray): (ST.Black, EMIT.Escape), # '\_'
(ST.Backslash, CH.Black): (ST.Black, EMIT.Escape), # '\a'
# NOTE: second character is a backslash, but new state is ST.Black!
(ST.Backslash, CH.Backslash): (ST.Black, EMIT.Escape), # '\\'
}
LAST_SPAN_ACTION = {
ST.Black: EMIT.Part,
ST.Backslash: EMIT.Escape,
# Ignore trailing IFS whitespace too. This is necessary for the case:
# IFS=':' ; read x y z <<< 'a : b : c :'.
ST.DE_White1: EMIT.Nothing,
ST.DE_Gray: EMIT.Delim,
ST.DE_White2: EMIT.Delim,
}