#!/usr/bin/perl6 use v6; grammar DSL { my $e = "document start"; token TOP { ^ * * $ } token include_block { 'include' \s+ '"' '"' \s* ';' \s* } token quant_block { \s+ \s* '{' \s* [[{$e=$/} ||||] \s*] * \s* '}' \s* } token on_block { 'on' \s+ \s* '{' \s* [[{$e=$/} |] \s*] * \s* '}' } token emit_block { 'emit' \s+ \s* '{' \s* [[{$e=$/} ||||] \s*] * \s* '}' } token decl { \s+ \s* ['=' \s* \s*]? ';' } token evolve { \' \s* '=' \s* \s* ';' } token default { 'default' \s+ \s* ';' } token if_ { 'if' \s+ \' \s* ';' } token after { 'after' \s+ \s* ';' } token comment { '//' \N* $$ } token name { \w+ } token filename { \w+ } token type { [':'|\w]+ } token quant_type { ['discrete'|'continuous'|'const'] } token bool { ['true'|'false'] } token expr { <-[;{}]>* } # MAYBE TODO: improve method error() { return $e; } } sub transform($quant_blocks) { my %quant_types; my %vars; my %consts; my %res = :const(''), :decl(''), :evolve(''), :on(''), :qdq(''), :emit(''), :gpe(''), :gen(''), :debug(''); my %rawexpr_evolve; # funs to replace def strings to C++-Code sub replace_consts($expr is copy) { for %consts.kv -> $name, $val { $expr = $expr.subst(rx/<<$name>>/, "$val /* $name */", :g); } return $expr; } sub replace_dt($expr is copy) { $expr = $expr.subst(rx/<<'dt'>>/, "td()", :g); return $expr; } sub replace_expr($expr is copy, %local_exprs) { # replace post-event vars ONCE for %vars.kv -> $prop, $quant { # post event is only defined for continuous quants next if %quant_types{$quant} eq 'discrete'; $expr = $expr.subst(rx/<<$prop>>"'"/, "(%local_exprs{$prop})", :g); } return $expr; } sub replace_vars($expr is copy) { # replace normal vars for %vars.kv -> $prop, $quant { if %quant_types{$quant} eq 'continuous' { $expr = $expr.subst(rx/<<$prop>>/, "_CP($prop)", :g); } else { die unless %quant_types{$quant} eq 'discrete'; $expr = $expr.subst(rx/<<$prop>>/, "_DP($prop)", :g); } } return $expr; } sub replace_all($expr is copy, %local_exprs) { $expr = replace_consts( replace_dt( replace_vars( replace_expr($expr, %local_exprs)))); $expr = $expr.subst(rx/"_PROT">>/, "q", :g); return $expr; } sub replace_all_after($expr is copy, %local_exprs) { $expr = $expr.subst(rx/"'"/, "_PROTTICK", :g); $expr = replace_vars($expr); $expr = $expr.subst(rx/"_PROTTICK"/, "'", :g); return replace_consts( replace_expr($expr, %local_exprs)); } # gather all properties (required to patch expressions) for @($quant_blocks) { my $qc = $_; my $qt = $_; %quant_types{$qc} = $qt; for @($_) { my $name = $_; if $qt eq 'const' { if not %consts{$name} { my $type = $_; %consts{$name} = $_; %res ~= "const $type $name = $_;\n"; } } else { die "multiple declaration of $_" if %(%vars, %consts){$name}; %vars{$name} = $qc; } } for @($_) { %rawexpr_evolve{$_} = $_; } } # print definitions for @($quant_blocks) { my $qc = $_; my $emit = $_; my %types; next if ($qc eq 'const'); %res = %res <<~>> "// Quantor: $qc\n"; for @($_) { %types{$_} = $_; if %quant_types{%vars{$_}} eq 'continuous' { %res ~= "GEN_CP($qc, $_, \"$_\", $_, (" ~ replace_consts($_) ~ "));\n"; } else { %res ~= "GEN_DP($qc, $_, \"$_\", $_);\n"; } } for @($_) { %res ~= "GEN_CP_EVOLVE($_, " ~ replace_all($_, %rawexpr_evolve) ~ ");\n"; } for @($_) { my $dqc = $_; my %rawexpr_emit = gather for @($_) { take %($_, $_); }; my %rawexpr_after = gather for @(%vars) { my $k=$_.key; take %($k, "_TP($k)"); }; %res ~= "GEN_QUANT_EMIT($qc, $dqc, $_[0]);\n"; if $_.elems > 0 { # TODO: generate has-var-delay statement at most # once per discrete quant %res ~= "GEN_QUANT_HASVARDELAY($dqc);\n" ~ "GEN_DP_DELAY($dqc, $qc, " ~ replace_all_after($_[0], %rawexpr_after) ~ ");\n"; } for @($_) { die "$_ of %vars{$_} != $qc, $dqc" unless (%vars{$_} eq $dqc) || (%vars{$_} eq $qc); %res ~= "GEN_CP_GENERATE($qc, $dqc, $_) \{ " ~ "value = " ~ replace_all($_, %rawexpr_emit) ~ "; \}\};\n"; } } for @($_) { my $src_quant = $_; %res ~= "GEN_QDQ($_, $qc);\n"; my %is_evolved; my %rawexpr_on = gather for @($_) { take %($_, $_); }; for @($_) { my $dprop = $_; %res ~= "GEN_CP_APPLY($dprop, $src_quant, true) \{\n" ~ " const %types{$dprop} tmp = " ~ replace_all($_, %rawexpr_on) ~ ";\n" ~ " transaction.template set<$dprop>(tmp);\n"; for @($emit) { my $dst_quant = $_; my %rawexpr_emit = gather for @($_) { take %($_, $_); }; for @($_) { if $_ eq $dprop { # %res ~= "std::cout << \"combine(tmp($dprop" ~ replace_consts($_) ~ ")\" << std::endl;"; %res ~= " intent.template get<$dst_quant>()" ~ ".combine(tmp" ~ replace_consts($_) ~ ");\n"; } } } %res ~= "\}\};\n"; # sic! %is_evolved{$dprop} = True; } for @($emit) { my $dst_quant = $_; for @($_) { unless %is_evolved{$_} { # HINT: use _CP for access because the value is unchanged %res ~= "GEN_CP_APPLY($_, $src_quant, false) \{\n" # ~ "std::cout << \"combine(_CP($_" ~ replace_consts($_) ~ ")\" << std::endl;" ~ " intent.template get<$dst_quant>()" ~ ".combine(_CP($_)" ~ replace_consts($_) ~ ");\n\}\};\n"; # TODO: replace consts } } } } } # create list of %res = "typedef boost::mpl::list<\n\t" ~ %vars.keys.map({"boost::mpl::pair<$_, boost::mpl::bool_>"}).join(",\n\t") ~ "\n> all;\n\n" ~ "typedef boost::mpl::list<\n\t" ~ %vars.keys.map({"boost::mpl::pair<$_, boost::mpl::bool_>"}).join(",\n\t") ~ "\n> all_ro;"; # push results %res = %res <<~>> "\n"; say "#ifndef RASIMU_SIMULATION_DEFINITION #define RASIMU_SIMULATION_DEFINITION #include \"core/property_abbrevations_begin.hpp\" namespace ModelConsts \{ %res \} %res %res %res %res %res %res %res"," namespace Lists \{ %res"," \} // generated by ",qqx{perl6 --version|grep version}," /* DEBUG MSGS %res */ #include \"core/property_abbrevations_end.hpp\" #endif // RASIMU_SIMULATION_DEFINITION"; } sub parse($src) { my $p = DSL.new; if $p.parse(slurp $src) { my @qbs = @($); for @($) { @qbs.push(parse($_ ~ ".model")); } return @qbs; } else { die "Error after:\n", $p.error; } } sub MAIN($src) { transform(parse($src)); #parse($src).perl.say; }