opulent 0.0.9 → 1.0.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|