opulent 1.5.5 → 1.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CODE_OF_CONDUCT.md +13 -0
- data/{LICENSE → LICENSE.md} +0 -0
- data/bin/opulent +0 -0
- data/lib/opulent.rb +10 -10
- data/lib/opulent/compiler.rb +15 -9
- data/lib/opulent/compiler/buffer.rb +123 -62
- data/lib/opulent/compiler/comment.rb +3 -4
- data/lib/opulent/compiler/control.rb +20 -26
- data/lib/opulent/compiler/define.rb +88 -36
- data/lib/opulent/compiler/doctype.rb +20 -22
- data/lib/opulent/compiler/eval.rb +23 -2
- data/lib/opulent/compiler/filter.rb +4 -5
- data/lib/opulent/compiler/node.rb +18 -12
- data/lib/opulent/compiler/root.rb +4 -5
- data/lib/opulent/compiler/text.rb +7 -2
- data/lib/opulent/compiler/yield.rb +2 -3
- data/lib/opulent/engine.rb +21 -20
- data/lib/opulent/exec.rb +21 -63
- data/lib/opulent/logger.rb +230 -3
- data/lib/opulent/parser.rb +14 -76
- data/lib/opulent/parser/comment.rb +45 -34
- data/lib/opulent/parser/control.rb +132 -111
- data/lib/opulent/parser/define.rb +15 -12
- data/lib/opulent/parser/doctype.rb +15 -15
- data/lib/opulent/parser/eval.rb +16 -6
- data/lib/opulent/parser/expression.rb +87 -84
- data/lib/opulent/parser/filter.rb +31 -25
- data/lib/opulent/parser/include.rb +38 -42
- data/lib/opulent/parser/node.rb +136 -118
- data/lib/opulent/parser/root.rb +24 -18
- data/lib/opulent/parser/text.rb +150 -123
- data/lib/opulent/parser/yield.rb +23 -23
- data/lib/opulent/settings.rb +70 -51
- data/lib/opulent/tokens.rb +17 -15
- data/lib/opulent/utils.rb +5 -4
- data/lib/opulent/version.rb +1 -1
- metadata +4 -43
- data/.libold/opulent.rb +0 -96
- data/.libold/opulent/context.rb +0 -80
- data/.libold/opulent/engine.rb +0 -88
- data/.libold/opulent/filter.rb +0 -101
- data/.libold/opulent/logger.rb +0 -67
- data/.libold/opulent/nodes.rb +0 -13
- data/.libold/opulent/nodes/block.rb +0 -29
- data/.libold/opulent/nodes/comment.rb +0 -35
- data/.libold/opulent/nodes/control.rb +0 -230
- data/.libold/opulent/nodes/define.rb +0 -42
- data/.libold/opulent/nodes/eval.rb +0 -41
- data/.libold/opulent/nodes/expression.rb +0 -28
- data/.libold/opulent/nodes/filter.rb +0 -70
- data/.libold/opulent/nodes/helper.rb +0 -69
- data/.libold/opulent/nodes/node.rb +0 -101
- data/.libold/opulent/nodes/root.rb +0 -62
- data/.libold/opulent/nodes/text.rb +0 -54
- data/.libold/opulent/nodes/theme.rb +0 -36
- data/.libold/opulent/parser.rb +0 -252
- data/.libold/opulent/parser/block.rb +0 -70
- data/.libold/opulent/parser/comment.rb +0 -32
- data/.libold/opulent/parser/control.rb +0 -83
- data/.libold/opulent/parser/define.rb +0 -39
- data/.libold/opulent/parser/eval.rb +0 -33
- data/.libold/opulent/parser/expression.rb +0 -350
- data/.libold/opulent/parser/filter.rb +0 -41
- data/.libold/opulent/parser/node.rb +0 -232
- data/.libold/opulent/parser/root.rb +0 -96
- data/.libold/opulent/parser/text.rb +0 -114
- data/.libold/opulent/parser/theme.rb +0 -36
- data/.libold/opulent/preprocessor.rb +0 -102
- data/.libold/opulent/runtime.rb +0 -144
- data/.libold/opulent/template.rb +0 -43
- data/.libold/opulent/tokens.rb +0 -276
- data/.libold/opulent/version.rb +0 -5
- data/.travis.yml +0 -4
- data/benchmark/benchmark.rb +0 -57
- data/benchmark/cases/node/node.haml +0 -7
- data/benchmark/cases/node/node.op +0 -7
- data/benchmark/cases/node/node.slim +0 -7
@@ -2,62 +2,58 @@
|
|
2
2
|
module Opulent
|
3
3
|
# @Parser
|
4
4
|
class Parser
|
5
|
-
# Check if we
|
5
|
+
# Check if we have an include node, which will include a new file inside
|
6
|
+
# of the current one to be parsed
|
6
7
|
#
|
7
|
-
#
|
8
|
-
# the definition children, the definition itself is not in the
|
9
|
-
# knowledgebase yet.
|
8
|
+
# @param parent [Array] Parent node to which we append to
|
10
9
|
#
|
11
|
-
|
12
|
-
|
13
|
-
#
|
14
|
-
# @param nodes [Array] Parent node to which we append to
|
15
|
-
#
|
16
|
-
def include_file(parent, indent)
|
17
|
-
if(match = accept :include)
|
10
|
+
def include_file(_parent, indent)
|
11
|
+
return unless accept :include
|
18
12
|
|
19
|
-
|
20
|
-
|
21
|
-
|
13
|
+
# Process data
|
14
|
+
name = accept :line_feed || ''
|
15
|
+
name.strip!
|
22
16
|
|
17
|
+
# Check if there is any string after the include input
|
18
|
+
Logger.error :parse, @code, @i, @j, :include_end if name.empty?
|
23
19
|
|
24
|
-
|
25
|
-
|
26
|
-
error :include_end
|
27
|
-
end
|
28
|
-
|
29
|
-
# Get the complete file path based on the current file being compiled
|
30
|
-
include_path = File.expand_path name, File.dirname(@file[-1][0])
|
31
|
-
|
32
|
-
# Try to see if it has any existing extension, otherwise add .op
|
33
|
-
include_path += Settings::FILE_EXTENSION if File.extname(name).empty?
|
34
|
-
|
35
|
-
# Throw an error if the file doesn't exist
|
36
|
-
error :include, name unless Dir[include_path].any?
|
20
|
+
# Get the complete file path based on the current file being compiled
|
21
|
+
include_path = File.expand_path name, File.dirname(@file[-1][0])
|
37
22
|
|
38
|
-
|
39
|
-
|
40
|
-
# Skip current file when including from same directory
|
41
|
-
next if file == @file[-1][0]
|
23
|
+
# Try to see if it has any existing extension, otherwise add .op
|
24
|
+
include_path += Settings::FILE_EXTENSION if File.extname(name).empty?
|
42
25
|
|
43
|
-
|
26
|
+
# Throw an error if the file doesn't exist
|
27
|
+
unless Dir[include_path].any?
|
28
|
+
Logger.error :parse, @code, @i, @j, :include, name
|
29
|
+
end
|
44
30
|
|
45
|
-
|
46
|
-
|
31
|
+
# include entire directory tree
|
32
|
+
Dir[include_path].each do |file|
|
33
|
+
# Skip current file when including from same directory
|
34
|
+
next if file == @file[-1][0]
|
47
35
|
|
48
|
-
|
49
|
-
error :include, file unless File.file? file
|
36
|
+
@file << [include_path, indent]
|
50
37
|
|
51
|
-
|
52
|
-
|
53
|
-
|
38
|
+
# Throw an error if the file doesn't exist
|
39
|
+
if File.directory? file
|
40
|
+
Logger.error :parse, @code, @i, @j, :include_dir, file
|
41
|
+
end
|
54
42
|
|
55
|
-
|
56
|
-
|
43
|
+
# Throw an error if the file doesn't exist
|
44
|
+
unless File.file? file
|
45
|
+
Logger.error :parse, @code, @i, @j, :include, file
|
57
46
|
end
|
58
47
|
|
59
|
-
|
48
|
+
# Indent all lines and prepare them for the parser
|
49
|
+
lines = indent_lines File.read(file), ' ' * indent
|
50
|
+
lines << ' '
|
51
|
+
|
52
|
+
# Indent all the output lines with the current indentation
|
53
|
+
@code.insert @i + 1, *lines.lines
|
60
54
|
end
|
55
|
+
|
56
|
+
true
|
61
57
|
end
|
62
58
|
end
|
63
59
|
end
|
data/lib/opulent/parser/node.rb
CHANGED
@@ -10,83 +10,82 @@ module Opulent
|
|
10
10
|
# @param parent [Node] Parent node to which we append the node
|
11
11
|
#
|
12
12
|
def node(parent, indent = nil)
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
13
|
+
return unless (name = lookahead(:node_lookahead) ||
|
14
|
+
lookahead(:shorthand_lookahead))
|
15
|
+
|
16
|
+
return nil if KEYWORDS.include? name[0].to_sym
|
17
|
+
|
18
|
+
# Accept either explicit node_name or implicit :div node_name
|
19
|
+
# with shorthand attributes
|
20
|
+
if (node_name = accept :node)
|
21
|
+
node_name = node_name.to_sym
|
22
|
+
shorthand = shorthand_attributes
|
23
|
+
elsif (shorthand = shorthand_attributes)
|
24
|
+
node_name = :div
|
25
|
+
end
|
24
26
|
|
25
|
-
|
26
|
-
|
27
|
+
# Node creation options
|
28
|
+
options = {}
|
27
29
|
|
28
|
-
|
29
|
-
|
30
|
-
options[:leading_whitespace] = true
|
31
|
-
if accept :leading_trailing_whitespace
|
32
|
-
options[:trailing_whitespace] = true
|
33
|
-
end
|
34
|
-
elsif accept_stripped :trailing_whitespace
|
35
|
-
options[:trailing_whitespace] = true
|
36
|
-
end
|
30
|
+
# Get leading whitespace
|
31
|
+
options[:leading_whitespace] = accept_stripped(:leading_whitespace)
|
37
32
|
|
38
|
-
|
39
|
-
|
33
|
+
# Get trailing whitespace
|
34
|
+
options[:trailing_whitespace] = accept_stripped(:trailing_whitespace)
|
40
35
|
|
41
|
-
|
42
|
-
|
36
|
+
# Get wrapped node attributes
|
37
|
+
atts = attributes(shorthand) || {}
|
43
38
|
|
44
|
-
|
45
|
-
|
39
|
+
# Inherit attributes from definition
|
40
|
+
options[:extension] = extend_attributes
|
46
41
|
|
47
|
-
|
48
|
-
|
42
|
+
# Get unwrapped node attributes
|
43
|
+
options[:attributes] = attributes_assignments atts, false
|
49
44
|
|
50
|
-
|
51
|
-
|
52
|
-
current_node[@options][:self_enclosing] = true
|
45
|
+
# Create node
|
46
|
+
current_node = [:node, node_name, options, [], indent]
|
53
47
|
|
54
|
-
|
55
|
-
|
56
|
-
|
48
|
+
# Check for self enclosing tags and definitions
|
49
|
+
def_check = !@definitions.keys.include?(node_name) &&
|
50
|
+
Settings::SELF_ENCLOSING.include?(node_name)
|
57
51
|
|
58
|
-
|
59
|
-
|
60
|
-
|
52
|
+
# Check if the node is explicitly self enclosing
|
53
|
+
if (close = accept_stripped :self_enclosing) || def_check
|
54
|
+
current_node[@options][:self_enclosing] = true
|
61
55
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
# Inline node element
|
66
|
-
unless (child_node = node current_node, indent)
|
67
|
-
error :inline_child
|
68
|
-
end
|
69
|
-
else
|
70
|
-
# Inline text element
|
71
|
-
text_node = text current_node, indent, false
|
56
|
+
unless close.nil? || close.strip.empty?
|
57
|
+
undo close
|
58
|
+
Logger.error :parse, @code, @i, @j, :self_enclosing
|
72
59
|
end
|
60
|
+
end
|
73
61
|
|
74
|
-
|
75
|
-
|
62
|
+
# Check whether we have explicit inline elements and add them
|
63
|
+
# with increased base indentation
|
64
|
+
if accept :inline_child
|
65
|
+
# Inline node element
|
66
|
+
Logger.error :parse,
|
67
|
+
@code,
|
68
|
+
@i,
|
69
|
+
@j,
|
70
|
+
:inline_child unless node current_node, indent
|
71
|
+
elsif comment current_node, indent
|
72
|
+
# Accept same line comments
|
73
|
+
else
|
74
|
+
# Accept inline text element
|
75
|
+
text current_node, indent, false
|
76
|
+
end
|
76
77
|
|
77
|
-
|
78
|
-
|
79
|
-
# end
|
78
|
+
# Add the current node to the root
|
79
|
+
root current_node, indent
|
80
80
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
end
|
81
|
+
# Create a clone of the definition model. Cloning the options is also
|
82
|
+
# necessary because it's a shallow copy
|
83
|
+
if @definitions.keys.include?(node_name)
|
84
|
+
@definition_stack << node_name
|
85
|
+
parent[@children] << process_definition(node_name, current_node)
|
86
|
+
@definition_stack.pop
|
87
|
+
else
|
88
|
+
parent[@children] << current_node
|
90
89
|
end
|
91
90
|
end
|
92
91
|
|
@@ -107,13 +106,18 @@ module Opulent
|
|
107
106
|
process_definition_child model[@options][:call]
|
108
107
|
process_definition_child model
|
109
108
|
|
110
|
-
|
109
|
+
model
|
111
110
|
end
|
112
111
|
|
112
|
+
# Process definition children for the current node.
|
113
|
+
#
|
114
|
+
# @param node [Node] Callee node
|
115
|
+
#
|
113
116
|
def process_definition_child(node)
|
114
117
|
node[@children].map! do |child|
|
115
118
|
if child[@type] == :node
|
116
|
-
if !@definition_stack.include?(child[@value]) &&
|
119
|
+
if !@definition_stack.include?(child[@value]) &&
|
120
|
+
@definitions.keys.include?(child[@value])
|
117
121
|
process_definition child[@value], child
|
118
122
|
else
|
119
123
|
process_definition_child child if child[@children]
|
@@ -154,20 +158,20 @@ module Opulent
|
|
154
158
|
#
|
155
159
|
def shorthand_attributes(atts = {})
|
156
160
|
while (key = accept :shorthand)
|
157
|
-
key = Settings::
|
161
|
+
key = Settings::SHORTHAND[key.to_sym]
|
158
162
|
|
159
163
|
# Check whether the value is escaped or unescaped
|
160
164
|
escaped = accept(:unescaped_value) ? false : true
|
161
165
|
|
162
166
|
# Get the attribute value and process it
|
163
167
|
if (value = accept(:node))
|
164
|
-
value = [:expression, value.inspect, {escaped: escaped}]
|
168
|
+
value = [:expression, value.inspect, { escaped: escaped }]
|
165
169
|
elsif (value = accept(:exp_string))
|
166
|
-
value = [:expression, value, {escaped: escaped}]
|
170
|
+
value = [:expression, value, { escaped: escaped }]
|
167
171
|
elsif (value = paranthesis)
|
168
|
-
value = [:expression, value, {escaped: escaped}]
|
172
|
+
value = [:expression, value, { escaped: escaped }]
|
169
173
|
else
|
170
|
-
error :shorthand
|
174
|
+
Logger.error :parse, @code, @i, @j, :shorthand
|
171
175
|
end
|
172
176
|
|
173
177
|
# IDs are unique, the rest of the attributes turn into arrays in
|
@@ -175,17 +179,19 @@ module Opulent
|
|
175
179
|
add_attribute(atts, key, value)
|
176
180
|
end
|
177
181
|
|
178
|
-
|
182
|
+
atts
|
179
183
|
end
|
180
184
|
|
185
|
+
# Get element attributes
|
186
|
+
#
|
187
|
+
# @atts [Hash] Accumulator for node attributes
|
188
|
+
#
|
181
189
|
def attributes(atts = {})
|
182
190
|
wrapped_attributes atts
|
183
191
|
attributes_assignments atts, false
|
184
|
-
|
185
|
-
return atts
|
192
|
+
atts
|
186
193
|
end
|
187
194
|
|
188
|
-
|
189
195
|
# Check if we match node attributes
|
190
196
|
#
|
191
197
|
# [ assignments ]
|
@@ -194,11 +200,14 @@ module Opulent
|
|
194
200
|
#
|
195
201
|
def wrapped_attributes(list)
|
196
202
|
if (bracket = accept :brackets)
|
197
|
-
|
198
|
-
|
203
|
+
accept_newline
|
204
|
+
attributes_assignments list, true
|
205
|
+
accept_newline
|
206
|
+
|
207
|
+
accept_stripped bracket.to_sym, :*
|
199
208
|
end
|
200
209
|
|
201
|
-
|
210
|
+
list
|
202
211
|
end
|
203
212
|
|
204
213
|
# Check if we match an expression node or
|
@@ -206,53 +215,63 @@ module Opulent
|
|
206
215
|
#
|
207
216
|
# [ assignments ]
|
208
217
|
#
|
209
|
-
# @param
|
218
|
+
# @param list [Hash] Parent to which we append nodes
|
210
219
|
# @param as_parameters [Boolean] Accept or reject identifier nodes
|
211
220
|
#
|
212
|
-
def attributes_assignments(
|
213
|
-
|
214
|
-
|
221
|
+
def attributes_assignments(list, wrapped = true)
|
222
|
+
if wrapped && lookahead(:exp_identifier_stripped_lookahead).nil? ||
|
223
|
+
!wrapped && lookahead(:assignment_lookahead).nil?
|
224
|
+
return list
|
215
225
|
end
|
216
226
|
|
217
|
-
|
218
|
-
argument = argument.to_sym
|
227
|
+
return unless (argument = accept_stripped :node)
|
219
228
|
|
220
|
-
|
221
|
-
# Check if we have an attribute escape or not
|
222
|
-
escaped = if accept :assignment_unescaped
|
223
|
-
false
|
224
|
-
else
|
225
|
-
true
|
226
|
-
end
|
229
|
+
argument = argument.to_sym
|
227
230
|
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
+
if accept_stripped :assignment
|
232
|
+
# Check if we have an attribute escape or not
|
233
|
+
escaped = if accept :assignment_unescaped
|
234
|
+
false
|
235
|
+
else
|
236
|
+
true
|
237
|
+
end
|
231
238
|
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
239
|
+
# Get the argument value if we have an assignment
|
240
|
+
if (value = expression(false, wrapped))
|
241
|
+
value[@options][:escaped] = escaped
|
242
|
+
|
243
|
+
# IDs are unique, the rest of the attributes turn into arrays in
|
244
|
+
# order to allow multiple values or identifiers
|
245
|
+
add_attribute(list, argument, value)
|
238
246
|
else
|
239
|
-
|
247
|
+
Logger.error :parse, @code, @i, @j, :assignments_colon
|
240
248
|
end
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
# the expression end. If they are not wrapped (inline), we require
|
245
|
-
# paranthesis and allow inline calls
|
246
|
-
if wrapped && accept_stripped(:assignment_terminator)
|
247
|
-
attributes_assignments parent, wrapped
|
248
|
-
elsif !wrapped && lookahead(:assignment_lookahead)
|
249
|
-
attributes_assignments parent, wrapped
|
249
|
+
else
|
250
|
+
unless list[argument]
|
251
|
+
list[argument] = [:expression, 'true', { escaped: false }]
|
250
252
|
end
|
253
|
+
end
|
251
254
|
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
+
# If our attributes are wrapped, we allow method calls without
|
256
|
+
# paranthesis, ruby style, therefore we need a terminator to signify
|
257
|
+
# the expression end. If they are not wrapped (inline), we require
|
258
|
+
# paranthesis and allow inline calls
|
259
|
+
if wrapped
|
260
|
+
# Accept optional comma between attributes
|
261
|
+
accept_stripped :assignment_terminator
|
262
|
+
|
263
|
+
# Lookahead for attributes on the current line and the next one
|
264
|
+
if lookahead(:exp_identifier_stripped_lookahead)
|
265
|
+
attributes_assignments list, wrapped
|
266
|
+
elsif lookahead_next_line(:exp_identifier_stripped_lookahead)
|
267
|
+
accept_newline
|
268
|
+
attributes_assignments list, wrapped
|
269
|
+
end
|
270
|
+
elsif !wrapped && lookahead(:assignment_lookahead)
|
271
|
+
attributes_assignments list, wrapped
|
255
272
|
end
|
273
|
+
|
274
|
+
list
|
256
275
|
end
|
257
276
|
|
258
277
|
# Extend node attributes with hash from
|
@@ -262,14 +281,13 @@ module Opulent
|
|
262
281
|
# +(paranthesis)
|
263
282
|
#
|
264
283
|
def extend_attributes
|
265
|
-
|
266
|
-
|
284
|
+
return unless accept :extend_attributes
|
285
|
+
unescaped = accept :unescaped_value
|
267
286
|
|
268
|
-
|
269
|
-
|
287
|
+
extension = expression(false, false, false)
|
288
|
+
extension[@options][:escaped] = !unescaped
|
270
289
|
|
271
|
-
|
272
|
-
end
|
290
|
+
extension
|
273
291
|
end
|
274
292
|
end
|
275
293
|
end
|
data/lib/opulent/parser/root.rb
CHANGED
@@ -9,9 +9,12 @@ module Opulent
|
|
9
9
|
# @param nodes [Array] Parent node to which we append to
|
10
10
|
#
|
11
11
|
def root(parent = @root, min_indent = -1)
|
12
|
-
while(@line = @code[(@i += 1)])
|
12
|
+
while (@line = @code[(@i += 1)])
|
13
|
+
# Reset character position cursor
|
14
|
+
@j = 0
|
15
|
+
|
13
16
|
# Skip to next iteration if we have a blank line
|
14
|
-
if @line =~ /\A\s*\Z/
|
17
|
+
next if @line =~ /\A\s*\Z/
|
15
18
|
|
16
19
|
# Reset the line offset
|
17
20
|
@offset = 0
|
@@ -23,7 +26,8 @@ module Opulent
|
|
23
26
|
# Stop using the current parent as root if it does not match the
|
24
27
|
# minimum indentation includements
|
25
28
|
unless min_indent < indent
|
26
|
-
@i -= 1
|
29
|
+
@i -= 1
|
30
|
+
break
|
27
31
|
end
|
28
32
|
|
29
33
|
# If last include path had a greater indentation, pop the last file path
|
@@ -31,23 +35,25 @@ module Opulent
|
|
31
35
|
|
32
36
|
# Try the main Opulent node types and process each one of them using
|
33
37
|
# their matching evaluation procedure
|
34
|
-
current_node =
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
# Throw an error if we couldn't find
|
47
|
-
|
38
|
+
current_node = node(parent, indent) ||
|
39
|
+
text(parent, indent) ||
|
40
|
+
comment(parent, indent) ||
|
41
|
+
define(parent, indent) ||
|
42
|
+
control(parent, indent) ||
|
43
|
+
evaluate(parent, indent) ||
|
44
|
+
filter(parent, indent) ||
|
45
|
+
block_yield(parent, indent) ||
|
46
|
+
include_file(parent, indent) ||
|
47
|
+
html_text(parent, indent) ||
|
48
|
+
doctype(parent, indent)
|
49
|
+
|
50
|
+
# Throw an error if we couldn't find any valid node
|
51
|
+
unless current_node
|
52
|
+
Logger.error :parse, @code, @i, @j, :unknown_node_type
|
53
|
+
end
|
48
54
|
end
|
49
55
|
|
50
|
-
|
56
|
+
parent
|
51
57
|
end
|
52
58
|
end
|
53
59
|
end
|