-
-
Save rightfold/9296916eb5f32c6580d6 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Entity { } | |
class Extern is Entity { | |
has Str $.name; | |
has Str %.names{Str}; | |
} | |
class Struct is Entity { | |
class Field { | |
has Str $.name; | |
has Str $.type; | |
} | |
has Str $.name; | |
has Field @.fields; | |
} | |
class Enum is Entity { | |
has Str $.name; | |
} | |
module Parse { | |
grammar Grammar { | |
rule TOP { <entity>* } | |
token identifier { | |
<[a..z A..Z]> <[a..z A..Z 0..9 \- _]>* | |
} | |
rule entity { <extern> || <struct> || <enum> } | |
rule extern { | |
extern $<name>=<identifier> \{ | |
<extern-name>* | |
\} | |
} | |
rule extern-name { | |
<identifier> ':' <identifier> ';' | |
} | |
rule struct { | |
struct $<name>=<identifier> \{ | |
<struct-field>* | |
\} | |
} | |
rule struct-field { | |
$<name>=<identifier> ':' $<type>=<identifier> ';' | |
} | |
rule enum { | |
enum $<name>=<identifier> \{ | |
\} | |
} | |
} | |
class Actions { | |
method TOP($/) { | |
make map { .ast }, @($<entity>); | |
} | |
method entity($/) { | |
make ($<extern> || $<struct> || $<enum>).ast; | |
} | |
method extern($/) { | |
make Extern.new(:name($<name>.Str)); | |
} | |
method struct($/) { | |
my @fields = map { .ast }, @<struct-field>; | |
make Struct.new(:name($<name>.Str), :@fields); | |
} | |
method struct-field($/) { | |
make Struct::Field.new(:name($<name>.Str), :type($<type>.Str)); | |
} | |
method enum($/) { | |
make Enum.new(:name($<name>.Str)); | |
} | |
} | |
our sub parse(Str $input) { | |
my $result = Grammar.parse($input, :actions(Actions.new)); | |
fail unless $result; | |
$result.ast; | |
} | |
} | |
sub camel-case(Str $x) { | |
$x.subst(/'-'<[a..z A..Z]>/, { .substr(1).uc }, :g); | |
} | |
sub pascal-case(Str $x) { | |
camel-case($x).tc; | |
} | |
sub snake-case(Str $x) { | |
$x.subst(/'-'/, '_'); | |
} | |
multi sub to-python3(Struct $entity) { | |
my $result = ''; | |
$result ~= "class {$entity.name ==> pascal-case()}:\n"; | |
$result ~= " def __init__(self{$entity.fields.map({ ", {$_.name ==> snake-case()}" }).join}):\n"; | |
if $entity.fields { | |
for $entity.fields { | |
$result ~= " assert isinstance({$_.name ==> snake-case()}, {$_.type})\n"; | |
} | |
$result ~= "\n"; | |
for $entity.fields { | |
$result ~= " self._{$_.name ==> snake-case()} = {$_.name ==> snake-case()}\n"; | |
} | |
} else { | |
$result ~= " pass\n"; | |
} | |
for $entity.fields { | |
$result ~= "\n"; | |
$result ~= " @property\n"; | |
$result ~= " def {$_.name ==> snake-case()}(self):\n"; | |
$result ~= " return self._{$_.name ==> snake-case()}\n" | |
} | |
$result ~= "\n"; | |
$result ~= " def update(self, **kwargs):\n"; | |
$result ~= " fields = dict(\n"; | |
for $entity.fields { | |
$result ~= " {$_.name ==> snake-case()}=self._{$_.name ==> snake-case()},\n"; | |
} | |
$result ~= " )\n"; | |
$result ~= " fields.update(kwargs)\n"; | |
$result ~= " return {$entity.name ==> pascal-case()}(**fields)"; | |
$result; | |
} | |
my $entities = Parse::parse(q:heredoc/EOF/); | |
extern int { | |
python3: int; | |
javascript: number; | |
} | |
extern string { | |
python3: str; | |
javascript: string; | |
} | |
struct user-foo { | |
id: int; | |
name: string; | |
email-address: string; | |
} | |
enum B { | |
} | |
EOF | |
$entities.grep(Struct).map(&to-python3).join('\n').say; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment