opulent 1.5.5 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|