my $outHeaderFile = "$headerOutDir/$prefix.h";
my $outSrcFile = "$srcOutDir/$prefix.cc";
my $stack = "Stack";
my $errors = 0;
sub report_error {
my $filename = shift;
my $line = shift;
my $error = shift;
print STDERR "$filename:$line: $error\n";
$errors = 1;
}
sub assoc_error {
my $filename = shift;
my $line = shift;
my $type = shift;
report_error($filename, $line, "no asy type associated to '$type'");
}
sub clean_type {
for (@_) {
s/\s//g;
}
}
sub clean_params {
for (@_) {
s/\n//g;
}
}
my %type_map;
sub read_types {
my @types = split /\n/, shift;
my $filename = shift;
my $line = shift;
for (@types) {
++$line;
# Remove // comments.
s/\/\/.*//g;
# Skip blank lines.
next if /^\s*$/;
my ($type,$code) =
m|(\w*(?:\s*\*)?)
\s*=>\s*
(.*)
|x;
if (not $type) {
report_error($filename, $line, "bad type declaration");
}
clean_type($type);
$type_map{$type} = $code;
}
}
# Scrape the symbol names of the operators from opsymbols.h.
my %opsymbols = ();
open(my $opsyms, $opsymbolsFile) ||
die("Couldn't open $opsymbolsFile");
while (<$opsyms>) {
if (m/^OPSYMBOL\(\"(.*)\", ([A-Za-z_]+)\);/) {
$opsymbols{ $1 } = $2;
}
}
close($opsyms);
# Turn a name into a symbol.
sub symbolize {
my $name = shift;
if ($name =~ /^[A-Za-z0-9_]+$/) {
return "SYM($name)";
}
if ($opsymbols{ $name }) {
return $opsymbols{ $name };
}
if ($name =~ /operator (\w+)/ && $opsymbols{ $1 }) {
return $opsymbols{ $1 }
}
return "symbol::trans(\"" . $name . "\")"
}
sub asy_params {
my $params = shift;
my @params = split m/,\s*/, $params;
my $filename = shift;
my $line = shift;
for (@params) {
my ($explicit, $type, $name, $default) =
m|^\s*
(explicit)*\s*(\w*(?:\s*\*)?)
\s*
(\w*)(=*)|xs;
clean_type($type);
if (not $type_map{$type}) {
assoc_error($filename, $line, $type);
}
$_ = "formal(" . $type_map{$type} . ", " .
symbolize(lc($name)) . ", " .
($default ? "true" : "false") . ", " .
($explicit ? "true" : "false") . ")";
}
return @params;
}
open STDIN, "<$srcTemplateDir/$prefix.in" or die "can't open input file $srcTemplateDir/$prefix.in";
open BASE, "<$runtimeBaseFile" or die "can't open $runtimeBaseFile";
open STDOUT, ">$outSrcFile" or die "can't open output file $outSrcFile";
### Begining of `$prefix.h'
my @header;
push @header, $autogenerated;
# TODO: Capitalize prefix
push @header, "#pragma once\n";
push @header, "namespace run {\n";
my $count = 0;
my @builtin;
while (<>) {
my ($comments,$type,$name,$cname,$params,$code) =
m|^((?:\s*//[^\n]*\n)*) # comment lines
\s*
(\w*(?:\s*\*)?) # return type
\s*
([^(:]*)\:*([^(]*) # function name
\s*
\(([\w\s*,=.+\-]*)\) # parameters
\s*
\{(.*)} # body
|xs;
if (not $type) {
report_error("$prefix.in", $source_line, "bad function definition");
}
if($cname) {push @header, "void $cname(vm::stack *);\n";}
else {$cname="gen_$prefix${count}";} # Unique C++ function name
# Build REGISTER_BLTIN command for builtin functions which are not added to
# the environment.
if (not $name and $cname) {
push @builtin, "#line $source_line \"$srcTemplateDir/$prefix.in\"\n"
. " REGISTER_BLTIN(run::" . $cname
. ',"' . $cname . '"' . ");\n";
}
# Handle marshalling of values to/from stack
my $qualifier = ($type eq "item" ? "" : "<$type>");
$code =~ s/\breturn ([^;]*);/{$stack->push$qualifier($1); return;}/g;
my $args = join("",c_params(@params));