summaryrefslogtreecommitdiff
path: root/internal/generated/generate.raku
blob: babb6557df44031afa66ad1dc35acdf4a0962138 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#!/usr/bin/env raku
#
# This Raku program takes a list of C struct and constant definitions and converts
# it to valid Go code.

#use Grammar::Debugger;

# Not quite C
grammar NQC {
    rule TOP { <construct>* }
    rule construct { <constant> | <statement> || <comment> }
    rule constant { '#define' <identifier> <number> }
    rule statement { <struct> ';' }
    rule struct { 'struct' <identifier> '{' <member>+ %% ';' '}' }
    rule member { <type> <identifier> <arraysize>? }
    rule comment { <single-line-comment> | <multi-line-comment> }
    rule single-line-comment { '//' <-[\n]>+ }
    rule multi-line-comment { '/*' .*? '*/' }
    token arraysize { '[' <identifier> ']' }
    token type { 'char' | '__s32' | '__u32' | '__u64' }
    token identifier { <[a..z A..Z 0..9 _]>+ }
    token number { \d+ }
}
 
class NQCToGoActions {
    method TOP($/) { make "package types\n\n" ~ $<construct>.map(*.made).join('') }
    method construct($/) { make $<constant>.made // $<statement>.made // '' }
    method statement($/) { make "\n" ~ $<struct>.made ~ "\n"; }
    method constant($/) { make 'const ' ~ $<identifier> ~ ' = ' ~ $<number> ~ "\n" }

    method struct($/) {
        make 'type ' ~ $<identifier>.made ~ " struct \{\n\t" ~
                       $<member>.map(*.made).join("\n\t") ~ "\n\}"
    }

    method member($/) {
        make $<identifier>.made ~ ' ' ~ ($<arraysize> ?? $<arraysize> !! '') ~ $<type>.made
    }

    method type($/) {
        make do given ~$/ {
            when 'char' { 'byte' }
            when '__s32' { 'int32' }
            when '__u32' { 'uint32' }
            when '__u64' { 'uint64' }
        };
    }

    method identifier($/) {
        # Convert identifier from snake_case (C) to CamelCase (Go)
        make $/.Str.split('_').map(*.tc).join('')
    }
}

multi sub MAIN('nqctogo') {
    NQC.parse($*IN.slurp, :actions(NQCToGoActions.new)).made.say;
}