/[suikacvs]/markup/html/whatpm/Whatpm/SWML/Parser.pm
Suika

Contents of /markup/html/whatpm/Whatpm/SWML/Parser.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.3 - (show annotations) (download)
Thu Nov 6 13:29:14 2008 UTC (17 years, 11 months ago) by wakaba
Branch: MAIN
Changes since 1.2: +49 -47 lines
++ whatpm/Whatpm/SWML/ChangeLog	6 Nov 2008 13:28:54 -0000
	* Parser.pm: Multiple |rt| elements in a |ruby| element was not
	allowed.  Don't use \s where SWML's definition of white space is
	required.  "The head element" definition was wrong.  Typo fixed.
	List algorithm bug fixed.

2008-11-06  Wakaba  <wakaba@suika.fam.cx>

1 package Whatpm::SWML::Parser;
2 use strict;
3
4 sub AA_NS () { q<http://pc5.2ch.net/test/read.cgi/hp/1096723178/aavocab#> }
5 sub HTML_NS () { q<http://www.w3.org/1999/xhtml> }
6 sub SW09_NS () { q<urn:x-suika-fam-cx:markup:suikawiki:0:9:> }
7 sub SW10_NS () { q<urn:x-suika-fam-cx:markup:suikawiki:0:10:> }
8 sub XML_NS () { q<http://www.w3.org/XML/1998/namespace> }
9
10 sub IN_SECTION_IM () { 0 }
11 sub IN_TABLE_ROW_IM () { 1 }
12 sub IN_PARAGRAPH_IM () { 2 }
13
14 sub BLOCK_START_TAG_TOKEN () { 1 }
15 sub BLOCK_END_TAG_TOKEN () { 2 }
16 sub CHARACTER_TOKEN () { 3 }
17 sub COMMENT_PARAGRAPH_START_TOKEN () { 4 }
18 sub EDITORIAL_NOTE_START_TOKEN () { 5 }
19 sub ELEMENT_TOKEN () { 6 }
20 sub EMPHASIS_TOKEN () { 7 }
21 sub EMPTY_LINE_TOKEN () { 8 }
22 sub END_OF_FILE_TOKEN () { 9 }
23 sub FORM_TOKEN () { 10 }
24 sub HEADING_START_TOKEN () { 11 }
25 sub HEADING_END_TOKEN () { 12 }
26 sub INLINE_START_TAG_TOKEN () { 13 }
27 sub INLINE_MIDDLE_TAG_TOKEN () { 14 }
28 sub INLINE_END_TAG_TOKEN () { 15 }
29 sub LABELED_LIST_START_TOKEN () { 16 }
30 sub LABELED_LIST_MIDDLE_TOKEN () { 17 }
31 sub LIST_START_TOKEN () { 18 }
32 sub PREFORMATTED_START_TOKEN () { 19 }
33 sub PREFORMATTED_END_TOKEN () { 20 }
34 sub QUOTATION_START_TOKEN () { 21 }
35 sub STRONG_TOKEN () { 22 }
36 sub TABLE_ROW_START_TOKEN () { 23 }
37 sub TABLE_ROW_END_TOKEN () { 24 }
38 sub TABLE_CELL_START_TOKEN () { 25 }
39 sub TABLE_CELL_END_TOKEN () { 26 }
40 sub TABLE_COLSPAN_CELL_TOKEN () { 27 }
41
42 sub new ($) {
43 my $self = bless {
44 }, $_[0];
45 return $self;
46 } # new
47
48 sub parse_char_string ($$$;$) {
49 my $self = shift;
50 my @s = split /\x0D\x0A?|\x0A/, ref $_[0] ? ${$_[0]} : $_[0], -1;
51
52 my $doc = $_[1];
53 $doc->inner_html
54 ('<html xmlns="http://www.w3.org/1999/xhtml"><head/><body/></html>');
55 for ($doc,
56 $doc->document_element,
57 $doc->document_element->first_child,
58 $doc->document_element->last_child) {
59 $_->set_user_data (manakai_source_line => 1);
60 $_->set_user_data (manakai_source_column => 1);
61 }
62
63 my $_onerror = $_[2] || sub {
64 my %opt = @_;
65 my $r = 'Line ' . $opt{line} . ' column ' . $opt{column} . ': ';
66
67 if ($opt{token}) {
68 $r .= 'Token ' . (defined $opt{token}->{value}
69 ? $opt{token}->{value} : $opt{token}->{type}) . ': ';
70 }
71
72 $r .= $opt{type} . ';' . $opt{level};
73
74 warn $r . "\n";
75 }; # $_onerror
76
77 my $line = 0;
78 my $column = 0;
79 my $token;
80 my @nt;
81
82 my $onerror = sub {
83 $_onerror->(line => $line, column => $column, token => $token, @_);
84 }; # $onerror
85
86 my $continuous_line;
87
88 my $tokenize_text = sub {
89 my $s = shift; # ref
90
91 if ($$s =~ s/^\[([0-9]+)\]//) {
92 push @nt, {type => ELEMENT_TOKEN,
93 local_name => 'anchor-end', namespace => SW09_NS,
94 anchor => $1, content => '[' . $1 . ']'};
95 $column += $+[0] - $-[0];
96 }
97
98 while (length $$s) {
99 if ($$s =~ s/^\[\[#([a-z-]+)//) {
100 $column = $+[0] - $-[0];
101 my $t = {type => FORM_TOKEN, name => $1,
102 line => $line, column => $column};
103 if ($$s =~ s/^\(([^()\\]*)\)//) {
104 $t->{id} = $1;
105 $column += $+[0] - $-[0];
106 }
107 my @param;
108 while ($$s =~ s/^://) {
109 if ($$s =~ s/^'((?>[^'\\]|\\.)*)//) {
110 $column += 1 + $+[0] - $-[0];
111 my $n = $1;
112 $n =~ tr/\\//d;
113 push @param, $n;
114 $column++ if $$s =~ s/\A\\\z//;
115 $column++ if $$s =~ s/^'//;
116 } elsif ($$s =~ s/^([^':][^:]*)//) {
117 $column += 1 + $+[0] - $-[0];
118 push @param, $1;
119 }
120 }
121 $t->{parameters} = \@param;
122 $column += 2 if $$s =~ s/^\]\]//;
123 push @nt, $t;
124 } elsif ($$s =~ s/^\[\[//) {
125 push @nt, {type => INLINE_START_TAG_TOKEN};
126 $column += 2;
127 } elsif ($$s =~ s/^\[([A-Z]+)(?>\(([^()\\]*)\))?(?>\@[0-9A-Za-z-]*)?\[//) {
128 push @nt, {type => INLINE_START_TAG_TOKEN,
129 tag_name => $1, classes => $2, language => $3,
130 line => $line, column => $column};
131 $column += $+[0] - $-[0];
132 } elsif ($$s =~ s/^\]\]//) {
133 push @nt, {type => INLINE_END_TAG_TOKEN,
134 line => $line, column => $column};
135 $column += 2;
136 } elsif ($$s =~ s/^(\]?)<([0-9A-Za-z%+._-]+)://) {
137 my $t = {type => $1 ? INLINE_END_TAG_TOKEN : ELEMENT_TOKEN,
138 res_scheme => $2, res_parameter => '',
139 line => $line, column => $column};
140 $column += $+[0] - $-[0];
141
142 while (length $$s) {
143 if ($$s =~ s/^([^>"]+)//) {
144 $t->{res_parameter} .= $1;
145 $column += $+[0] - $-[0];
146 } elsif ($$s =~ s/^("(?>[^"\\]|\\.)*)//) {
147 $t->{res_parameter} .= $1;
148 $column += $+[0] - $-[0];
149 $column++ if $$s =~ s/\A\\\z//;
150 $column++ if $$s =~ s/^"//;
151 } else {
152 last;
153 }
154 }
155
156 $column++ if $$s =~ s/^>//;
157
158 $t->{content} = $t->{res_scheme} . ':' . $t->{res_parameter};
159 if ($t->{res_scheme} !~ /[A-Z]/) {
160 $t->{res_parameter} = $t->{content};
161 $t->{res_scheme} = 'URI';
162 }
163
164 if ($t->{type} == INLINE_END_TAG_TOKEN) {
165 $column++ if $$s =~ s/^\]//;
166 } else {
167 $t->{local_name} = 'anchor-external';
168 $t->{namespace} = SW09_NS;
169 }
170 push @nt, $t;
171 } elsif ($$s =~ s/^\]>>([0-9]+)\]//) {
172 push @nt, {type => INLINE_END_TAG_TOKEN,
173 anchor => $1,
174 line => $line, column => $column};
175 $column += $+[0] - $-[0];
176 } elsif ($$s =~ s/^\][\x09\x20]*(?>\@([0-9a-zA-Z-]*))?\[//) {
177 push @nt, {type => INLINE_MIDDLE_TAG_TOKEN,
178 language => $1,
179 line => $line, column => $column};
180 $column += $+[0] - $-[0];
181 } elsif ($$s =~ s/\^''('?)//) {
182 push @nt, {type => $1 ? STRONG_TOKEN : EMPHASIS_TOKEN,
183 line => $line, column => $column};
184 $column += $+[0] - $-[0];
185 } elsif ($$s =~ s/^>>([0-9]+)//) {
186 push @nt, {type => ELEMENT_TOKEN,
187 local_name => 'anchor-internal', namespace => SW09_NS,
188 anchor => $1,
189 line => $line, column => $column};
190 $column += $+[0] - $-[0];
191 } elsif ($$s =~ s/^__&&//) {
192 if ($$s =~ s/^(.+?)&&__//) {
193 push @nt, {type => ELEMENT_TOKEN,
194 local_name => 'replace', namespace => SW09_NS,
195 by => $1,
196 line => $line, column => $column};
197 $column += 4 + $+[0] - $-[0];
198 } else {
199 push @nt, {type => CHARACTER_TOKEN,
200 data => '__&&',
201 line => $line, column => $column};
202 $column += 4;
203 }
204 } elsif ($$s =~ s/^([^<>\['_]+)//) {
205 push @nt, {type => CHARACTER_TOKEN, data => $1,
206 line => $line, column => $column};
207 $column += $+[0] - $-[0];
208 } else {
209 push @nt, {type => CHARACTER_TOKEN, data => substr ($$s, 0, 1),
210 line => $line, column => $column};
211 substr ($$s, 0, 1) = '';
212 $column++;
213 }
214 }
215 }; # $tokenize_text
216
217 my $get_next_token = sub {
218 if (@nt) {
219 return shift @nt;
220 }
221
222 if (not @s) {
223 return {type => END_OF_FILE_TOKEN, line => $line, column => $column};
224 }
225
226 my $s = shift @s;
227 ($line, $column) = ($line + 1, 1);
228 if ($s eq '') {
229 undef $continuous_line;
230 return {type => EMPTY_LINE_TOKEN, line => $line, column => $column};
231 } elsif ($s =~ /^[\x09\x20]/) {
232 push @nt, {type => PREFORMATTED_START_TOKEN,
233 line => $line, column => $column};
234 $tokenize_text->(\$s);
235 while (@s) {
236 my $s = shift @s;
237 ($line, $column) = ($line + 1, 1);
238 if ($s eq '') {
239 push @nt, {type => PREFORMATTED_END_TOKEN,
240 line => $line, column => $column};
241 unshift @s, $s;
242 $line--;
243 last;
244 } elsif ($s =~ /\A\](INS|DEL)\][\x09\x20]*\z/) {
245 push @nt, {type => PREFORMATTED_END_TOKEN,
246 line => $line, column => $column};
247 push @nt, {type => BLOCK_END_TAG_TOKEN, tag_name => $1,
248 line => $line, column => $column};
249 last;
250 } else {
251 push @nt, {type => CHARACTER_TOKEN, data => "\x0A",
252 line => $line, column => $column};
253 $tokenize_text->(\$s);
254 }
255 }
256 return shift @nt;
257 } elsif ($s =~ s/^(\*+)[\x09\x20]*//) {
258 push @nt, {type => HEADING_START_TOKEN, depth => length $1,
259 line => $line, column => $column};
260 $column += $+[0] - $-[0];
261 $tokenize_text->(\$s);
262 push @nt, {type => HEADING_END_TOKEN,
263 line => $line, column => $column};
264 undef $continuous_line;
265 return shift @nt;
266 } elsif ($s =~ s/^([-=]+)[\x09\x20]*//) {
267 push @nt, {type => LIST_START_TOKEN, depth => $1,
268 line => $line, column => $column};
269 $column += $+[0] - $-[0];
270 $tokenize_text->(\$s);
271 $continuous_line = 1;
272 return shift @nt;
273 } elsif ($s =~ s/^:([^:]*)//) {
274 my $name = $1;
275 if ($s eq '') {
276 push @nt, {type => CHARACTER_TOKEN, data => ':',
277 line => $line, column => $column};
278 $column++;
279 $tokenize_text->(\$name);
280 } else {
281 my $real_column = $column + 1 + length $name;
282 push @nt, {type => LABELED_LIST_START_TOKEN,
283 line => $line, column => $column};
284 $name =~ s/\A[\x09\x20]*//;
285 $column += 1 + $+[0] - $-[0];
286 $name =~ s/[\x09\x20]+\z//;
287 $tokenize_text->(\$s);
288 $column = $real_column;
289 push @nt, {type => LABELED_LIST_MIDDLE_TOKEN,
290 line => $line, column => $column};
291 $column += $+[0] - $-[0] if $s =~ s/^:[\x09\x20]*//;
292 $tokenize_text->(\$s);
293 }
294 $continuous_line = 1;
295 return shift @nt;
296 } elsif ($s =~ s/^(>+)//) {
297 my $depth = length $1;
298 if ($depth == 2 and $s =~ /^[0-9]/) {
299 push @nt, {type => CHARACTER_TOKEN, data => "\x0A",
300 line => $line, column => $column}
301 if $continuous_line;
302 $s = '>>' . $s;
303 $tokenize_text->(\$s);
304 } else {
305 push @nt, {type => QUOTATION_START_TOKEN, depth => $depth,
306 line => $line, column => $column};
307 $column += $depth;
308 $column += $+[0] - $-[0] if $s =~ s/^[\x09\x20]+//;
309 if ($s =~ s/^\@\@[\x09\x20]*//) {
310 push @nt, {type => EDITORIAL_NOTE_START_TOKEN,
311 line => $line, column => $column};
312 $column += $+[0] - $-[0];
313 } elsif ($s =~ s/^;;[\x09\x20]*//) {
314 push @nt, {type => COMMENT_PARAGRAPH_START_TOKEN,
315 line => $line, column => $column};
316 $column += $+[0] - $-[0];
317 }
318 $tokenize_text->(\$s);
319 }
320 $continuous_line = 1;
321 return shift @nt;
322 } elsif ($s =~ /\A\[(INS|DEL)(?>\(([^()\\]*)\))?\[[\x09\x20]*\z/) {
323 undef $continuous_line;
324 return {type => BLOCK_START_TAG_TOKEN, tag_name => $1,
325 classes => $2,
326 line => $line, column => $column};
327 } elsif ($s =~ /\A\[PRE(?>\(([^()\\]*)\))?\[[\x09\x20]*\z/) {
328 undef $continuous_line;
329 push @nt, {type => BLOCK_START_TAG_TOKEN, tag_name => 'PRE',
330 classes => $1,
331 line => $line, column => $column};
332 while (@s) {
333 my $s = shift @s;
334 ($line, $column) = ($line + 1, 1);
335 if ($s =~ /\A\]PRE\][\x09\x20]*\z/) {
336 push @nt, {type => BLOCK_END_TAG_TOKEN, tag_name => 'PRE',
337 line => $line, column => $column};
338 undef $continuous_line;
339 last;
340 } else {
341 push @nt, {type => CHARACTER_TOKEN, data => "\x0A",
342 line => $line, column => $column}
343 if $continuous_line;
344 $tokenize_text->(\$s);
345 $continuous_line = 1;
346 }
347 }
348 return shift @nt;
349 } elsif ($s =~ s/^\@\@[\x09\x20]*//) {
350 push @nt, {type => EDITORIAL_NOTE_START_TOKEN,
351 line => $line, column => $column};
352 $column += $+[0] - $-[0];
353 $tokenize_text->(\$s);
354 $continuous_line = 1;
355 return shift @nt;
356 } elsif ($s =~ s/^;;[\x09\x20]*//) {
357 push @nt, {type => COMMENT_PARAGRAPH_START_TOKEN,
358 line => $line, column => $column};
359 $column += $+[0] - $-[0];
360 $tokenize_text->(\$s);
361 undef $continuous_line;
362 return shift @nt;
363 } elsif ($s =~ /\A\](INS|DEL)\][\x09\x20]*\z/) {
364 $continuous_line = 1;
365 return {type => BLOCK_END_TAG_TOKEN, tag_name => $1,
366 line => $line, column => $column};
367 } elsif ($s =~ /^,/) {
368 push @nt, {type => TABLE_ROW_START_TOKEN,
369 line => $line, column => $column};
370 while ($s =~ s/^,[\x09\x20]*//) {
371 $column += $+[0] - $-[0];
372 my $cell;
373 my $cell_quoted;
374 my $column_quoted = $column;
375 my $column_cell = $column;
376 if ($s =~ s/^"//) {
377 $s =~ s/^((?>[^"\\]|\\.)*)//;
378 $cell_quoted = $1;
379 $column += 1 + length $cell_quoted;
380 $cell_quoted =~ tr/\\//d;
381 $column++ if $s =~ s/\A\\\z//;
382 $column++ if $s =~ s/^"//;
383 }
384 if ($s =~ s/^([^,]+)//) {
385 $cell = $1;
386 $column += length $cell;
387 $cell =~ s/[\x09\x20]+\z//;
388 }
389 if (not defined $cell_quoted and defined $cell and
390 $cell eq '==') {
391 push @nt, {type => TABLE_COLSPAN_CELL_TOKEN,
392 line => $line, column => $column_cell};
393 } else {
394 push @nt, {type => TABLE_CELL_START_TOKEN,
395 line => $line,
396 column => defined $column_quoted ? $column_quoted: $column_cell};
397 my $real_column = $column;
398 $column = $column_quoted + 1;
399 $tokenize_text->(\$cell_quoted) if defined $cell_quoted;
400 ## NOTE: When a quoted-pair is used, column numbers
401 ## reported in this $tokenize_text call might be wrong.
402 $column = $column_cell;
403 $tokenize_text->(\$cell) if defined $cell;
404 $column = $column_quoted;
405 push @nt, {type => TABLE_CELL_END_TOKEN,
406 line => $line,
407 column => $column};
408 }
409 }
410 push @nt, {type => TABLE_ROW_END_TOKEN,
411 line => $line, column => $column};
412 undef $continuous_line;
413 return shift @nt;
414 } elsif ($s eq '__IMAGE__') {
415 my $image = $doc->create_element_ns (SW09_NS, 'image');
416 $image->set_user_data (manakai_source_line => $line);
417 $image->set_user_data (manakai_source_column => 1);
418 $image->text_content (join "\x0A", $s, @s);
419 ($line, $column) = ($line + @s, 1);
420 @s = ();
421 $doc->document_element->append_child ($image);
422 return {type => END_OF_FILE_TOKEN,
423 line => $line, column => $column};
424 } else {
425 push @nt, {type => CHARACTER_TOKEN, data => "\x0A",
426 line => $line, column => $column} if $continuous_line;
427 $tokenize_text->(\$s);
428 $continuous_line = 1;
429 return shift @nt;
430 }
431 }; # $get_next_token
432
433 ## NOTE: The "initial" mode.
434 if (@s and $s[0] =~ /^#\?/) {
435 ## NOTE: "Parse a magic line".
436
437 my $s = shift @s;
438 if ($s =~ s/^([^\x09\x20]+)//) {
439 $column += $+[0] - $-[0];
440 my ($name, $version) = split m#/#, $1, 2;
441 my $el = $doc->document_element;
442 $el->set_attribute_ns (SW09_NS, 'sw:Name' => $name);
443 $el->set_attribute_ns (SW09_NS, 'sw:Version' => $version)
444 if defined $version;
445 }
446
447 my $head = $doc->first_child->first_child;
448 while (length $s) {
449 $column += $+[0] - $-[0] if $s =~ s/^[\x09\x20]+//;
450 my $name = '';
451 if ($s =~ s/^([^=]*)=//) {
452 $name = $1;
453 $column += length $name + 1;
454 }
455 my $param = $doc->create_element_ns (SW09_NS, 'parameter');
456 $param->set_attribute (name => $name);
457 $param->set_user_data (manakai_source_line => $line);
458 $param->set_user_data (manakai_source_column => $column);
459 $head->append_child ($param);
460
461 $column++ if $s =~ s/^"//;
462 if ($s =~ s/^([^"]+)//) {
463 my $values = $1;
464 $column += length $values;
465 $values =~ tr/\\//d;
466 for (split /,/, $values, -1) {
467 my $value = $doc->create_element_ns (SW09_NS, 'value');
468 $value->text_content ($_);
469 $value->set_user_data (manakai_source_line => $line);
470 $value->set_user_data (manakai_source_column => $column);
471 $param->append_child ($value);
472 }
473 }
474 $column++ if $s =~ s/^"//;
475 }
476
477 $line = 2;
478 $column = 1;
479 }
480
481 ## NOTE: Switched to the "body" mode.
482
483 my $oe = [{node => $doc->document_element->last_child,
484 section_depth => 0,
485 quotation_depth => 0,
486 list_depth => 0}];
487 my $structural_elements = {
488 body => 1, section => 1, insert => 1, delete => 1, blockquote => 1,
489 h1 => 1, ul => 1, ol => 1, dl => 1, li => 1, dt => 1, dd => 1,
490 table => 1, tbody => 1, tr => 1, td => 1, p => 1, 'comment-p' => 1,
491 ed => 1, pre => 1,
492 };
493
494 my $im = IN_SECTION_IM;
495 $token = $get_next_token->();
496
497 A: {
498 if ($im == IN_PARAGRAPH_IM) {
499 if ($token->{type} == CHARACTER_TOKEN) {
500 $oe->[-1]->{node}->manakai_append_text ($token->{data});
501 $token = $get_next_token->();
502 redo A;
503 } elsif ($token->{type} == INLINE_START_TAG_TOKEN) {
504 if (not defined $token->{tag_name}) {
505 my $el = $doc->create_element_ns (SW09_NS, 'anchor');
506 $oe->[-1]->{node}->append_child ($el);
507 push @$oe, {%{$oe->[-1]}, node => $el};
508 $el->set_user_data (manakai_source_line => $token->{line});
509 $el->set_user_data (manakai_source_column => $token->{column});
510
511 $token = $get_next_token->();
512 redo A;
513 } else {
514 my $type = {
515 AA => [AA_NS, 'aa'],
516 ABBR => [HTML_NS, 'abbr'],
517 CITE => [HTML_NS, 'cite'],
518 CODE => [HTML_NS, 'code'],
519 CSECTION => [SW10_NS, 'csection'],
520 DEL => [HTML_NS, 'del'],
521 DFN => [HTML_NS, 'dfn'],
522 INS => [HTML_NS, 'ins'],
523 KBD => [HTML_NS, 'kbd'],
524 KEY => [SW10_NS, 'key'],
525 Q => [HTML_NS, 'q'],
526 QN => [SW10_NS, 'qn'],
527 RUBY => [HTML_NS, 'ruby'],
528 RUBYB => [HTML_NS, 'rubyb'],
529 SAMP => [HTML_NS, 'samp'],
530 SPAN => [HTML_NS, 'span'],
531 SRC => [SW10_NS, 'src'],
532 SUB => [HTML_NS, 'sub'],
533 SUP => [HTML_NS, 'sup'],
534 TIME => [HTML_NS, 'time'],
535 VAR => [HTML_NS, 'var'],
536 WEAK => [SW09_NS, 'weak'],
537 }->{$token->{tag_name}} || [SW10_NS, $token->{tag_name}];
538 my $el = $doc->create_element_ns (SW10_NS, 'td');
539 $oe->[-1]->{node}->append_child ($el);
540 push @$oe, {%{$oe->[-1]}, node => $el};
541 $el->set_user_data (manakai_source_line => $token->{line});
542 $el->set_user_data (manakai_source_column => $token->{column});
543
544 $el->set_attribute (class => $token->{classes})
545 if defined $token->{classes};
546 $el->set_attribute_ns (XML_NS, 'xml:lang' => $token->{language})
547 if defined $token->{language};
548
549 $token = $get_next_token->();
550 redo A;
551 }
552 } elsif ($token->{type} == INLINE_MIDDLE_TAG_TOKEN) {
553 my ($ns, $ln, $pop) = @{{
554 rt => [HTML_NS, 'rt', 1],
555 title => [SW10_NS, 'attrvalue', 1],
556 nsuri => [SW10_NS, 'attrvalue', 1],
557 qn => [SW10_NS, 'nsuri'],
558 ruby => [HTML_NS, 'rt'],
559 rubyb => [HTML_NS, 'rt'],
560 }->{$oe->[-1]->{node}->manakai_local_name} || [SW10_NS, 'title']};
561 pop @$oe if $pop;
562
563 my $el = $doc->create_element_ns ($ns, $ln);
564 $oe->[-1]->{node}->append_child ($el);
565 push @$oe, {%{$oe->[-1]}, node => $el};
566 $el->set_user_data (manakai_source_line => $token->{line});
567 $el->set_user_data (manakai_source_column => $token->{column});
568
569 $el->set_attribute_ns (XML_NS, 'xml:lang' => $token->{language})
570 if defined $token->{language};
571
572 $token = $get_next_token->();
573 redo A;
574 } elsif ($token->{type} == INLINE_END_TAG_TOKEN) {
575 pop @$oe if {
576 rt => 1, title => 1, nsuri => 1, attrvalue => 1,
577 }->{$oe->[-1]->{node}->manakai_local_name};
578
579 if ({%$structural_elements,
580 strong => 1, em => 1}->{$oe->[-1]->{node}->manakai_local_name}) {
581 my $el = $doc->create_element_ns
582 (SW09_NS,
583 defined $token->{res_scheme}
584 ? 'anchor-external' : 'anchor-internal');
585 $oe->[-1]->{node}->append_child ($el);
586 push @$oe, {%{$oe->[-1]}, node => $el};
587 $el->set_user_data (manakai_source_line => $token->{line});
588 $el->set_user_data (manakai_source_column => $token->{column});
589 $el->text_content (']]');
590 }
591
592 $oe->[-1]->{node}->set_attribute_ns (SW09_NS, 'sw:anchor',
593 $token->{anchor})
594 if defined $token->{anchor};
595 $oe->[-1]->{node}->set_attribute_ns (SW09_NS, 'sw:resScheme',
596 $token->{res_scheme})
597 if defined $token->{res_scheme};
598 $oe->[-1]->{node}->set_attribute_ns (SW09_NS, 'sw:resParameter',
599 $token->{res_parameter})
600 if defined $token->{res_parameter};
601
602 pop @$oe;
603
604 $token = $get_next_token->();
605 redo A;
606 } elsif ($token->{type} == STRONG_TOKEN) {
607 my $el = $doc->create_element_ns (HTML_NS, 'strong');
608 $oe->[-1]->{node}->append_child ($el);
609 push @$oe, {%{$oe->[-1]}, node => $el};
610 $el->set_user_data (manakai_source_line => $token->{line});
611 $el->set_user_data (manakai_source_column => $token->{column});
612
613 $token = $get_next_token->();
614 redo A;
615 } elsif ($token->{type} == EMPHASIS_TOKEN) {
616 my $el = $doc->create_element_ns (HTML_NS, 'em');
617 $oe->[-1]->{node}->append_child ($el);
618 push @$oe, {%{$oe->[-1]}, node => $el};
619 $el->set_user_data (manakai_source_line => $token->{line});
620 $el->set_user_data (manakai_source_column => $token->{column});
621
622 $token = $get_next_token->();
623 redo A;
624 } elsif ($token->{type} == FORM_TOKEN) {
625 ## There is an exact code clone.
626 if ($token->{name} eq 'form') {
627 my $el = $doc->create_element_ns (SW09_NS, 'form');
628 $oe->[-1]->{node}->append_child ($el);
629 push @$oe, {%{$oe->[-1]}, node => $el};
630 $el->set_user_data (manakai_source_line => $token->{line});
631 $el->set_user_data (manakai_source_column => $token->{column});
632
633 $el->set_attribute (id => $token->{id}) if defined $token->{id};
634 $el->set_attribute (input => shift @{$token->{parameters}})
635 if @{$token->{parameter}};
636 $el->set_attribute (template => shift @{$token->{parameters}})
637 if @{$token->{parameter}};
638 $el->set_attribute (option => shift @{$token->{parameters}})
639 if @{$token->{parameter}};
640 $el->set_attribute (parameter => join ':', @{$token->{parameters}})
641 if @{$token->{parameter}};
642
643 $token = $get_next_token->();
644 redo A;
645 } else {
646 my $el = $doc->create_element_ns (SW09_NS, 'form');
647 $oe->[-1]->{node}->append_child ($el);
648 push @$oe, {%{$oe->[-1]}, node => $el};
649 $el->set_user_data (manakai_source_line => $token->{line});
650 $el->set_user_data (manakai_source_column => $token->{column});
651
652 $el->set_attribute (ref => $token->{name});
653 $el->set_attribute (id => $token->{id}) if defined $token->{id};
654 $el->set_attribute (parameter => join ':', @{$token->{parameters}})
655 if @{$token->{parameter}};
656
657 $token = $get_next_token->();
658 redo A;
659 }
660 } elsif ($token->{type} == ELEMENT_TOKEN) {
661 ## NOTE: There is an exact code clone.
662 my $el = $doc->create_element_ns
663 ($token->{namespace}, $token->{local_name});
664 $oe->[-1]->{node}->append_child ($el);
665 push @$oe, {%{$oe->[-1]}, node => $el};
666 $el->set_user_data (manakai_source_line => $token->{line});
667 $el->set_user_data (manakai_source_column => $token->{column});
668
669 $el->set_attribute_ns (SW09_NS, 'sw:anchor', $token->{anchor})
670 if defined $token->{anchor};
671 $el->set_attribute (by => $token->{by}) if defined $token->{by};
672 $el->set_attribute_ns (SW09_NS, 'sw:resScheme', $token->{res_scheme})
673 if defined $token->{res_scheme};
674 $el->set_attribute_ns (SW09_NS, 'sw:resParameter',
675 $token->{res_parameter})
676 if defined $token->{res_parameter};
677 $el->text_content ($token->{content}) if defined $token->{content};
678
679 $token = $get_next_token->();
680 redo A;
681 } elsif ($token->{type} == LABELED_LIST_MIDDLE_TOKEN) {
682 pop @$oe while not $structural_elements
683 ->{$oe->[-1]->{node}->manakai_local_name};
684 pop @$oe if $oe->[-1]->{node}->manakai_local_name eq 'dt';
685
686 my $el = $doc->create_element_ns (HTML_NS, 'dt');
687 $oe->[-1]->{node}->append_child ($el);
688 push @$oe, {%{$oe->[-1]}, node => $el};
689 $el->set_user_data (manakai_source_line => $token->{line});
690 $el->set_user_data (manakai_source_column => $token->{column});
691
692 $token = $get_next_token->();
693 redo A;
694 } elsif ($token->{type} == HEADING_END_TOKEN) {
695 pop @$oe while not $structural_elements
696 ->{$oe->[-1]->{node}->manakai_local_name};
697 pop @$oe if $oe->[-1]->{node}->manakai_local_name eq 'h1';
698
699 $im = IN_SECTION_IM;
700 $token = $get_next_token->();
701 redo A;
702 } elsif ($token->{type} == TABLE_CELL_END_TOKEN) {
703 pop @$oe while not $structural_elements
704 ->{$oe->[-1]->{node}->manakai_local_name};
705 pop @$oe if $oe->[-1]->{node}->manakai_local_name eq 'td';
706
707 $im = IN_TABLE_ROW_IM;
708 $token = $get_next_token->();
709 redo A;
710 } elsif (($token->{type} == BLOCK_END_TAG_TOKEN and
711 $token->{tag_name} eq 'PRE') or
712 $token->{type} == PREFORMATTED_END_TOKEN) {
713 pop @$oe while not $structural_elements
714 ->{$oe->[-1]->{node}->manakai_local_name};
715 pop @$oe if $oe->[-1]->{node}->manakai_local_name eq 'pre';
716
717 $im = IN_SECTION_IM;
718 $token = $get_next_token->();
719 redo A;
720 } else {
721 pop @$oe while not $structural_elements
722 ->{$oe->[-1]->{node}->manakai_local_name};
723
724 $im = IN_SECTION_IM;
725 ## Reconsume.
726 redo A;
727 }
728 } elsif ($im == IN_SECTION_IM) {
729 if ($token->{type} == HEADING_START_TOKEN) {
730 B: {
731 pop @$oe and redo B
732 if not {body => 1, section => 1, insert => 1, delete => 1}
733 ->{$oe->[-1]->{node}->manakai_local_name} or
734 $token->{depth} <= $oe->[-1]->{section_depth};
735 if ($token->{depth} > $oe->[-1]->{section_depth} + 1) {
736 my $el = $doc->create_element_ns (HTML_NS, 'section');
737 $oe->[-1]->{node}->append_child ($el);
738 push @$oe, {node => $el,
739 section_depth => $oe->[-1]->{section_depth} + 1,
740 quotation_depth => 0, list_depth => 0};
741 redo B;
742 }
743 } # B
744
745 my $el = $doc->create_element_ns (HTML_NS, 'section');
746 $oe->[-1]->{node}->append_child ($el);
747 push @$oe, {node => $el,
748 section_depth => $oe->[-1]->{section_depth} + 1,
749 quotation_depth => 0, list_depth => 0};
750
751 my $el2 = $doc->create_element_ns (HTML_NS, 'h1');
752 $oe->[-1]->{node}->append_child ($el2);
753 push @$oe, {%{$oe->[-1]}, node => $el2};
754
755 $im = IN_PARAGRAPH_IM;
756 $token = $get_next_token->();
757 redo A;
758 } elsif ($token->{type} == BLOCK_START_TAG_TOKEN and
759 ($token->{tag_name} eq 'INS' or
760 $token->{tag_name} eq 'DEL')) {
761 my $el = $doc->create_element_ns
762 (SW09_NS, ($token->{tag_name} eq 'INS' ? 'insert' : 'delete'));
763 $oe->[-1]->{node}->append_child ($el);
764 push @$oe, {node => $el, section_depth => 0,
765 quotation_depth => 0, list_depth => 0};
766 $el->set_attribute (class => $token->{classes})
767 if defined $token->{classes};
768 $token = $get_next_token->();
769 redo A;
770 } elsif ($token->{type} == QUOTATION_START_TOKEN) {
771 B: {
772 pop @$oe and redo B
773 if not {body => 1, section => 1, insert => 1, delete => 1,
774 blockquote => 1}
775 ->{$oe->[-1]->{node}->manakai_local_name} or
776 $token->{depth} <= $oe->[-1]->{quotation_depth};
777 if ($token->{depth} > $oe->[-1]->{quotation_depth} + 1) {
778 my $el = $doc->create_element_ns (HTML_NS, 'blockquote');
779 $oe->[-1]->{node}->append_child ($el);
780 push @$oe, {node => $el, section_depth => 0,
781 quotation_depth => $oe->[-1]->{quotation_depth} + 1,
782 list_depth => 0};
783 redo B;
784 }
785 } # B
786
787 my $el = $doc->create_element_ns (HTML_NS, 'blockquote');
788 $oe->[-1]->{node}->append_child ($el);
789 push @$oe, {node => $el, section_depth => 0,
790 quotation_depth => $oe->[-1]->{quotation_depth} + 1,
791 list_depth => 0};
792
793 $token = $get_next_token->();
794 redo A;
795 } elsif ($token->{type} == LIST_START_TOKEN) {
796 my $depth = length $token->{depth};
797 my $list_type = substr ($token->{depth}, -1, 1) eq '-' ? 'ul' : 'ol';
798 B: {
799 pop @$oe and redo B if $oe->[-1]->{list_depth} > $depth;
800 pop @$oe and redo B if $oe->[-1]->{list_depth} == $depth and
801 $list_type ne $oe->[-1]->{node}->manakai_local_name;
802 if ($oe->[-1]->{list_depth} < $depth) {
803 my $type = substr $token->{depth}, $oe->[-1]->{list_depth}, 1;
804 my $el = $doc->create_element_ns
805 (HTML_NS, $type eq '-' ? 'ul' : 'ol');
806 $oe->[-1]->{node}->append_child ($el);
807 push @$oe, {%{$oe->[-1]}, node => $el,
808 list_depth => $oe->[-1]->{list_depth} + 1};
809 if ($oe->[-1]->{list_depth} < $depth) {
810 my $el = $doc->create_element_ns (HTML_NS, 'li');
811 $oe->[-1]->{node}->append_child ($el);
812 push @$oe, {%{$oe->[-1]}, node => $el};
813 }
814 redo B;
815 }
816 } # B
817
818 my $el = $doc->create_element_ns (HTML_NS, 'li');
819 $oe->[-1]->{node}->append_child ($el);
820 push @$oe, {%{$oe->[-1]}, node => $el};
821
822 $im = IN_PARAGRAPH_IM;
823 $token = $get_next_token->();
824 redo A;
825 } elsif ($token->{type} == LABELED_LIST_START_TOKEN) {
826 pop @$oe if $oe->[-1]->{node}->manakai_local_name eq 'dd';
827 if ($oe->[-1]->{node}->manakai_local_name ne 'dl') {
828 my $el = $doc->create_element_ns (HTML_NS, 'dl');
829 $oe->[-1]->{node}->append_child ($el);
830 push @$oe, {%{$oe->[-1]}, node => $el};
831 }
832
833 my $el = $doc->create_element_ns (HTML_NS, 'dt');
834 $oe->[-1]->{node}->append_child ($el);
835 push @$oe, {%{$oe->[-1]}, node => $el};
836
837 $im = IN_PARAGRAPH_IM;
838 $token = $get_next_token->();
839 redo A;
840 } elsif ($token->{type} == TABLE_ROW_START_TOKEN) {
841 my $el = $doc->create_element_ns (HTML_NS, 'table');
842 $oe->[-1]->{node}->append_child ($el);
843 push @$oe, {%{$oe->[-1]}, node => $el};
844
845 $el = $doc->create_element_ns (HTML_NS, 'tbody');
846 $oe->[-1]->{node}->append_child ($el);
847 push @$oe, {%{$oe->[-1]}, node => $el};
848
849 $el = $doc->create_element_ns (HTML_NS, 'tr');
850 $oe->[-1]->{node}->append_child ($el);
851 push @$oe, {%{$oe->[-1]}, node => $el};
852
853 $im = IN_TABLE_ROW_IM;
854 $token = $get_next_token->();
855 redo A;
856 } elsif (($token->{type} == BLOCK_START_TAG_TOKEN and
857 $token->{tag_name} eq 'PRE') or
858 $token->{type} == PREFORMATTED_START_TOKEN) {
859 my $el = $doc->create_element_ns (HTML_NS, 'pre');
860 $oe->[-1]->{node}->append_child ($el);
861 push @$oe, {%{$oe->[-1]}, node => $el};
862
863 $el->set_attribute (class => $token->{classes})
864 if defined $token->{classes};
865
866 $im = IN_PARAGRAPH_IM;
867 $token = $get_next_token->();
868 redo A;
869 } elsif ($token->{type} == COMMENT_PARAGRAPH_START_TOKEN) {
870 my $el = $doc->create_element_ns (SW10_NS, 'comment-p');
871 $oe->[-1]->{node}->append_child ($el);
872 push @$oe, {%{$oe->[-1]}, node => $el};
873
874 $im = IN_PARAGRAPH_IM;
875 $token = $get_next_token->();
876 redo A;
877 } elsif ($token->{type} == EDITORIAL_NOTE_START_TOKEN) {
878 my $el = $doc->create_element_ns (SW10_NS, 'ed');
879 $oe->[-1]->{node}->append_child ($el);
880 push @$oe, {%{$oe->[-1]}, node => $el};
881
882 $im = IN_PARAGRAPH_IM;
883 $token = $get_next_token->();
884 redo A;
885 } elsif ($token->{type} == EMPTY_LINE_TOKEN) {
886 pop @$oe while not {body => 1, section => 1, insert => 1, delete => 1}
887 ->{$oe->[-1]->{node}->manakai_local_name};
888 $token = $get_next_token->();
889 redo A;
890 } elsif ($token->{type} == BLOCK_END_TAG_TOKEN) {
891 if ($token->{tag_name} eq 'INS') {
892 for (reverse 1..$#$oe) {
893 if ($oe->[$_]->{node}->manakai_local_name eq 'insert') {
894 splice @$oe, $_;
895 last;
896 }
897 }
898 } elsif ($token->{tag_name} eq 'DEL') {
899 for (reverse 1..$#$oe) {
900 if ($oe->[$_]->{node}->manakai_local_name eq 'delete') {
901 splice @$oe, $_;
902 last;
903 }
904 }
905 } else {
906 ## NOTE: Ignore the token.
907 }
908 $token = $get_next_token->();
909 redo A;
910 } elsif ($token->{type} == FORM_TOKEN) {
911 ## There is an exact code clone.
912 if ($token->{name} eq 'form') {
913 my $el = $doc->create_element_ns (SW09_NS, 'form');
914 $oe->[-1]->{node}->append_child ($el);
915 push @$oe, {%{$oe->[-1]}, node => $el};
916 $el->set_user_data (manakai_source_line => $token->{line});
917 $el->set_user_data (manakai_source_column => $token->{column});
918
919 $el->set_attribute (id => $token->{id}) if defined $token->{id};
920 $el->set_attribute (input => shift @{$token->{parameters}})
921 if @{$token->{parameter}};
922 $el->set_attribute (template => shift @{$token->{parameters}})
923 if @{$token->{parameter}};
924 $el->set_attribute (option => shift @{$token->{parameters}})
925 if @{$token->{parameter}};
926 $el->set_attribute (parameter => join ':', @{$token->{parameters}})
927 if @{$token->{parameter}};
928
929 $token = $get_next_token->();
930 redo A;
931 } else {
932 my $el = $doc->create_element_ns (SW09_NS, 'form');
933 $oe->[-1]->{node}->append_child ($el);
934 push @$oe, {%{$oe->[-1]}, node => $el};
935 $el->set_user_data (manakai_source_line => $token->{line});
936 $el->set_user_data (manakai_source_column => $token->{column});
937
938 $el->set_attribute (ref => $token->{name});
939 $el->set_attribute (id => $token->{id}) if defined $token->{id};
940 $el->set_attribute (parameter => join ':', @{$token->{parameters}})
941 if @{$token->{parameter}};
942
943 $token = $get_next_token->();
944 redo A;
945 }
946 } elsif ($token->{type} == ELEMENT_TOKEN and
947 $token->{local_name} eq 'replace') {
948 ## NOTE: There is an exact code clone.
949 my $el = $doc->create_element_ns
950 ($token->{namespace}, $token->{local_name});
951 $oe->[-1]->{node}->append_child ($el);
952 push @$oe, {%{$oe->[-1]}, node => $el};
953 $el->set_user_data (manakai_source_line => $token->{line});
954 $el->set_user_data (manakai_source_column => $token->{column});
955
956 $el->set_attribute_ns (SW09_NS, 'sw:anchor', $token->{anchor})
957 if defined $token->{anchor};
958 $el->set_attribute (by => $token->{by}) if defined $token->{by};
959 $el->set_attribute_ns (SW09_NS, 'sw:resScheme', $token->{res_scheme})
960 if defined $token->{res_scheme};
961 $el->set_attribute_ns (SW09_NS, 'sw:resParameter',
962 $token->{res_parameter})
963 if defined $token->{res_parameter};
964 $el->text_content ($token->{content}) if defined $token->{content};
965
966 $token = $get_next_token->();
967 redo A;
968 } elsif ($token->{type} == END_OF_FILE_TOKEN) {
969 return;
970 } elsif ({LABELED_LIST_MIDDLE_TOKEN => 1,
971 HEADING_END_TOKEN => 1,
972 PREFORMATTED_END_TOKEN => 1,
973 TABLE_ROW_END_TOKEN => 1,
974 TABLE_CELL_START_TOKEN => 1,
975 TABLE_CELL_END_TOKEN => 1,
976 TABLE_COLSPAN_CELL_TOKEN => 1}->{$token->{type}}) {
977 ## NOTE: Ignore the token.
978 } else {
979 my $el = $doc->create_element_ns (HTML_NS, 'p');
980 $oe->[-1]->{node}->append_child ($el);
981 push @$oe, {%{$oe->[-1]}, node => $el};
982
983 $im = IN_PARAGRAPH_IM;
984 ## Reprocess.
985 redo A;
986 }
987 } elsif ($im == IN_TABLE_ROW_IM) {
988 if ($token->{type} == TABLE_CELL_START_TOKEN) {
989 my $el = $doc->create_element_ns (HTML_NS, 'td');
990 $oe->[-1]->{node}->append_child ($el);
991 push @$oe, {%{$oe->[-1]}, node => $el};
992 $el->set_user_data (manakai_source_line => $token->{line});
993 $el->set_user_data (manakai_source_column => $token->{column});
994
995 $im = IN_PARAGRAPH_IM;
996 $token = $get_next_token->();
997 redo A;
998 } elsif ($token->{type} == TABLE_COLSPAN_CELL_TOKEN) {
999 my $lc = $oe->[-1]->{node}->last_child;
1000 if ($lc and $lc->manakai_local_name eq 'td') {
1001 $lc->set_attribute
1002 (colspan => ($lc->get_attribute ('colspan') || 0) + 1);
1003 } else {
1004 my $el = $doc->create_element_ns (SW10_NS, 'td');
1005 $oe->[-1]->{node}->append_child ($el);
1006 $el->set_user_data (manakai_source_line => $token->{line});
1007 $el->set_user_data (manakai_source_column => $token->{column});
1008 }
1009
1010 $token = $get_next_token->();
1011 redo A;
1012 } elsif ($token->{type} == TABLE_ROW_END_TOKEN) {
1013 pop @$oe if $oe->[-1]->{node}->manakai_local_name eq 'tr';
1014 $token = $get_next_token->();
1015 redo A;
1016 } elsif ($token->{type} == TABLE_ROW_START_TOKEN) {
1017 my $el = $doc->create_element_ns (HTML_NS, 'tr');
1018 $oe->[-1]->{node}->append_child ($el);
1019 push @$oe, {%{$oe->[-1]}, node => $el};
1020 $el->set_user_data (manakai_source_line => $token->{line});
1021 $el->set_user_data (manakai_source_column => $token->{column});
1022
1023 $token = $get_next_token->();
1024 redo A;
1025 } else {
1026 $im = IN_SECTION_IM;
1027 ## Reprocess.
1028 redo A;
1029 }
1030 } else {
1031 die "$0: Unknown insertion mode: $im";
1032 }
1033 } # A
1034 } # parse_char_string
1035
1036 1;

[email protected]
ViewVC Help
Powered by ViewVC 1.1.24