#!/usr/bin/perl -w

use strict;

my %sce_lang = (
   perl => "PL",
   html => "H",
   ruby => "RB",
   vbscript => "B",
   xslt => "XML",
);

my %LexerConstant;
open(my $fh, "<", "SciLexer_gen.h") || die "Can't open 'SciLexer_gen.h': $!";
while (<$fh>) {
    if (/^\#define\s+(\w+)\s+(\d+)/) {
        $LexerConstant{$1} = $2;
    }
    else {
        warn "Can't parse: $_";
    }
}
close($fh);

my @generic = qw(default comment keyword variable operator number string regex);
my %generic = map {uc($_) => uc($_)} @generic;
while (<DATA>) {
    next if /^\s*(\#|$)/;
    my($gen, @rest) = split;
    $generic{$_} = $gen for @rest;
}
close(DATA);

my $i = 0;
for (@generic) {
    printf "#define %-25s %2d\n", "STYLE_GENERIC_\U$_", $i++;
}
print "\n";

print "static const char* style_names[] = {\n";
for (@generic) {
    print qq(    "$_",\n);
}
print qq(    "unused"\n);
print "};\n\n";

for my $lang (sort keys %sce_lang) {
    my $prefix = "SCE_$sce_lang{$lang}_";
    delete $LexerConstant{$prefix . "UPPER_BOUND"};
    my @constants = grep /^$prefix/, keys %LexerConstant;
    die unless @constants;
    @constants = sort {$LexerConstant{$a} <=> $LexerConstant{$b}} @constants;
    my $max = $LexerConstant{$constants[-1]};
    my %name = map { $LexerConstant{$_} => $_ } @constants;
    print "static int ${lang}_style_name_parts[] = {\n";
    for my $i (0 .. $max) {
	my $name = $name{$i} || "";
	my $basename = $name ? substr($name, length($prefix)) : "";
	my $style;
	for ($name, $basename) {
	    $style ||= "STYLE_GENERIC_$generic{$_}" if exists $generic{$_};
	}
	$style ||= "STYLE_GENERIC_DEFAULT";
	printf "    %-25s /* %s */\n", "$style,", $name || $i;
    }
    print "    STYLE_GENERIC_DEFAULT     /* dummy */\n";
    print "};\n\n";
}

print <<'EOT';
static struct {
    int lang;
    int* style_name_parts;
} style_name_parts[] = {
EOT

for my $lang (sort keys %sce_lang) {
    print "    { SCLEX_\U$lang\E, ${lang}_style_name_parts },\n";
}
print "};\n\n";

__END__
# extra generic mappings
# html
KEYWORD SCE_H_TAG SCE_H_TAGUNKNOWN SCE_H_TAGEND
VARIABLE SCE_H_ATTRIBUTE SCE_H_ATTRIBUTEUNKNOWN
STRING SCE_H_DOUBLESTRING SCE_H_SINGLESTRING

# perl
VARIABLE SCE_PL_SCALAR SCE_PL_IDENTIFIER SCE_PL_ARRAY SCE_PL_HASH SCE_PL_SYMBOLTABLE SCE_PL_SUB
COMMENT SCE_PL_COMMENTLINE SCE_PL_POD SCE_PL_DATASECTION
KEYWORD SCE_PL_WORD
OPERATOR SCE_PL_PUNCTUATION SCE_PL_VARIABLE_INDEXER SCE_PL_SUB_ARGS
STRING SCE_PL_CHARACTER SCE_PL_LONGQUOTE SCE_PL_BACKTICKS
STRING SCE_PL_HERE_Q SCE_PL_HERE_QQ SCE_PL_HERE_QX
STRING SCE_PL_STRING_Q SCE_PL_STRING_QQ SCE_PL_STRING_QX SCE_PL_STRING_QR SCE_PL_STRING_QW
REGEX SCE_PL_REGSUBST

# ruby
VARIABLE SCE_RB_IDENTIFIER
COMMENT SCE_RB_COMMENTLINE SCE_RB_POD
KEYWORD SCE_RB_WORD
STRING SCE_RB_CHARACTER
STRING SCE_RB_HERE_Q SCE_RB_HERE_QQ SCE_RB_HERE_QX
STRING SCE_RB_STRING_Q SCE_RB_STRING_QQ SCE_RB_STRING_QX SCE_RB_STRING_QR SCE_RB_STRING_QW

# vb
VARIABLE SCE_B_IDENTIFIER
STRING SCE_B_DATE SCE_B_STRINGEOL
KEYWORD SCE_B_KEYWORD2 SCE_B_KEYWORD3 SCE_B_KEYWORD4
