bade 0.2.0 → 0.2.1
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/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
|