#!/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 { * } rule construct { | | } rule constant { '#define' <-[\n]>+ } rule statement { ';' } rule struct { 'struct' '{' + %% ';' '}' } rule member { ? } rule comment { | } rule single-line-comment { '//' <-[\n]>+ } rule multi-line-comment { '/*' .*? '*/' } token arraysize { '[' ']' } 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" ~ $.map(*.made).join('') } method construct($/) { make $.made // $.made // '' } method statement($/) { make "\n" ~ $.made ~ "\n"; } method constant($/) { make 'const ' ~ $ ~ ' = ' ~ $ ~ "\n" } method struct($/) { make 'type ' ~ $.made ~ " struct \{\n\t" ~ $.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 = $.lc.substr(0,1); my Str @format = $.map({ $_..made ~ ':%v' }); my Str @args = $.map({ "$self-ref." ~ $_..made }); return qq:to/END/; func ({$self-ref} {$}) String() string \{ \treturn fmt.Sprintf("{@format.join(' ')}", {@args.join(', ')}) \} END } method member($/) { make $.made ~ ' ' ~ ($ // '') ~ $.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;