summaryrefslogtreecommitdiff
path: root/internal/generated/nqc.raku
blob: f358e2a4a87d01d61b3b6f178b2918b385a94eef (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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
#!/usr/bin/env raku
#
# This Raku program takes a list of C struct and constant definitions and converts
# it to valid Go code.

use v6.d;
#use Grammar::Debugger;

# Not quite C
grammar NQC {
    rule TOP { <construct>* }
    rule construct { <constant> | <statement> | <comment> }
    rule constant { '#define' <identifier> <number> <-[\n]>+ }
    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 "// This file was generated - don't change manually!\n" ~
             "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\}\n\n"
            ~ self!struct-go-string-method($/);
    }

    # Generate String() method on the Go struct, for pretty printing.
    method !struct-go-string-method($/) returns Str {
        my Str $self-ref = $<identifier>.lc.substr(0,1);
        my Str @format = $<member>.map({ $_.<identifier>.made ~ ':%v' });
        my Str @args = $<member>.map({ "$self-ref." ~ $_.<identifier>.made });

        return qq:to/END/;
               func ({$self-ref} {$<identifier>}) String() string \{
               \treturn fmt.Sprintf("{@format.join(' ')}", {@args.join(', ')})
               \}
               END
    }

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

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

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

say NQC.parse($*IN.slurp, :actions(NQCToGoActions)).made;