opulent 1.5.5 → 1.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (78) hide show
  1. checksums.yaml +4 -4
  2. data/CODE_OF_CONDUCT.md +13 -0
  3. data/{LICENSE → LICENSE.md} +0 -0
  4. data/bin/opulent +0 -0
  5. data/lib/opulent.rb +10 -10
  6. data/lib/opulent/compiler.rb +15 -9
  7. data/lib/opulent/compiler/buffer.rb +123 -62
  8. data/lib/opulent/compiler/comment.rb +3 -4
  9. data/lib/opulent/compiler/control.rb +20 -26
  10. data/lib/opulent/compiler/define.rb +88 -36
  11. data/lib/opulent/compiler/doctype.rb +20 -22
  12. data/lib/opulent/compiler/eval.rb +23 -2
  13. data/lib/opulent/compiler/filter.rb +4 -5
  14. data/lib/opulent/compiler/node.rb +18 -12
  15. data/lib/opulent/compiler/root.rb +4 -5
  16. data/lib/opulent/compiler/text.rb +7 -2
  17. data/lib/opulent/compiler/yield.rb +2 -3
  18. data/lib/opulent/engine.rb +21 -20
  19. data/lib/opulent/exec.rb +21 -63
  20. data/lib/opulent/logger.rb +230 -3
  21. data/lib/opulent/parser.rb +14 -76
  22. data/lib/opulent/parser/comment.rb +45 -34
  23. data/lib/opulent/parser/control.rb +132 -111
  24. data/lib/opulent/parser/define.rb +15 -12
  25. data/lib/opulent/parser/doctype.rb +15 -15
  26. data/lib/opulent/parser/eval.rb +16 -6
  27. data/lib/opulent/parser/expression.rb +87 -84
  28. data/lib/opulent/parser/filter.rb +31 -25
  29. data/lib/opulent/parser/include.rb +38 -42
  30. data/lib/opulent/parser/node.rb +136 -118
  31. data/lib/opulent/parser/root.rb +24 -18
  32. data/lib/opulent/parser/text.rb +150 -123
  33. data/lib/opulent/parser/yield.rb +23 -23
  34. data/lib/opulent/settings.rb +70 -51
  35. data/lib/opulent/tokens.rb +17 -15
  36. data/lib/opulent/utils.rb +5 -4
  37. data/lib/opulent/version.rb +1 -1
  38. metadata +4 -43
  39. data/.libold/opulent.rb +0 -96
  40. data/.libold/opulent/context.rb +0 -80
  41. data/.libold/opulent/engine.rb +0 -88
  42. data/.libold/opulent/filter.rb +0 -101
  43. data/.libold/opulent/logger.rb +0 -67
  44. data/.libold/opulent/nodes.rb +0 -13
  45. data/.libold/opulent/nodes/block.rb +0 -29
  46. data/.libold/opulent/nodes/comment.rb +0 -35
  47. data/.libold/opulent/nodes/control.rb +0 -230
  48. data/.libold/opulent/nodes/define.rb +0 -42
  49. data/.libold/opulent/nodes/eval.rb +0 -41
  50. data/.libold/opulent/nodes/expression.rb +0 -28
  51. data/.libold/opulent/nodes/filter.rb +0 -70
  52. data/.libold/opulent/nodes/helper.rb +0 -69
  53. data/.libold/opulent/nodes/node.rb +0 -101
  54. data/.libold/opulent/nodes/root.rb +0 -62
  55. data/.libold/opulent/nodes/text.rb +0 -54
  56. data/.libold/opulent/nodes/theme.rb +0 -36
  57. data/.libold/opulent/parser.rb +0 -252
  58. data/.libold/opulent/parser/block.rb +0 -70
  59. data/.libold/opulent/parser/comment.rb +0 -32
  60. data/.libold/opulent/parser/control.rb +0 -83
  61. data/.libold/opulent/parser/define.rb +0 -39
  62. data/.libold/opulent/parser/eval.rb +0 -33
  63. data/.libold/opulent/parser/expression.rb +0 -350
  64. data/.libold/opulent/parser/filter.rb +0 -41
  65. data/.libold/opulent/parser/node.rb +0 -232
  66. data/.libold/opulent/parser/root.rb +0 -96
  67. data/.libold/opulent/parser/text.rb +0 -114
  68. data/.libold/opulent/parser/theme.rb +0 -36
  69. data/.libold/opulent/preprocessor.rb +0 -102
  70. data/.libold/opulent/runtime.rb +0 -144
  71. data/.libold/opulent/template.rb +0 -43
  72. data/.libold/opulent/tokens.rb +0 -276
  73. data/.libold/opulent/version.rb +0 -5
  74. data/.travis.yml +0 -4
  75. data/benchmark/benchmark.rb +0 -57
  76. data/benchmark/cases/node/node.haml +0 -7
  77. data/benchmark/cases/node/node.op +0 -7
  78. data/benchmark/cases/node/node.slim +0 -7
@@ -1,36 +0,0 @@
1
- # @Opulent
2
- module Opulent
3
- # @Nodes
4
- module Nodes
5
- # @Theme
6
- #
7
- # Node class used to describe a HTML Element used for building a
8
- # page model during the parsing process
9
- #
10
- class Theme
11
- # Allow direct access to node variables
12
- attr_accessor :name, :indent, :parent, :children
13
-
14
- # Initialize node instance variables
15
- #
16
- # @param name [String] name of the html node
17
- # @param indentation [Fixnum] node indentation for restructuring
18
- # @param attributes [Hash] stores key="value" attributes
19
- # @param children [Array] collection of the node's child elements
20
- #
21
- def initialize(name = '', parent = nil, indent = 0, children = [])
22
- @name = name
23
- @parent = parent
24
- @indent = indent
25
- @children = children
26
- end
27
-
28
- # Add a new node to the nodes array
29
- #
30
- def push(node)
31
- @children << node
32
- self
33
- end
34
- end
35
- end
36
- end
@@ -1,252 +0,0 @@
1
- require_relative 'parser/root'
2
- require_relative 'parser/node'
3
- require_relative 'parser/eval'
4
- require_relative 'parser/expression'
5
- require_relative 'parser/define'
6
- require_relative 'parser/text'
7
- require_relative 'parser/filter'
8
- require_relative 'parser/control'
9
- require_relative 'parser/theme'
10
- require_relative 'parser/block'
11
- require_relative 'parser/comment'
12
-
13
- # @Opulent
14
- module Opulent
15
- # @Lexer
16
- module Parser
17
- # @Singleton
18
- class << self
19
- # Include Opulent tokens regular expressions to be checked using the
20
- # accept (or expect) method together with lookahead expressions
21
- include Root
22
- include Node
23
- include Expression
24
- include Evaluate
25
- include Define
26
- include Text
27
- include Filter
28
- include Control
29
- include Theme
30
- include Block
31
- include Comment
32
-
33
- # Analyze the input code and check for matching tokens.
34
- # In case no match was found, throw an exception.
35
- # In special cases, modify the token hash.
36
- #
37
- # @param code [String] Opulent code that needs to be analyzed
38
- # @return Nodes array
39
- #
40
- def parse(code)
41
- # Code to be parsed
42
- @code = code
43
-
44
- # Keeps track of consumed code
45
- @consumed = ""
46
-
47
- # Current line being parsed, used for error reporting
48
- @current_line = 1
49
-
50
- # Node creation wrapper for comprehensible node creation
51
- @create = Nodes::Helper.new
52
-
53
- # Create root node, our wrapper for all the HTML elements we use
54
- # which knows how to evaluate each of them to output the final code
55
- # The root also stores custom node definitions collection from which we
56
- # replace the nodes which use them
57
- @root = @create.root
58
-
59
- # Loop until we have no tokens left to parse or we find an error
60
- root @root
61
-
62
- # We still have code left to parse
63
- error :root unless @code.strip.empty?
64
-
65
- return @root
66
- end
67
-
68
- # Accept and consume or reject a given token as long as we have tokens
69
- # remaining. Shift the code with the match length plus any extra character
70
- # count around the capture group
71
- #
72
- # @param identifier [RegEx] Token syntax to be accepted by the parser
73
- # @param required [Boolean] Expect the given token syntax
74
- # @param strip [Boolean] Left strip the current code to remove whitespace
75
- #
76
- def accept(identifier, required = false, strip = true)
77
- # Get token from tokens knowledgebase
78
- token = Tokens[identifier]
79
-
80
- # If the token's capture group is smaller than the whole match,
81
- # advance the code chunk with more spaces
82
- extra = token[:extra] || 0
83
-
84
- # Remove leading whitespace between expressions
85
- if @code && strip
86
- if (stripped = @code[/\A +/]) then @consumed += stripped end
87
- @code.lstrip!
88
- end
89
-
90
- # Check to see if
91
- if @code =~ token[:regex]
92
- @current_line += 1 if identifier == :newline
93
-
94
- shift = $1.size + extra
95
-
96
- @consumed += @code[0..shift - 1] if shift > 0
97
- @code = @code[shift..-1]
98
-
99
- return $1
100
- elsif required
101
- error :expect, identifier
102
- else
103
- return nil
104
- end
105
- end
106
-
107
- # Accept and consume or reject a given token as long as we have tokens
108
- # remaining on the current line only. Shift the code with the match length
109
- # plus any extra character count around the capture group
110
- #
111
- # @param identifier [RegEx] Token syntax to be accepted by the parser
112
- # @param required [Boolean] Expect the given token syntax
113
- # @param strip [Boolean] Left strip the current code to remove whitespace
114
- #
115
- def accept_line(identifier, required = false, strip = true)
116
- # Get token from tokens knowledgebase
117
- token = Tokens[identifier]
118
-
119
- # If the token's capture group is smaller than the whole match,
120
- # advance the code chunk with more spaces
121
- extra = token[:extra] || 0
122
-
123
- # Remove leading whitespace between expressions
124
- if @code.lines.first && strip
125
- if (stripped = @code.lines.first[/\A +/]) then @consumed += stripped end
126
- @code.gsub! /\A +/, ''
127
- end
128
-
129
- # Check to see if
130
- if @code.lines.first =~ token[:regex]
131
- @current_line += 1 if identifier == :newline
132
-
133
- shift = $1.size + extra
134
-
135
- @consumed += @code[0..shift - 1] if shift > 0
136
- @code = @code[shift..-1]
137
-
138
- return $1
139
- elsif required
140
- error :expect, identifier
141
- else
142
- return nil
143
- end
144
- end
145
-
146
- # Wrapper method for accepting unstripped tokens such as whitespace or a
147
- # certain required sequence directly
148
- #
149
- # @param identifier [RegEx] Token syntax to be accepted by the parser
150
- # @param required [Boolean] Expect the given token syntax
151
- #
152
- def accept_unstripped(identifier, required = false)
153
- accept(identifier, required, false)
154
- end
155
-
156
- # Wrapper method for accepting unstripped tokens such as whitespace or a
157
- # certain required sequence directly on the current line only
158
- #
159
- # @param identifier [RegEx] Token syntax to be accepted by the parser
160
- # @param required [Boolean] Expect the given token syntax
161
- #
162
- def accept_line_unstripped(identifier, required = false)
163
- accept_line(identifier, required, false)
164
- end
165
-
166
- # Look ahead in the current code to see if we can match an input token.
167
- # No modifications will be done to the code.
168
- #
169
- # @param token [RegEx] Token syntax to be accepted by the parser
170
- # @param strip [Boolean] Left strip the current code to remove whitespace
171
- #
172
- def lookahead(token, strip = true)
173
- # Get token from tokens knowledgebase
174
- token = Tokens[token]
175
-
176
- # We don't want to modify anything in the code directly, so we use a
177
- # local code variable
178
- code = @code
179
-
180
- # Remove leading whitespace between expressions
181
- code = code.lstrip if code && strip
182
-
183
- # Check to see if
184
- if code =~ token[:regex]
185
- return $~[:capture]
186
- else
187
- return nil
188
- end
189
- end
190
-
191
- # Undo a found match by removing the token from the consumed code and
192
- # adding it back to the code chunk
193
- #
194
- # @param match [String] Matched string to be undone
195
- #
196
- def undo(match)
197
- unless match.empty?
198
- @consumed = @consumed[0..-match.length]
199
- @code = match + @code
200
- return nil
201
- end
202
- end
203
-
204
- # Give an explicit error report where an unexpected sequence of tokens
205
- # appears and give indications on how to solve it
206
- #
207
- # @param context [Symbol] Context name in which the error happens
208
- # @param data [Array] Additional error information
209
- #
210
- def error(context, *data)
211
- consumed = @consumed.lines.last.strip if @consumed.lines.last
212
- code = @code.empty? ? ' END' : @code.lines.first.strip
213
-
214
- message = case context
215
- when :root
216
- "Unknown node type encountered on line #{@current_line} of input at:\n\n" +
217
- "#{consumed}" + Logger.red(code)
218
- when :expect
219
- "Expected to find token :#{data[0]} on line #{@current_line} of input at:\n\n" +
220
- "#{consumed}" + Logger.red(code)
221
- when :assignments_colon
222
- "Unexpected end of element attributes reached on line #{@current_line} of input.\n\n" +
223
- "Expected to find an attribute at:\n\n" +
224
- "#{consumed}" + Logger.red(code)
225
- when :assignments_comma
226
- "Unexpected end of element attributes reached on line #{@current_line} of input.\n\n" +
227
- "Expected to find an attribute value at:\n\n" +
228
- "#{consumed}" + Logger.red(code)
229
- when :expression
230
- "Unexpected end of expression reached on line #{@current_line} of input.\n\n" +
231
- "Expected to find another expression term at:\n\n" +
232
- "#{consumed}" + Logger.red(code)
233
- when :whitespace_expression
234
- "Unexpected end of expression reached on line #{@current_line} of input.\n\n" +
235
- "Please use paranthesis for method parameters at:\n\n" +
236
- "#{consumed}" + Logger.red(code)
237
- when :definition
238
- "Unexpected start of definition on line #{@current_line - 1} of input.\n\n" +
239
- "Found a definition inside another definition or element at:\n\n" +
240
- (@consumed.lines[-2] || "") + Logger.red(consumed + "\n " + code)
241
- else
242
- "#{consumed}" + Logger.red(code)
243
- end
244
-
245
- # Reconstruct lines to display where errors occur
246
- fail "\n\nOpulent " + Logger.red("[Parser Error]") + "\n---\n" +
247
- "A parsing error has been encountered in the \"#{context}\" context.\n" +
248
- "#{message}\n\n\n"
249
- end
250
- end
251
- end
252
- end
@@ -1,70 +0,0 @@
1
- # @Opulent
2
- module Opulent
3
- # @Parser
4
- module Parser
5
- # @Block
6
- module Block
7
- # Match a yield with a explicit or implicit target
8
- #
9
- # yield target
10
- #
11
- # @param parent [Node] Parent node to which we append the definition
12
- #
13
- def block_yield(parent)
14
- if lookahead :yield_lookahead
15
- # Get current line's indentation
16
- indent = accept(:indent, false, false) || ""
17
-
18
- if accept :yield
19
- # Get definition name
20
- yield_name = if(yield_name = accept(:yield_identifier, false, false))
21
- yield_name.strip.to_sym
22
- else
23
- Engine::DEFAULT_YIELD
24
- end
25
-
26
- # Create a new node
27
- node = @create.block_yield yield_name, parent, indent.size
28
-
29
- # Consume the newline from the end of the element
30
- error :yield unless accept(:line_feed, false, false).strip.empty?
31
- accept :newline, false, false
32
-
33
- return node
34
- end
35
- end
36
- end
37
-
38
- # Match a block with a explicit target
39
- #
40
- # block target
41
- #
42
- # @param parent [Node] Parent node to which we append the definition
43
- #
44
- def block(parent)
45
- if lookahead :block_lookahead
46
- # Get current line's indentation
47
- indent = accept_unstripped(:indent) || ""
48
-
49
- if accept :block
50
- # Get definition name
51
- block_name = if(block_name = accept_unstripped(:yield_identifier))
52
- block_name.strip.to_sym
53
- else
54
- Engine::DEFAULT_YIELD
55
- end
56
-
57
- # Create a new node
58
- node = @create.block block_name, parent, indent.size
59
-
60
- # Consume the newline from the end of the element
61
- error :block unless accept_unstripped(:line_feed).strip.empty?
62
- accept_unstripped :newline
63
-
64
- return node
65
- end
66
- end
67
- end
68
- end
69
- end
70
- end
@@ -1,32 +0,0 @@
1
- # @SugarCube
2
- module Opulent
3
- # @Parser
4
- module Parser
5
- # @Text
6
- module Comment
7
- # Match one line or multiline comments
8
- #
9
- def comment(parent)
10
- if lookahead(:comment_lookahead)
11
- indent = accept_unstripped(:indent) || ""
12
- indent = indent.size
13
-
14
- if (comment_feed = accept_unstripped :comment)
15
- comment_feed += accept_unstripped(:newline) || ""
16
- comment_feed += get_indented_lines indent
17
-
18
- # If we have a comment which is visible in the output, we will
19
- # create a new comment element. Otherwise, we ignore the current
20
- # gathered text and we simply begin the root parsing again
21
- if comment_feed[0] == '!'
22
- return @create.comment comment_feed[1..-1].strip, parent, indent
23
- else
24
- root parent
25
- return nil
26
- end
27
- end
28
- end
29
- end
30
- end
31
- end
32
- end
@@ -1,83 +0,0 @@
1
- # @SugarCube
2
- module Opulent
3
- # @Parser
4
- module Parser
5
- # @Control
6
- module Control
7
- # Match an if-else control structure
8
- #
9
- def control(parent)
10
- if lookahead :control_lookahead
11
- indent = indent || accept_unstripped(:indent) || ""
12
-
13
- # Accept eval or multiline eval syntax and return a new node,
14
- if (structure = accept_unstripped(:control))
15
- structure = structure.to_sym
16
-
17
- # Handle each and the other control structures
18
- condition = accept_unstripped(:line_feed).strip
19
- accept_unstripped :newline
20
-
21
- # Process each control structure condition
22
- if structure == :each
23
- # Check if arguments provided correctly
24
- error :each_arguments unless condition.match Tokens[:each_pattern][:regex]
25
-
26
- # Split provided arguments for the each structure
27
- condition = condition.split('in').map(&:strip)
28
- condition[0] = condition[0].split(',').map(&:strip).map(&:to_sym)
29
- end
30
-
31
- # Else and default structures are not allowed to have any condition
32
- # set and the other control structures require a condition
33
- if structure == :else
34
- error :condition_exists unless condition.empty?
35
- else
36
- error :condition_missing if condition.empty?
37
- end
38
-
39
- # Add the condition and create a new child to the control parent.
40
- # The control parent keeps condition -> children matches for our
41
- # document's content
42
- add_options = Proc.new do |control_parent|
43
- control_parent.value << condition
44
- control_parent.children << []
45
-
46
- root control_parent
47
- end
48
-
49
- # If the current control structure has a matching parent, we search
50
- # for that type of element in the siblings with the same indentation
51
- # otherwise we return a new control structure parent
52
- if (parent_type = control_parent structure)
53
- begin
54
- last = -1
55
- until parent_type.include? parent.children[last].name
56
- last -= 1
57
- end
58
- add_options[parent.children[last]]
59
- rescue NoMethodError
60
- error :control_parent
61
- end
62
- else
63
- control_node = @create.control(structure, condition, parent, indent.size)
64
- end
65
-
66
- control_node
67
- end
68
- end
69
- end
70
-
71
- # Check if the current control structure requires a parent node and
72
- # return the parent's node type
73
- #
74
- def control_parent(structure)
75
- case structure
76
- when :else then [:if, :unless, :case]
77
- when :elsif then [:if]
78
- when :when then [:case]
79
- end
80
- end
81
- end
82
- end
83
- end