opulent 0.0.9 → 1.0.2
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/.gitignore +9 -0
- data/.libold/opulent.rb +96 -0
- data/.libold/opulent/context.rb +80 -0
- data/.libold/opulent/engine.rb +88 -0
- data/.libold/opulent/filter.rb +101 -0
- data/.libold/opulent/logger.rb +67 -0
- data/.libold/opulent/nodes.rb +13 -0
- data/.libold/opulent/nodes/block.rb +29 -0
- data/.libold/opulent/nodes/comment.rb +35 -0
- data/.libold/opulent/nodes/control.rb +230 -0
- data/.libold/opulent/nodes/define.rb +42 -0
- data/.libold/opulent/nodes/eval.rb +41 -0
- data/.libold/opulent/nodes/expression.rb +28 -0
- data/.libold/opulent/nodes/filter.rb +70 -0
- data/.libold/opulent/nodes/helper.rb +69 -0
- data/.libold/opulent/nodes/node.rb +101 -0
- data/.libold/opulent/nodes/root.rb +62 -0
- data/.libold/opulent/nodes/text.rb +54 -0
- data/.libold/opulent/nodes/theme.rb +36 -0
- data/.libold/opulent/parser.rb +252 -0
- data/.libold/opulent/parser/block.rb +70 -0
- data/.libold/opulent/parser/comment.rb +32 -0
- data/.libold/opulent/parser/control.rb +83 -0
- data/.libold/opulent/parser/define.rb +39 -0
- data/.libold/opulent/parser/eval.rb +33 -0
- data/.libold/opulent/parser/expression.rb +350 -0
- data/.libold/opulent/parser/filter.rb +41 -0
- data/.libold/opulent/parser/node.rb +232 -0
- data/.libold/opulent/parser/root.rb +96 -0
- data/.libold/opulent/parser/text.rb +114 -0
- data/.libold/opulent/parser/theme.rb +36 -0
- data/.libold/opulent/preprocessor.rb +102 -0
- data/.libold/opulent/runtime.rb +144 -0
- data/.libold/opulent/template.rb +43 -0
- data/.libold/opulent/tokens.rb +276 -0
- data/.libold/opulent/version.rb +5 -0
- data/.rspec +2 -0
- data/.travis.yml +4 -0
- data/Gemfile +2 -0
- data/LICENSE +21 -0
- data/README.md +102 -0
- data/Rakefile +6 -0
- data/benchmark/benchmark.rb +46 -0
- data/benchmark/cases/node/node.haml +17 -0
- data/benchmark/cases/node/node.op +14 -0
- data/benchmark/cases/node/node.slim +19 -0
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/docs/syntax.md +3 -0
- data/docs/usage.md +3 -0
- data/lib/opulent.rb +11 -64
- data/lib/opulent/compiler.rb +132 -0
- data/lib/opulent/compiler/block.rb +31 -0
- data/lib/opulent/compiler/comment.rb +22 -0
- data/lib/opulent/compiler/control.rb +152 -0
- data/lib/opulent/compiler/define.rb +88 -0
- data/lib/opulent/compiler/eval.rb +15 -0
- data/lib/opulent/compiler/filter.rb +54 -0
- data/lib/opulent/compiler/node.rb +232 -0
- data/lib/opulent/compiler/root.rb +19 -0
- data/lib/opulent/compiler/text.rb +60 -0
- data/lib/opulent/context.rb +88 -0
- data/lib/opulent/engine.rb +60 -0
- data/lib/opulent/filters.rb +222 -0
- data/lib/opulent/logger.rb +47 -0
- data/lib/opulent/parser.rb +196 -0
- data/lib/opulent/parser/block.rb +56 -0
- data/lib/opulent/parser/comment.rb +27 -0
- data/lib/opulent/parser/control.rb +112 -0
- data/lib/opulent/parser/define.rb +30 -0
- data/lib/opulent/parser/eval.rb +21 -0
- data/lib/opulent/parser/expression.rb +344 -0
- data/lib/opulent/parser/filter.rb +25 -0
- data/lib/opulent/parser/node.rb +246 -0
- data/lib/opulent/parser/root.rb +48 -0
- data/lib/opulent/parser/text.rb +127 -0
- data/lib/opulent/settings.rb +79 -0
- data/lib/opulent/template.rb +67 -0
- data/lib/opulent/tokens.rb +166 -0
- data/lib/opulent/version.rb +4 -0
- data/opulent.gemspec +36 -0
- metadata +160 -7
@@ -0,0 +1,47 @@
|
|
1
|
+
# @Opulent
|
2
|
+
module Opulent
|
3
|
+
# @Logger
|
4
|
+
module Logger
|
5
|
+
# @Singleton
|
6
|
+
class << self
|
7
|
+
# Color the input text with the chosen color
|
8
|
+
#
|
9
|
+
# @param text [String] the string that will be colored
|
10
|
+
# @param color_code [String] preset code for certain colors
|
11
|
+
#
|
12
|
+
def colorize(text, color_code)
|
13
|
+
require_windows_libs
|
14
|
+
"#{color_code}#{text}\e[0m"
|
15
|
+
end
|
16
|
+
|
17
|
+
# Colors available in the terminal
|
18
|
+
#
|
19
|
+
def black(text); colorize(text, "\e[30m"); end
|
20
|
+
def red(text); colorize(text, "\e[31m"); end
|
21
|
+
def green(text); colorize(text, "\e[32m"); end
|
22
|
+
def yellow(text); colorize(text, "\e[33m"); end
|
23
|
+
def blue(text); colorize(text, "\e[34m"); end
|
24
|
+
def magenta(text); colorize(text, "\e[35m"); end
|
25
|
+
def cyan(text); colorize(text, "\e[36m"); end
|
26
|
+
def white(text); colorize(text, "\e[37m"); end
|
27
|
+
def default(text); colorize(text, "\e[38m"); end
|
28
|
+
|
29
|
+
# Require windows libraries for ANSI Console output
|
30
|
+
#
|
31
|
+
def require_windows_libs
|
32
|
+
begin
|
33
|
+
require 'Win32/Console/ANSI' if RUBY_PLATFORM =~ /win32/
|
34
|
+
rescue LoadError
|
35
|
+
raise 'You must run "gem install win32console" to use Opulent\'s
|
36
|
+
error reporting on Windows.'
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Pretty print Nodes with their important details
|
41
|
+
#
|
42
|
+
def pretty_print(model, indent = 0)
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,196 @@
|
|
1
|
+
require_relative 'parser/block.rb'
|
2
|
+
require_relative 'parser/comment.rb'
|
3
|
+
require_relative 'parser/control.rb'
|
4
|
+
require_relative 'parser/define.rb'
|
5
|
+
require_relative 'parser/eval.rb'
|
6
|
+
require_relative 'parser/expression.rb'
|
7
|
+
require_relative 'parser/filter.rb'
|
8
|
+
require_relative 'parser/node.rb'
|
9
|
+
require_relative 'parser/root.rb'
|
10
|
+
require_relative 'parser/text.rb'
|
11
|
+
|
12
|
+
# @Opulent
|
13
|
+
module Opulent
|
14
|
+
# @Parser
|
15
|
+
class Parser
|
16
|
+
attr_reader :type, :value, :options, :children, :indent
|
17
|
+
|
18
|
+
# All node Objects (Array) must follow the next convention in order
|
19
|
+
# to make parsing faster
|
20
|
+
#
|
21
|
+
# [:node_type, :value, :attributes, :children, :indent]
|
22
|
+
#
|
23
|
+
def initialize
|
24
|
+
@type = 0
|
25
|
+
@value = 1
|
26
|
+
@options = 2
|
27
|
+
@children = 3
|
28
|
+
@indent = 4
|
29
|
+
end
|
30
|
+
|
31
|
+
# Initialize the parsing process by splitting the code into lines and
|
32
|
+
# instantiationg parser variables with their default values
|
33
|
+
#
|
34
|
+
# @param code [String] Opulent code that needs to be analyzed
|
35
|
+
#
|
36
|
+
# @return Nodes array
|
37
|
+
#
|
38
|
+
def parse(code)
|
39
|
+
# Split the code into lines and parse them one by one
|
40
|
+
@code = code.lines
|
41
|
+
|
42
|
+
# Node definitions encountered up to the current point
|
43
|
+
@definitions = {}
|
44
|
+
|
45
|
+
# Current line index
|
46
|
+
@i = -1
|
47
|
+
|
48
|
+
# Initialize root node
|
49
|
+
@root = [:root, nil, {}, [], -1]
|
50
|
+
|
51
|
+
# Get all nodes starting from the root element
|
52
|
+
root @root
|
53
|
+
end
|
54
|
+
|
55
|
+
# Check and accept or reject a given token as long as we have tokens
|
56
|
+
# remaining. Shift the code with the match length plus any extra character
|
57
|
+
# count around the capture group
|
58
|
+
#
|
59
|
+
# @param token [RegEx] Token to be accepted by the parser
|
60
|
+
# @param required [Boolean] Expect the given token syntax
|
61
|
+
# @param strip [Boolean] Left strip the current code to remove whitespace
|
62
|
+
#
|
63
|
+
def accept(token, required = false, strip = false)
|
64
|
+
# Consume leading whitespace if we want to ignore it
|
65
|
+
accept :whitespace if strip
|
66
|
+
|
67
|
+
# We reached the end of the parsing process and there are no more lines
|
68
|
+
# left to parse
|
69
|
+
return nil unless @line
|
70
|
+
|
71
|
+
# Match the token to the current line. If we find it, return the match.
|
72
|
+
# If it is required, signal an :expected error
|
73
|
+
if (match = @line[@offset..-1].match(Tokens[token]))
|
74
|
+
# Advance current offset with match length
|
75
|
+
@offset += match[0].size
|
76
|
+
|
77
|
+
return match[0]
|
78
|
+
elsif required
|
79
|
+
error :expected, token
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
# Helper method which automatically sets the stripped options to true, so that we
|
84
|
+
# do not have to explicitly specify it
|
85
|
+
#
|
86
|
+
# @param token [RegEx] Token to be accepted by the parser
|
87
|
+
# @param required [Boolean] Expect the given token syntax
|
88
|
+
#
|
89
|
+
def accept_stripped(token, required = false)
|
90
|
+
accept(token, required, true)
|
91
|
+
end
|
92
|
+
|
93
|
+
# Check if the lookahead matches the chosen regular expression
|
94
|
+
#
|
95
|
+
# @param token [RegEx] Token to be checked by the parser
|
96
|
+
#
|
97
|
+
def lookahead(token)
|
98
|
+
return nil unless @line
|
99
|
+
|
100
|
+
# Check if we match the token to the current line.
|
101
|
+
@line[@offset..-1].match Tokens[token]
|
102
|
+
end
|
103
|
+
|
104
|
+
# Check if the lookahead matches the chosen regular expression on the
|
105
|
+
# following line which needs to be parsed
|
106
|
+
#
|
107
|
+
# @param token [RegEx] Token to be checked by the parser
|
108
|
+
#
|
109
|
+
def lookahead_next_line(token)
|
110
|
+
return nil unless @code[@i + 1]
|
111
|
+
|
112
|
+
# Check if we match the token to the current line.
|
113
|
+
@code[@i + 1].match Tokens[token]
|
114
|
+
end
|
115
|
+
|
116
|
+
# Undo a found match by removing the token from the consumed code and
|
117
|
+
# adding it back to the code chunk
|
118
|
+
#
|
119
|
+
# @param match [String] Matched string to be undone
|
120
|
+
#
|
121
|
+
def undo(match)
|
122
|
+
unless match.empty?
|
123
|
+
@offset -= match.size
|
124
|
+
return nil
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
# Allow expressions to continue on a new line in certain conditions
|
129
|
+
#
|
130
|
+
def accept_newline
|
131
|
+
if @line[@offset..-1].strip.empty?
|
132
|
+
@line = @code[(@i += 1)]
|
133
|
+
@offset = 0
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
# Give an explicit error report where an unexpected sequence of tokens
|
138
|
+
# appears and give indications on how to solve it
|
139
|
+
#
|
140
|
+
# @param message [Symbol] Error message to display to the user
|
141
|
+
#
|
142
|
+
def error(error, *data)
|
143
|
+
message = case error
|
144
|
+
when :unknown_node_type
|
145
|
+
"An unknown node type has been encountered at:\n\n#{Logger.red @line}"
|
146
|
+
when :expected
|
147
|
+
data[0] = "#{Tokens.bracket data[0]}" if [:'(', :'{', :'[', :'<'].include? data[0]
|
148
|
+
"Expected to find a :#{data[0]} token at: \n\n#{@line[0..@offset-1]}#{Logger.red @line[@offset..-1].rstrip}"
|
149
|
+
when :root
|
150
|
+
"Unknown node type encountered on line #{@i+1} of input at:\n\n" +
|
151
|
+
"#{@line[0..@offset-1]}#{Logger.red @line[@offset..-1].rstrip}"
|
152
|
+
when :assignments_colon
|
153
|
+
"Unexpected end of element attributes reached on line #{@i+1} of input.\n\n" +
|
154
|
+
"Expected to find an attribute at:\n\n" +
|
155
|
+
"#{@line[0..@offset-1]}#{Logger.red @line[@offset..-1].rstrip}"
|
156
|
+
when :assignments_comma
|
157
|
+
"Unexpected end of element attributes reached on line #{@i+1} of input.\n\n" +
|
158
|
+
"Expected to find an attribute value at:\n\n" +
|
159
|
+
"#{@line[0..@offset-1]}#{Logger.red @line[@offset..-1].rstrip}"
|
160
|
+
when :expression
|
161
|
+
"Unexpected end of expression reached on line #{@i+1} of input.\n\n" +
|
162
|
+
"Expected to find another expression term at:\n\n" +
|
163
|
+
"#{@line[0..@offset-1]}#{Logger.red @line[@offset..-1].rstrip}"
|
164
|
+
when :control_child
|
165
|
+
"Unexpected control structure child found on line #{@i+1} of input.\n\n" +
|
166
|
+
"Expected to find a parent #{data[0]} structure at:\n\n" +
|
167
|
+
"#{@line[0..@offset-1]}#{Logger.red @line[@offset..-1].rstrip}"
|
168
|
+
when :case_children
|
169
|
+
"Unexpected control structure child found on line #{@i+1} of input.\n\n" +
|
170
|
+
"Case structure cannot have any child elements at:\n\n" +
|
171
|
+
"#{@code[@i-1][0..@offset-1]}#{Logger.red @code[@i][@offset..-1].rstrip}"
|
172
|
+
when :whitespace_expression
|
173
|
+
"Unexpected end of expression reached on line #{@i+1} of input.\n\n" +
|
174
|
+
"Please use paranthesis for method parameters at:\n\n" +
|
175
|
+
"#{@line[0..@offset-1]}#{Logger.red @line[@offset..-1].rstrip}"
|
176
|
+
when :definition
|
177
|
+
"Unexpected start of definition on line #{@i+1} of input.\n\n" +
|
178
|
+
"Found a definition inside another definition or element at:\n\n" +
|
179
|
+
"#{@line[0..@offset-1]}#{Logger.red @line[@offset..-1].rstrip}"
|
180
|
+
when :self_enclosing
|
181
|
+
"Unexpected content found after self enclosing node on line #{@i+1} of input at:\n\n" +
|
182
|
+
"#{@line[0..@offset-1]}#{Logger.red @line[@offset..-1].rstrip}"
|
183
|
+
when :self_enclosing_children
|
184
|
+
"Unexpected child elements found for self enclosing node on line #{data[0]+1} of input at:\n\n" +
|
185
|
+
"#{@code[data[0]]}#{Logger.red @code[data[0] + 1]}"
|
186
|
+
else
|
187
|
+
"#{@line[0..@offset-1]}#{Logger.red @line[@offset..-1].rstrip}"
|
188
|
+
end
|
189
|
+
|
190
|
+
# Reconstruct lines to display where errors occur
|
191
|
+
fail "\n\nOpulent " + Logger.red("[Parser Error]") +
|
192
|
+
"\n---\n" +
|
193
|
+
"#{message}\n\n\n"
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# @Opulent
|
2
|
+
module Opulent
|
3
|
+
# @Parser
|
4
|
+
class Parser
|
5
|
+
# Match a yield with a explicit or implicit target
|
6
|
+
#
|
7
|
+
# yield target
|
8
|
+
#
|
9
|
+
# @param parent [Node] Parent node to which we append the definition
|
10
|
+
#
|
11
|
+
def block_yield(parent, indent)
|
12
|
+
if accept :yield
|
13
|
+
# Get definition name
|
14
|
+
if(yield_name = accept_stripped(:yield_identifier))
|
15
|
+
yield_name = yield_name.strip.to_sym
|
16
|
+
else
|
17
|
+
yield_name = Settings::DefaultYield
|
18
|
+
end
|
19
|
+
|
20
|
+
# Consume the newline from the end of the element
|
21
|
+
error :yield unless accept(:line_feed).strip.empty?
|
22
|
+
|
23
|
+
# Create a new node
|
24
|
+
yield_node = [:yield, yield_name, {}, [], indent]
|
25
|
+
|
26
|
+
parent[@children] << yield_node
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# Match a block with a explicit target
|
31
|
+
#
|
32
|
+
# block target
|
33
|
+
#
|
34
|
+
# @param parent [Node] Parent node to which we append the definition
|
35
|
+
#
|
36
|
+
def block(parent, indent)
|
37
|
+
if accept :block
|
38
|
+
# Get definition name
|
39
|
+
if(block_name = accept_stripped(:yield_identifier))
|
40
|
+
block_name = block_name.strip.to_sym
|
41
|
+
else
|
42
|
+
block_name = Settings::DefaultYield
|
43
|
+
end
|
44
|
+
|
45
|
+
# Consume the newline from the end of the element
|
46
|
+
error :block unless accept(:line_feed).strip.empty?
|
47
|
+
|
48
|
+
# Create a new node
|
49
|
+
block_node = [:block, block_name, {}, [], indent]
|
50
|
+
root block_node, indent
|
51
|
+
|
52
|
+
parent[@children] << block_node
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# @Opulent
|
2
|
+
module Opulent
|
3
|
+
# @Parser
|
4
|
+
class Parser
|
5
|
+
# Match one line or multiline comments
|
6
|
+
#
|
7
|
+
def comment(parent, indent)
|
8
|
+
if (accept :comment)
|
9
|
+
multiline = true if (accept :comment)
|
10
|
+
|
11
|
+
buffer = accept(:line_feed)
|
12
|
+
buffer += accept(:newline) || ""
|
13
|
+
buffer += get_indented_lines indent if multiline
|
14
|
+
|
15
|
+
|
16
|
+
# If we have a comment which is visible in the output, we will
|
17
|
+
# create a new comment element. Otherwise, we ignore the current
|
18
|
+
# gathered text and we simply begin the root parsing again
|
19
|
+
if buffer[0] == '!'
|
20
|
+
parent[@children] << [:comment, buffer[1..-1].strip, {}, nil, indent]
|
21
|
+
end
|
22
|
+
|
23
|
+
return parent
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,112 @@
|
|
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
|
+
if (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
|
+
error :each_arguments unless condition.match Tokens[:each_pattern]
|
19
|
+
|
20
|
+
# Split provided arguments for the each structure
|
21
|
+
condition = condition.split('in').map(&:strip)
|
22
|
+
condition[0] = condition[0].split(',').map(&:strip).map(&:to_sym)
|
23
|
+
end
|
24
|
+
|
25
|
+
# Else and default structures are not allowed to have any condition
|
26
|
+
# set and the other control structures require a condition
|
27
|
+
if structure == :else
|
28
|
+
error :condition_exists unless condition.empty?
|
29
|
+
else
|
30
|
+
error :condition_missing if condition.empty?
|
31
|
+
end
|
32
|
+
|
33
|
+
# Add the condition and create a new child to the control parent.
|
34
|
+
# The control parent keeps condition -> children matches for our
|
35
|
+
# document's content
|
36
|
+
add_options = Proc.new do |control_parent|
|
37
|
+
control_parent.value << condition
|
38
|
+
control_parent.children << []
|
39
|
+
|
40
|
+
root control_parent
|
41
|
+
end
|
42
|
+
|
43
|
+
# If the current control structure is a parent which allows multiple
|
44
|
+
# branches, such as an if or case, we create an array of conditions
|
45
|
+
# which can be matched and an array of children belonging to each
|
46
|
+
# conditional branch
|
47
|
+
if [:if, :unless].include? structure
|
48
|
+
# Create the control structure and get its child nodes
|
49
|
+
control_structure = [structure, [condition], {}, [], indent]
|
50
|
+
root control_structure, indent
|
51
|
+
|
52
|
+
# Turn children into an array because we allow multiple branches
|
53
|
+
control_structure[@children] = [control_structure[@children]]
|
54
|
+
|
55
|
+
# Add it to the parent node
|
56
|
+
parent[@children] << control_structure
|
57
|
+
|
58
|
+
elsif structure == :case
|
59
|
+
# Create the control structure and get its child nodes
|
60
|
+
control_structure = [structure, [], {condition: condition}, [], indent]
|
61
|
+
|
62
|
+
|
63
|
+
# Add it to the parent node
|
64
|
+
parent[@children] << control_structure
|
65
|
+
|
66
|
+
# If the control structure is a child structure, we need to find the
|
67
|
+
# node it belongs to amont the current parent. Search from end to
|
68
|
+
# beginning until we find the node parent
|
69
|
+
elsif control_child structure
|
70
|
+
# During the search, we try to find the matching parent type
|
71
|
+
unless control_parent(structure).include? parent[@children][-1][@type]
|
72
|
+
error :control_child, control_parent(structure)
|
73
|
+
end
|
74
|
+
|
75
|
+
# Gather child elements for current structure
|
76
|
+
control_structure = [structure, [condition], {}, [], indent]
|
77
|
+
root control_structure, indent
|
78
|
+
|
79
|
+
# Add the new condition and children to our parent structure
|
80
|
+
parent[@children][-1][@value] << condition
|
81
|
+
parent[@children][-1][@children] << control_structure[@children]
|
82
|
+
|
83
|
+
# When our control structure isn't a complex composite, we create
|
84
|
+
# it the same way as a normal node
|
85
|
+
else
|
86
|
+
control_structure = [structure, condition, {}, [], indent]
|
87
|
+
root control_structure, indent
|
88
|
+
|
89
|
+
parent[@children] << control_structure
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
# Check if the current control structure requires a parent node and
|
95
|
+
# return the parent's node type
|
96
|
+
#
|
97
|
+
def control_child(structure)
|
98
|
+
[:else, :elsif, :when].include? structure
|
99
|
+
end
|
100
|
+
|
101
|
+
# Check if the current control structure requires a parent node and
|
102
|
+
# return the parent's node type
|
103
|
+
#
|
104
|
+
def control_parent(structure)
|
105
|
+
case structure
|
106
|
+
when :else then [:if, :unless, :case]
|
107
|
+
when :elsif then [:if]
|
108
|
+
when :when then [:case]
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# @Opulent
|
2
|
+
module Opulent
|
3
|
+
# @Parser
|
4
|
+
class Parser
|
5
|
+
# Check if we match a new node definition to use within our page.
|
6
|
+
#
|
7
|
+
# Definitions will not be recursive because, by the time we parse
|
8
|
+
# the definition children, the definition itself is not in the
|
9
|
+
# knowledgebase yet.
|
10
|
+
#
|
11
|
+
# However, we may use previously defined nodes inside new definitions,
|
12
|
+
# due to the fact that they are known at parse time.
|
13
|
+
#
|
14
|
+
# @param nodes [Array] Parent node to which we append to
|
15
|
+
#
|
16
|
+
def define(parent, indent)
|
17
|
+
if(match = accept :def)
|
18
|
+
# Process data
|
19
|
+
name = accept(:node, :*).to_sym
|
20
|
+
|
21
|
+
# Create node
|
22
|
+
definition = [:def, name, {parameters: attributes}, [], indent]
|
23
|
+
root(definition, indent)
|
24
|
+
|
25
|
+
# Add to parent
|
26
|
+
@definitions[name] = definition
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|