bade 0.2.0 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Bade.gemspec +16 -15
- data/lib/bade/ast/document.rb +1 -1
- data/lib/bade/ast/node/doctype_node.rb +6 -6
- data/lib/bade/ast/node/static_text_node.rb +27 -0
- data/lib/bade/ast/node_registrator.rb +3 -4
- data/lib/bade/ast/string_serializer.rb +4 -3
- data/lib/bade/generator.rb +94 -88
- data/lib/bade/parser.rb +28 -587
- data/lib/bade/parser/parser_constants.rb +18 -0
- data/lib/bade/parser/parser_lines.rb +213 -0
- data/lib/bade/parser/parser_mixin.rb +139 -0
- data/lib/bade/parser/parser_ruby_code.rb +77 -0
- data/lib/bade/parser/parser_tag.rb +116 -0
- data/lib/bade/parser/parser_text.rb +78 -0
- data/lib/bade/precompiled.rb +2 -2
- data/lib/bade/renderer.rb +17 -12
- data/lib/bade/ruby_extensions/array.rb +9 -13
- data/lib/bade/ruby_extensions/string.rb +15 -8
- data/lib/bade/runtime/block.rb +6 -10
- data/lib/bade/runtime/mixin.rb +2 -1
- data/lib/bade/runtime/render_binding.rb +5 -5
- data/lib/bade/version.rb +1 -1
- metadata +25 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2b9d41889101a2207790a83bb4ae4900892e766b
|
4
|
+
data.tar.gz: 5d3019af48cbd0119a6b8c4d44f2d74b76e86c84
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cd6c63f0df98925562ebb9d9624c7e13542a5a6f1d76c8ef236b74cccfe1376065ec8e53e2c802f44177c9b67c88fa7218baef70f33dfac3e59505f0370dfbf2
|
7
|
+
data.tar.gz: 72225de15eeb899be67127bd9331b690529843e03be7c7fcf4402554551332a525b07bd9313c28e9ce578ac4eb31640a318ca87388d7a62163dd89c5391607a2
|
data/Bade.gemspec
CHANGED
@@ -7,21 +7,22 @@ require 'bade/version'
|
|
7
7
|
|
8
8
|
|
9
9
|
Gem::Specification.new do |spec|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
10
|
+
spec.name = 'bade'
|
11
|
+
spec.version = Bade::VERSION
|
12
|
+
spec.authors = ['Roman Kříž']
|
13
|
+
spec.email = ['samnung@gmail.com']
|
14
|
+
spec.summary = 'Minimalistic template engine for Ruby.'
|
15
|
+
spec.homepage = 'https://github.com/epuber-io/bade'
|
16
|
+
spec.license = 'MIT'
|
17
|
+
spec.required_ruby_version = '>= 2.0'
|
18
18
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
19
|
+
spec.files = Dir['bin/**/*'] + Dir['lib/**/*'] + %w(Bade.gemspec Gemfile README.md)
|
20
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
21
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
22
|
+
spec.require_paths = ['lib']
|
23
23
|
|
24
|
-
|
25
|
-
|
26
|
-
|
24
|
+
spec.add_development_dependency 'bundler', '~> 1'
|
25
|
+
spec.add_development_dependency 'rspec', '~> 3.2'
|
26
|
+
spec.add_development_dependency 'rake', '~> 11'
|
27
|
+
spec.add_development_dependency 'rubocop', '~> 0.35'
|
27
28
|
end
|
data/lib/bade/ast/document.rb
CHANGED
@@ -10,14 +10,14 @@ module Bade
|
|
10
10
|
#
|
11
11
|
def xml_output
|
12
12
|
case value
|
13
|
-
|
14
|
-
|
13
|
+
when 'xml'
|
14
|
+
'<?xml version="1.0" encoding="utf-8" ?>'
|
15
15
|
|
16
|
-
|
17
|
-
|
16
|
+
when 'html'
|
17
|
+
'<!DOCTYPE html>'
|
18
18
|
|
19
|
-
|
20
|
-
|
19
|
+
else
|
20
|
+
raise Parser::ParserInternalError, 'Unknown doctype type'
|
21
21
|
end
|
22
22
|
end
|
23
23
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bade
|
4
|
+
module AST
|
5
|
+
class StaticTextNode < Node
|
6
|
+
# @return [String]
|
7
|
+
#
|
8
|
+
attr_accessor :value
|
9
|
+
|
10
|
+
# @return [Bool]
|
11
|
+
#
|
12
|
+
attr_accessor :escaped
|
13
|
+
|
14
|
+
def initialize(*args)
|
15
|
+
super
|
16
|
+
|
17
|
+
@escaped = false
|
18
|
+
end
|
19
|
+
|
20
|
+
# @param [ValueNode] other
|
21
|
+
#
|
22
|
+
def ==(other)
|
23
|
+
super && value == other.value && escaped == other.escaped
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -9,6 +9,7 @@ module Bade
|
|
9
9
|
require_relative 'node/value_node'
|
10
10
|
require_relative 'node/mixin_node'
|
11
11
|
require_relative 'node/doctype_node'
|
12
|
+
require_relative 'node/static_text_node'
|
12
13
|
|
13
14
|
class << self
|
14
15
|
# @return [Hash<Symbol, Class>]
|
@@ -40,15 +41,13 @@ module Bade
|
|
40
41
|
def create(type, lineno)
|
41
42
|
klass = registered_types[type]
|
42
43
|
|
43
|
-
if klass.nil?
|
44
|
-
raise ::KeyError, "Undefined node type #{type.inspect}"
|
45
|
-
end
|
44
|
+
raise ::KeyError, "Undefined node type #{type.inspect}" if klass.nil?
|
46
45
|
|
47
46
|
klass.new(type, lineno: lineno)
|
48
47
|
end
|
49
48
|
end
|
50
49
|
|
51
|
-
register_type
|
50
|
+
register_type StaticTextNode, :static_text
|
52
51
|
register_type ValueNode, :newline
|
53
52
|
register_type ValueNode, :code
|
54
53
|
register_type ValueNode, :output
|
@@ -21,7 +21,8 @@ module Bade
|
|
21
21
|
when Document
|
22
22
|
node_to_s(root.root, 0)
|
23
23
|
else
|
24
|
-
|
24
|
+
msg = "Root attribute passed into initializer must be subclass of #{Node} or #{Document}, is #{root.class}!"
|
25
|
+
raise AttributeError, msg
|
25
26
|
end
|
26
27
|
end
|
27
28
|
|
@@ -46,7 +47,7 @@ module Bade
|
|
46
47
|
other = node.name
|
47
48
|
when KeyValueNode
|
48
49
|
other = "#{node.name}:#{node.value}"
|
49
|
-
when ValueNode
|
50
|
+
when ValueNode, StaticTextNode
|
50
51
|
escaped_sign = if node.escaped
|
51
52
|
'& '
|
52
53
|
elsif node.escaped.nil?
|
@@ -63,7 +64,7 @@ module Bade
|
|
63
64
|
raise "Unknown node class #{node.class} of type #{node.type} for serializing"
|
64
65
|
end
|
65
66
|
|
66
|
-
other = ' ' + other if other && other.
|
67
|
+
other = ' ' + other if other && !other.empty?
|
67
68
|
|
68
69
|
"#{indent}(#{type_s}#{other}#{children_s})"
|
69
70
|
end
|
data/lib/bade/generator.rb
CHANGED
@@ -12,14 +12,14 @@ module Bade
|
|
12
12
|
CURRENT_INDENT_NAME = :__indent
|
13
13
|
BASE_INDENT_NAME = :__base_indent
|
14
14
|
|
15
|
-
DEFAULT_BLOCK_NAME = 'default_block'
|
15
|
+
DEFAULT_BLOCK_NAME = 'default_block'.freeze
|
16
16
|
|
17
17
|
# @param [Document] document
|
18
18
|
#
|
19
19
|
# @return [String]
|
20
20
|
#
|
21
21
|
def self.document_to_lambda_string(document)
|
22
|
-
generator =
|
22
|
+
generator = new
|
23
23
|
generator.generate_lambda_string(document)
|
24
24
|
end
|
25
25
|
|
@@ -37,7 +37,7 @@ module Bade
|
|
37
37
|
buff_code ''
|
38
38
|
buff_code "lambda do |#{NEW_LINE_NAME}: \"\\n\", #{BASE_INDENT_NAME}: ' '|"
|
39
39
|
|
40
|
-
code_indent
|
40
|
+
code_indent do
|
41
41
|
buff_code "self.#{NEW_LINE_NAME} = #{NEW_LINE_NAME}"
|
42
42
|
buff_code "self.#{BASE_INDENT_NAME} = #{BASE_INDENT_NAME}"
|
43
43
|
|
@@ -46,7 +46,7 @@ module Bade
|
|
46
46
|
buff_code "output = #{BUFF_NAME}.join"
|
47
47
|
buff_code 'self.__reset'
|
48
48
|
buff_code 'output'
|
49
|
-
|
49
|
+
end
|
50
50
|
|
51
51
|
buff_code 'end'
|
52
52
|
|
@@ -58,13 +58,19 @@ module Bade
|
|
58
58
|
|
59
59
|
# @param [String] text
|
60
60
|
#
|
61
|
-
def buff_print_text(text, indent: false, new_line: false)
|
62
|
-
buff_print_value(%Q{
|
61
|
+
def buff_print_text(text, indent: false, new_line: false) # rubocop:disable Lint/UnusedMethodArgument
|
62
|
+
buff_print_value("%Q{#{text}}") unless text.empty?
|
63
|
+
end
|
64
|
+
|
65
|
+
# @param [String] text
|
66
|
+
#
|
67
|
+
def buff_print_static_text(text)
|
68
|
+
buff_print_value("'#{text.gsub("'", "\\'")}'") unless text.empty?
|
63
69
|
end
|
64
70
|
|
65
71
|
def buff_print_value(value)
|
66
72
|
# buff_code %Q{#{BUFF_NAME} << #{CURRENT_INDENT_NAME}} if indent
|
67
|
-
buff_code(
|
73
|
+
buff_code("#{BUFF_NAME} << #{value}")
|
68
74
|
end
|
69
75
|
|
70
76
|
def buff_code(text)
|
@@ -93,80 +99,70 @@ module Bade
|
|
93
99
|
# @param nodes [Array<Node>]
|
94
100
|
#
|
95
101
|
def visit_nodes(nodes)
|
96
|
-
nodes.each
|
102
|
+
nodes.each do |node|
|
97
103
|
visit_node(node)
|
98
|
-
|
104
|
+
end
|
99
105
|
end
|
100
106
|
|
101
107
|
# @param current_node [Node]
|
102
108
|
#
|
103
109
|
def visit_node(current_node)
|
104
110
|
case current_node.type
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
when :mixin_call
|
141
|
-
params = formatted_mixin_params(current_node)
|
142
|
-
buff_code "#{MIXINS_NAME}['#{current_node.name}'].call!(#{params})"
|
143
|
-
|
144
|
-
when :output
|
145
|
-
data = current_node.value
|
146
|
-
output_code = if current_node.escaped
|
147
|
-
"\#{__html_escaped(#{data})}"
|
148
|
-
else
|
149
|
-
"\#{#{data}}"
|
150
|
-
end
|
151
|
-
buff_print_text output_code
|
152
|
-
|
153
|
-
when :newline
|
154
|
-
# buff_print_value(NEW_LINE_NAME)
|
155
|
-
|
156
|
-
when :import
|
157
|
-
base_path = File.expand_path(current_node.value, File.dirname(@document.file_path))
|
158
|
-
load_path = if base_path.end_with?('.rb') && File.exist?(base_path)
|
159
|
-
base_path
|
160
|
-
elsif File.exist?("#{base_path}.rb")
|
161
|
-
"#{base_path}.rb"
|
111
|
+
when :root
|
112
|
+
visit_node_children(current_node)
|
113
|
+
|
114
|
+
when :static_text
|
115
|
+
buff_print_static_text(current_node.value)
|
116
|
+
|
117
|
+
when :tag
|
118
|
+
visit_tag(current_node)
|
119
|
+
|
120
|
+
when :code
|
121
|
+
buff_code(current_node.value)
|
122
|
+
|
123
|
+
when :html_comment
|
124
|
+
buff_print_text '<!-- '
|
125
|
+
visit_node_children(current_node)
|
126
|
+
buff_print_text ' -->'
|
127
|
+
|
128
|
+
when :comment
|
129
|
+
comment_text = '#' + current_node.children.map(&:value).join("\n#")
|
130
|
+
buff_code(comment_text)
|
131
|
+
|
132
|
+
when :doctype
|
133
|
+
buff_print_text current_node.xml_output
|
134
|
+
|
135
|
+
when :mixin_decl
|
136
|
+
visit_block_decl(current_node)
|
137
|
+
|
138
|
+
when :mixin_call
|
139
|
+
params = formatted_mixin_params(current_node)
|
140
|
+
buff_code "#{MIXINS_NAME}['#{current_node.name}'].call!(#{params})"
|
141
|
+
|
142
|
+
when :output
|
143
|
+
data = current_node.value
|
144
|
+
output_code = if current_node.escaped
|
145
|
+
"\#{__html_escaped(#{data})}"
|
162
146
|
else
|
163
|
-
|
147
|
+
"\#{#{data}}"
|
164
148
|
end
|
149
|
+
buff_print_text output_code
|
165
150
|
|
166
|
-
|
151
|
+
when :newline
|
152
|
+
# buff_print_value(NEW_LINE_NAME)
|
167
153
|
|
168
|
-
|
169
|
-
|
154
|
+
when :import
|
155
|
+
base_path = File.expand_path(current_node.value, File.dirname(@document.file_path))
|
156
|
+
load_path = if base_path.end_with?('.rb') && File.exist?(base_path)
|
157
|
+
base_path
|
158
|
+
elsif File.exist?("#{base_path}.rb")
|
159
|
+
"#{base_path}.rb"
|
160
|
+
end
|
161
|
+
|
162
|
+
buff_code "load('#{load_path}')" unless load_path.nil?
|
163
|
+
|
164
|
+
else
|
165
|
+
raise "Unknown type #{current_node.type}"
|
170
166
|
end
|
171
167
|
end
|
172
168
|
|
@@ -180,19 +176,15 @@ module Bade
|
|
180
176
|
|
181
177
|
text = "<#{current_node.name}"
|
182
178
|
|
183
|
-
|
184
|
-
text += "#{attributes}"
|
185
|
-
end
|
179
|
+
text += attributes.to_s unless attributes.empty?
|
186
180
|
|
187
|
-
other_than_new_lines = children_wo_attributes.any? { |
|
188
|
-
node.type != :newline
|
189
|
-
}
|
181
|
+
other_than_new_lines = children_wo_attributes.any? { |n| n.type != :newline }
|
190
182
|
|
191
|
-
if other_than_new_lines
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
183
|
+
text += if other_than_new_lines
|
184
|
+
'>'
|
185
|
+
else
|
186
|
+
'/>'
|
187
|
+
end
|
196
188
|
|
197
189
|
conditional_nodes = current_node.children.select { |n| n.type == :output && n.conditional }
|
198
190
|
|
@@ -223,7 +215,7 @@ module Bade
|
|
223
215
|
visit_node(last_node) if is_last_newline
|
224
216
|
end
|
225
217
|
|
226
|
-
unless conditional_nodes.empty?
|
218
|
+
unless conditional_nodes.empty? # rubocop:disable Style/GuardClause
|
227
219
|
@code_indent -= 1
|
228
220
|
|
229
221
|
buff_code 'end'
|
@@ -239,16 +231,14 @@ module Bade
|
|
239
231
|
xml_attributes = []
|
240
232
|
|
241
233
|
tag_node.attributes.each do |attr|
|
242
|
-
unless all_attributes.include?(attr.name)
|
243
|
-
xml_attributes << attr.name
|
244
|
-
end
|
234
|
+
xml_attributes << attr.name unless all_attributes.include?(attr.name)
|
245
235
|
|
246
236
|
all_attributes[attr.name] << attr.value
|
247
237
|
end
|
248
238
|
|
249
239
|
xml_attributes.map do |attr_name|
|
250
240
|
joined = all_attributes[attr_name].join('), (')
|
251
|
-
|
241
|
+
"\#{__tag_render_attribute('#{attr_name}', (#{joined}))}"
|
252
242
|
end.join
|
253
243
|
end
|
254
244
|
|
@@ -274,7 +264,7 @@ module Bade
|
|
274
264
|
blocks = mixin_node.blocks
|
275
265
|
|
276
266
|
other_children = (mixin_node.children - mixin_node.blocks - mixin_node.params)
|
277
|
-
if other_children.
|
267
|
+
if other_children.count { |n| n.type != :newline } > 0
|
278
268
|
def_block_node = AST::NodeRegistrator.create(:mixin_block, mixin_node.lineno)
|
279
269
|
def_block_node.name = DEFAULT_BLOCK_NAME
|
280
270
|
def_block_node.children = other_children
|
@@ -282,7 +272,7 @@ module Bade
|
|
282
272
|
blocks << def_block_node
|
283
273
|
end
|
284
274
|
|
285
|
-
if blocks.
|
275
|
+
if !blocks.empty?
|
286
276
|
buff_code '__blocks = {}'
|
287
277
|
|
288
278
|
blocks.each do |block|
|
@@ -347,6 +337,22 @@ module Bade
|
|
347
337
|
end
|
348
338
|
end
|
349
339
|
|
340
|
+
# @param [MixinDeclarationNode] current_node
|
341
|
+
#
|
342
|
+
# @return [nil]
|
343
|
+
#
|
344
|
+
def visit_block_decl(current_node)
|
345
|
+
params = formatted_mixin_params(current_node)
|
346
|
+
buff_code "#{MIXINS_NAME}['#{current_node.name}'] = __create_mixin('#{current_node.name}', &lambda { |#{params}|"
|
347
|
+
|
348
|
+
code_indent do
|
349
|
+
blocks_name_declaration(current_node)
|
350
|
+
visit_nodes(current_node.children - current_node.params)
|
351
|
+
end
|
352
|
+
|
353
|
+
buff_code '})'
|
354
|
+
end
|
355
|
+
|
350
356
|
|
351
357
|
|
352
358
|
# @param [String] str
|
data/lib/bade/parser.rb
CHANGED
@@ -8,7 +8,11 @@ require_relative 'ruby_extensions/string'
|
|
8
8
|
require_relative 'ruby_extensions/array'
|
9
9
|
|
10
10
|
module Bade
|
11
|
+
# Class to parse input string into AST::Document
|
12
|
+
#
|
11
13
|
class Parser
|
14
|
+
# Error representing syntax error in specific file, line and column
|
15
|
+
#
|
12
16
|
class SyntaxError < StandardError
|
13
17
|
attr_reader :error, :file, :line, :lineno, :column
|
14
18
|
|
@@ -23,16 +27,19 @@ module Bade
|
|
23
27
|
def to_s
|
24
28
|
line = @line.lstrip
|
25
29
|
column = @column + line.size - @line.size
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
}
|
30
|
+
<<-MSG.strip_heredoc
|
31
|
+
#{error}
|
32
|
+
#{file}, Line #{lineno}, Column #{@column}
|
33
|
+
#{line}
|
34
|
+
#{' ' * column}^
|
35
|
+
MSG
|
31
36
|
end
|
32
37
|
end
|
33
38
|
|
34
39
|
class ParserInternalError < StandardError; end
|
35
40
|
|
41
|
+
require_relative 'parser/parser_constants'
|
42
|
+
|
36
43
|
# @type @stacks [Array<Bade::Node>]
|
37
44
|
|
38
45
|
# @return [Array<String>]
|
@@ -52,7 +59,7 @@ module Bade
|
|
52
59
|
@tabsize = tabsize
|
53
60
|
@file_path = file_path
|
54
61
|
|
55
|
-
@tab_re = /\G((?: {#{tabsize}})*) {0,#{tabsize-1}}\t/
|
62
|
+
@tab_re = /\G((?: {#{tabsize}})*) {0,#{tabsize - 1}}\t/
|
56
63
|
@tab = '\1' + ' ' * tabsize
|
57
64
|
|
58
65
|
reset
|
@@ -67,7 +74,7 @@ module Bade
|
|
67
74
|
|
68
75
|
@dependency_paths = []
|
69
76
|
|
70
|
-
if str.
|
77
|
+
if str.is_a?(Array)
|
71
78
|
reset(str, [[@root]])
|
72
79
|
else
|
73
80
|
reset(str.split(/\r?\n/, -1), [[@root]]) # -1 is for not suppressing empty lines
|
@@ -80,62 +87,6 @@ module Bade
|
|
80
87
|
@document
|
81
88
|
end
|
82
89
|
|
83
|
-
|
84
|
-
|
85
|
-
WORD_RE = ''.respond_to?(:encoding) ? '\p{Word}' : '\w'
|
86
|
-
NAME_RE_STRING = "(#{WORD_RE}(?:#{WORD_RE}|:|-|_)*)"
|
87
|
-
|
88
|
-
ATTR_NAME_RE_STRING = "\\A\\s*#{NAME_RE_STRING}"
|
89
|
-
CODE_ATTR_RE = /#{ATTR_NAME_RE_STRING}\s*&?:\s*/
|
90
|
-
|
91
|
-
TAG_RE = /\A#{NAME_RE_STRING}/
|
92
|
-
CLASS_TAG_RE = /\A\.#{NAME_RE_STRING}/
|
93
|
-
ID_TAG_RE = /\A##{NAME_RE_STRING}/
|
94
|
-
|
95
|
-
def reset(lines = nil, stacks = nil)
|
96
|
-
# Since you can indent however you like in Slim, we need to keep a list
|
97
|
-
# of how deeply indented you are. For instance, in a template like this:
|
98
|
-
#
|
99
|
-
# doctype # 0 spaces
|
100
|
-
# html # 0 spaces
|
101
|
-
# head # 1 space
|
102
|
-
# title # 4 spaces
|
103
|
-
#
|
104
|
-
# indents will then contain [0, 1, 4] (when it's processing the last line.)
|
105
|
-
#
|
106
|
-
# We uses this information to figure out how many steps we must "jump"
|
107
|
-
# out when we see an de-indented line.
|
108
|
-
@indents = [0]
|
109
|
-
|
110
|
-
# Whenever we want to output something, we'll *always* output it to the
|
111
|
-
# last stack in this array. So when there's a line that expects
|
112
|
-
# indentation, we simply push a new stack onto this array. When it
|
113
|
-
# processes the next line, the content will then be outputted into that
|
114
|
-
# stack.
|
115
|
-
@stacks = stacks
|
116
|
-
|
117
|
-
@lineno = 0
|
118
|
-
@lines = lines
|
119
|
-
|
120
|
-
# @return [String]
|
121
|
-
@line = @orig_line = nil
|
122
|
-
end
|
123
|
-
|
124
|
-
def next_line
|
125
|
-
if @lines.empty?
|
126
|
-
@orig_line = @line = nil
|
127
|
-
|
128
|
-
last_newlines = remove_last_newlines
|
129
|
-
@root.children += last_newlines
|
130
|
-
|
131
|
-
nil
|
132
|
-
else
|
133
|
-
@orig_line = @lines.shift
|
134
|
-
@lineno += 1
|
135
|
-
@line = @orig_line.dup
|
136
|
-
end
|
137
|
-
end
|
138
|
-
|
139
90
|
# Calculate indent for line
|
140
91
|
#
|
141
92
|
# @param [String] line
|
@@ -151,9 +102,8 @@ module Bade
|
|
151
102
|
# @param [Symbol] type
|
152
103
|
#
|
153
104
|
def append_node(type, indent: @indents.length, add: false, value: nil)
|
154
|
-
|
155
|
-
|
156
|
-
end
|
105
|
+
# add necessary stack items to match required indent
|
106
|
+
@stacks << @stacks.last.dup while indent >= @stacks.length
|
157
107
|
|
158
108
|
parent = @stacks[indent].last
|
159
109
|
node = AST::NodeRegistrator.create(type, @lineno)
|
@@ -161,9 +111,7 @@ module Bade
|
|
161
111
|
|
162
112
|
node.value = value unless value.nil?
|
163
113
|
|
164
|
-
if add
|
165
|
-
@stacks[indent] << node
|
166
|
-
end
|
114
|
+
@stacks[indent] << node if add
|
167
115
|
|
168
116
|
node
|
169
117
|
end
|
@@ -176,332 +124,18 @@ module Bade
|
|
176
124
|
last_node.children.pop(last_newlines_count)
|
177
125
|
end
|
178
126
|
|
179
|
-
def parse_line
|
180
|
-
if @line.strip.length == 0
|
181
|
-
append_node(:newline) unless @lines.empty?
|
182
|
-
return
|
183
|
-
end
|
184
|
-
|
185
|
-
indent = get_indent(@line)
|
186
|
-
|
187
|
-
# left strip
|
188
|
-
@line.remove_indent!(indent, @tabsize)
|
189
|
-
|
190
|
-
# If there's more stacks than indents, it means that the previous
|
191
|
-
# line is expecting this line to be indented.
|
192
|
-
expecting_indentation = @stacks.length > @indents.length
|
193
|
-
|
194
|
-
if indent > @indents.last
|
195
|
-
@indents << indent
|
196
|
-
else
|
197
|
-
# This line was *not* indented more than the line before,
|
198
|
-
# so we'll just forget about the stack that the previous line pushed.
|
199
|
-
if expecting_indentation
|
200
|
-
last_newlines = remove_last_newlines
|
201
|
-
|
202
|
-
@stacks.pop
|
203
|
-
|
204
|
-
new_node = @stacks.last.last
|
205
|
-
new_node.children += last_newlines
|
206
|
-
end
|
207
|
-
|
208
|
-
# This line was deindented.
|
209
|
-
# Now we're have to go through the all the indents and figure out
|
210
|
-
# how many levels we've deindented.
|
211
|
-
while indent < @indents.last
|
212
|
-
last_newlines = remove_last_newlines
|
213
|
-
|
214
|
-
@indents.pop
|
215
|
-
@stacks.pop
|
216
|
-
|
217
|
-
new_node = @stacks.last.last
|
218
|
-
new_node.children += last_newlines
|
219
|
-
end
|
220
|
-
|
221
|
-
# Remove old stacks we don't need
|
222
|
-
while not @stacks[indent].nil? and indent < @stacks[indent].length - 1
|
223
|
-
last_newlines = remove_last_newlines
|
224
|
-
|
225
|
-
@stacks[indent].pop
|
226
|
-
|
227
|
-
new_node = @stacks.last.last
|
228
|
-
new_node.children += last_newlines
|
229
|
-
end
|
230
|
-
|
231
|
-
# This line's indentation happens lie "between" two other line's
|
232
|
-
# indentation:
|
233
|
-
#
|
234
|
-
# hello
|
235
|
-
# world
|
236
|
-
# this # <- This should not be possible!
|
237
|
-
syntax_error('Malformed indentation') if indent != @indents.last
|
238
|
-
end
|
239
|
-
|
240
|
-
parse_line_indicators
|
241
|
-
end
|
242
|
-
|
243
|
-
module LineIndicatorRegexps
|
244
|
-
IMPORT = /\Aimport /
|
245
|
-
MIXIN_DECL = /\Amixin #{NAME_RE_STRING}/
|
246
|
-
MIXIN_CALL = /\A\+#{NAME_RE_STRING}/
|
247
|
-
BLOCK_DECLARATION = /\Ablock #{NAME_RE_STRING}/
|
248
|
-
HTML_COMMENT = /\A\/\/! /
|
249
|
-
NORMAL_COMMENT = /\A\/\//
|
250
|
-
TEXT_BLOCK_START = /\A\|( ?)/
|
251
|
-
INLINE_HTML = /\A</
|
252
|
-
CODE_BLOCK = /\A-/
|
253
|
-
OUTPUT_BLOCK = /\A(\??)(&?)=/
|
254
|
-
DOCTYPE = /\Adoctype\s/i
|
255
|
-
TAG_CLASS_START_BLOCK = /\A\./
|
256
|
-
TAG_ID_START_BLOCK = /\A#/
|
257
|
-
end
|
258
|
-
|
259
|
-
module ParseRubyCodeRegexps
|
260
|
-
END_NEW_LINE = /\A\s*\n/
|
261
|
-
END_PARAMS_ARG = /\A\s*[,)]/
|
262
|
-
end
|
263
|
-
|
264
|
-
def parse_line_indicators(add_newline: true)
|
265
|
-
case @line
|
266
|
-
when LineIndicatorRegexps::IMPORT
|
267
|
-
@line = $'
|
268
|
-
parse_import
|
269
|
-
|
270
|
-
when LineIndicatorRegexps::MIXIN_DECL
|
271
|
-
# Mixin declaration
|
272
|
-
@line = $'
|
273
|
-
parse_mixin_declaration($1)
|
274
|
-
|
275
|
-
when LineIndicatorRegexps::MIXIN_CALL
|
276
|
-
# Mixin call
|
277
|
-
@line = $'
|
278
|
-
parse_mixin_call($1)
|
279
|
-
|
280
|
-
when LineIndicatorRegexps::BLOCK_DECLARATION
|
281
|
-
@line = $'
|
282
|
-
if @stacks.last.last.type == :mixin_call
|
283
|
-
node = append_node(:mixin_block, add: true)
|
284
|
-
node.name = $1
|
285
|
-
else
|
286
|
-
# keyword block used outside of mixin call
|
287
|
-
parse_tag($&)
|
288
|
-
end
|
289
|
-
|
290
|
-
when LineIndicatorRegexps::HTML_COMMENT
|
291
|
-
# HTML comment
|
292
|
-
append_node(:html_comment, add: true)
|
293
|
-
parse_text_block $', @indents.last + @tabsize
|
294
|
-
|
295
|
-
when LineIndicatorRegexps::NORMAL_COMMENT
|
296
|
-
# Comment
|
297
|
-
append_node(:comment, add: true)
|
298
|
-
parse_text_block $', @indents.last + @tabsize
|
299
|
-
|
300
|
-
when LineIndicatorRegexps::TEXT_BLOCK_START
|
301
|
-
# Found a text block.
|
302
|
-
parse_text_block $', @indents.last + @tabsize
|
303
|
-
|
304
|
-
when LineIndicatorRegexps::INLINE_HTML
|
305
|
-
# Inline html
|
306
|
-
append_node(:text, value: @line)
|
307
|
-
|
308
|
-
when LineIndicatorRegexps::CODE_BLOCK
|
309
|
-
# Found a code block.
|
310
|
-
append_node(:code, value: $'.strip)
|
311
|
-
|
312
|
-
when LineIndicatorRegexps::OUTPUT_BLOCK
|
313
|
-
# Found an output block.
|
314
|
-
# We expect the line to be broken or the next line to be indented.
|
315
|
-
@line = $'
|
316
|
-
output_node = append_node(:output)
|
317
|
-
output_node.conditional = $1.length == 1
|
318
|
-
output_node.escaped = $2.length == 1
|
319
|
-
output_node.value = parse_ruby_code(ParseRubyCodeRegexps::END_NEW_LINE)
|
320
|
-
|
321
|
-
when LineIndicatorRegexps::DOCTYPE
|
322
|
-
# Found doctype declaration
|
323
|
-
append_node(:doctype, value: $'.strip)
|
324
|
-
|
325
|
-
when TAG_RE
|
326
|
-
# Found a HTML tag.
|
327
|
-
@line = $' if $1
|
328
|
-
parse_tag($&)
|
329
|
-
|
330
|
-
when LineIndicatorRegexps::TAG_CLASS_START_BLOCK
|
331
|
-
# Found class name -> implicit div
|
332
|
-
parse_tag 'div'
|
333
|
-
|
334
|
-
when LineIndicatorRegexps::TAG_ID_START_BLOCK
|
335
|
-
# Found id name -> implicit div
|
336
|
-
parse_tag 'div'
|
337
|
-
|
338
|
-
else
|
339
|
-
syntax_error 'Unknown line indicator'
|
340
|
-
end
|
341
|
-
|
342
|
-
append_node(:newline) if add_newline && !@lines.empty?
|
343
|
-
end
|
344
|
-
|
345
127
|
def parse_import
|
346
|
-
|
128
|
+
# TODO: change this to something better
|
129
|
+
path = eval(@line) # rubocop:disable Lint/Eval
|
347
130
|
append_node(:import, value: path)
|
348
131
|
|
349
132
|
@dependency_paths << path unless @dependency_paths.include?(path)
|
350
133
|
end
|
351
134
|
|
352
|
-
module MixinRegexps
|
353
|
-
TEXT_START = /\A /
|
354
|
-
BLOCK_EXPANSION = /\A:\s+/
|
355
|
-
OUTPUT_CODE = /\A(&?)=/
|
356
|
-
|
357
|
-
PARAMS_END = /\A\s*\)/
|
358
|
-
|
359
|
-
PARAMS_END_SPACES = /^\s*$/
|
360
|
-
PARAMS_ARGS_DELIMITER = /\A\s*,/
|
361
|
-
|
362
|
-
PARAMS_PARAM_NAME = /\A\s*#{NAME_RE_STRING}/
|
363
|
-
PARAMS_BLOCK_NAME = /\A\s*&#{NAME_RE_STRING}/
|
364
|
-
PARAMS_KEY_PARAM_NAME = CODE_ATTR_RE
|
365
|
-
end
|
366
|
-
|
367
|
-
def parse_mixin_call(mixin_name)
|
368
|
-
mixin_name = fixed_trailing_colon(mixin_name)
|
369
|
-
|
370
|
-
mixin_node = append_node(:mixin_call, add: true)
|
371
|
-
mixin_node.name = mixin_name
|
372
|
-
|
373
|
-
parse_mixin_call_params
|
374
|
-
|
375
|
-
case @line
|
376
|
-
when MixinRegexps::TEXT_START
|
377
|
-
@line = $'
|
378
|
-
parse_text
|
379
|
-
|
380
|
-
when MixinRegexps::BLOCK_EXPANSION
|
381
|
-
# Block expansion
|
382
|
-
@line = $'
|
383
|
-
parse_line_indicators(add_newline: false)
|
384
|
-
|
385
|
-
when MixinRegexps::OUTPUT_CODE
|
386
|
-
# Handle output code
|
387
|
-
parse_line_indicators(add_newline: false)
|
388
|
-
|
389
|
-
when ''
|
390
|
-
# nothing
|
391
|
-
|
392
|
-
else
|
393
|
-
syntax_error "Unknown symbol after mixin calling, line = `#{@line}'"
|
394
|
-
end
|
395
|
-
end
|
396
|
-
|
397
|
-
def parse_mixin_call_params
|
398
|
-
# between tag name and attribute must not be space
|
399
|
-
# and skip when is nothing other
|
400
|
-
if @line.start_with?('(')
|
401
|
-
@line.remove_first!
|
402
|
-
else
|
403
|
-
return
|
404
|
-
end
|
405
|
-
|
406
|
-
while true
|
407
|
-
case @line
|
408
|
-
when MixinRegexps::PARAMS_KEY_PARAM_NAME
|
409
|
-
@line = $'
|
410
|
-
attr_node = append_node(:mixin_key_param)
|
411
|
-
attr_node.name = fixed_trailing_colon($1)
|
412
|
-
attr_node.value = parse_ruby_code(ParseRubyCodeRegexps::END_PARAMS_ARG)
|
413
|
-
|
414
|
-
when MixinRegexps::PARAMS_ARGS_DELIMITER
|
415
|
-
# args delimiter
|
416
|
-
@line = $'
|
417
|
-
next
|
418
|
-
|
419
|
-
when MixinRegexps::PARAMS_END_SPACES
|
420
|
-
# spaces and/or end of line
|
421
|
-
next_line
|
422
|
-
next
|
423
|
-
|
424
|
-
when MixinRegexps::PARAMS_END
|
425
|
-
# Find ending delimiter
|
426
|
-
@line = $'
|
427
|
-
break
|
428
|
-
|
429
|
-
else
|
430
|
-
attr_node = append_node(:mixin_param)
|
431
|
-
attr_node.value = parse_ruby_code(ParseRubyCodeRegexps::END_PARAMS_ARG)
|
432
|
-
end
|
433
|
-
end
|
434
|
-
end
|
435
|
-
|
436
|
-
def parse_mixin_declaration(mixin_name)
|
437
|
-
mixin_node = append_node(:mixin_decl, add: true)
|
438
|
-
mixin_node.name = mixin_name
|
439
|
-
|
440
|
-
parse_mixin_declaration_params
|
441
|
-
end
|
442
|
-
|
443
|
-
def parse_mixin_declaration_params
|
444
|
-
# between tag name and attribute must not be space
|
445
|
-
# and skip when is nothing other
|
446
|
-
if @line.start_with?('(')
|
447
|
-
@line.remove_first!
|
448
|
-
else
|
449
|
-
return
|
450
|
-
end
|
451
|
-
|
452
|
-
while true
|
453
|
-
case @line
|
454
|
-
when MixinRegexps::PARAMS_KEY_PARAM_NAME
|
455
|
-
# Value ruby code
|
456
|
-
@line = $'
|
457
|
-
attr_node = append_node(:mixin_key_param)
|
458
|
-
attr_node.name = fixed_trailing_colon($1)
|
459
|
-
attr_node.value = parse_ruby_code(ParseRubyCodeRegexps::END_PARAMS_ARG)
|
460
|
-
|
461
|
-
when MixinRegexps::PARAMS_PARAM_NAME
|
462
|
-
@line = $'
|
463
|
-
append_node(:mixin_param, value: $1)
|
464
|
-
|
465
|
-
when MixinRegexps::PARAMS_BLOCK_NAME
|
466
|
-
@line = $'
|
467
|
-
append_node(:mixin_block_param, value: $1)
|
468
|
-
|
469
|
-
when MixinRegexps::PARAMS_ARGS_DELIMITER
|
470
|
-
# args delimiter
|
471
|
-
@line = $'
|
472
|
-
next
|
473
|
-
|
474
|
-
when MixinRegexps::PARAMS_END
|
475
|
-
# Find ending delimiter
|
476
|
-
@line = $'
|
477
|
-
break
|
478
|
-
|
479
|
-
else
|
480
|
-
syntax_error('wrong mixin attribute syntax')
|
481
|
-
end
|
482
|
-
end
|
483
|
-
end
|
484
|
-
|
485
|
-
def parse_text
|
486
|
-
text = @line
|
487
|
-
text = text.gsub(/&\{/, '#{ __html_escaped ')
|
488
|
-
append_node(:text, value: text)
|
489
|
-
end
|
490
|
-
|
491
|
-
|
492
|
-
module TagRegexps
|
493
|
-
BLOCK_EXPANSION = /\A:\s+/
|
494
|
-
OUTPUT_CODE = LineIndicatorRegexps::OUTPUT_BLOCK
|
495
|
-
TEXT_START = /\A /
|
496
|
-
|
497
|
-
PARAMS_ARGS_DELIMITER = /\A\s*,/
|
498
|
-
PARAMS_END = /\A\s*\)/
|
499
|
-
end
|
500
|
-
|
501
135
|
# @param value [String]
|
502
136
|
#
|
503
137
|
def fixed_trailing_colon(value)
|
504
|
-
if String
|
138
|
+
if value.is_a?(String) && value.end_with?(':')
|
505
139
|
value = value.remove_last
|
506
140
|
@line.prepend(':')
|
507
141
|
end
|
@@ -509,205 +143,6 @@ module Bade
|
|
509
143
|
value
|
510
144
|
end
|
511
145
|
|
512
|
-
|
513
|
-
# @param [String] tag tag name
|
514
|
-
#
|
515
|
-
def parse_tag(tag)
|
516
|
-
tag = fixed_trailing_colon(tag)
|
517
|
-
|
518
|
-
if tag.is_a?(AST::Node)
|
519
|
-
tag_node = tag
|
520
|
-
else
|
521
|
-
tag_node = append_node(:tag, add: true)
|
522
|
-
tag_node.name = tag
|
523
|
-
end
|
524
|
-
|
525
|
-
parse_tag_attributes
|
526
|
-
|
527
|
-
case @line
|
528
|
-
when TagRegexps::BLOCK_EXPANSION
|
529
|
-
# Block expansion
|
530
|
-
@line = $'
|
531
|
-
parse_line_indicators(add_newline: false)
|
532
|
-
|
533
|
-
when TagRegexps::OUTPUT_CODE
|
534
|
-
# Handle output code
|
535
|
-
parse_line_indicators(add_newline: false)
|
536
|
-
|
537
|
-
when CLASS_TAG_RE
|
538
|
-
# Class name
|
539
|
-
@line = $'
|
540
|
-
|
541
|
-
attr_node = append_node(:tag_attr)
|
542
|
-
attr_node.name = 'class'
|
543
|
-
attr_node.value = fixed_trailing_colon($1).single_quote
|
544
|
-
|
545
|
-
parse_tag tag_node
|
546
|
-
|
547
|
-
when ID_TAG_RE
|
548
|
-
# Id name
|
549
|
-
@line = $'
|
550
|
-
|
551
|
-
attr_node = append_node(:tag_attr)
|
552
|
-
attr_node.name = 'id'
|
553
|
-
attr_node.value = fixed_trailing_colon($1).single_quote
|
554
|
-
|
555
|
-
parse_tag tag_node
|
556
|
-
|
557
|
-
when TagRegexps::TEXT_START
|
558
|
-
# Text content
|
559
|
-
@line = $'
|
560
|
-
parse_text
|
561
|
-
|
562
|
-
when ''
|
563
|
-
# nothing
|
564
|
-
|
565
|
-
else
|
566
|
-
syntax_error "Unknown symbol after tag definition #{@line}"
|
567
|
-
end
|
568
|
-
end
|
569
|
-
|
570
|
-
def parse_tag_attributes
|
571
|
-
# Check to see if there is a delimiter right after the tag name
|
572
|
-
|
573
|
-
# between tag name and attribute must not be space
|
574
|
-
# and skip when is nothing other
|
575
|
-
if @line.start_with?('(')
|
576
|
-
@line.remove_first!
|
577
|
-
else
|
578
|
-
return
|
579
|
-
end
|
580
|
-
|
581
|
-
while true
|
582
|
-
case @line
|
583
|
-
when CODE_ATTR_RE
|
584
|
-
# Value ruby code
|
585
|
-
@line = $'
|
586
|
-
attr_node = append_node(:tag_attr)
|
587
|
-
attr_node.name = $1
|
588
|
-
attr_node.value = parse_ruby_code(ParseRubyCodeRegexps::END_PARAMS_ARG)
|
589
|
-
|
590
|
-
when TagRegexps::PARAMS_ARGS_DELIMITER
|
591
|
-
# args delimiter
|
592
|
-
@line = $'
|
593
|
-
next
|
594
|
-
|
595
|
-
when TagRegexps::PARAMS_END
|
596
|
-
# Find ending delimiter
|
597
|
-
@line = $'
|
598
|
-
break
|
599
|
-
|
600
|
-
else
|
601
|
-
# Found something where an attribute should be
|
602
|
-
@line.lstrip!
|
603
|
-
syntax_error('Expected attribute') unless @line.empty?
|
604
|
-
|
605
|
-
# Attributes span multiple lines
|
606
|
-
append_node(:newline)
|
607
|
-
syntax_error('Expected closing tag attributes delimiter `)`') if @lines.empty?
|
608
|
-
next_line
|
609
|
-
end
|
610
|
-
end
|
611
|
-
end
|
612
|
-
|
613
|
-
def parse_text_block(first_line, text_indent = nil)
|
614
|
-
if !first_line || first_line.empty?
|
615
|
-
text_indent = nil
|
616
|
-
else
|
617
|
-
@line = first_line
|
618
|
-
parse_text
|
619
|
-
end
|
620
|
-
|
621
|
-
until @lines.empty?
|
622
|
-
if @lines.first.blank?
|
623
|
-
next_line
|
624
|
-
append_node(:newline)
|
625
|
-
else
|
626
|
-
indent = get_indent(@lines.first)
|
627
|
-
break if indent <= @indents.last
|
628
|
-
|
629
|
-
next_line
|
630
|
-
|
631
|
-
@line.remove_indent!(text_indent ? text_indent : indent, @tabsize)
|
632
|
-
|
633
|
-
parse_text
|
634
|
-
|
635
|
-
# The indentation of first line of the text block
|
636
|
-
# determines the text base indentation.
|
637
|
-
text_indent ||= indent
|
638
|
-
end
|
639
|
-
end
|
640
|
-
end
|
641
|
-
|
642
|
-
# Parse ruby code, ended with outer delimiters
|
643
|
-
#
|
644
|
-
# @param [String, Regexp] outer_delimiters
|
645
|
-
#
|
646
|
-
# @return [Void] parsed ruby code
|
647
|
-
#
|
648
|
-
def parse_ruby_code(outer_delimiters)
|
649
|
-
code = String.new
|
650
|
-
end_re = if Regexp === outer_delimiters
|
651
|
-
outer_delimiters
|
652
|
-
else
|
653
|
-
/\A\s*[#{Regexp.escape outer_delimiters.to_s}]/
|
654
|
-
end
|
655
|
-
delimiters = []
|
656
|
-
|
657
|
-
until @line.empty? or (delimiters.count == 0 and @line =~ end_re)
|
658
|
-
char = @line[0]
|
659
|
-
|
660
|
-
# backslash escaped delimiter
|
661
|
-
if char == '\\' && RUBY_ALL_DELIMITERS.include?(@line[1])
|
662
|
-
code << @line.slice!(0, 2)
|
663
|
-
next
|
664
|
-
end
|
665
|
-
|
666
|
-
case char
|
667
|
-
when RUBY_START_DELIMITERS_RE
|
668
|
-
if RUBY_NOT_NESTABLE_DELIMITERS.include?(char) && delimiters.last == char
|
669
|
-
# end char of not nestable delimiter
|
670
|
-
delimiters.pop
|
671
|
-
else
|
672
|
-
# diving
|
673
|
-
delimiters << char
|
674
|
-
end
|
675
|
-
|
676
|
-
when RUBY_END_DELIMITERS_RE
|
677
|
-
# rising
|
678
|
-
if char == RUBY_DELIMITERS_REVERSE[delimiters.last]
|
679
|
-
delimiters.pop
|
680
|
-
end
|
681
|
-
end
|
682
|
-
|
683
|
-
code << @line.slice!(0)
|
684
|
-
end
|
685
|
-
|
686
|
-
unless delimiters.empty?
|
687
|
-
syntax_error('Unexpected end of ruby code')
|
688
|
-
end
|
689
|
-
|
690
|
-
code.strip
|
691
|
-
end
|
692
|
-
|
693
|
-
RUBY_DELIMITERS_REVERSE = {
|
694
|
-
'(' => ')',
|
695
|
-
'[' => ']',
|
696
|
-
'{' => '}'
|
697
|
-
}.freeze
|
698
|
-
|
699
|
-
RUBY_QUOTES = %w(' ").freeze
|
700
|
-
|
701
|
-
RUBY_NOT_NESTABLE_DELIMITERS = RUBY_QUOTES
|
702
|
-
|
703
|
-
RUBY_START_DELIMITERS = (%w(\( [ {) + RUBY_NOT_NESTABLE_DELIMITERS).freeze
|
704
|
-
RUBY_END_DELIMITERS = (%w(\) ] }) + RUBY_NOT_NESTABLE_DELIMITERS).freeze
|
705
|
-
RUBY_ALL_DELIMITERS = (RUBY_START_DELIMITERS + RUBY_END_DELIMITERS).uniq.freeze
|
706
|
-
|
707
|
-
RUBY_START_DELIMITERS_RE = /\A[#{Regexp.escape RUBY_START_DELIMITERS.join}]/
|
708
|
-
RUBY_END_DELIMITERS_RE = /\A[#{Regexp.escape RUBY_END_DELIMITERS.join}]/
|
709
|
-
|
710
|
-
|
711
146
|
# ----------- Errors ---------------
|
712
147
|
|
713
148
|
# Raise specific error
|
@@ -715,8 +150,14 @@ module Bade
|
|
715
150
|
# @param [String] message
|
716
151
|
#
|
717
152
|
def syntax_error(message)
|
718
|
-
|
719
|
-
|
153
|
+
column = @orig_line && @line ? @orig_line.size - @line.size : 0
|
154
|
+
raise SyntaxError.new(message, file_path, @orig_line, @lineno, column)
|
720
155
|
end
|
156
|
+
|
157
|
+
require_relative 'parser/parser_lines'
|
158
|
+
require_relative 'parser/parser_tag'
|
159
|
+
require_relative 'parser/parser_mixin'
|
160
|
+
require_relative 'parser/parser_ruby_code'
|
161
|
+
require_relative 'parser/parser_text'
|
721
162
|
end
|
722
163
|
end
|