Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bebop v3 #40

Open
andrewmd5 opened this issue Mar 13, 2024 · 2 comments
Open

Bebop v3 #40

andrewmd5 opened this issue Mar 13, 2024 · 2 comments

Comments

@andrewmd5
Copy link

andrewmd5 commented Mar 13, 2024

Hey! So I just wanted to drop a note that Bebop v3 is officially out and it has a number of breaking changes to the schema languages.

With that being said, it also has a new compiler extension layer which would allow you to write a Go generator in Go, and I wanted to see if you'd be interested in collaborating to bring this project into the ecosystem in a more standard way, so folks can use bebopc to generate code, and continue relying on your runtime.

You can find an example of a Go extension here.

@200sc
Copy link
Owner

200sc commented Mar 16, 2024

Just so I understand, is there an existing extension format that requires the use of e.g. gjson and tiny go or bebopc just supports any wasm based extension?

In the latter case, it's not unreasonable to offer a prebuilt wasm target using this codebase, however there's a number of questions, e.g. does the extension parse the AST or is it provided the AST to render; how are the incompatibilities around recursive type definitions, etc resolved; does bebopc support an output mode compatible with distinct modules or would the extension have to output assuming all dependencies are adjacent in the output file, and so on.

I'll open issues for the new functionality (mut, env vars, custom decorators, tempo)

@andrewmd5
Copy link
Author

Just so I understand, is there an existing extension format that requires the use of e.g. gjson and tiny go or bebopc just supports any wasm based extension?

I need to improve the documentation, but there is a new extension format called chords (you can find the chord compiler on the release page). Chords are ultimately just WASM/WASI binaries, and bebopc has glue code to interact with them. Right now, there is built in support for chords produced from TinyGo, Javascript, and AssemblyScript.

At a high-level, bebopc feeds a JSON string (the AST) to the extension which contains all the definitions in a schema:

{
  "definitions": {
    "Instrument": {
      "kind": "enum",
      "documentation": "A a collection of would play see  for more information",
      "decorators": {
        "flags": {}
      },
      "isBitFlags": true,
      "minimalEncodedSize": 4,
      "baseType": "uint32",
      "members": {
        "Default": {
          "value": "0"
        },
        "Sax": {
          "documentation": "What",
          "value": "1"
        },
        "Trumpet": {
          "decorators": {
            "deprecated": {
              "arguments": {
                "reason": {
                  "type": "string",
                  "value": "Use of Trumpet is not recommended"
                }
              }
            }
          },
          "value": "2"
        },
        "Clarinet": {
          "value": "3"
        }
      }
    },
    "Musician": {
      "kind": "struct",
      "documentation": "A musician in the band",
      "minimalEncodedSize": 32,
      "mutable": false,
      "isFixedSize": false,
      "fields": {
        "name": {
          "documentation": "The name of the musician",
          "type": "string"
        },
        "plays": {
          "documentation": "The instrument the musician plays",
          "type": "Instrument"
        },
        "birthDate": {
          "type": "date"
        },
        "id": {
          "type": "guid"
        }
      }
    },
    "Something": {
      "kind": "struct",
      "minimalEncodedSize": 28,
      "mutable": false,
      "isFixedSize": false,
      "fields": {
        "name": {
          "type": "string"
        },
        "age": {
          "type": "uint32"
        },
        "arrayOfMaps": {
          "type": "array",
          "array": {
            "depth": 0,
            "memberType": "map",
            "map": {
              "keyType": "string",
              "valueType": "string"
            }
          }
        },
        "complexIntMapArray": {
          "type": "array",
          "array": {
            "depth": 0,
            "memberType": "map",
            "map": {
              "keyType": "string",
              "valueType": "array",
              "array": {
                "depth": 0,
                "memberType": "int32"
              }
            }
          }
        },
        "testMap": {
          "type": "map",
          "map": {
            "keyType": "string",
            "valueType": "string"
          }
        },
        "complexMap": {
          "type": "map",
          "map": {
            "keyType": "string",
            "valueType": "array",
            "array": {
              "depth": 0,
              "memberType": "string"
            }
          }
        },
        "nestedMap": {
          "type": "map",
          "map": {
            "keyType": "string",
            "valueType": "map",
            "map": {
              "keyType": "string",
              "valueType": "string"
            }
          }
        }
      }
    },
    "Song": {
      "kind": "message",
      "documentation": "A song",
      "minimalEncodedSize": 5,
      "fields": {
        "title": {
          "documentation": "The title of the song",
          "type": "string",
          "index": 1
        },
        "year": {
          "documentation": "The year the song was released",
          "type": "uint16",
          "index": 2
        },
        "performers": {
          "documentation": "The musicians who performed the song",
          "decorators": {
            "deprecated": {
              "arguments": {
                "reason": {
                  "type": "string",
                  "value": "Use of performers is not recommended"
                }
              }
            }
          },
          "type": "array",
          "array": {
            "depth": 0,
            "memberType": "Musician"
          },
          "index": 3
        }
      }
    },
    "MySong": {
      "kind": "struct",
      "minimalEncodedSize": 4,
      "discriminatorInParent": 1,
      "mutable": true,
      "isFixedSize": false,
      "fields": {
        "name": {
          "type": "string"
        }
      },
      "parent": "SongOrMusician"
    },
    "Test": {
      "kind": "message",
      "minimalEncodedSize": 5,
      "discriminatorInParent": 2,
      "fields": {
        "name": {
          "type": "string",
          "index": 1
        }
      },
      "parent": "SongOrMusician"
    },
    "SongOrMusician": {
      "kind": "union",
      "minimalEncodedSize": 9,
      "branches": {
        "MySong": 1,
        "Test": 2
      }
    }
  },
  "services": {
    "Music": {
      "kind": "service",
      "documentation": "A service for getting songs",
      "decorators": {
        "debug": {
          "arguments": {
            "astring": {
              "type": "string",
              "value": "dadad"
            },
            "anumber": {
              "type": "uint32",
              "value": "2"
            },
            "aboolean": {
              "type": "bool",
              "value": "false"
            },
            "anumber2": {
              "type": "uint32",
              "value": "0"
            }
          }
        }
      },
      "methods": {
        "getSongsByMusicianUnary": {
          "decorators": {
            "deprecated": {
              "arguments": {
                "reason": {
                  "type": "string",
                  "value": "Use of getSongsByMusician is not recommended"
                }
              }
            }
          },
          "documentation": "Gets a stream of songs by the specified musician",
          "type": "Unary",
          "requestType": "Musician",
          "responseType": "Song",
          "id": 4079743983
        },
        "getSongsByMusicianDuplex": {
          "type": "DuplexStream",
          "requestType": "Musician",
          "responseType": "Song",
          "id": 3611889031
        },
        "getSongsByMusicianClientStream": {
          "type": "ClientStream",
          "requestType": "Musician",
          "responseType": "Song",
          "id": 444332555
        },
        "getSongsByMusicianServerStream": {
          "type": "ServerStream",
          "requestType": "Musician",
          "responseType": "Song",
          "id": 3879401943
        }
      }
    }
  },
  "constants": {
    "exampleConstGuid": {
      "kind": "const",
      "documentation": "An ID for my favorite song",
      "type": "guid",
      "value": "e215a946b26f4567a27613136f0a1708"
    }
  },
  "config": {
    "alias": "acme",
    "outFile": "yo.json",
    "namespace": "",
    "emitNotice": true,
    "emitBinarySchema": true,
    "services": "both",
    "options": {}
  }
}

The extension can then render a string and return it to the compiler. In an extensions chord.json file it contributes a "generator" and that generate is surfaced through bebopc just like all the existing built-ins. I will document everything in detail over the next few days and get feedback from you on that.

The reason I used TinyGo is simply because exporting with Go's WASI target didn't seem to work, and that meant I had to use gjson to parse the string sent by the compiler. The example I provided probably isn't the greatest since Go is not a language I'm strong in.

Right now, the extension would have to commit its result assuming all dependencies are adjacent in the output file. I'm open to feedback here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants