Add built local::lib
[catagits/Gitalist.git] / local-lib5 / lib / perl5 / Syntax / Highlight / Engine / Kate / ToolKit.pm
CommitLineData
3fea05b9 1# Copyright (c) 2006 Hans Jeuken. All rights reserved.
2# This program is free software; you can redistribute it and/or
3# modify it under the same terms as Perl itself.
4
5package Syntax::Highlight::Engine::Kate::ToolKit;
6
7our $VERSION = '0.06';
8
9use strict;
10use warnings;
11use XML::Dumper;
12require Syntax::Highlight::Engine::Kate::XMLData;
13
14use File::Basename;
15
16my $regfile = "SHEKREGISTRY.xml";
17my $regchars = "\\^.\$|()[]{}*+?~!%^&/";
18
19my %tests = (
20 AnyChar => \&testRuleAnyChar,
21 DetectChar => \&testRuleDetectChar,
22 Detect2Chars => \&testRuleDetect2Chars,
23 DetectIdentifier => \&testRuleDetectIdentifier,
24 DetectSpaces => \&testRuleDetectSpaces,
25 Float => \&testRuleFloat,
26 HlCChar => \&testRuleHlCChar,
27 HlCHex => \&testRuleHlCHex,
28 HlCOct => \&testRuleHlCOct,
29 HlCStringChar => \&testRuleHlCStringChar,
30 IncludeRules => \&testRuleIncludeRules,
31 Int => \&testRuleInt,
32 keyword => \&testRuleKeyword,
33 LineContinue => \&testRuleLineContinue,
34 RangeDetect => \&testRuleRangeDetect,
35 RegExpr => \&testRuleRegExpr,
36 StringDetect => \&testRuleStringDetect,
37);
38
39my %parses = (
40 AnyChar => \&pmRuleAnyChar,
41 DetectChar => \&pmRuleDetectChar,
42 Detect2Chars => \&pmRuleDetect2Chars,
43 DetectIdentifier => \&pmRuleDetectIdentifier,
44 DetectSpaces => \&pmRuleDetectSpaces,
45 Float => \&pmRuleFloat,
46 HlCChar => \&pmRuleHlCChar,
47 HlCHex => \&pmRuleHlCHex,
48 HlCOct => \&pmRuleHlCOct,
49 HlCStringChar => \&pmRuleHlCStringChar,
50 IncludeRules => \&pmRuleIncludeRules,
51 Int => \&pmRuleInt,
52 keyword => \&pmRuleKeyword,
53 LineContinue => \&pmRuleLineContinue,
54 RangeDetect => \&pmRuleRangeDetect,
55 RegExpr => \&pmRuleRegExpr,
56 StringDetect => \&pmRuleStringDetect,
57);
58
59
60my @stdoptions = qw(lookAhead column firstNonSpace context attribute);
61my $stringtest = sub { return (length(shift) > 0) };
62my $booltest = sub { my $l = lc(shift) ; return (($l eq 'true') or ($l eq 'false') or ($l eq '0') or ($l eq '1')) };
63my $chartest = sub { return (length(shift) eq 1) };
64
65my %testopts = (
66 attribute => $stringtest,
67 char => $chartest,
68 char1 => $chartest,
69 column => sub { return (shift =~ /^\d+$/)},
70 context => $stringtest,
71 dynamic => $booltest,
72 firstNonSpace =>$booltest,
73 insensitive => $booltest,
74 lookAhead => $booltest,
75 minimal => $booltest,
76 String => $stringtest,
77);
78
79sub new {
80 my $proto = shift;
81 my $class = ref($proto) || $proto;
82
83 my $self = {
84 indent => 0,
85 indentchar => ' ',
86 curlang => '',
87 curcontext => '',
88 guiadd => sub { },
89 logcmd => sub { warn shift },
90 outcmd => sub { print shift },
91 policy => 'abort',
92 polcmd => sub { return 0 },
93 reportdata => [],
94 registered => {},
95 runtestspace => '',
96 verbose => 1,
97 version => '0.01',
98 };
99 bless ($self, $class);
100 return $self;
101}
102
103
104sub booleanize {
105 my ($self, $d) = @_;
106 if (lc($d) eq 'true') { $d = 1 };
107 if (lc($d) eq 'false') { $d = 0 };
108 if (($d ne 0) and ($d ne 1)) { return undef };
109 return $d;
110}
111
112sub checkIntegrity {
113 my $self = shift;
114 my @l = @_;
115 unless (@l) { @l = $self->registered };
116 while (@l) {
117 my $lang = shift @l;
118 $self->curlang($lang);
119 $self->indent(0);
120 my $xml = $self->xmldata($lang);
121 if (defined($xml)) {
122 my $ctx = $xml->contexts;
123 foreach my $k (sort keys %$ctx) {
124 $self->curcontext($k);
125 $self->lprint("checking context $k");
126 $self->indentUp;
127 my $itl = $ctx->{$k}->{'items'};
128 $self->testContextItems(@$itl);
129 $self->indentDown;
130 }
131 } else {
132 $self->log("could not retrieve data for $lang");
133 }
134 }
135}
136
137sub curcontext {
138 my $self = shift;
139 if (@_) { $self->{'curcontext'} = shift; };
140 return $self->{'curcontext'};
141}
142
143sub curlang {
144 my $self = shift;
145 if (@_) { $self->{'curlang'} = shift; };
146 return $self->{'curlang'};
147}
148
149sub guiadd {
150 my $self = shift;
151 if (@_) { $self->{'guiadd'} = shift; };
152 return $self->{'guiadd'};
153}
154
155sub indent {
156 my $self = shift;
157 if (@_) { $self->{'indent'} = shift; };
158 return $self->{'indent'};
159}
160
161sub indentchar {
162 my $self = shift;
163 if (@_) { $self->{'indentchar'} = shift; };
164 return $self->{'indentchar'};
165}
166
167sub indentDown {
168 my $self = shift;
169 if ($self->indent > 0) {
170 $self->indent($self->indent - 1);
171 } else {
172 $self->log("indentation already 0\n");
173 }
174}
175
176sub indentUp {
177 my $self = shift;
178 $self->indent($self->indent + 1);
179}
180
181sub log {
182 my ($self, $msg) = @_;
183 my $c = $self->logcmd;
184 &$c($msg);
185}
186
187sub logcmd {
188 my $self = shift;
189 if (@_) { $self->{'logcmd'} = shift; };
190 return $self->{'logcmd'};
191}
192
193sub lprint {
194 my ($self, $txt) = @_;
195 if (defined($txt)) { #check if only a newline should be given
196 if ($txt ne '') { #do not indent empty lines
197 my $c = 0;
198 while ($c < $self->{'indent'}) {
199 $txt = $self->indentchar . $txt;
200 $c ++;
201 }
202 }
203 } else {
204 $txt = '';
205 }
206 my $c = $self->outcmd;
207 &$c("$txt\n");
208}
209
210sub moduleName {
211 my ($self, $name) = @_;
212 my %numb = (
213 '1' => 'One',
214 '2' => 'Two',
215 '3' => 'Three',
216 '4' => 'Four',
217 '5' => 'Five',
218 '6' => 'Six',
219 '7' => 'Seven',
220 '8' => 'Eight',
221 '9' => 'Nine',
222 '0' => 'Zero',
223 );
224 if ($name =~ s/^(\d)//) {
225 $name = $numb{$1} . $name;
226 }
227 $name =~ s/\.//;
228 $name =~ s/\+/plus/g;
229 $name =~ s/\-/minus/g;
230 $name =~ s/#/dash/g;
231 $name =~ s/[^0-9a-zA-Z]/_/g;
232 $name =~ s/__/_/g;
233 $name =~ s/_$//;
234 $name = ucfirst($name);
235 return $name;
236}
237
238sub outcmd {
239 my $self = shift;
240 if (@_) { $self->{'outcmd'} = shift; };
241 return $self->{'outcmd'};
242}
243
244
245sub pmGenerate {
246 my $self = shift;
247 my @l = @_;
248 unless (@l) { @l = $self->registered };
249 while (@l) {
250 my $lang = shift @l;
251 my $vbck = $self->verbose;
252 $self->verbose(0);
253 $self->indent(0);
254 $self->curlang($lang);
255 my $xml = $self->xmldata($lang);
256 my $file = basename($xml->filename);
257 my $lh = $xml->language;
258 my $name = $self->moduleName($lang);
259 my $i = $xml->itemdata;
260 my %itemdata = %$i;
261 my $l = $xml->lists;
262 my %lists = %$l;
263 my $c = $xml->contexts;
264 my %contexts = %$c;
265
266 $self->lprint("# Copyright (c) 2005 - 2006 Hans Jeuken. All rights reserved.");
267 $self->lprint("# This program is free software; you can redistribute it and/or");
268 $self->lprint("# modify it under the same terms as Perl itself.");
269 $self->lprint;
270 $self->lprint("# This file was generated from the '$file' file of the syntax highlight");
271 $self->lprint("# engine of the kate text editor (http://www.kate-editor.org");
272 $self->lprint;
273 if (exists $lh->{'version'}) {
274 $self->lprint("#kate xml version " . $lh->{'version'});
275 }
276 if (exists $lh->{'kateversion'}) {
277 $self->lprint("#kate version " . $lh->{"kateversion"});
278 }
279 if (exists $lh->{'author'}) {
280 $self->lprint("#kate author " . $lh->{"author"});
281 }
282 my $time = localtime;
283 $self->lprint("#generated: $time, localtime");
284 $self->lprint;
285 $self->lprint("package Syntax::Highlight::Engine::Kate::$name;");
286 $self->lprint;
287 $self->lprint("use vars qw(\$VERSION);");
288 $self->lprint("\$VERSION = '" . $self->version . "';");
289 $self->lprint;
290 $self->lprint("use strict;");
291 $self->lprint("use warnings;");
292 $self->lprint("use base('Syntax::Highlight::Engine::Kate::Template');");
293 $self->lprint;
294 $self->lprint("sub new {");
295 $self->indentUp;
296 $self->lprint("my \$proto = shift;");
297 $self->lprint("my \$class = ref(\$proto) || \$proto;");
298 $self->lprint("my \$self = \$class->SUPER::new(\@_);");
299 if (%itemdata) {
300 $self->lprint("\$self->attributes({");
301 $self->indentUp;
302 foreach my $at (sort keys %itemdata) {
303 my $v = $itemdata{$at};
304 $self->lprint("'$at' => '$v',");
305 }
306 $self->indentDown;
307 $self->lprint("});");
308 }
309 if (%lists) {
310 foreach my $k (sort keys %lists) {
311 $self->lprint("\$self->listAdd('$k',");
312 $self->indentUp;
313 my $il = $lists{$k};
314 foreach my $i (sort @$il) {
315 $i =~ s/\\/\\\\/g;
316 $i =~ s/\'/\\'/g;
317 $self->lprint($self->stringalize($i) . ",");
318 }
319 $self->indentDown;
320 $self->lprint(");");
321 }
322 }
323 $self->lprint("\$self->contextdata({");
324 $self->indentUp;
325 foreach my $ctx (sort keys %contexts) {
326 my $p = $contexts{$ctx};
327 $self->lprint("'$ctx' => {");
328 $self->indentUp;
329 $self->lprint("callback => \\&" . $self->pmMethodName($ctx) . ",");
330 if (exists $p->{'attribute'}) {
331 my $coi = $p->{'attribute'};
332 $self->lprint("attribute => '$coi',");
333 }
334 if (exists $p->{'lineEndContext'}) {
335 my $e = $p->{'lineEndContext'};
336 unless ($e eq '#stay') {
337 $self->lprint("lineending => '$e',");
338 }
339 }
340 if (exists $p->{'lineBeginContext'}) {
341 my $e = $p->{'lineBeginContext'};
342 unless ($e eq '#stay') {
343 $self->lprint("linebeginning => '$e',");
344 }
345 }
346 if (exists $p->{'fallthrough'}) {
347 my $e = $p->{'fallthrough'};
348 if ($e eq 'true') {
349 if (exists $p->{'fallthroughContext'}) {
350 my $e = $p->{'fallthroughContext'};
351 $self->lprint("fallthrough => '$e',");
352 }
353 }
354 }
355 if (exists $p->{'dynamic'}) {
356 my $e = $p->{'dynamic'};
357 if ($e eq 'true') {
358 $self->lprint("dynamic => 1,");
359 }
360 }
361 $self->indentDown;
362 $self->lprint("},");
363 }
364 $self->indentDown;
365 $self->lprint("});");
366
367 my $deliminators = ".():!+,-<=>%&*/;?[]^{|}~\\";
368 my $wdelim = $xml->weakDeliminator;
369 while ($wdelim ne '') {
370 $wdelim =~ s/^(.)//;
371 my $wd = $1;
372 if (index($regchars, $wd) >= 0) { $wd = "\\$wd" };
373 $deliminators =~ s/$wd//;
374 }
375 my $adelim = $xml->additionalDeliminator;
376 $deliminators = $deliminators . $adelim;
377 my @delimchars = split //, $deliminators;
378 my $tmp = '';
379 for (@delimchars) {
380 my $dc = $_;
381 if (index($regchars, $dc ) >= 0) { $dc = "\\$dc" };
382 $tmp = "$tmp|$dc";
383 }
384 $tmp = '\\s|' . $tmp;
385 $self->lprint("\$self->deliminators(" . $self->stringalize($tmp) . ");");
386 $self->lprint("\$self->basecontext(" . $self->stringalize($xml->basecontext) . ");");
387 $self->lprint("\$self->keywordscase(" . $xml->keywordscase . ");");
388 $self->lprint("\$self->initialize;");
389 $self->lprint("bless (\$self, \$class);");
390 $self->lprint("return \$self;");
391 $self->indentDown;
392 $self->lprint("}");
393 $self->lprint;
394 $self->lprint("sub language {");
395 $self->indentUp;
396 $self->lprint("return " . $self->stringalize($lang) . ";");
397 $self->indentDown;
398 $self->lprint("}");
399 $self->lprint;
400
401 foreach my $ctxt (sort keys %contexts) {
402 $self->curcontext($ctxt);
403 $self->lprint("sub " . $self->pmMethodName($ctxt) . " {");
404 $self->indentUp;
405 $self->lprint("my (\$self, \$text) = \@_;");
406 my $c = $contexts{$ctxt};
407 my $it = $c->{'items'};
408 $self->pmParseRules(@$it);
409 # $self->indentDown;
410 # $self->lprint("}\n\n");
411 $self->lprint("return 0;");
412 $self->indentDown;
413 $self->lprint("};");
414 $self->lprint;
415 }
416
417 $self->lprint;
418 $self->lprint("1;");
419 $self->lprint;
420 $self->lprint("__END__");
421 $self->lprint;
422 $self->lprint("=head1 NAME");
423 $self->lprint;
424 $self->lprint("Syntax::Highlight::Engine::Kate::$name - a Plugin for $lang syntax highlighting");
425 $self->lprint;
426 $self->lprint("=head1 SYNOPSIS");
427 $self->lprint;
428 $self->lprint(" require Syntax::Highlight::Engine::Kate::$name;");
429 $self->lprint(" my \$sh = new Syntax::Highlight::Engine::Kate::$name([");
430 #todotodotodotodo
431 $self->lprint(" ]);");
432 $self->lprint;
433 $self->lprint("=head1 DESCRIPTION");
434 $self->lprint;
435 $self->lprint("Syntax::Highlight::Engine::Kate::$name is a plugin module that provides syntax highlighting");
436 $self->lprint("for $lang to the Syntax::Haghlight::Engine::Kate highlighting engine.");
437 $self->lprint;
438 $self->lprint("This code is generated from the syntax definition files used");
439 $self->lprint("by the Kate project.");
440 $self->lprint("It works quite fine, but can use refinement and optimization.");
441 $self->lprint;
442 $self->lprint("It inherits Syntax::Higlight::Engine::Kate::Template. See also there.");
443 $self->lprint;
444 $self->lprint("=cut");
445 $self->lprint;
446 $self->lprint("=head1 AUTHOR");
447 $self->lprint;
448 $self->lprint("Hans Jeuken (haje <at> toneel <dot> demon <dot> nl)");
449 $self->lprint;
450 $self->lprint("=cut");
451 $self->lprint;
452 $self->lprint("=head1 BUGS");
453 $self->lprint;
454 $self->lprint("Unknown. If you find any, please contact the author");
455 $self->lprint;
456 $self->lprint("=cut");
457 $self->lprint;
458
459 $self->verbose($vbck);
460 }
461}
462
463sub pmMethodName {
464 my ($self, $in) = @_;
465 $in =~ s/\(/Bo/g;
466 $in =~ s/\)/Bc/g;
467 $in =~ s/\{/Co/g;
468 $in =~ s/\}/Cc/g;
469 $in =~ s/\[/So/g;
470 $in =~ s/\]/Sc/g;
471 $in =~ s/([^A-za-z0-9_])//g;
472 return "parse$in";
473}
474
475sub pmParseRules {
476 my $self = shift;
477 for (@_) {
478 my $rule = $_;
479 foreach my $k (sort keys %$rule) {
480 $self->lprint("# $k => '" . $rule->{$k} . "'");
481 }
482 my $test = $tests{$rule->{'type'}};
483 if (&$test($self, $rule)) {
484 my $call = $parses{$rule->{'type'}};
485 &$call($self, $rule);
486 } else {
487 $self->lprint("#This rule is buggy, not sending it to output");
488 }
489 }
490}
491
492sub pmParseRuleFinish {
493 my ($self, $rule) = @_;
494 $self->indentUp;
495 if (exists $rule->{'items'}) {
496 my $i = $rule->{'items'};
497 $self->pmParseRules(@$i); #recursive;
498 } else {
499 $self->lprint("return 1");
500 }
501 $self->indentDown;
502 $self->lprint("}");
503
504}
505
506sub pmParseRuleConvertArgs {
507 my $self = shift;
508 my $rule = shift;
509 my $r = "";
510 my %default = (
511 lookAhead => 0,
512 insensitive => 0,
513 minimal => 0,
514 dynamic => 0,
515 context => '#stay',
516 firstNonSpace => 0,
517 );
518 while (@_) {
519 my $n = shift;
520 my $d;
521 if (exists($rule->{$n})) {
522 $d = $rule->{$n};
523 } elsif (exists($default{$n})) {
524 $d = $default{$n};
525 } else {
526 $d = undef;
527 }
528 if (defined($d)) {
529 my @boole = qw(insensitive dynamic firstNonSpace lookAhead minimal);
530 my @str = qw(String char char1 context attribute);
531 if ($n eq 'String') {
532 $d = $self->stringalize($d);
533 } elsif (grep {$n eq $_} @boole) {
534 $d = $self->booleanize($d);
535 } elsif (grep {$n eq $_} @str) {
536 $d = $self->stringalize($d);
537 }
538 } else {
539 $d = "undef"
540 }
541 if ($r ne '') {
542 $r = $r . ', '
543 }
544 $r = $r . $d;
545 }
546 return $r
547}
548
549sub pmRuleAnyChar {
550 my ($self, $rule) = @_;
551 my $optxt = $self->pmParseRuleConvertArgs($rule, qw/String insensitive/, @stdoptions);
552 $self->lprint("if (\$self->testAnyChar(\$text, $optxt)) {");
553 $self->pmParseRuleFinish($rule);
554}
555
556sub pmRuleDetectChar {
557 my ($self, $rule) = @_;
558 my $optxt = $self->pmParseRuleConvertArgs($rule, qw/char insensitive dynamic/, @stdoptions);
559 $self->lprint("if (\$self->testDetectChar(\$text, $optxt)) {");
560 $self->pmParseRuleFinish($rule);
561}
562
563sub pmRuleDetect2Chars {
564 my ($self, $rule) = @_;
565 my $optxt = $self->pmParseRuleConvertArgs($rule, qw/char char1 insensitive dynamic/, @stdoptions);
566 $self->lprint("if (\$self->testDetect2Chars(\$text, $optxt)) {");
567 $self->pmParseRuleFinish($rule);
568}
569
570sub pmRuleDetectIdentifier {
571 my ($self, $rule) = @_;
572 my $optxt = $self->pmParseRuleConvertArgs($rule, @stdoptions);
573 $self->lprint("if (\$self->testDetectIdentifier(\$text, $optxt)) {");
574 $self->pmParseRuleFinish($rule);
575}
576
577sub pmRuleDetectSpaces {
578 my ($self, $rule) = @_;
579 my $optxt = $self->pmParseRuleConvertArgs($rule, @stdoptions);
580 $self->lprint("if (\$self->testDetectSpaces(\$text, $optxt)) {");
581 $self->pmParseRuleFinish($rule);
582}
583
584sub pmRuleFloat {
585 my ($self, $rule) = @_;
586 my $optxt = $self->pmParseRuleConvertArgs($rule, @stdoptions);
587 $self->lprint("if (\$self->testFloat(\$text, $optxt)) {");
588 $self->pmParseRuleFinish($rule);
589}
590
591sub pmRuleHlCChar {
592 my ($self, $rule) = @_;
593 my $optxt = $self->pmParseRuleConvertArgs($rule, @stdoptions);
594 $self->lprint("if (\$self->testHlCChar(\$text, $optxt)) {");
595 $self->pmParseRuleFinish($rule);
596}
597
598sub pmRuleHlCHex {
599 my ($self, $rule) = @_;
600 my $optxt = $self->pmParseRuleConvertArgs($rule, @stdoptions);
601 $self->lprint("if (\$self->testHlCHex(\$text, $optxt)) {");
602 $self->pmParseRuleFinish($rule);
603}
604
605sub pmRuleHlCOct {
606 my ($self, $rule) = @_;
607 my $optxt = $self->pmParseRuleConvertArgs($rule, @stdoptions);
608 $self->lprint("if (\$self->testHlCOct(\$text, $optxt)) {");
609 $self->pmParseRuleFinish($rule);
610}
611
612sub pmRuleHlCStringChar {
613 my ($self, $rule) = @_;
614 my $optxt = $self->pmParseRuleConvertArgs($rule, @stdoptions);
615 $self->lprint("if (\$self->testHlCStringChar(\$text, $optxt)) {");
616 $self->pmParseRuleFinish($rule);
617}
618
619sub pmRuleIncludeRules {
620 my ($self, $rule) = @_;
621 my $context = $self->stringalize($rule->{'context'});
622 my $ed;
623 if ($context =~ s/^(')##/$1/) {
624 $ed = "includePlugin";
625 } else {
626 $ed = "includeRules";
627 }
628 $self->lprint("if (\$self->$ed($context, \$text)) {");
629 $self->pmParseRuleFinish($rule);
630}
631
632sub pmRuleInt {
633 my ($self, $rule) = @_;
634 my $optxt = $self->pmParseRuleConvertArgs($rule, @stdoptions);
635 $self->lprint("if (\$self->testInt(\$text, $optxt)) {");
636 $self->pmParseRuleFinish($rule);
637}
638
639sub pmRuleKeyword {
640 my ($self, $rule) = @_;
641 my $optxt = $self->pmParseRuleConvertArgs($rule, 'String', @stdoptions);
642 $self->lprint("if (\$self->testKeyword(\$text, $optxt)) {");
643 $self->pmParseRuleFinish($rule);
644}
645
646sub pmRuleLineContinue {
647 my ($self, $rule) = @_;
648 my $optxt = $self->pmParseRuleConvertArgs($rule, @stdoptions);
649 $self->lprint("if (\$self->testLineContinue(\$text, $optxt)) {");
650 $self->pmParseRuleFinish($rule);
651}
652
653sub pmRuleRangeDetect {
654 my ($self, $rule) = @_;
655 my $optxt = $self->pmParseRuleConvertArgs($rule, qw/char char1 insensitive/, @stdoptions);
656 $self->lprint("if (\$self->testRangeDetect(\$text, $optxt)) {");
657 $self->pmParseRuleFinish($rule);
658}
659
660sub pmRuleRegExpr {
661 my ($self, $rule) = @_;
662 my $optxt = $self->pmParseRuleConvertArgs($rule, qw/insensitive dynamic/, @stdoptions);
663 my $string = $rule->{'String'};
664 my $minimal = $rule->{'minimal'};
665 unless (defined($minimal)) { $minimal = 0 }
666 $minimal = $self->booleanize($minimal);
667 my $reg = '';
668 if ($minimal) {
669 my $lastchar = '';
670 while ($string ne '') {
671 if ($string =~ s/^(\*|\+)//) {
672 $reg = "$reg$1";
673 if ($lastchar ne "\\") {
674 $reg = "$reg?";
675 }
676 $lastchar = $1;
677 } else {
678 $string =~ s/^(.)//;
679 $reg = "$reg$1";
680 $lastchar = $1;
681 }
682 }
683 } else {
684 $reg = $string;
685 }
686 $reg = $self->stringalize($reg);
687 $self->lprint("if (\$self->testRegExpr(\$text, $reg, $optxt)) {");
688 $self->pmParseRuleFinish($rule);
689}
690
691sub pmRuleStringDetect {
692 my ($self, $rule) = @_;
693 my $optxt = $self->pmParseRuleConvertArgs($rule, qw/String insensitive dynamic/, @stdoptions);
694 $self->lprint("if (\$self->testStringDetect(\$text, $optxt)) {");
695 $self->pmParseRuleFinish($rule);
696}
697
698sub policy {
699 my $self = shift;
700 if (@_) { $self->{'policy'} = shift; };
701 return $self->{'policy'};
702}
703
704sub register {
705 my ($self, $new) = @_;
706 my $reg = $self->{'registered'};
707 my $k = new Syntax::Highlight::Engine::Kate::XMLData($new);
708 if (defined($k)) {
709 my $name = $k->language->{'name'};
710 if (exists $reg->{$name}) {
711 $self->log("language $name already registered, aborting");
712 } else {
713 $reg->{$name} = $k;
714 my $cmd = $self->guiadd;
715 &$cmd($name);
716 return $name;
717 }
718 } else {
719 $self->log("cannot load $new");
720 }
721 return undef
722}
723
724sub registered {
725 my $self = shift;
726 my $reg = $self->{'registered'};
727 return sort {uc($a) cmp uc($b)} keys %$reg;
728}
729
730
731sub registryLoad {
732 my $self = shift;
733 unless (-e $regfile) { return };
734 my $dump = new XML::Dumper;
735 my $h = $dump->xml2pl($regfile);
736 foreach my $k (sort keys %$h) {
737 my $n = $self->register($k);
738 my $x = $self->xmldata($n);
739 my $m = $h->{$k};
740 foreach my $l (keys %$m) {
741 $x->metadata($l, $m->{$l});
742 }
743 }
744}
745
746sub registrySave {
747 my $self = shift;
748 my @keys = $self->registered;
749 my %h = ();
750 foreach my $k (@keys) {
751 my $x = $self->xmldata($k);
752 $h{$x->filename} = $x->metadataBackup;
753 }
754 my $dump = new XML::Dumper;
755 $dump->pl2xml(\%h, $regfile);
756}
757
758sub reportAdd {
759 my ($self, $status, $rule, $msg) = @_;
760 if ($self->verbose) {
761 my $st = 'OK ';
762 unless ($status) { $st = 'ERROR ' };
763 $self->lprint($st . $msg);
764 }
765 my $lang = $self->curlang;
766 my $context = $self->curcontext;
767 my $log = $self->reportdata;
768 push @$log, [$status, $lang, $context, $rule, $msg];
769}
770
771sub reportClear {
772 my $self = shift;
773 $self->reportdata([]);
774}
775
776sub reportdata {
777 my $self = shift;
778 if (@_) { $self->{'reportdata'} = shift; };
779 return $self->{'reportdata'};
780}
781
782sub reportGenerate {
783 my ($self, $status) = @_;
784 unless (defined($status)) { $status = -1 };
785 my @pos = ('Fail', 'Pass');
786 my @items = ();
787 my $l = $self->reportdata;
788 if ($status ne -1) {
789 foreach my $t (@$l) {
790 if ($t->[0] eq $status) {
791 push @items, $t;
792 }
793 }
794 } else {
795 @items = @$l
796 }
797 foreach my $i (@items) {
798 my $txt = $pos[$i->[0]] . " ";
799 $txt = $txt . $self->textLength($i->[1], 16);
800 $txt = $txt . $self->textLength($i->[2], 30);
801 $txt = $txt . $self->textLength($i->[3], 14);
802 $self->lprint($txt . " : " . $i->[4]);
803 }
804}
805
806
807#sub runtestLoad {
808# (my $self, $code) = @_;
809# my $sp = new Safe('MySafe');
810# $sp->reval($code);
811# if ($@) { $self->log(%@) }
812# my $name = $self->moduleName($self->xmldata($curentry)->language->{'name'});
813# my $mod = "MySafe::Syntax::Highlight::Engine::Kate::$name";
814# $sp->share('&' . $mod . '::highlight');
815# $sp->share('&' . $mod . '::reset');
816# my $p;
817# eval ('$p = new ' . $mod);
818# if ($@) { $self->log(%@) }
819# if (defined($p)) {
820# $self->runtest($p)
821# } else {
822# $self->runtest('');
823# }
824#}
825#
826sub runtest {
827 my $self = shift;
828 if (@_) { $self->{'runtest'} = shift; };
829 return $self->{'runtest'};
830}
831
832sub stringalize {
833 my ($self, $in) = @_;
834 $in =~ s/\\/\\\\/g;
835 $in =~ s/\'/\\'/g;
836# $in =~ s/\$/\\\$/g;
837 $in = "'$in'";
838 return $in;
839}
840
841sub testContextItems {
842 my $self = shift;
843 my @test = sort keys %testopts;
844 while (@_) {
845 my $item = shift;
846 my $type = $item->{'type'};
847 $self->lprint("testing rule $type");
848 $self->indentUp;
849 if (exists $tests{$type}) {
850 my $c = $tests{$type};
851 &$c($self, $item);
852 } else {
853 $self->reportType(0, $type, "rule type $type does NOT exist");
854 }
855 if (exists $item->{'items'}) {
856 my $i = $item->{'items'};
857 $self->lprint("testing sub rules");
858 $self->indentUp;
859 $self->testContextItems(@$i); #recursive
860 $self->indentDown;
861 }
862 $self->indentDown;
863 }
864}
865
866sub testRuleOptions {
867 my ($self, $item) = @_;
868 my @test = sort keys %testopts;
869 my $type = $item->{'type'};
870 my $result = 1;
871 #test the options to the rule
872 foreach my $t (@test) {
873 my $o = $item->{$t};
874 if (defined($o)) {
875 my $c = $testopts{$t};
876 if (&$c($o)) {
877 $self->reportAdd(1, $type, "option '$t' with value '$o' is valid");
878 } else {
879 $self->reportAdd(0, $type, "option '$t', value '$o' is NOT valid");
880 $result = 0;
881 }
882 }
883 }
884 #test if attribute points to something defined
885 if (exists($item->{'attribute'})) {
886 my $att = $item->{'attribute'};
887 if (exists $self->xmldata($self->curlang)->itemdata->{$att}) {
888 $self->reportAdd(1, $type, "attribute '$att' is defined in itemdata");
889 } else {
890 $self->reportAdd(0, $type, "attribute '$att' is NOT defined in itemdata");
891 $result = 0;
892 }
893 }
894 #test if context points to something defined
895 if (exists($item->{'context'})) {
896 my $ctx = $item->{'context'};
897 if ($ctx eq '#stay') {
898 $self->reportAdd(1, $type, "context '$ctx' recognized");
899 } elsif ($ctx =~ /^##(.+)/) {
900 my $x = $self->xmldata($1);
901 if (defined($1)) {
902 $self->reportAdd(1, $type, "context '$ctx' refers to language '$1'");
903 } else {
904 $self->reportAdd(0, $type, "context '$ctx' refers to undefined language '$1'");
905 $result = 0;
906 }
907 } elsif ($ctx =~ /^[#pop]+$/) {
908 $self->reportAdd(1, $type, "context '$ctx' recognized");
909 } elsif (exists $self->xmldata($self->curlang)->contexts->{$ctx}) {
910 $self->reportAdd(1, $type, "context '$ctx' is defined in contexts");
911 } else {
912 $self->reportAdd(0, $type, "context '$ctx' is NOT defined in contexts");
913 $result = 0;
914 }
915 }
916 return $result;
917}
918
919sub testRuleAnyChar {
920 my ($self, $item) = @_;
921 my $result = 1;
922 unless ($self->testRuleOptions($item)) { $result = 0 };
923 return $result;
924}
925
926sub testRuleDetectChar {
927 my ($self, $item) = @_;
928 my $result = 1;
929 unless ($self->testRuleOptions($item)) { $result = 0 };
930 return $result;
931}
932
933sub testRuleDetect2Chars {
934 my ($self, $item) = @_;
935 my $result = 1;
936 unless ($self->testRuleOptions($item)) { $result = 0 };
937 return $result;
938}
939
940sub testRuleDetectIdentifier {
941 my ($self, $item) = @_;
942 my $result = 1;
943 unless ($self->testRuleOptions($item)) { $result = 0 };
944 return $result;
945}
946
947sub testRuleDetectSpaces {
948 my ($self, $item) = @_;
949 my $result = 1;
950 unless ($self->testRuleOptions($item)) { $result = 0 };
951 return $result;
952}
953
954sub testRuleFloat {
955 my ($self, $item) = @_;
956 my $result = 1;
957 unless ($self->testRuleOptions($item)) { $result = 0 };
958 return $result;
959}
960
961sub testRuleHlCChar {
962 my ($self, $item) = @_;
963 my $result = 1;
964 unless ($self->testRuleOptions($item)) { $result = 0 };
965 return $result;
966}
967
968sub testRuleHlCHex {
969 my ($self, $item) = @_;
970 my $result = 1;
971 unless ($self->testRuleOptions($item)) { $result = 0 };
972 return $result;
973}
974
975sub testRuleHlCOct {
976 my ($self, $item) = @_;
977 my $result = 1;
978 unless ($self->testRuleOptions($item)) { $result = 0 };
979 return $result;
980}
981
982sub testRuleHlCStringChar {
983 my ($self, $item) = @_;
984 my $result = 1;
985 unless ($self->testRuleOptions($item)) { $result = 0 };
986 return $result;
987}
988
989sub testRuleIncludeRules {
990 my ($self, $item) = @_;
991 my $result = 1;
992 unless ($self->testRuleOptions($item)) { $result = 0 };
993 return $result;
994}
995
996sub testRuleInt {
997 my ($self, $item) = @_;
998 my $result = 1;
999 unless ($self->testRuleOptions($item)) { $result = 0 };
1000 return $result;
1001}
1002
1003sub testRuleKeyword {
1004 my ($self, $item) = @_;
1005 my $s = $item->{'String'};
1006 my $l = $self->xmldata($self->curlang)->lists->{$s};
1007 my $val = 0;
1008 if (defined($l) ) {
1009 $self->reportAdd(1, $item->{'type'}, "$s refers to an existing list");
1010 $val = 1;
1011 } else {
1012 $self->reportAdd(0, $item->{'type'}, "$s does not refer to an existing list");
1013 }
1014 return $val;
1015}
1016
1017sub testRuleLineContinue {
1018 my ($self, $item) = @_;
1019 my $result = 1;
1020 unless ($self->testRuleOptions($item)) { $result = 0 };
1021 return $result;
1022}
1023
1024sub testRuleRangeDetect {
1025 my ($self, $item) = @_;
1026 my $result = 1;
1027 unless ($self->testRuleOptions($item)) { $result = 0 };
1028 return $result;
1029}
1030
1031sub testRuleRegExpr {
1032 my ($self, $item) = @_;
1033 my $s = $item->{'String'};
1034 my $res = "regex test '$s'";
1035 my $stub = "stubtext";
1036 eval "\$stub =~ /\$s/";
1037 my $val = 0;
1038 if ($@) {
1039 my $bck = $@;
1040 chomp $bck;
1041 $self->reportAdd(0, $item->{'type'}, "$res : $bck");
1042 } else {
1043 $self->reportAdd(1, $item->{'type'}, $res);
1044 $val = 1;
1045 }
1046# $self->lprint($res);
1047 return $val;
1048}
1049
1050
1051sub testRuleStringDetect {
1052 my ($self, $item) = @_;
1053 my $result = 1;
1054 unless ($self->testRuleOptions($item)) { $result = 0 };
1055 return $result;
1056}
1057
1058sub textLength {
1059 my ($cw, $txt, $length) = @_;
1060 while (length($txt) < $length) { $txt = $txt . " " }
1061 return $txt;
1062}
1063
1064
1065sub verbose {
1066 my $self = shift;
1067 if (@_) { $self->{'verbose'} = shift; };
1068 return $self->{'verbose'};
1069}
1070
1071sub version {
1072 my $self = shift;
1073 if (@_) { $self->{'version'} = shift; };
1074 return $self->{'version'};
1075}
1076
1077sub xmldata {
1078 my ($self, $lang) = @_;
1079 if (defined($lang)) {
1080 my $r = $self->{'registered'};
1081 unless (exists $r->{$lang}) { return undef }
1082 return $r->{$lang}
1083 } else {
1084 $self->log("language not specified, cannot return xmldata object");
1085 return undef;
1086 }
1087}
1088
10891;