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
data/lib/opulent/parser.rb
CHANGED
@@ -22,7 +22,7 @@ module Opulent
|
|
22
22
|
#
|
23
23
|
# [:node_type, :value, :attributes, :children, :indent]
|
24
24
|
#
|
25
|
-
def initialize(
|
25
|
+
def initialize(settings = {})
|
26
26
|
# Convention accessors
|
27
27
|
@type = 0
|
28
28
|
@value = 1
|
@@ -30,17 +30,20 @@ module Opulent
|
|
30
30
|
@children = 3
|
31
31
|
@indent = 4
|
32
32
|
|
33
|
+
# Inherit settings from Engine
|
34
|
+
@settings = settings
|
35
|
+
|
33
36
|
# Set current compiled file as the first in the file stack together with
|
34
37
|
# its base indentation. The stack is used to allow include directives to
|
35
38
|
# be used with the last parent path found
|
36
|
-
@file = [[file, -1]]
|
39
|
+
@file = [[@settings.delete(:file), -1]]
|
37
40
|
|
38
41
|
# Create a definition stack to disallow recursive calls. When inside a
|
39
42
|
# definition and a named node is called, we render it as a plain node
|
40
43
|
@definition_stack = []
|
41
44
|
|
42
45
|
# Initialize definitions for the parser
|
43
|
-
@definitions =
|
46
|
+
@definitions = @settings.delete(:def) || {}
|
44
47
|
end
|
45
48
|
|
46
49
|
# Initialize the parsing process by splitting the code into lines and
|
@@ -57,6 +60,9 @@ module Opulent
|
|
57
60
|
# Current line index
|
58
61
|
@i = -1
|
59
62
|
|
63
|
+
# Current character index
|
64
|
+
@j = 0
|
65
|
+
|
60
66
|
# Initialize root node
|
61
67
|
@root = [:root, nil, {}, [], -1]
|
62
68
|
|
@@ -64,7 +70,7 @@ module Opulent
|
|
64
70
|
# nodes and definitions
|
65
71
|
root @root
|
66
72
|
|
67
|
-
|
73
|
+
[@root, @definitions]
|
68
74
|
end
|
69
75
|
|
70
76
|
# Check and accept or reject a given token as long as we have tokens
|
@@ -88,10 +94,11 @@ module Opulent
|
|
88
94
|
if (match = @line[@offset..-1].match(Tokens[token]))
|
89
95
|
# Advance current offset with match length
|
90
96
|
@offset += match[0].size
|
97
|
+
@j += match[0].size
|
91
98
|
|
92
99
|
return match[0]
|
93
100
|
elsif required
|
94
|
-
error :expected, token
|
101
|
+
Logger.error :parse, @code, @i, @j, :expected, token
|
95
102
|
end
|
96
103
|
end
|
97
104
|
|
@@ -144,6 +151,7 @@ module Opulent
|
|
144
151
|
def accept_newline
|
145
152
|
return unless @line[@offset..-1].strip.empty?
|
146
153
|
@line = @code[(@i += 1)]
|
154
|
+
@j = 0
|
147
155
|
@offset = 0
|
148
156
|
end
|
149
157
|
|
@@ -154,77 +162,7 @@ module Opulent
|
|
154
162
|
#
|
155
163
|
def indent_lines(text, indent)
|
156
164
|
text ||= ''
|
157
|
-
text.lines.
|
158
|
-
result += indent + line
|
159
|
-
end
|
160
|
-
end
|
161
|
-
|
162
|
-
# Give an explicit error report where an unexpected sequence of tokens
|
163
|
-
# appears and give indications on how to solve it
|
164
|
-
#
|
165
|
-
# @param message [Symbol] Error message to display to the user
|
166
|
-
#
|
167
|
-
def error(error, *data)
|
168
|
-
message = case error
|
169
|
-
when :unknown_node_type
|
170
|
-
"An unknown node type has been encountered at:\n\n#{Logger.red @line}"
|
171
|
-
when :expected
|
172
|
-
if [:'(', :'{', :'[', :'<'].include? data[0]
|
173
|
-
data[0] = "#{Tokens.bracket data[0]}"
|
174
|
-
end
|
175
|
-
"Expected to find a :#{data[0]} token on line #{@i+1} of input at: " \
|
176
|
-
"\n\n#{@line[0..@offset-1]}#{Logger.red @line[@offset..-1].rstrip}"
|
177
|
-
when :root
|
178
|
-
"Unknown node type encountered on line #{@i+1} of input at:\n\n" +
|
179
|
-
"#{@line[0..@offset-1]}#{Logger.red @line[@offset..-1].rstrip}"
|
180
|
-
when :assignments_colon
|
181
|
-
"Unexpected end of element attributes reached on line #{@i+1} of input.\n\n" +
|
182
|
-
"Expected to find an attribute at:\n\n" +
|
183
|
-
"#{@line[0..@offset-1]}#{Logger.red @line[@offset..-1].rstrip}"
|
184
|
-
when :assignments_comma
|
185
|
-
"Unexpected end of element attributes reached on line #{@i+1} of input.\n\n" +
|
186
|
-
"Expected to find an attribute value at:\n\n" +
|
187
|
-
"#{@line[0..@offset-1]}#{Logger.red @line[@offset..-1].rstrip}"
|
188
|
-
when :expression
|
189
|
-
"Unexpected end of expression reached on line #{@i+1} of input.\n\n" +
|
190
|
-
"Expected to find another expression term at:\n\n" +
|
191
|
-
"#{@line[0..@offset-1]}#{Logger.red @line[@offset..-1].rstrip}"
|
192
|
-
when :control_child
|
193
|
-
"Unexpected control structure child found on line #{@i+1} of input.\n\n" +
|
194
|
-
"Expected to find a parent #{data[0]} structure at:\n\n" +
|
195
|
-
"#{@line[0..@offset-1]}#{Logger.red @line[@offset..-1].rstrip}"
|
196
|
-
when :case_children
|
197
|
-
"Unexpected control structure child found on line #{@i+1} of input.\n\n" +
|
198
|
-
"Case structure cannot have any child elements at:\n\n" +
|
199
|
-
"#{@code[@i-1][0..@offset-1]}#{Logger.red @code[@i][@offset..-1].rstrip}"
|
200
|
-
when :whitespace_expression
|
201
|
-
"Unexpected end of expression reached on line #{@i+1} of input.\n\n" +
|
202
|
-
"Please use paranthesis for method parameters at:\n\n" +
|
203
|
-
"#{@line[0..@offset-1]}#{Logger.red @line[@offset..-1].rstrip}"
|
204
|
-
when :definition
|
205
|
-
"Unexpected start of definition on line #{@i+1} of input.\n\n" +
|
206
|
-
"Found a definition inside another definition or element at:\n\n" +
|
207
|
-
"#{@line[0..@offset-1]}#{Logger.red @line[@offset..-1].rstrip}"
|
208
|
-
when :self_enclosing
|
209
|
-
"Unexpected content found after self enclosing node on line #{@i+1} of input at:\n\n" +
|
210
|
-
"#{@line[0..@offset-1]}#{Logger.red @line[@offset..-1].rstrip}"
|
211
|
-
when :self_enclosing_children
|
212
|
-
"Unexpected child elements found for self enclosing node on line #{data[0]+1} of input at:\n\n" +
|
213
|
-
"#{@code[data[0]]}#{Logger.red @code[data[0] + 1]}"
|
214
|
-
when :include
|
215
|
-
"The included file #{data[0]} does not exist or an incorrect path has been specified."
|
216
|
-
when :include_dir
|
217
|
-
"The included file path #{data[0]} is a directory."
|
218
|
-
when :include_end
|
219
|
-
"Missing argument for include on line #{@i+1} of input at:\n\n" +
|
220
|
-
"#{@line[0..@offset-1]}#{Logger.red @line[@offset..-1].rstrip}"
|
221
|
-
else
|
222
|
-
"#{@line[0..@offset-1]}#{Logger.red @line[@offset..-1].rstrip}"
|
223
|
-
end
|
224
|
-
|
225
|
-
# Reconstruct lines to display where errors occur
|
226
|
-
fail "\n\nOpulent " + Logger.red('[Parser Error]') +
|
227
|
-
"\n---\n#{message}\n\n\n"
|
165
|
+
text.lines.map { |line| indent + line }.join
|
228
166
|
end
|
229
167
|
end
|
230
168
|
end
|
@@ -1,34 +1,45 @@
|
|
1
|
-
# @Opulent
|
2
|
-
module Opulent
|
3
|
-
# @Parser
|
4
|
-
class Parser
|
5
|
-
# Match one line or multiline comments
|
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
|
-
|
1
|
+
# @Opulent
|
2
|
+
module Opulent
|
3
|
+
# @Parser
|
4
|
+
class Parser
|
5
|
+
# Match one line or multiline comments
|
6
|
+
#
|
7
|
+
# @param parent [Node] Parent node of comment
|
8
|
+
# @param indent [Fixnum] Number of indentation characters
|
9
|
+
#
|
10
|
+
def comment(parent, indent)
|
11
|
+
return unless accept :comment
|
12
|
+
|
13
|
+
# Get first comment line
|
14
|
+
buffer = accept(:line_feed)
|
15
|
+
buffer += accept(:newline) || ''
|
16
|
+
|
17
|
+
# Get indented comment lines
|
18
|
+
buffer += get_indented_lines indent
|
19
|
+
|
20
|
+
# If we have a comment which is visible in the output, we will
|
21
|
+
# create a new comment element. Otherwise, we ignore the current
|
22
|
+
# gathered text and we simply begin the root parsing again
|
23
|
+
if buffer[0] == '!'
|
24
|
+
offset = 1
|
25
|
+
options = {}
|
26
|
+
|
27
|
+
# Allow leading comment newline
|
28
|
+
if buffer[1] == '^'
|
29
|
+
offset = 2
|
30
|
+
options[:newline] = true
|
31
|
+
end
|
32
|
+
|
33
|
+
parent[@children] << [
|
34
|
+
:comment,
|
35
|
+
buffer[offset..-1].strip,
|
36
|
+
options,
|
37
|
+
nil,
|
38
|
+
indent
|
39
|
+
]
|
40
|
+
end
|
41
|
+
|
42
|
+
parent
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -1,111 +1,132 @@
|
|
1
|
-
# @Opulent
|
2
|
-
module Opulent
|
3
|
-
# @Parser
|
4
|
-
class Parser
|
5
|
-
# Match an if-else control structure
|
6
|
-
#
|
7
|
-
def control(parent, indent)
|
8
|
-
# Accept eval or multiline eval syntax and return a new node,
|
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
|
-
end
|
1
|
+
# @Opulent
|
2
|
+
module Opulent
|
3
|
+
# @Parser
|
4
|
+
class Parser
|
5
|
+
# Match an if-else control structure
|
6
|
+
#
|
7
|
+
def control(parent, indent)
|
8
|
+
# Accept eval or multiline eval syntax and return a new node,
|
9
|
+
return unless (structure = accept(:control))
|
10
|
+
structure = structure.to_sym
|
11
|
+
|
12
|
+
# Handle each and the other control structures
|
13
|
+
condition = accept(:line_feed).strip
|
14
|
+
|
15
|
+
# Process each control structure condition
|
16
|
+
if structure == :each
|
17
|
+
# Check if arguments provided correctly
|
18
|
+
unless condition.match Tokens[:each_pattern]
|
19
|
+
Logger.error :parse, @code, @i, @j, :each_arguments
|
20
|
+
end
|
21
|
+
|
22
|
+
# Conditions for each iterator
|
23
|
+
condition = [
|
24
|
+
Regexp.last_match[1].split(' '),
|
25
|
+
Regexp.last_match[2].split(/,(.+)$/).map(&:strip).map(&:to_sym)
|
26
|
+
]
|
27
|
+
|
28
|
+
# Array loop as default
|
29
|
+
condition[0].unshift '{}' if condition[0].length == 1
|
30
|
+
end
|
31
|
+
|
32
|
+
# Else and default structures are not allowed to have any condition
|
33
|
+
# set and the other control structures require a condition
|
34
|
+
if structure == :else
|
35
|
+
unless condition.empty?
|
36
|
+
Logger.error :parse, @code, @i, @j, :condition_exists
|
37
|
+
end
|
38
|
+
else
|
39
|
+
if condition.empty?
|
40
|
+
Logger.error :parse, @code, @i, @j, :condition_missing
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# Add the condition and create a new child to the control parent.
|
45
|
+
# The control parent keeps condition -> children matches for our
|
46
|
+
# document's content
|
47
|
+
# add_options = proc do |control_parent|
|
48
|
+
# control_parent.value << condition
|
49
|
+
# control_parent.children << []
|
50
|
+
#
|
51
|
+
# root control_parent
|
52
|
+
# end
|
53
|
+
|
54
|
+
# If the current control structure is a parent which allows multiple
|
55
|
+
# branches, such as an if or case, we create an array of conditions
|
56
|
+
# which can be matched and an array of children belonging to each
|
57
|
+
# conditional branch
|
58
|
+
if [:if, :unless].include? structure
|
59
|
+
# Create the control structure and get its child nodes
|
60
|
+
control_structure = [structure, [condition], {}, [], indent]
|
61
|
+
root control_structure, indent
|
62
|
+
|
63
|
+
# Turn children into an array because we allow multiple branches
|
64
|
+
control_structure[@children] = [control_structure[@children]]
|
65
|
+
|
66
|
+
# Add it to the parent node
|
67
|
+
parent[@children] << control_structure
|
68
|
+
|
69
|
+
elsif structure == :case
|
70
|
+
# Create the control structure and get its child nodes
|
71
|
+
control_structure = [
|
72
|
+
structure,
|
73
|
+
[],
|
74
|
+
{ condition: condition },
|
75
|
+
[],
|
76
|
+
indent
|
77
|
+
]
|
78
|
+
|
79
|
+
# Add it to the parent node
|
80
|
+
parent[@children] << control_structure
|
81
|
+
|
82
|
+
# If the control structure is a child structure, we need to find the
|
83
|
+
# node it belongs to amont the current parent. Search from end to
|
84
|
+
# beginning until we find the node parent
|
85
|
+
elsif control_child structure
|
86
|
+
# During the search, we try to find the matching parent type
|
87
|
+
unless control_parent(structure).include? parent[@children][-1][@type]
|
88
|
+
Logger.error :parse,
|
89
|
+
@code,
|
90
|
+
@i,
|
91
|
+
@j,
|
92
|
+
:control_child,
|
93
|
+
control_parent(structure)
|
94
|
+
end
|
95
|
+
|
96
|
+
# Gather child elements for current structure
|
97
|
+
control_structure = [structure, [condition], {}, [], indent]
|
98
|
+
root control_structure, indent
|
99
|
+
|
100
|
+
# Add the new condition and children to our parent structure
|
101
|
+
parent[@children][-1][@value] << condition
|
102
|
+
parent[@children][-1][@children] << control_structure[@children]
|
103
|
+
|
104
|
+
# When our control structure isn't a complex composite, we create
|
105
|
+
# it the same way as a normal node
|
106
|
+
else
|
107
|
+
control_structure = [structure, condition, {}, [], indent]
|
108
|
+
root control_structure, indent
|
109
|
+
|
110
|
+
parent[@children] << control_structure
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
# Check if the current control structure requires a parent node and
|
115
|
+
# return the parent's node type
|
116
|
+
#
|
117
|
+
def control_child(structure)
|
118
|
+
[:else, :elsif, :when].include? structure
|
119
|
+
end
|
120
|
+
|
121
|
+
# Check if the current control structure requires a parent node and
|
122
|
+
# return the parent's node type
|
123
|
+
#
|
124
|
+
def control_parent(structure)
|
125
|
+
case structure
|
126
|
+
when :else then [:if, :unless, :case]
|
127
|
+
when :elsif then [:if]
|
128
|
+
when :when then [:case]
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|