Files
filament/tools/beamsplitter/main.go
T
Philip Rideout c82ae6a3a7 beamsplitter: add recursive descent parser
This removes usage of regexps from the parsing phase and splits the
program into three sub-packages: parser, database, and emitters.

The parser now generates an AST according to the formal grammar
described in the README:

https://github.com/google/filament/blob/pr/beamsplitter_rewrite2/tools/beamsplitter/README.md#grammar

This allows for nice readable error messages. More importantly, it
permits the C++ syntax to be less restrictive and paves the way for
possible expansion of the tool beyond `Options.h`.

I looked at the C++ AST generated by clang but it is huge and unwieldy.
For our purposes this simplified AST is much easier to work with.

The new lexer is inspired by the following Rob Pike talk.
- https://www.youtube.com/watch?v=HxaD_trXwRE

Beamsplitter does not use the state machine described in the above
prezo, but it does use a Go channel for separating the parser from the
lexer. In our case, the lexer is actually a recursive descent parser
with simple lookahead functionality. This made it easy for the "real"
parser to create an ergonomic coarse-grained AST.

This is a big change but it is a no-op in terms of the generated code.
2022-05-23 09:36:29 -07:00

101 lines
2.8 KiB
Go

/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package main
import (
"fmt"
"log"
"os"
"path/filepath"
"runtime"
db "beamsplitter/database"
"beamsplitter/emitters"
"beamsplitter/parse"
)
var CHECK_API_SYNTAX = false
func findFilamentRoot() string {
var (
_, b, _, _ = runtime.Caller(0)
thisFolder = filepath.Dir(b)
toolsFolder = filepath.Dir(thisFolder)
)
return filepath.Dir(toolsFolder)
}
func main() {
const sourceFilename = "Options.h"
log.SetFlags(0)
log.SetPrefix(sourceFilename + ":")
root := findFilamentRoot()
sourcePath := filepath.Join(root, "filament", "include", "filament", sourceFilename)
data, err := os.ReadFile(sourcePath)
if err != nil {
log.Fatal(err)
}
contents := string(data)
ast := parse.Parse(contents)
definitions := db.Create(ast, contents)
emitters.EmitSerializer(definitions, filepath.Join(root, "libs", "viewer", "src"))
jsfolder := filepath.Join(root, "web", "filament-js")
emitters.EmitJavaScript(definitions, "View", jsfolder)
emitters.EditTypeScript(definitions, "View", jsfolder)
javafolder := filepath.FromSlash("com/google/android/filament")
javafolder = filepath.Join(root, "android/filament-android/src/main/java", javafolder)
emitters.EditJava(definitions, "View", javafolder)
fmt.Print(`
Note that this tool does not generate bindings for setter methods on
filament::View. If you added or renamed one of the setter methods, you
will likely need to manually modify the following files:
- web/filament-js/extensions.js
- web/filament-js/jsbindings.cpp
- web/filament-js/filament.d.ts
- filament/include/filament/View.h
- filament/src/View.cpp
- filament/src/details/View.cpp
- android/filament-android/src/main/java/.../View.java
- android/filament-android/src/main/cpp/View.cpp
`)
if CHECK_API_SYNTAX {
sources := []string{}
apiPath := filepath.Join(root, "filament", "include", "filament")
entries, err := os.ReadDir(apiPath)
for _, entry := range entries {
sources = append(sources, filepath.Join(apiPath, entry.Name()))
}
for _, source := range sources {
log.SetPrefix(filepath.Base(source) + ":")
data, err = os.ReadFile(source)
if err != nil {
log.Fatal(err)
}
contents = string(data)
parse.Parse(contents)
}
}
}