zenml 1.0.1 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -6,9 +6,9 @@ require 'rexml/document'
6
6
  include REXML
7
7
 
8
8
 
9
- class ZenithalParser
9
+ module ZenithalParserMethod
10
10
 
11
- TAG_START = "\\"
11
+ ELEMENT_START = "\\"
12
12
  MACRO_START = "&"
13
13
  ESCAPE_START = "`"
14
14
  ATTRIBUTE_START = "|"
@@ -19,262 +19,297 @@ class ZenithalParser
19
19
  ATTRIBUTE_SEPARATOR = ","
20
20
  CONTENT_START = "<"
21
21
  CONTENT_END = ">"
22
- BRACE_START = "{"
23
- BRACE_END = "}"
24
- BRACKET_START = "["
25
- BRACKET_END = "]"
26
- SLASH_START = "/"
27
- SLASH_END = "/"
22
+ SPECIAL_ELEMENT_STARTS = {:brace => "{", :bracket => "[", :slash => "/"}
23
+ SPECIAL_ELEMENT_ENDS = {:brace => "}", :bracket => "]", :slash => "/"}
28
24
  COMMENT_DELIMITER = "#"
29
- INSTRUCTION_MARK = "?"
30
- TRIM_MARK = "*"
31
- VERBAL_MARK = "~"
32
- MULTIPLE_MARK = "+"
33
25
  SYSTEM_INSTRUCTION_NAME = "zml"
34
- ENTITIES = {"amp" => "&", "lt" => "<", "gt" => ">", "apos" => "'", "quot" => "\"",
35
- "lcub" => "{", "rcub" => "}", "lbrace" => "{", "rbrace" => "}", "lsqb" => "[", "rsqb" => "]", "lbrack" => "[", "rbrack" => "]",
36
- "sol" => "/", "bsol" => "\\", "verbar" => "|", "vert" => "|", "grave" => "`", "num" => "#"}
37
- ESCAPES = ["&", "<", ">", "'", "\"", "{", "}", "[", "]", "/", "\\", "|", "`", "#"]
38
- VALID_START_CHARS = [0x3A, 0x41..0x5A, 0x5F, 0x61..0x7A, 0xC0..0xD6, 0xD8..0xF6, 0xF8..0x2FF, 0x370..0x37D, 0x37F..0x1FFF, 0x200C..0x200D,
39
- 0x2070..0x218F, 0x2C00..0x2FEF, 0x3001..0xD7FF, 0xF900..0xFDCF, 0xFDF0..0xFFFD, 0x10000..0xEFFFF]
40
- VALID_MIDDLE_CHARS = [0x2D, 0x2E, 0x30..0x39, 0xB7, 0x0300..0x036F, 0x203F..0x2040]
41
-
42
- attr_writer :brace_name
43
- attr_writer :bracket_name
44
- attr_writer :slash_name
45
-
46
- def initialize(source)
47
- @source = StringReader.new(source)
48
- @version = nil
49
- @brace_name = nil
50
- @bracket_name = nil
51
- @slash_name = nil
52
- @macros = {}
26
+ MARKS = {:instruction => "?", :trim => "*", :verbal => "~", :multiple => "+"}
27
+ ESCAPE_CHARS = ["&", "<", ">", "'", "\"", "{", "}", "[", "]", "/", "\\", "|", "`", "#"]
28
+ SPACE_CHARS = [0x20, 0x9, 0xD, 0xA]
29
+ VALID_FIRST_IDENTIFIER_CHARS = [
30
+ 0x3A, 0x5F,
31
+ 0x41..0x5A, 0x61..0x7A, 0xC0..0xD6, 0xD8..0xF6, 0xF8..0x2FF,
32
+ 0x370..0x37D, 0x37F..0x1FFF,
33
+ 0x200C..0x200D, 0x2070..0x218F, 0x2C00..0x2FEF,
34
+ 0x3001..0xD7FF, 0xF900..0xFDCF, 0xFDF0..0xFFFD, 0x10000..0xEFFFF
35
+ ]
36
+ VALID_MIDDLE_IDENTIFIER_CHARS = [
37
+ 0x2D, 0x2E, 0x3A, 0x5F, 0xB7,
38
+ 0x30..0x39,
39
+ 0x41..0x5A, 0x61..0x7A, 0xC0..0xD6, 0xD8..0xF6, 0xF8..0x2FF,
40
+ 0x300..0x36F,
41
+ 0x370..0x37D, 0x37F..0x1FFF,
42
+ 0x200C..0x200D, 0x2070..0x218F, 0x2C00..0x2FEF,
43
+ 0x203F..0x2040,
44
+ 0x3001..0xD7FF, 0xF900..0xFDCF, 0xFDF0..0xFFFD, 0x10000..0xEFFFF
45
+ ]
46
+
47
+ private
48
+
49
+ def parse_document
50
+ parser = Parser.build(self) do
51
+ document = Document.new
52
+ children = !parse_nodes(false)
53
+ !parse_eof
54
+ children.each do |child|
55
+ document.add(child)
56
+ end
57
+ next document
58
+ end
59
+ return parser
53
60
  end
54
61
 
55
- def parse
56
- document = Document.new
57
- children = parse_nodes
58
- children.each do |child|
59
- document.add(child)
62
+ def parse_nodes(verbal)
63
+ parser = Parser.build(self) do
64
+ parsers = [parse_text(verbal)]
65
+ unless verbal
66
+ parsers.push(parse_element, parse_line_comment, parse_block_comment)
67
+ @special_element_names.each do |kind, name|
68
+ parsers.push(parse_special_element(kind))
69
+ end
70
+ end
71
+ nodes = Nodes[]
72
+ raw_nodes = !parsers.inject(:|).many
73
+ raw_nodes.each do |raw_node|
74
+ nodes << raw_node
75
+ end
76
+ next nodes
60
77
  end
61
- return document
62
- end
63
-
64
- def parse_nodes(option = {}, in_slash = false)
65
- children = []
66
- while char = @source.read
67
- if char == TAG_START || char == MACRO_START
68
- @source.unread
69
- children.concat(parse_element)
70
- elsif @brace_name && char == BRACE_START
71
- @source.unread
72
- children << parse_brace
73
- elsif @bracket_name && char == BRACKET_START
74
- @source.unread
75
- children << parse_bracket
76
- elsif @slash_name && !in_slash && char == SLASH_START
77
- @source.unread
78
- children << parse_slash
79
- elsif char == COMMENT_DELIMITER
80
- @source.unread
81
- children << parse_comment
82
- elsif char == CONTENT_END || (@brace_name && char == BRACE_END) || (@bracket_name && char == BRACKET_END) || (@slash_name && char == SLASH_END)
83
- @source.unread
84
- break
85
- else
86
- @source.unread
87
- children << parse_text(option)
78
+ return parser
79
+ end
80
+
81
+ def parse_element
82
+ parser = Parser.build(self) do
83
+ start_char = !parse_char_any([ELEMENT_START, MACRO_START])
84
+ name = !parse_identifier
85
+ marks = !parse_marks
86
+ attributes = !parse_attributes.maybe || {}
87
+ children_list = !parse_children_list(marks.include?(:verbal))
88
+ if name == SYSTEM_INSTRUCTION_NAME
89
+ !parse_space
90
+ end
91
+ if start_char == MACRO_START
92
+ marks.push(:macro)
88
93
  end
94
+ next create_nodes(name, marks, attributes, children_list)
89
95
  end
90
- return children
96
+ return parser
91
97
  end
92
98
 
93
- def parse_verbal_nodes(option = {})
94
- children = []
95
- while char = @source.read
96
- next_char = @source.peek
97
- if char == CONTENT_END
98
- @source.unread
99
- break
100
- else
101
- @source.unread
102
- children << parse_verbal_text(option)
99
+ def parse_special_element(kind)
100
+ parser = Parser.build(self) do
101
+ unless @special_element_names[kind]
102
+ !parse_none
103
103
  end
104
+ !parse_char(SPECIAL_ELEMENT_STARTS[kind])
105
+ children = !parse_nodes(false)
106
+ !parse_char(SPECIAL_ELEMENT_ENDS[kind])
107
+ next create_nodes(@special_element_names[kind], [], {}, [children])
104
108
  end
105
- return children
109
+ return parser
106
110
  end
107
111
 
108
- def parse_element
109
- first_char = @source.read
110
- unless first_char == TAG_START || first_char == MACRO_START
111
- raise ZenithalParseError.new(@source)
112
+ def parse_marks
113
+ return parse_mark.many
114
+ end
115
+
116
+ def parse_mark
117
+ parsers = MARKS.map do |mark, query|
118
+ next parse_char(query).map{|_| mark}
112
119
  end
113
- name, option = parse_element_name
114
- if first_char == MACRO_START
115
- option[:macro] = true
120
+ return parsers.inject(:|)
121
+ end
122
+
123
+ def parse_attributes
124
+ parser = Parser.build(self) do
125
+ !parse_char(ATTRIBUTE_START)
126
+ first_attribute = !parse_attribute(false)
127
+ rest_attribtues = !parse_attribute(true).many
128
+ attributes = first_attribute.merge(*rest_attribtues)
129
+ !parse_char(ATTRIBUTE_END)
130
+ next attributes
131
+ end
132
+ return parser
133
+ end
134
+
135
+ def parse_attribute(comma)
136
+ parser = Parser.build(self) do
137
+ !parse_char(ATTRIBUTE_SEPARATOR) if comma
138
+ !parse_space
139
+ name = !parse_identifier
140
+ !parse_space
141
+ value = !parse_attribute_value.maybe || name
142
+ !parse_space
143
+ next {name => value}
144
+ end
145
+ return parser
146
+ end
147
+
148
+ def parse_attribute_value
149
+ parser = Parser.build(self) do
150
+ !parse_char(ATTRIBUTE_EQUAL)
151
+ !parse_space
152
+ value = !parse_quoted_string
153
+ next value
116
154
  end
117
- attributes = parse_attributes
118
- children_list = parse_children_list(option)
119
- nodes = create_nodes(name, attributes, children_list, option)
120
- return nodes
155
+ return parser
121
156
  end
122
157
 
123
- def parse_element_name
124
- name, marks, option = "", [], {}
125
- while char = @source.read
126
- if char == ATTRIBUTE_START || char == CONTENT_START || char == CONTENT_END || char =~ /\s/
127
- @source.unread
128
- break
129
- elsif char == INSTRUCTION_MARK || char == TRIM_MARK || char == VERBAL_MARK || char == MULTIPLE_MARK
130
- marks << char
131
- elsif name.empty? && marks.empty? && ZenithalParser.valid_start_char?(char)
132
- name << char
133
- elsif !name.empty? && marks.empty? && ZenithalParser.valid_char?(char)
134
- name << char
135
- else
136
- raise ZenithalParseError.new(@source)
137
- end
158
+ def parse_quoted_string
159
+ parser = Parser.build(self) do
160
+ !parse_char(ATTRIBUTE_VALUE_START)
161
+ texts = !(parse_quoted_string_plain | parse_escape).many
162
+ !parse_char(ATTRIBUTE_VALUE_END)
163
+ next texts.join
138
164
  end
139
- skip_spaces
140
- if marks.include?(INSTRUCTION_MARK)
141
- option[:instruction] = true
165
+ return parser
166
+ end
167
+
168
+ def parse_quoted_string_plain
169
+ parser = Parser.build(self) do
170
+ chars = !parse_char_out([ATTRIBUTE_VALUE_END, ESCAPE_START]).many(1)
171
+ next chars.join
142
172
  end
143
- if marks.include?(TRIM_MARK)
144
- option[:trim_indents] = true
173
+ return parser
174
+ end
175
+
176
+ def parse_children_list(verbal)
177
+ parser = Parser.build(self) do
178
+ first_children = !(parse_empty_children | parse_children(verbal))
179
+ rest_children_list = !parse_children(verbal).many
180
+ children_list = [first_children] + rest_children_list
181
+ next children_list
182
+ end
183
+ return parser
184
+ end
185
+
186
+ def parse_children(verbal)
187
+ parser = Parser.build(self) do
188
+ !parse_char(CONTENT_START)
189
+ children = !parse_nodes(verbal)
190
+ !parse_char(CONTENT_END)
191
+ next children
145
192
  end
146
- if marks.include?(VERBAL_MARK)
147
- option[:verbal] = true
193
+ return parser
194
+ end
195
+
196
+ def parse_empty_children
197
+ parser = Parser.build(self) do
198
+ !parse_char(CONTENT_END)
199
+ next Nodes[]
148
200
  end
149
- if marks.include?(MULTIPLE_MARK)
150
- option[:multiple] = true
201
+ return parser
202
+ end
203
+
204
+ def parse_text(verbal)
205
+ parser = Parser.build(self) do
206
+ texts = !(parse_text_plain(verbal) | parse_escape).many(1)
207
+ next Text.new(texts.join, true, nil, false)
151
208
  end
152
- return name, option
209
+ return parser
153
210
  end
154
211
 
155
- def parse_attributes
156
- attributes = {}
157
- if @source.read == ATTRIBUTE_START
158
- current_key = nil
159
- skip_spaces
160
- loop do
161
- key, value = parse_attribute
162
- attributes[key] = value
163
- char = @source.read
164
- if char == ATTRIBUTE_SEPARATOR
165
- skip_spaces
166
- elsif char == ATTRIBUTE_END
167
- @source.unread
168
- break
169
- else
170
- raise ZenithalParseError.new(@source)
212
+ def parse_text_plain(verbal)
213
+ parser = Parser.build(self) do
214
+ out_chars = [ESCAPE_START, CONTENT_END]
215
+ unless verbal
216
+ out_chars.push(ELEMENT_START, MACRO_START, CONTENT_START, COMMENT_DELIMITER)
217
+ @special_element_names.each do |kind, name|
218
+ out_chars.push(SPECIAL_ELEMENT_STARTS[kind], SPECIAL_ELEMENT_ENDS[kind]) if name
171
219
  end
172
220
  end
173
- unless @source.read == ATTRIBUTE_END
174
- raise ZenithalParseError.new(@source)
175
- end
176
- else
177
- @source.unread
221
+ chars = !parse_char_out(out_chars).many(1)
222
+ next chars.join
178
223
  end
179
- return attributes
224
+ return parser
180
225
  end
181
226
 
182
- def parse_attribute
183
- key = parse_attribute_key
184
- skip_spaces
185
- if @source.read == ATTRIBUTE_EQUAL
186
- skip_spaces
187
- value = parse_attribute_value
188
- else
189
- @source.unread
190
- value = key
227
+ def parse_line_comment
228
+ parser = Parser.build(self) do
229
+ !parse_char(COMMENT_DELIMITER)
230
+ !parse_char(COMMENT_DELIMITER)
231
+ content = !parse_line_comment_content
232
+ next Comment.new(" " + content.strip + " ")
191
233
  end
192
- skip_spaces
193
- return key, value
194
- end
195
-
196
- def parse_attribute_key
197
- key = ""
198
- while char = @source.read
199
- if char == ATTRIBUTE_EQUAL || char == ATTRIBUTE_END || char =~ /\s/
200
- @source.unread
201
- break
202
- elsif key.empty? && ZenithalParser.valid_start_char?(char)
203
- key << char
204
- elsif !key.empty? && ZenithalParser.valid_char?(char)
205
- key << char
206
- else
207
- raise ZenithalParseError.new(@source)
208
- end
234
+ return parser
235
+ end
236
+
237
+ def parse_line_comment_content
238
+ parser = Parser.build(self) do
239
+ chars = !parse_char_out(["\n"]).many
240
+ !parse_char("\n")
241
+ next chars.join
209
242
  end
210
- return key
243
+ return parser
211
244
  end
212
245
 
213
- def parse_attribute_value
214
- unless @source.read == ATTRIBUTE_VALUE_START
215
- raise ZenithalParseError.new(@source)
246
+ def parse_block_comment
247
+ parser = Parser.build(self) do
248
+ !parse_char(COMMENT_DELIMITER)
249
+ !parse_char(CONTENT_START)
250
+ content = !parse_block_comment_content
251
+ !parse_char(CONTENT_END)
252
+ !parse_char(COMMENT_DELIMITER)
253
+ next Comment.new(" " + content.strip + " ")
216
254
  end
217
- value = ""
218
- while char = @source.read
219
- next_char = @source.peek
220
- if char == ATTRIBUTE_VALUE_END
221
- break
222
- elsif char == ESCAPE_START && ESCAPES.include?(next_char)
223
- @source.unread
224
- value << parse_escape_string
225
- else
226
- value << char
227
- end
255
+ return parser
256
+ end
257
+
258
+ def parse_block_comment_content
259
+ parser = Parser.build(self) do
260
+ chars = !parse_char_out([CONTENT_END]).many
261
+ next chars.join
228
262
  end
229
- return value
230
- end
231
-
232
- def parse_children_list(option = {})
233
- children_list = []
234
- first_char = @source.read
235
- if first_char == CONTENT_START
236
- loop do
237
- children = []
238
- if option[:verbal] || option[:instruction]
239
- children = parse_verbal_nodes(option)
240
- else
241
- children = parse_nodes(option)
242
- end
243
- if option[:trim_indents]
244
- trim_indents(children)
245
- end
246
- children_list << children
247
- unless @source.read == CONTENT_END
248
- raise ZenithalParseError.new(@source)
249
- end
250
- space_count = skip_spaces
251
- unless @source.read == CONTENT_START
252
- @source.unread(space_count + 1)
253
- break
254
- end
255
- end
256
- elsif first_char == CONTENT_END
257
- children_list << []
258
- else
259
- raise ZenithalParseError.new(@source)
263
+ return parser
264
+ end
265
+
266
+ def parse_escape
267
+ parser = Parser.build(self) do
268
+ !parse_char(ESCAPE_START)
269
+ char = !parse_char_any(ESCAPE_CHARS)
270
+ next char
260
271
  end
261
- return children_list
272
+ return parser
273
+ end
274
+
275
+ def parse_identifier
276
+ parser = Parser.build(self) do
277
+ first_char = !parse_first_identifier_char
278
+ rest_chars = !parse_middle_identifier_char.many
279
+ identifier = first_char + rest_chars.join
280
+ next identifier
281
+ end
282
+ return parser
283
+ end
284
+
285
+ def parse_first_identifier_char
286
+ return parse_char_any(VALID_FIRST_IDENTIFIER_CHARS)
262
287
  end
263
288
 
264
- def create_nodes(name, attributes, children_list, option = {})
265
- nodes = []
266
- unless option[:macro]
267
- if option[:instruction]
289
+ def parse_middle_identifier_char
290
+ return parse_char_any(VALID_MIDDLE_IDENTIFIER_CHARS)
291
+ end
292
+
293
+ def parse_space
294
+ return parse_char_any(SPACE_CHARS).many
295
+ end
296
+
297
+ def create_nodes(name, marks, attributes, children_list)
298
+ nodes = Nodes[]
299
+ unless marks.include?(:macro)
300
+ if marks.include?(:trim)
301
+ children_list.each do |children|
302
+ children.trim_indents
303
+ end
304
+ end
305
+ if marks.include?(:instruction)
268
306
  unless children_list.size <= 1
269
- raise ZenithalParseError.new(@source)
307
+ throw(:error, error_message("Processing instruction cannot have more than one argument"))
270
308
  end
271
309
  nodes = create_instructions(name, attributes, children_list.first)
272
- if name == SYSTEM_INSTRUCTION_NAME
273
- skip_spaces
274
- end
275
310
  else
276
- unless option[:multiple] || children_list.size <= 1
277
- raise ZenithalParseError.new(@source)
311
+ unless marks.include?(:multiple) || children_list.size <= 1
312
+ throw(:error, error_message("Normal node cannot have more than one argument"))
278
313
  end
279
314
  nodes = create_elements(name, attributes, children_list)
280
315
  end
@@ -284,28 +319,13 @@ class ZenithalParser
284
319
  return nodes
285
320
  end
286
321
 
287
- def create_elements(name, attributes, children_list)
288
- elements = []
289
- children_list.each do |children|
290
- element = Element.new(name)
291
- attributes.each do |key, value|
292
- element.add_attribute(key, value)
293
- end
294
- children.each do |child|
295
- element.add(child)
296
- end
297
- elements << element
298
- end
299
- return elements
300
- end
301
-
302
322
  def create_instructions(target, attributes, children)
303
- instructions = []
323
+ instructions = Nodes[]
304
324
  if target == SYSTEM_INSTRUCTION_NAME
305
325
  @version = attributes["version"] if attributes["version"]
306
- @brace_name = attributes["brace"] if attributes["brace"]
307
- @bracket_name = attributes["bracket"] if attributes["bracket"]
308
- @slash_name = attributes["slash"] if attributes["slash"]
326
+ @special_element_names[:brace] = attributes["brace"] if attributes["brace"]
327
+ @special_element_names[:bracket] = attributes["bracket"] if attributes["bracket"]
328
+ @special_element_names[:slash] = attributes["slash"] if attributes["slash"]
309
329
  elsif target == "xml"
310
330
  instruction = XMLDecl.new
311
331
  instruction.version = attributes["version"] || XMLDecl::DEFAULT_VERSION
@@ -327,224 +347,78 @@ class ZenithalParser
327
347
  return instructions
328
348
  end
329
349
 
350
+ def create_elements(name, attributes, children_list)
351
+ elements = Nodes[]
352
+ children_list.each do |children|
353
+ element = Element.new(name)
354
+ attributes.each do |key, value|
355
+ element.add_attribute(key, value)
356
+ end
357
+ children.each do |child|
358
+ element.add(child)
359
+ end
360
+ elements << element
361
+ end
362
+ return elements
363
+ end
364
+
330
365
  def process_macro(name, attributes, children_list)
331
- elements = []
366
+ elements = Nodes[]
332
367
  if @macros.key?(name)
333
- elements = @macros[name].call(attributes, children_list)
334
- elsif ENTITIES.key?(name)
335
- text = Text.new(ENTITIES[name], true, nil, false)
336
- elements << text
368
+ raw_elements = @macros[name].call(attributes, children_list)
369
+ raw_elements.each do |raw_element|
370
+ elements << raw_element
371
+ end
337
372
  else
338
- raise ZenithalParseError.new(@source)
373
+ throw(:error, error_message("No such macro"))
339
374
  end
340
375
  return elements
341
376
  end
342
377
 
343
- def register_macro(name, &block)
344
- @macros.store(name, block)
378
+ def error_message(message)
379
+ return "[line #{@source.lineno}] #{message}"
345
380
  end
346
381
 
347
- def parse_brace
348
- unless @source.read == BRACE_START
349
- raise ZenithalParseError.new(@source)
350
- end
351
- children = parse_nodes
352
- unless @source.read == BRACE_END
353
- raise ZenithalParseError.new(@source)
354
- end
355
- element = Element.new(@brace_name)
356
- children.each do |child|
357
- element.add(child)
358
- end
359
- return element
360
- end
382
+ end
361
383
 
362
- def parse_bracket
363
- unless @source.read == BRACKET_START
364
- raise ZenithalParseError.new(@source)
365
- end
366
- children = parse_nodes
367
- unless @source.read == BRACKET_END
368
- raise ZenithalParseError.new(@source)
369
- end
370
- element = Element.new(@bracket_name)
371
- children.each do |child|
372
- element.add(child)
373
- end
374
- return element
375
- end
376
384
 
377
- def parse_slash
378
- unless @source.read == SLASH_START
379
- raise ZenithalParseError.new(@source)
380
- end
381
- children = parse_nodes({}, true)
382
- unless @source.read == SLASH_END
383
- raise ZenithalParseError.new(@source)
384
- end
385
- element = Element.new(@slash_name)
386
- children.each do |child|
387
- element.add(child)
388
- end
389
- return element
390
- end
385
+ class ZenithalParser
391
386
 
392
- def parse_comment
393
- unless @source.read == COMMENT_DELIMITER
394
- raise ZenithalParseError.new(@source)
395
- end
396
- char = @source.read
397
- string = ""
398
- if char == COMMENT_DELIMITER
399
- while char = @source.read
400
- if char == "\n"
401
- @source.unread
402
- break
403
- else
404
- string << char
405
- end
406
- end
407
- elsif char == CONTENT_START
408
- while char = @source.read
409
- if char == CONTENT_END
410
- next_char = @source.read
411
- if next_char == COMMENT_DELIMITER
412
- break
413
- else
414
- string << char
415
- @source.unread
416
- end
417
- else
418
- string << char
419
- end
420
- end
421
- else
422
- raise ZenithalParseError.new(@source)
423
- end
424
- comment = Comment.new(" #{string.strip} ")
425
- return comment
426
- end
427
-
428
- def parse_text(option = {})
429
- string = ""
430
- while char = @source.read
431
- next_char = @source.peek
432
- if char == TAG_START || char == MACRO_START
433
- @source.unread
434
- break
435
- elsif (@brace_name && char == BRACE_START) || (@bracket_name && char == BRACKET_START) || (@slash_name && char == SLASH_START)
436
- @source.unread
437
- break
438
- elsif char == CONTENT_END
439
- @source.unread
440
- break
441
- elsif (@brace_name && char == BRACE_END) || (@bracket_name && char == BRACKET_END) || (@slash_name && char == SLASH_END)
442
- @source.unread
443
- break
444
- elsif char == COMMENT_DELIMITER
445
- @source.unread
446
- break
447
- elsif char == ESCAPE_START && ESCAPES.include?(next_char)
448
- @source.unread
449
- string << parse_escape_string
450
- else
451
- string << char
452
- end
453
- end
454
- text = Text.new(string, true, nil, false)
455
- return text
456
- end
457
-
458
- def parse_verbal_text(option = {})
459
- string = ""
460
- while char = @source.read
461
- next_char = @source.peek
462
- if char == CONTENT_END
463
- @source.unread
464
- break
465
- elsif char == ESCAPE_START && ESCAPES.include?(next_char)
466
- @source.unread
467
- string << parse_escape_string
468
- else
469
- string << char
470
- end
471
- end
472
- text = Text.new(string, true, nil, false)
473
- return text
474
- end
387
+ include CommonParserMethod
388
+ include ZenithalParserMethod
475
389
 
476
- def parse_escape_string
477
- unless @source.read == ESCAPE_START
478
- raise ZenithalParseError.new(@source)
479
- end
480
- char = @source.read
481
- return char
482
- end
390
+ attr_reader :source
483
391
 
484
- def skip_spaces
485
- count = 0
486
- while @source.read =~ /\s/
487
- count += 1
488
- end
489
- @source.unread
490
- return count
392
+ def initialize(source)
393
+ @source = StringReader.new(source)
394
+ @version = nil
395
+ @special_element_names = {:brace => nil, :bracket => nil, :slash => nil}
396
+ @macros = {}
491
397
  end
492
398
 
493
- def trim_spaces(children)
494
- if children.first.is_a?(Text)
495
- children.first.value = children.first.value.lstrip
496
- end
497
- if children.last.is_a?(Text)
498
- children.last.value = children.last.value.rstrip
399
+ def parse
400
+ result = parse_document.exec
401
+ if result.success?
402
+ return result.value
403
+ else
404
+ raise ZenithalParseError.new(result.message)
499
405
  end
500
406
  end
501
407
 
502
- def trim_indents(children)
503
- texts = []
504
- if children.last.is_a?(Text)
505
- children.last.value = children.last.value.rstrip
506
- end
507
- children.each do |child|
508
- case child
509
- when Text
510
- texts << child
511
- when Parent
512
- texts.concat(ZenithalParser.get_all_texts(child))
513
- end
514
- end
515
- indent_length = 10000
516
- texts.each do |text|
517
- text.value.scan(/\n(\x20+)/) do |match|
518
- indent_length = [match[0].length, indent_length].min
519
- end
520
- end
521
- texts.each do |text|
522
- text.value = text.value.gsub(/\n(\x20+)/){"\n" + " " * ($1.length - indent_length)}
523
- end
524
- if children.first.is_a?(Text)
525
- children.first.value = children.first.value.lstrip
526
- end
408
+ def register_macro(name, &block)
409
+ @macros.store(name, block)
527
410
  end
528
411
 
529
- def self.valid_start_char?(char)
530
- return VALID_START_CHARS.any?{|s| s === char.ord}
412
+ def brace_name=(name)
413
+ @special_element_names[:brace] = name
531
414
  end
532
415
 
533
- def self.valid_char?(char)
534
- return VALID_START_CHARS.any?{|s| s === char.ord} || VALID_MIDDLE_CHARS.any?{|s| s === char.ord}
416
+ def bracket_name=(name)
417
+ @special_element_names[:bracket] = name
535
418
  end
536
419
 
537
- def self.get_all_texts
538
- texts = []
539
- self.children.each do |child|
540
- case child
541
- when Text
542
- texts << child
543
- when Parent
544
- texts.concat(get_all_texts(child))
545
- end
546
- end
547
- return texts
420
+ def slash_name=(name)
421
+ @special_element_names[:slash] = name
548
422
  end
549
423
 
550
424
  end