1
+ -- https://github.com/Lautenschlager-id/prepdir/blob/master/init.lua
2
+
3
+ local prepdir
4
+ do
5
+ local format = string.format
6
+ local gsub = string.gsub
7
+ local match = string.match
8
+ local sub = string.sub
9
+ local rep = string.rep
10
+
11
+ local conditionalSymbols = {
12
+ [' &' ] = " and" ,
13
+ [' |' ] = " or" ,
14
+ [' !' ] = " not " ,
15
+ [" !=" ] = " ~="
16
+ }
17
+ local symbolReplace = " [&|!]=?"
18
+
19
+ local prefix = " ()\t *@#"
20
+ local endOfLine = " \r ?\n ()"
21
+ local expression = " ([%w_ %+%-%*/%[%]%(%){}&|!%.<>~='\" ]+)"
22
+
23
+ local tokenCallbacks = { }
24
+ local tokenMatchers = {
25
+ IF = prefix .. " IF " .. expression .. endOfLine ,
26
+ ELIF = prefix .. " ELIF " .. expression .. endOfLine ,
27
+ ELSE = prefix .. " ELSE" .. endOfLine ,
28
+ ENDIF = prefix .. " ENDIF" .. endOfLine ,
29
+ __NEXT = prefix .. " (%S+)"
30
+ }
31
+
32
+ local READING_CHUNK , chunks = false
33
+
34
+ tokenCallbacks .IF = function (src , endPos )
35
+ if READING_CHUNK then return end
36
+
37
+ local iniPos , condition , endPos = match (src , tokenMatchers .IF , endPos )
38
+ if not iniPos then return end
39
+
40
+ READING_CHUNK = true
41
+
42
+ chunks [# chunks + 1 ] = {
43
+ __len = 1 ,
44
+ c = {
45
+ [1 ] = {
46
+ iniPos = iniPos ,
47
+ endPos = endPos ,
48
+ condition = condition
49
+ }
50
+ }
51
+ }
52
+
53
+ return endPos
54
+ end
55
+
56
+ tokenCallbacks .ELIF = function (src , endPos )
57
+ if not READING_CHUNK then return end
58
+
59
+ local iniPos , condition , endPos = match (src , tokenMatchers .ELIF , endPos )
60
+ assert (iniPos )
61
+
62
+ local chunk = chunks [# chunks ]
63
+ chunk .__len = chunk .__len + 1
64
+ chunk .c [chunk .__len ] = {
65
+ iniPos = iniPos ,
66
+ endPos = endPos ,
67
+ condition = condition
68
+ }
69
+
70
+ return endPos
71
+ end
72
+
73
+ tokenCallbacks .ELSE = function (src , endPos )
74
+ if not READING_CHUNK then return end
75
+
76
+ local iniPos , endPos = match (src , tokenMatchers .ELSE , endPos )
77
+ assert (iniPos )
78
+
79
+ local chunk = chunks [# chunks ]
80
+ chunk .__len = chunk .__len + 1
81
+ chunk .c [chunk .__len ] = {
82
+ iniPos = iniPos ,
83
+ endPos = endPos ,
84
+ condition = " true"
85
+ }
86
+
87
+ return endPos
88
+ end
89
+
90
+ tokenCallbacks .ENDIF = function (src , endPos )
91
+ if not READING_CHUNK then return end
92
+
93
+ local iniPos , endPos = match (src , tokenMatchers .ENDIF , endPos )
94
+ if not iniPos then return end
95
+
96
+ READING_CHUNK = false
97
+
98
+ local chunk = chunks [# chunks ]
99
+ chunk .c .endif = {
100
+ iniPos = iniPos ,
101
+ endPos = endPos
102
+ }
103
+
104
+ return endPos
105
+ end
106
+
107
+ tokenCallbacks .__NEXT = function (src , endPos )
108
+ local iniPos , token = match (src , tokenMatchers .__NEXT , endPos )
109
+ if not iniPos then return end
110
+
111
+ return token
112
+ end
113
+
114
+ local parser = function (src )
115
+ READING_CHUNK , chunks = false , { }
116
+
117
+ local endPos , ifPos
118
+ repeat
119
+ -- Opens the conditional
120
+ endPos = tokenCallbacks .IF (src , endPos )
121
+ if not endPos then
122
+ break
123
+ end
124
+ ifPos = endPos
125
+
126
+ -- Gets all sub conditionals
127
+ local nextToken
128
+ repeat
129
+ nextToken = tokenCallbacks .__NEXT (src , endPos )
130
+ if nextToken == " ELIF" then
131
+ endPos = tokenCallbacks .ELIF (src , endPos )
132
+ else
133
+ break
134
+ end
135
+ until false
136
+
137
+ -- Check of else
138
+ if nextToken == " ELSE" then
139
+ endPos = tokenCallbacks .ELSE (src , endPos )
140
+ nextToken = nil
141
+ end
142
+
143
+ -- Finish conditional
144
+ nextToken = nextToken or tokenCallbacks .__NEXT (src , endPos )
145
+ if nextToken ~= " ENDIF" then
146
+ error (string.format (" [PREPDIR] @[%d:] Mandatory token ENDIF to close \z
147
+ token IF in @[%d]" , endPos , ifPos ))
148
+ end
149
+ endPos = tokenCallbacks .ENDIF (src , endPos )
150
+ until false
151
+
152
+ local cc
153
+ for c = 1 , # chunks do
154
+ c = chunks [c ]
155
+ cc = c .c
156
+ for sc = 1 , c .__len do
157
+ sc = cc [sc ]
158
+ sc .condition = gsub (sc .condition , symbolReplace , conditionalSymbols )
159
+ end
160
+ end
161
+ end
162
+
163
+ local evaluateCondition = function (condition , settings )
164
+ return load (" return " .. condition , ' ' , ' t' , settings )()
165
+ end
166
+
167
+ local sliceString = function (str , boundaries )
168
+ assert (# boundaries % 2 == 0 )
169
+
170
+ for b = # boundaries , 1 , - 2 do
171
+ local _ , totalLines = gsub (sub (str , boundaries [b - 1 ], boundaries [b ] - 1 ), ' \n ' , ' ' )
172
+ str = sub (str , 1 , boundaries [b - 1 ] - 1 ) .. rep (' \n ' , totalLines ) .. sub (str , boundaries [b ])
173
+ end
174
+
175
+ return str
176
+ end
177
+
178
+ local matcher = function (src , settings )
179
+ local boundaries , totalBoundaries = { }, 0
180
+
181
+ local cc , scObj
182
+ for c = 1 , # chunks do
183
+ c = chunks [c ]
184
+ cc = c .c
185
+
186
+ totalBoundaries = totalBoundaries + 1
187
+ boundaries [totalBoundaries ] = cc [1 ].iniPos
188
+
189
+ for sc = 1 , c .__len do
190
+ scObj = cc [sc ]
191
+ if evaluateCondition (scObj .condition , settings ) then
192
+ totalBoundaries = totalBoundaries + 1
193
+ boundaries [totalBoundaries ] = scObj .endPos
194
+
195
+ totalBoundaries = totalBoundaries + 1
196
+ boundaries [totalBoundaries ] = (cc [sc + 1 ] or cc .endif ).iniPos
197
+ break
198
+ end
199
+ end
200
+
201
+ totalBoundaries = totalBoundaries + 1
202
+ boundaries [totalBoundaries ] = cc .endif .endPos
203
+ end
204
+
205
+ return sliceString (src , boundaries )
206
+ end
207
+
208
+ prepdir = function (src , settings )
209
+ -- Retrieve
210
+ src = src .. " \n " -- For pattern matching
211
+
212
+ -- Get chunks
213
+ parser (src )
214
+
215
+ src = matcher (src , settings )
216
+
217
+ return sub (src , 1 , - 2 )
218
+ end
219
+ end
220
+
221
+ return prepdir
0 commit comments