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,48 @@
|
|
1
|
+
# @Opulent
|
2
|
+
module Opulent
|
3
|
+
# @Parser
|
4
|
+
class Parser
|
5
|
+
# Analyze the input code and check for matching tokens.
|
6
|
+
# In case no match was found, throw an exception.
|
7
|
+
# In special cases, modify the token hash.
|
8
|
+
#
|
9
|
+
# @param nodes [Array] Parent node to which we append to
|
10
|
+
#
|
11
|
+
def root(parent = @root, min_indent = -1)
|
12
|
+
while(@line = @code[(@i += 1)])
|
13
|
+
# Skip to next iteration if we have a blank line
|
14
|
+
if @line =~ /\A\s*\Z/ then next end
|
15
|
+
|
16
|
+
# Reset the line offset
|
17
|
+
@offset = 0
|
18
|
+
|
19
|
+
# Parse the current line by trying to match each node type towards it
|
20
|
+
# Add current indentation to the indent stack
|
21
|
+
indent = accept(:indent).size
|
22
|
+
|
23
|
+
# Stop using the current parent as root if it does not match the
|
24
|
+
# minimum indentation requirements
|
25
|
+
unless min_indent < indent
|
26
|
+
@i -= 1; break
|
27
|
+
end
|
28
|
+
|
29
|
+
# Try the main Opulent node types and process each one of them using
|
30
|
+
# their matching evaluation procedure
|
31
|
+
current_node = node(parent, indent) ||
|
32
|
+
text(parent, indent) ||
|
33
|
+
comment(parent, indent) ||
|
34
|
+
define(parent, indent) ||
|
35
|
+
control(parent, indent) ||
|
36
|
+
evaluate(parent, indent) ||
|
37
|
+
filter(parent, indent) ||
|
38
|
+
block_yield(parent, indent) ||
|
39
|
+
block(parent, indent)
|
40
|
+
|
41
|
+
# Throw an error if we couldn't find a valid node
|
42
|
+
error :unknown_node_type unless current_node
|
43
|
+
end
|
44
|
+
|
45
|
+
return parent
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,127 @@
|
|
1
|
+
# @Opulent
|
2
|
+
module Opulent
|
3
|
+
# @Parser
|
4
|
+
class Parser
|
5
|
+
# Match one line or multiline, escaped or unescaped text
|
6
|
+
#
|
7
|
+
# @param parent [Array] Parent node element
|
8
|
+
# @param indent [Fixnum] Size of the current indentation
|
9
|
+
# @param multiline_or_print [Boolean] Allow only multiline text or print
|
10
|
+
#
|
11
|
+
def text(parent, indent = nil, multiline_or_print = true)
|
12
|
+
# Try to see if we can match a multiline operator. If we can accept_stripped only
|
13
|
+
# multiline, which is the case for filters, undo the operation.
|
14
|
+
if accept :multiline
|
15
|
+
multiline = true
|
16
|
+
elsif multiline_or_print
|
17
|
+
return nil unless lookahead :print_lookahead
|
18
|
+
end
|
19
|
+
|
20
|
+
# Get text node type
|
21
|
+
type = if accept(:print) then :print else :text end
|
22
|
+
|
23
|
+
# Check if the text or print node is escaped or unescaped
|
24
|
+
escaped = accept(:unescaped_value) ? false : true
|
25
|
+
|
26
|
+
# Get text value
|
27
|
+
value = accept :line_feed
|
28
|
+
value = value[1..-1] if value[0] == '\\'
|
29
|
+
|
30
|
+
# Create the text node using input data
|
31
|
+
text_node = [:plain, type, {value: value.strip, escaped: escaped, evaluate: false}, nil, indent]
|
32
|
+
|
33
|
+
# If we have a multiline node, get all the text which has higher
|
34
|
+
# indentation than our indentation node.
|
35
|
+
if multiline
|
36
|
+
text_node[@options][:value] += accept(:newline) || ""
|
37
|
+
text_node[@options][:value] += get_indented_lines(indent)
|
38
|
+
text_node[@options][:value].strip!
|
39
|
+
elsif value.empty?
|
40
|
+
# If our value is empty and we're not going to add any more lines to
|
41
|
+
# our buffer, skip the node
|
42
|
+
return nil
|
43
|
+
end
|
44
|
+
|
45
|
+
if text_node[@options][:value] =~ Settings::InterpolationCheck
|
46
|
+
text_node[@options][:evaluate] = true
|
47
|
+
end
|
48
|
+
|
49
|
+
# Increase indentation if this is an inline text node
|
50
|
+
text_node[@indent] += Settings[:indent] unless multiline_or_print
|
51
|
+
|
52
|
+
# Add text node to the parent element
|
53
|
+
parent[@children] << text_node
|
54
|
+
end
|
55
|
+
|
56
|
+
# Match one line or multiline, escaped or unescaped text
|
57
|
+
#
|
58
|
+
def html_text(parent, indent)
|
59
|
+
if (text_feed = accept_stripped :html_text)
|
60
|
+
text_node = [:plain, :text, {value: text_feed.strip, escaped: false}, nil, indent]
|
61
|
+
|
62
|
+
parent[@children] << text_node
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# Match a whitespace by preventing code trimming
|
67
|
+
#
|
68
|
+
def whitespace(required = false)
|
69
|
+
accept :whitespace, required
|
70
|
+
end
|
71
|
+
|
72
|
+
# Gather all the lines which have higher indentation than the one given as
|
73
|
+
# parameter and put them into the buffer
|
74
|
+
#
|
75
|
+
# @param indentation [Fixnum] parent node strating indentation
|
76
|
+
#
|
77
|
+
def get_indented_lines(indent)
|
78
|
+
buffer = ''
|
79
|
+
|
80
|
+
# Gather multiple blank lines between lines of text
|
81
|
+
blank_lines = Proc.new do
|
82
|
+
while lookahead_next_line :line_whitespace
|
83
|
+
@line = @code[(@i += 1)]
|
84
|
+
@offset = 0
|
85
|
+
|
86
|
+
buffer += accept :line_whitespace
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
# Get blank lines until we match something
|
91
|
+
blank_lines[]
|
92
|
+
|
93
|
+
# Get the next indentation after the parent line
|
94
|
+
# and set it as primary indent
|
95
|
+
next_indent = first_indent = (lookahead_next_line(:indent).to_s || "").size
|
96
|
+
|
97
|
+
# While the indentation is smaller, add the line feed to our buffer
|
98
|
+
while next_indent > indent
|
99
|
+
# Advance current line and reset offset
|
100
|
+
@line = @code[(@i += 1)]
|
101
|
+
@offset = 0
|
102
|
+
|
103
|
+
# Get leading whitespace trimmed with first_indent's size
|
104
|
+
next_line_indent = accept(:indent)[first_indent..-1] || ""
|
105
|
+
next_line_indent = next_line_indent.size
|
106
|
+
|
107
|
+
# Add next line feed, prepend the indent and append the newline
|
108
|
+
buffer += " " * next_line_indent if next_line_indent > 0
|
109
|
+
buffer += accept_stripped(:line_feed) || ""
|
110
|
+
buffer += accept_stripped(:newline) || ""
|
111
|
+
|
112
|
+
# Get blank lines until we match something
|
113
|
+
blank_lines[]
|
114
|
+
|
115
|
+
# Check the indentation on the following line. When we reach EOF,
|
116
|
+
# set the indentation to 0 and cause the loop to stop
|
117
|
+
if (next_indent = lookahead_next_line :indent)
|
118
|
+
next_indent = next_indent[0].size
|
119
|
+
else
|
120
|
+
next_indent = 0
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
return buffer
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# @Opulent
|
2
|
+
module Opulent
|
3
|
+
# @Settings
|
4
|
+
module Settings
|
5
|
+
# Default yield target which is used for child block replacements
|
6
|
+
DefaultYield = :children
|
7
|
+
|
8
|
+
# Default yield target which is used for child block replacements
|
9
|
+
DefaultEachKey = :key
|
10
|
+
|
11
|
+
# Default yield target which is used for child block replacements
|
12
|
+
DefaultEachValue = :value
|
13
|
+
|
14
|
+
# List of self enclosing node elements
|
15
|
+
SelfEnclosing = %i(img link input meta br hr area base col command embed keygen param source track wbr)
|
16
|
+
|
17
|
+
# List of inline node parents which can be either inline or have complex
|
18
|
+
# structures inside of them, such as anchor tags
|
19
|
+
MultiNode = %i(a)
|
20
|
+
|
21
|
+
# List of inline node names
|
22
|
+
InlineNode = %i(text a span strong em br i b small label sub sup abbr var code kbd)
|
23
|
+
|
24
|
+
# Check whether text should or shouldn't be evaluated
|
25
|
+
InterpolationCheck = /(?<!\\)\#\{.*\}/
|
26
|
+
|
27
|
+
# Check if the attribute value is a bare string
|
28
|
+
EvaluationCheck = /\A(("((?:[^"\\]|\\.)*?)")|('(?:[^'\\]|\\.)*?')|true|false|nil)\Z/
|
29
|
+
|
30
|
+
# Shorthand attribute associations
|
31
|
+
Shorthand = {
|
32
|
+
:'.' => :class,
|
33
|
+
:'#' => :id,
|
34
|
+
:'&' => :name
|
35
|
+
}
|
36
|
+
|
37
|
+
# @Singleton
|
38
|
+
class << self
|
39
|
+
# Opulent runtime options
|
40
|
+
Defaults = {
|
41
|
+
pretty: true,
|
42
|
+
indent: 2,
|
43
|
+
dependency_manager: true
|
44
|
+
}
|
45
|
+
|
46
|
+
# Set defaults as initial options
|
47
|
+
@@options = Defaults
|
48
|
+
|
49
|
+
# Get an option at runtime
|
50
|
+
#
|
51
|
+
# @param name [Symbol] Identifier for the option
|
52
|
+
#
|
53
|
+
def [](name)
|
54
|
+
@@options[name]
|
55
|
+
end
|
56
|
+
|
57
|
+
# Set a new option at runtime
|
58
|
+
#
|
59
|
+
# @param name [Symbol] Identifier for the option
|
60
|
+
# @param value Option value to be set
|
61
|
+
#
|
62
|
+
def []=(name, value)
|
63
|
+
@@options[name] = value
|
64
|
+
end
|
65
|
+
|
66
|
+
# Update the engine options with the required option changes
|
67
|
+
#
|
68
|
+
# @param opts [Hash] Option extension hash
|
69
|
+
#
|
70
|
+
def update_settings(opts)
|
71
|
+
@@options = Defaults
|
72
|
+
|
73
|
+
opts.each do |key, value|
|
74
|
+
@@options[key] = value
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# @Opulent
|
2
|
+
module Opulent
|
3
|
+
# @OpulentTemplate
|
4
|
+
class OpulentTemplate < ::Tilt::Template
|
5
|
+
self.default_mime_type = 'text/html'
|
6
|
+
|
7
|
+
# Do whatever preparation is necessary to setup the underlying template
|
8
|
+
# engine. Called immediately after template data is loaded. Instance
|
9
|
+
# variables set in this method are available when #evaluate is called.
|
10
|
+
#
|
11
|
+
# Subclasses must provide an implementation of this method.
|
12
|
+
#
|
13
|
+
def prepare
|
14
|
+
# Set the file which is being evaluated
|
15
|
+
@options[:file] = eval_file
|
16
|
+
|
17
|
+
# Enable caching for the current rendered file
|
18
|
+
@options[:cache] = true
|
19
|
+
|
20
|
+
# Set up the rendering engine
|
21
|
+
@engine = ::Opulent.new @options
|
22
|
+
#@engine.update_options @options
|
23
|
+
end
|
24
|
+
|
25
|
+
# Execute the compiled template and return the result string. Template
|
26
|
+
# evaluation is guaranteed to be performed in the scope object with the
|
27
|
+
# locals specified and with support for yielding to the block.
|
28
|
+
#
|
29
|
+
# This method is only used by source generating templates. Subclasses that
|
30
|
+
# override render() may not support all features.
|
31
|
+
#
|
32
|
+
def evaluate(scope, locals, &block)
|
33
|
+
# if @engine.respond_to?(:precompiled_method_return_value, true)
|
34
|
+
# super
|
35
|
+
# else
|
36
|
+
# @engine.render(data, locals, &block)
|
37
|
+
# end
|
38
|
+
if @engine.preamble
|
39
|
+
super
|
40
|
+
else
|
41
|
+
locals[:scope] = scope
|
42
|
+
@engine.render(data, locals, &block)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# A string containing the (Ruby) source code for the template. The
|
47
|
+
# default Template#evaluate implementation requires either this
|
48
|
+
# method or the #precompiled method be overridden. When defined,
|
49
|
+
# the base Template guarantees correct file/line handling, locals
|
50
|
+
# support, custom scopes, proper encoding, and support for template
|
51
|
+
# compilation.
|
52
|
+
#
|
53
|
+
def precompiled_template(locals)
|
54
|
+
# This here should be evaluated in order to return the precompiled code
|
55
|
+
# as text to the user.
|
56
|
+
# For example:
|
57
|
+
# _buff = [] # This should be in preamble
|
58
|
+
# _buff << "<html>",
|
59
|
+
# _buff << compile('a * b')
|
60
|
+
# _buff << "</html>"
|
61
|
+
@engine.preamble
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# Register Opulent to Tilt
|
66
|
+
::Tilt.register OpulentTemplate, 'op', 'opl', 'opulent'
|
67
|
+
end
|
@@ -0,0 +1,166 @@
|
|
1
|
+
module Opulent
|
2
|
+
# Opulent Keywords
|
3
|
+
Keywords = %i(def block yield if else elsif unless case when each while until)
|
4
|
+
|
5
|
+
# @Tokens
|
6
|
+
class Tokens
|
7
|
+
# All tokens available within Opulent
|
8
|
+
#
|
9
|
+
@@tokens = {
|
10
|
+
# Indentation
|
11
|
+
indent: /\A */,
|
12
|
+
|
13
|
+
# Node
|
14
|
+
node: /\A\w+(\-\w+)*/,
|
15
|
+
node_lookahead: /\A(\w+(\-\w+)*)/,
|
16
|
+
|
17
|
+
# Shorthand attributes
|
18
|
+
shorthand: /\A[\.\#\&]/,
|
19
|
+
shorthand_lookahead: /\A[\.\#\&][a-zA-Z\_\(\"]/,
|
20
|
+
|
21
|
+
# Leading and trailing whitespace
|
22
|
+
leading_whitespace: /\A(\<\-)/,
|
23
|
+
leading_trailing_whitespace: /\A(\>)/,
|
24
|
+
trailing_whitespace: /\A(\-\>)/,
|
25
|
+
|
26
|
+
# Self enclosing node
|
27
|
+
self_enclosing: /\A\/(.*)/,
|
28
|
+
|
29
|
+
# Definition
|
30
|
+
def: /\Adef +/,
|
31
|
+
|
32
|
+
# Node Attributes
|
33
|
+
attributes_bracket: /\A\(\[\{/,
|
34
|
+
extend_attributes: /\A(\+)/,
|
35
|
+
|
36
|
+
# Attribute assignments
|
37
|
+
assignment: /\A *(\:|\=)/,
|
38
|
+
assignment_unescaped: /\A\~/,
|
39
|
+
assignment_terminator: /\A(\,|\;)\s*/,
|
40
|
+
assignment_lookahead: /\A *([a-zA-Z]([\-\_]?[a-zA-Z0-9]+)* *[\:\=] *)/,
|
41
|
+
|
42
|
+
# Node inline child
|
43
|
+
inline_child: /\A *\> */,
|
44
|
+
|
45
|
+
# Comments
|
46
|
+
comment: /\A\//,
|
47
|
+
|
48
|
+
# Intepreted filters
|
49
|
+
filter: /\A\:[a-zA-Z]([\-\_]?[a-zA-Z0-9]+)*/,
|
50
|
+
|
51
|
+
# Print nodes
|
52
|
+
print: /\A\=/,
|
53
|
+
print_lookahead: /\A *=/,
|
54
|
+
|
55
|
+
# Unescaped value
|
56
|
+
unescaped_value: /\A\~/,
|
57
|
+
|
58
|
+
# Multiline Text
|
59
|
+
multiline: /\A(\|)/,
|
60
|
+
|
61
|
+
# HTML Text
|
62
|
+
html_text: /\A(\<.+\>.*)/,
|
63
|
+
|
64
|
+
# Yield
|
65
|
+
yield: /\A(yield)/,
|
66
|
+
yield_identifier: /\A[a-zA-Z]([\_]?[a-zA-Z0-9]+)*/,
|
67
|
+
|
68
|
+
# Yield
|
69
|
+
block: /\A(block)/,
|
70
|
+
|
71
|
+
# Conditional Structures
|
72
|
+
control: /\A(if|elsif|else|unless|case|when|each|while|until)/,
|
73
|
+
each_pattern: /\A(\w+( *, *\w+)? +)?in +.+/,
|
74
|
+
|
75
|
+
# Text
|
76
|
+
text: /\A\|/,
|
77
|
+
|
78
|
+
# Brackets
|
79
|
+
round_bracket: /\A(\()/,
|
80
|
+
square_bracket: /\A(\[)/,
|
81
|
+
curly_bracket: /\A(\{)/,
|
82
|
+
angular_bracket: /\A(\<)/,
|
83
|
+
|
84
|
+
# Receive matching brackets for allowing multiple bracket types for
|
85
|
+
# element attributes
|
86
|
+
:brackets => /\A([\(\[\{])/,
|
87
|
+
:'(' => /\A(\))/,
|
88
|
+
:'[' => /\A(\])/,
|
89
|
+
:'{' => /\A(\})/,
|
90
|
+
:'<' => /\A(\>)/,
|
91
|
+
|
92
|
+
# Terminators
|
93
|
+
comma: /\A(\s*\,\s*)/,
|
94
|
+
colon: /\A(\s*\:\s*)/,
|
95
|
+
semicolon: /\A(\s*\;\s*)/,
|
96
|
+
|
97
|
+
# Expression
|
98
|
+
exp_context: /\A(\$(.|\-.)?|\@|\@\@)/,
|
99
|
+
exp_method_call: /\A(\.[a-zA-Z\_][a-zA-Z0-9\_]*[\!\?]?)/,
|
100
|
+
exp_module: /\A(\:\:)/,
|
101
|
+
exp_identifier: /\A([a-zA-Z\_][a-zA-Z0-9\_]*[\!\?]?)/,
|
102
|
+
exp_assignment: /\A(\=)/,
|
103
|
+
exp_operation: /\A( *(\+|\-|\*\*|\*|\/|\<\<|\>\>|\.\.|\%|\<\=\>|\<\=|\^|\<|\>\=|\>|\=\~|\!\~|\=\=\=|\=\=|\!|not|\&\&|\&|and|\|\||\||or) *)/,
|
104
|
+
exp_regex: /\A(\/((?:[^\/\\]|\\.)*?)\/)/,
|
105
|
+
exp_string: /\A(("((?:[^"\\]|\\.)*?)")|('(?:[^'\\]|\\.)*?'))/,
|
106
|
+
exp_percent: /\A(\%[wWqQrxsiI]?.)/,
|
107
|
+
exp_double: /\A([0-9]+\.[0-9]+([eE][-+]?[0-9]+)?)/,
|
108
|
+
exp_fixnum: /\A([0-9]+)/,
|
109
|
+
exp_nil: /\A(nil)/,
|
110
|
+
exp_boolean: /\A(true|false)/,
|
111
|
+
exp_ternary: /\A( *\? *)/,
|
112
|
+
exp_ternary_else: /\A( *\: *)/,
|
113
|
+
|
114
|
+
exp_identifier_lookahead: /\A[a-zA-Z\_][a-zA-Z0-9\_]*[\!\?]?/,
|
115
|
+
|
116
|
+
# Hash
|
117
|
+
hash_terminator: /\A(\s*(\,)\s*)/,
|
118
|
+
hash_assignment: /\A(\s*(\=\>)\s*)/,
|
119
|
+
hash_symbol: /\A([a-zA-Z\_][a-zA-Z0-9\_]*\:(?!\:))/,
|
120
|
+
|
121
|
+
# Whitespace
|
122
|
+
whitespace: /\A +/,
|
123
|
+
|
124
|
+
# Evaluation
|
125
|
+
eval: /\A\-(.*)/,
|
126
|
+
eval_multiline: /\A\+(.*)/,
|
127
|
+
|
128
|
+
# Whitespace
|
129
|
+
newline: /\A(\n+)/,
|
130
|
+
|
131
|
+
# Feed
|
132
|
+
line_feed: /\A(.*)/,
|
133
|
+
line_whitespace: /\A\s*\Z/
|
134
|
+
}
|
135
|
+
|
136
|
+
# Return the matching closing bracket
|
137
|
+
#
|
138
|
+
# @param bracket [String] Opening bracket for the capture group
|
139
|
+
#
|
140
|
+
def self.bracket(bracket)
|
141
|
+
case bracket
|
142
|
+
when '(' then return ')'
|
143
|
+
when '[' then return ']'
|
144
|
+
when '{' then return '}'
|
145
|
+
when '<' then return '>'
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
# Return the requested token to the parser
|
150
|
+
#
|
151
|
+
# @param name [Symbol] Token requested by the parser accept method
|
152
|
+
#
|
153
|
+
def self.[](name)
|
154
|
+
@@tokens[name]
|
155
|
+
end
|
156
|
+
|
157
|
+
# Set a new token at runtime
|
158
|
+
#
|
159
|
+
# @param name [Symboidentifierl] Identifier for the token
|
160
|
+
# @param token [Token] Token data to be set
|
161
|
+
#
|
162
|
+
def self.[]=(name, token)
|
163
|
+
@@tokens[name] = token
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|