docs/dup/beamsplitter.html
This Go program consumes C++ header file(s) and generates Java bindings, JavaScript bindings, and C++ code that performs JSON serialization.
To install the Go compiler on macOS, just do:
brew install go
To build and invoke the code generator, do:
cd tools/beamsplitter ; go run .
Special directives in the form %codegen_foo% are called emitter flags. They are typically embedded in a comment associated with a particular struct field.
| flag | description |
|---|---|
| codegen_skip_json | Field is skipped when generating JSON serialization code. |
| codegen_skip_javascript | Field is skipped when generating JavaScript and TypeScript bindings. |
| codegen_java_flatten | Field is replaced with constituent sub-fields. |
| codegen_java_float | Field will be forced to have a float representation in Java. |
filament/include/filament/Options.hThe following files are created:
libs/viewer/src/Settings_generated.hlibs/viewer/src/Settings_generated.cppweb/filament-js/jsbindings_generated.cppweb/filament-js/jsenums_generated.cppweb/filament-js/extensions_generated.jsAdditionally, in-place edits are made to the following files:
web/filament-js/filament.d.tsandroid/filament-android/src/main/java/.../View.javaThere are many ways in which the source file format is more restrictive than the full C++ language, but here are some of the highlights:
#include files are ignored.The following formal grammar describes the above limitations in greater detail, but with some caveats:
UTILS_PUBLIC and UTILS_DEPRECATED).%codegen_foo% are detected in a post-processing phase and removed from all comments.root = namespace ;
namespace = "namespace" , [ident] , "{" , { block } , "}" ;
block = class | struct | enum | namespace | using | forward_declaration;
forward_declaration = ("class" | "struct" ) , ident , ";" ;
template = "template" , "TemplateArgs" ;
class = [template] , "class" , ident , [":" , [ "public"] , "SimpleType" ]
, "{" , struct_body , "}" , ";" ;
struct = [template] , "struct" , ident , "{" , struct_body , "}" , ";" ;
enum = "enum" , "class" , ident , [":" , type]
, "{" , , ident , { "," , ident } , [","] , "}" , ";" ;
using = "using" , ident , "=", type , ";" ;
struct_body = { access_specifier | field | method | block } ;
access_specifier = ("public" | "private" | "protected" ) , ":" ;
method = [template] , { "constexpr" , "friend" } ,
, type , ident , "MethodArgs" , specifiers , ( ";" | "MethodBody" ) ;
specifiers = { "const" | "noexcept" } ;
field = type , ident , [array] , ["=" , "DefaultValue"] ";" ;
array = "[" , "ArrayLength", "]" ;
type = "SimpleType" ;
ident = "Identifier" ;
The above grammar uses the following notation:
" ... " denotes a terminal{ ... } denotes zero or more repetition[...] denotes an optional quantity( ... ) is used for groupinga | b denotes a choicea , b denotes concatenation; terminates a production| Terminal name | Description |
|---|---|
| SimpleType (*) | examples: Texture* const, uint8_t, BlendMode |
| MethodBody | unparsed implementation of a function or method, including outer {} |
| MethodArgs | similar to above; an unparsed blob, but delimited with () |
| TemplateArgs | similar to above; an unparsed blob, but delimited with <> |
| DefaultValue (**) | an unparsed expression with certain restrictions |
| Identifier | [A-Za-z_][A-Za-z0-9_]* |
| ArrayLength | [1-9][0-9]* |
(*) SimpleType should not contain parentheses or commas, so C callbacks are not allowed unless you alias them first.
(**) If DefaultValue is a vector, it must be in the form: { x, y, z }.
Initially inspired by the following Rob Pike talk.
Beamsplitter does not use the state machine described in the above prezo, but it does use a channel for separating the parser from the lexer. The beamsplitter lexer is actually a recursive descent parser with simple lookahead functionality. This makes it easy for the "real" parser to create a coarse-grained AST.
The companion to the above talk is Go's template lexer, which can be studied here:
Wikipedia has a good example of recursive descent: