Skip to content

Instantly share code, notes, and snippets.

@rightfold

rightfold/.pm6 Secret

Created January 28, 2015 12:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rightfold/9296916eb5f32c6580d6 to your computer and use it in GitHub Desktop.
Save rightfold/9296916eb5f32c6580d6 to your computer and use it in GitHub Desktop.
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