zenml 1.0.1 → 1.1.0
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/source/zenml.rb +2 -1
- data/source/zenml/error.rb +2 -3
- data/source/zenml/old_parser.rb +550 -0
- data/source/zenml/parser.rb +302 -428
- data/source/zenml/parser_utility.rb +223 -0
- data/source/zenml/reader.rb +9 -0
- data/source/zenml/utility.rb +40 -0
- metadata +4 -2
data/source/zenml/parser.rb
CHANGED
@@ -6,9 +6,9 @@ require 'rexml/document'
|
|
6
6
|
include REXML
|
7
7
|
|
8
8
|
|
9
|
-
|
9
|
+
module ZenithalParserMethod
|
10
10
|
|
11
|
-
|
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
|
-
|
23
|
-
|
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
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
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
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
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
|
62
|
-
end
|
63
|
-
|
64
|
-
def
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
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
|
96
|
+
return parser
|
91
97
|
end
|
92
98
|
|
93
|
-
def
|
94
|
-
|
95
|
-
|
96
|
-
|
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
|
109
|
+
return parser
|
106
110
|
end
|
107
111
|
|
108
|
-
def
|
109
|
-
|
110
|
-
|
111
|
-
|
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
|
-
|
114
|
-
|
115
|
-
|
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
|
-
|
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
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
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
|
-
|
140
|
-
|
141
|
-
|
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
|
-
|
144
|
-
|
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
|
-
|
147
|
-
|
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
|
-
|
150
|
-
|
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
|
209
|
+
return parser
|
153
210
|
end
|
154
211
|
|
155
|
-
def
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
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
|
-
|
174
|
-
|
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
|
224
|
+
return parser
|
180
225
|
end
|
181
226
|
|
182
|
-
def
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
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
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
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
|
243
|
+
return parser
|
211
244
|
end
|
212
245
|
|
213
|
-
def
|
214
|
-
|
215
|
-
|
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
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
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
|
230
|
-
end
|
231
|
-
|
232
|
-
def
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
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
|
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
|
265
|
-
|
266
|
-
|
267
|
-
|
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
|
-
|
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
|
277
|
-
|
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
|
-
@
|
307
|
-
@
|
308
|
-
@
|
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
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
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
|
-
|
373
|
+
throw(:error, error_message("No such macro"))
|
339
374
|
end
|
340
375
|
return elements
|
341
376
|
end
|
342
377
|
|
343
|
-
def
|
344
|
-
@
|
378
|
+
def error_message(message)
|
379
|
+
return "[line #{@source.lineno}] #{message}"
|
345
380
|
end
|
346
381
|
|
347
|
-
|
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
|
-
|
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
|
-
|
393
|
-
|
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
|
-
|
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
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
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
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
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
|
503
|
-
|
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
|
530
|
-
|
412
|
+
def brace_name=(name)
|
413
|
+
@special_element_names[:brace] = name
|
531
414
|
end
|
532
415
|
|
533
|
-
def
|
534
|
-
|
416
|
+
def bracket_name=(name)
|
417
|
+
@special_element_names[:bracket] = name
|
535
418
|
end
|
536
419
|
|
537
|
-
def
|
538
|
-
|
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
|