├── .clang-format ├── .devcontainer └── devcontainer.json ├── .github ├── dependabot.yml ├── release.yml └── workflows │ ├── auto-approve.yaml │ ├── brgen-test.yaml │ ├── build.yml │ ├── codeql.yml │ ├── deploy.yml │ ├── puppeteer-test.yml │ ├── release.yml │ └── test.yml ├── .gitignore ├── .licensed.yml ├── .vscode ├── c_cpp_properties.json ├── launch.json ├── settings.json └── tasks.json ├── CMakeLists.txt ├── CONTRIBUTE.md ├── Dockerfile ├── LICENSE ├── README.md ├── SECURITY.md ├── arch.md ├── astlib ├── ast2c │ ├── ast.c │ ├── ast.h │ └── test.c ├── ast2csharp │ ├── ast.cs │ └── ast2csharp.csproj ├── ast2dart │ └── lib │ │ └── ast.dart ├── ast2go │ ├── ast │ │ └── ast.go │ ├── gen │ │ └── gen.go │ ├── generate_nix.go │ ├── generate_win.go │ ├── js │ │ └── set.go │ └── request │ │ ├── exec.go │ │ ├── generator.go │ │ ├── request.go │ │ └── response.go ├── ast2py │ ├── __init__.py │ ├── ast.py │ ├── example.py │ └── test.py ├── ast2rust │ ├── Cargo.lock │ ├── Cargo.toml │ ├── core │ │ ├── Cargo.lock │ │ ├── Cargo.toml │ │ └── src │ │ │ ├── ast.rs │ │ │ ├── eval.rs │ │ │ ├── lib.rs │ │ │ ├── test.rs │ │ │ └── traverse.rs │ └── macros │ │ ├── Cargo.toml │ │ └── src │ │ └── lib.rs └── ast2ts │ ├── package-lock.json │ ├── package.json │ ├── src │ ├── analyze.ts │ ├── ast.ts │ └── index.ts │ └── tsconfig.json ├── brgen.json ├── brgen.sln ├── build.bat ├── build.sh ├── build_all.bat ├── docker-compose.yml ├── docker_vscode ├── c_cpp_properties.json ├── launch.json ├── settings.json └── tasks.json ├── example ├── 9p.bgn ├── arp.bgn ├── asn1.bgn ├── ast_step │ ├── step1.bgn │ ├── step2.bgn │ ├── step3.bgn │ ├── step4.bgn │ ├── step5.bgn │ ├── step6.bgn │ ├── step7.bgn │ ├── step8.bgn │ └── step9.bgn ├── att.bgn ├── attestation_object.bgn ├── avro.bgn ├── ax25.bgn ├── bgp.bgn ├── bmp.bgn ├── bmp.txt ├── bpf.bgn ├── brgen_help │ ├── ast_enum.bgn │ ├── game.bgn │ ├── generator.bgn │ ├── key.bgn │ ├── lexer_enum.bgn │ ├── segment_routing_header.bgn │ ├── share.bgn │ ├── ssa.bgn │ ├── vm2.bgn │ └── vm_enum.bgn ├── can.bgn ├── capnproto.bgn ├── cbor.bgn ├── ccsds.bgn ├── chg.bgn ├── cmsg.bgn ├── coap.bgn ├── core_can_proto.bgn ├── dccp.bgn ├── dhcp.bgn ├── dhcpv6.bgn ├── dns.bgn ├── dnssec.bgn ├── dq2.bgn ├── dq4.bgn ├── elf.bgn ├── ether.bgn ├── etherip.bgn ├── fastcgi.bgn ├── feature_test │ ├── analyze_block_trait.bgn │ ├── assert_or_implicit_yeild.bgn │ ├── bit_fields.bgn │ ├── comma_match.bgn │ ├── const_length.bgn │ ├── edge_case1.bgn │ ├── for_in.bgn │ ├── import_and_use.bgn │ ├── loop_ref.bgn │ ├── nested_state.bgn │ ├── regexp.bgn │ ├── simple_binary.bgn │ ├── sort_test.bgn │ ├── state_variable.bgn │ ├── state_variable2.bgn │ ├── test_import.bgn │ ├── tree_test.bgn │ ├── trial_match.bgn │ ├── union.bgn │ └── varint_test.bgn ├── fido_u2f.bgn ├── from_kaitai │ └── btrfs_stream.bgn ├── fs.txt ├── gen_step │ ├── step1.bgn │ ├── step2.bgn │ ├── step3.bgn │ ├── step4.bgn │ ├── step4_a.bgn │ ├── step4_b.bgn │ ├── step5.bgn │ ├── step6.bgn │ └── step7.bgn ├── gif.bgn ├── gpio_r1.bgn ├── gre.bgn ├── gzip.bgn ├── hci.bgn ├── http.bgn ├── http2.bgn ├── icmp.bgn ├── icn.bgn ├── ico.bgn ├── ieee802_11.bgn ├── ietf_hackathon │ ├── bgp_ls.bgn │ ├── initial_registory.bgn │ ├── routing.bgn │ └── sid.bgn ├── igmp.bgn ├── ike.bgn ├── il.bgn ├── impromptu_app_protocol.bgn ├── ip.bgn ├── ipsec.bgn ├── ipv6addr.bgn ├── isis.bgn ├── l2cap.bgn ├── l2tp.bgn ├── llama2.bgn ├── llcp.bgn ├── llvm_ir.bgn ├── mach-o.bgn ├── minecraft.bgn ├── mp3.bgn ├── mp4.bgn ├── mpls.bgn ├── mptcp.bgn ├── mqtt.bgn ├── mrt.bgn ├── msgpack.bgn ├── nes.bgn ├── nes_sound_register.bgn ├── netlink.bgn ├── ntfs.bgn ├── ntp.bgn ├── ospfv2.bgn ├── ospfv3.bgn ├── pcap.bgn ├── pcapng.bgn ├── pcep.bgn ├── pe_header.bgn ├── pefile.txt ├── pefile_map.json ├── png.bgn ├── ppp.bgn ├── protobuf.bgn ├── qr_code.bgn ├── quic_frame.bgn ├── quic_packet.bgn ├── quic_transport_parameter.bgn ├── quic_varint.bgn ├── radius.bgn ├── rdp.bgn ├── rip.bgn ├── rtp.bgn ├── rudp.bgn ├── s2j_test │ ├── arp.bgn.json │ ├── asn1.bgn.json │ ├── attestation_object.bgn.json │ ├── avro.bgn.json │ ├── bgp.bgn.json │ ├── bpf.bgn.json │ ├── can.bgn.json │ ├── capnproto.bgn.json │ ├── cbor.bgn.json │ ├── ccsds.bgn.json │ ├── chg.bgn.json │ ├── dhcp.bgn.json │ ├── dhcpv6.bgn.json │ ├── dns.bgn.json │ ├── dnssec.bgn.json │ ├── elf.bgn.json │ ├── ether.bgn.json │ ├── etherip.bgn.json │ ├── gif.bgn.json │ ├── http.bgn.json │ ├── http2.bgn.json │ ├── icmp.bgn.json │ ├── ieee802_11.bgn.json │ ├── igmp.bgn.json │ ├── ike.bgn.json │ ├── impromptu_app_protocol.bgn.json │ ├── ip.bgn.json │ ├── ipsec.bgn.json │ ├── ipv6addr.bgn.json │ ├── l2tp.bgn.json │ ├── llvm_ir.bgn.json │ ├── mach-o.bgn.json │ ├── mp3.bgn.json │ ├── mp4.bgn.json │ ├── mqtt.bgn.json │ ├── msgpack.bgn.json │ ├── nes.bgn.json │ ├── ntfs.bgn.json │ ├── ntp.bgn.json │ ├── pcap.bgn.json │ ├── pcapng.bgn.json │ ├── pe_header.bgn.json │ ├── ppp.bgn.json │ ├── protobuf.bgn.json │ ├── quic_frame.bgn.json │ ├── quic_packet.bgn.json │ ├── quic_transport_parameter.bgn.json │ ├── quic_varint.bgn.json │ ├── rtp.bgn.json │ ├── sctp.bgn.json │ ├── simple.bgn.json │ ├── smf.bgn.json │ ├── stl.bgn.json │ ├── stub.bgn.json │ ├── stun.bgn.json │ ├── swf_rect.bgn.json │ ├── syslog.bgn.json │ ├── tar.bgn.json │ ├── tcp_segment.bgn.json │ ├── tftp.bgn.json │ ├── tls_record.bgn.json │ ├── tzdb.bgn.json │ ├── udp.bgn.json │ ├── usb.bgn.json │ ├── wasm.bgn.json │ ├── wasmos.bgn.json │ ├── wave.bgn.json │ ├── websocket.bgn.json │ ├── wireguard.bgn.json │ └── zip.bgn.json ├── safetensor.bgn ├── sctp.bgn ├── simple.bgn ├── smf.bgn ├── socks.bgn ├── softether.bgn ├── sqlite.bgn ├── srv6.bgn ├── ssh.bgn ├── stl.bgn ├── stp.bgn ├── stub.bgn ├── stun.bgn ├── swf_rect.bgn ├── syslog.bgn ├── tar.bgn ├── tcp_segment.bgn ├── tftp.bgn ├── tls_ech.bgn ├── tls_record.bgn ├── tor.bgn ├── tor_prop220.bgn ├── tor_prop224.bgn ├── tor_rend.bgn ├── tpacket.bgn ├── tpm2.bgn ├── tpm2_enum.txt ├── ts.bgn ├── tzdb.bgn ├── udp.bgn ├── usb.bgn ├── vm_test │ └── udp_test.bgn ├── vrrp.bgn ├── wasm.bgn ├── wasmos.bgn ├── wasmos_def.txt ├── wave.bgn ├── webauthn.bgn ├── webauthn_cosepubkey.bgn ├── websocket.bgn ├── wimax.bgn ├── wire_data │ ├── capnproto.dat │ ├── request.dat │ ├── tcp.dat │ ├── udp.dat │ ├── unknwon_raspi.bgn │ ├── varint.dat │ └── websocket.dat ├── wireguard.bgn ├── x64.bgn ├── xfs.bgn └── zip.bgn ├── go.mod ├── go.sum ├── lsp ├── .vscodeignore ├── LICENSE ├── client │ ├── package-lock.json │ ├── package.json │ ├── src │ │ └── extension.ts │ └── tsconfig.json ├── package-lock.json ├── package.json └── server │ ├── package-lock.json │ ├── package.json │ ├── src │ └── server.ts │ └── tsconfig.json ├── renovate.json ├── script ├── clean.bat ├── clone_utils.bat ├── clone_utils.sh ├── cmptest_debug.sh ├── collect_licenses.sh ├── copy_bmgen_stub.py ├── copy_example.py ├── dirty_patch.py ├── export_tag.sh ├── fetch_rebrgen.sh ├── gen_deep.bat ├── gen_enum.bat ├── gen_large.py ├── gen_sample.bat ├── gen_samples.sh ├── generate.py ├── install_lsp.bat ├── license_note.txt ├── link_path.sh ├── make_ast_doc.sh ├── make_cpp_test.sh ├── make_cpp_tests.sh ├── push_and_watch.bat ├── tag.txt └── tag_release.bat ├── spec ├── brgen_cmptest_config_schema.json ├── brgen_generated_mapping_schema.json ├── brgen_json_schema.json ├── brgen_test_info_schema.json ├── draft1.md ├── draft2.md ├── draft3.md ├── draft4.md └── generator_spec_file.md ├── src ├── CMakeLists.txt ├── core │ ├── ast │ │ ├── ast.h │ │ ├── expr_layer.h │ │ ├── file.h │ │ ├── json.h │ │ ├── kill_node.h │ │ ├── line_map.h │ │ ├── node │ │ │ ├── ast_enum.h │ │ │ ├── base.h │ │ │ ├── deep_copy.h │ │ │ ├── expr.h │ │ │ ├── literal.h │ │ │ ├── node_type.h │ │ │ ├── scope.h │ │ │ ├── statement.h │ │ │ ├── translated.h │ │ │ └── type.h │ │ ├── node_type_list.h │ │ ├── parse.cpp │ │ ├── parse.h │ │ ├── stream.h │ │ ├── tool │ │ │ ├── compare.h │ │ │ ├── eval.h │ │ │ ├── extract_config.h │ │ │ ├── ident.h │ │ │ ├── metadata.h │ │ │ ├── sort.h │ │ │ ├── stringer.h │ │ │ └── tmp_ident.h │ │ └── traverse.h │ ├── common │ │ ├── debug.h │ │ ├── error.h │ │ ├── expected.h │ │ ├── file.h │ │ └── util.h │ ├── lexer │ │ ├── lexer.h │ │ ├── lexer_enum.h │ │ └── token.h │ └── middle │ │ ├── analyze_block_trait.cpp │ │ ├── analyze_block_trait.h │ │ ├── replace_assert.h │ │ ├── replace_error.h │ │ ├── replace_metadata.h │ │ ├── replace_order_spec.h │ │ ├── replacer.h │ │ ├── resolve_available.h │ │ ├── resolve_import.h │ │ ├── resolve_io_operation.h │ │ ├── resolve_state_dependency.h │ │ ├── type_attribute.cpp │ │ ├── type_attribute.h │ │ ├── typing.cpp │ │ └── typing.h ├── request │ ├── generator.hpp │ └── stream.hpp ├── test │ ├── CMakeLists.txt │ ├── core │ │ ├── ast_test.cpp │ │ ├── ast_test_component.cpp │ │ ├── ast_test_component.h │ │ ├── deep_copy_test.cpp │ │ ├── derive_test.cpp │ │ ├── from_json_test.cpp │ │ ├── lexer_test.cpp │ │ ├── middle_test.cpp │ │ ├── middle_test.h │ │ ├── section_writer_test.cpp │ │ ├── type_attribute_test.cpp │ │ └── typing_test.cpp │ ├── test_tool │ │ ├── fuzzing_test.go │ │ └── test_log_server │ │ │ └── main.go │ └── tool │ │ └── json2c │ │ └── ctype_test.cpp ├── tool │ ├── brgen │ │ ├── config.go │ │ ├── generator.go │ │ ├── generator_handler.go │ │ ├── main.go │ │ └── stdin_stream.go │ ├── cmptest │ │ ├── Cargo.lock │ │ ├── Cargo.toml │ │ └── src │ │ │ ├── main.rs │ │ │ └── testutil.rs │ ├── common │ │ ├── em_main.h │ │ ├── generate.h │ │ ├── load_json.h │ │ ├── print.h │ │ └── send.h │ ├── ctobgn │ │ └── main.cpp │ ├── gen │ │ ├── ast2c │ │ │ └── gen_ast2c.go │ │ ├── ast2csharp │ │ │ └── gen_ast2csharp.go │ │ ├── ast2dart │ │ │ └── gen_ast2dart.go │ │ ├── ast2go │ │ │ └── gen_ast2go.go │ │ ├── ast2mermaid │ │ │ └── gen_ast2mermaid.go │ │ ├── ast2py │ │ │ └── gen_ast2py.go │ │ ├── ast2rust │ │ │ └── gen_ast2rust.go │ │ ├── ast2ts │ │ │ └── gen_ast2ts.go │ │ ├── cpp_deep_copy │ │ │ └── main.go │ │ ├── enum_gen │ │ │ └── enum_gen.go │ │ ├── gen.go │ │ └── type.go │ ├── hex2bin │ │ ├── hex.h │ │ └── main.cpp │ ├── json2c │ │ ├── ctype.h │ │ ├── generate.h │ │ └── main.cpp │ ├── json2cpp2 │ │ ├── generate.h │ │ └── main.cpp │ ├── json2go │ │ ├── generate.go │ │ ├── js.go │ │ └── main.go │ ├── json2graphviz │ │ └── main.go │ ├── json2kaitai │ │ ├── js.go │ │ ├── kaitai.go │ │ ├── main.go │ │ └── schema.go │ ├── json2llvm │ │ ├── Cargo.lock │ │ ├── Cargo.toml │ │ ├── build.rs │ │ └── src │ │ │ ├── generate.rs │ │ │ └── main.rs │ ├── json2mermaid │ │ └── main.go │ ├── json2rust │ │ ├── Cargo.lock │ │ ├── Cargo.toml │ │ └── src │ │ │ ├── generator.rs │ │ │ ├── lib.rs │ │ │ └── main.rs │ ├── json2spicy │ │ └── spicy.go │ ├── json2ts │ │ ├── generate.cpp │ │ ├── generate.h │ │ └── main.cpp │ ├── json2vm │ │ └── main.cpp │ ├── json2vm2 │ │ └── main.cpp │ ├── rfc2bgn │ │ └── main.cpp │ ├── s2jgo │ │ ├── capability.go │ │ ├── common.go │ │ ├── s2j_dlopen.go │ │ ├── s2j_stub.go │ │ ├── s2j_test.go │ │ └── s2j_win.go │ ├── src2json │ │ ├── capi.h │ │ ├── capi_export.h │ │ ├── entry.cpp │ │ ├── entry.h │ │ ├── hook.h │ │ ├── network.cpp │ │ ├── src2json.cpp │ │ ├── test.cpp │ │ ├── test.h │ │ └── version.h │ └── ssagen │ │ ├── main.go │ │ └── ssa │ │ ├── compile.go │ │ └── ssa.go ├── vm │ ├── compile.cpp │ ├── compile.h │ ├── vm.cpp │ ├── vm.h │ ├── vm2 │ │ ├── compile.cpp │ │ ├── compile.h │ │ ├── interpret.cpp │ │ ├── interpret.h │ │ ├── jit_x64.cpp │ │ ├── layout.cpp │ │ ├── layout.h │ │ ├── vm2.h │ │ └── vm_enum.h │ └── vm_enum.h └── writer │ ├── bit_io.h │ ├── config.h │ ├── context.h │ ├── section.h │ └── writer.h ├── test-brgen.json ├── test.bat ├── testkit ├── cmptest.json ├── cpp │ ├── CMakeLists.txt │ ├── config.json │ ├── setup.py │ ├── stub.hpp │ └── test_template.cpp ├── go │ ├── config.json │ ├── setup.py │ ├── test_class.go │ └── test_template.go └── rust │ ├── Cargo.lock │ ├── Cargo.toml │ ├── config.json │ ├── setup.py │ └── src │ ├── main.rs │ └── target.rs └── web ├── dev ├── package-lock.json ├── package.json ├── src │ ├── compiler-explorer │ │ ├── api.ts │ │ └── types.ts │ ├── cpp_include.ts │ ├── generator.ts │ ├── index.tsx │ ├── s2j │ │ ├── brgen_lsp.ts │ │ ├── caller.ts │ │ ├── dummy_fs.ts │ │ ├── em_work_ctx.ts │ │ ├── emscripten_mod.ts │ │ ├── file_select.ts │ │ ├── go_work_ctx.ts │ │ ├── inputServiceStub.js │ │ ├── job_mgr.ts │ │ ├── msg.ts │ │ ├── request_queue.ts │ │ ├── update.tsx │ │ └── worker │ │ │ ├── bmgen │ │ │ ├── bmgen_worker.ts │ │ │ └── util.ts │ │ │ ├── json2c_worker.ts │ │ │ ├── json2cpp2_worker.ts │ │ │ ├── json2go_worker.ts │ │ │ ├── json2kaitai_worker.ts │ │ │ ├── json2rust_worker.ts │ │ │ ├── json2ts_worker.ts │ │ │ └── src2json_worker.ts │ ├── save-data │ │ └── save.ts │ ├── storage.ts │ ├── types.ts │ └── ui.tsx ├── stub │ └── bmgen │ │ ├── bm2cpp.js │ │ ├── bm2rust.js │ │ ├── bm_caller.js │ │ └── bmgen.js ├── test │ └── puppet.mjs ├── tsconfig.json ├── wasmCopy.js.txt └── webpack.config.js ├── doc ├── .hugo_build.lock ├── archetypes │ └── default.md ├── content │ ├── _index.md │ └── docs │ │ ├── ast.md │ │ ├── bnf.md │ │ ├── builtin.md │ │ ├── change.md │ │ ├── config.md │ │ ├── exec_model.md │ │ ├── for_ai.md │ │ ├── generator_dev.md │ │ ├── language.md │ │ ├── metadata.md │ │ ├── overview.md │ │ ├── setup.md │ │ ├── src_core.md │ │ ├── src_tool.md │ │ └── todo.md ├── go.mod ├── go.sum ├── hugo.toml └── layouts │ └── shortcodes │ └── mermaid.html └── public └── index.html /.clang-format: -------------------------------------------------------------------------------- 1 | UseTab: Never 2 | BasedOnStyle: Google 3 | BreakBeforeBraces: Custom 4 | SortIncludes: false 5 | ColumnLimit: 0 6 | IndentWidth: 4 7 | NamespaceIndentation: All 8 | AllowShortFunctionsOnASingleLine: Empty 9 | BraceWrapping: 10 | AfterFunction: false 11 | BeforeElse: true 12 | AfterControlStatement: false 13 | AfterNamespace: false 14 | AfterClass: false 15 | AfterStruct: false 16 | AfterEnum: false 17 | AfterUnion: false 18 | AfterExternBlock: false 19 | BeforeCatch: false 20 | BeforeLambdaBody: false 21 | BeforeWhile: false 22 | RequiresExpressionIndentation: OuterScope 23 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | # Maintain dependence for GitHub Actions 4 | - package-ecosystem: "github-actions" 5 | directory: "/" 6 | schedule: 7 | interval: "weekly" 8 | 9 | # Maintain dependence for golang 10 | - package-ecosystem: "gomod" 11 | directory: "/**" 12 | schedule: 13 | interval: "weekly" 14 | 15 | - package-ecosystem: "npm" 16 | directory: "/**" 17 | schedule: 18 | interval: "weekly" 19 | - package-ecosystem: "cargo" 20 | directory: "/**" 21 | schedule: 22 | interval: "weekly" -------------------------------------------------------------------------------- /.github/release.yml: -------------------------------------------------------------------------------- 1 | changelog: 2 | categories: 3 | - title: 🏕 Features 4 | labels: 5 | - '*' 6 | exclude: 7 | labels: 8 | - dependencies 9 | - title: 👒 Dependencies 10 | labels: 11 | - dependencies -------------------------------------------------------------------------------- /.github/workflows/auto-approve.yaml: -------------------------------------------------------------------------------- 1 | name: Auto approve 2 | 3 | on: 4 | pull_request: 5 | types: [opened, synchronize, ready_for_review] 6 | 7 | jobs: 8 | auto-approve: 9 | runs-on: ubuntu-latest 10 | if: | 11 | github.event.pull_request.user.login == github.repository_owner && 12 | ! github.event.pull_request.draft 13 | permissions: 14 | pull-requests: write 15 | steps: 16 | - name: Auto approve 17 | uses: hmarr/auto-approve-action@8f929096a962e83ccdfa8afcf855f39f12d4dac7 # v4 18 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: brgen-test 2 | run-name: brgen test 3 | on: 4 | - push 5 | jobs: 6 | test-linux: 7 | runs-on: ubuntu-latest 8 | timeout-minutes: 10 9 | steps: 10 | - name: Timeline 11 | uses: Kesin11/actions-timeline@427ee2cf860166e404d0d69b4f2b24012bb7af4f # v2.2.3 12 | with: 13 | github-token: ${{ secrets.GITHUB_TOKEN }} 14 | - name: Checkout repository 15 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 16 | - name: Set up Ninja 17 | uses: seanmiddleditch/gha-setup-ninja@3b1f8f94a2f8254bd26914c4ab9474d4f0015f67 # master 18 | - name: Set up Clang 19 | uses: egor-tensin/setup-clang@ef434b41eb33a70396fb336b1bae39c76d740c3d # v1.4 20 | with: 21 | version: latest 22 | platform: x64 23 | - name: Install libc++-dev and libc++abi-dev 24 | run: sudo apt-get install libc++-dev libc++abi-dev -y 25 | - name: Build 26 | run: | 27 | . build.sh 28 | - name: Test 29 | run: | 30 | CTEST_OUTPUT_ON_FAILURE=1 BASE_PATH=${{ github.workspace }} ninja -C built/native/Debug test 31 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /tool/ 2 | /lib/ 3 | CMakeFiles 4 | /test/ 5 | /ignore/ 6 | .ninja_deps 7 | .ninja_log 8 | build.ninja 9 | CMakeCache.txt 10 | cmake_install.cmake 11 | /_deps/ 12 | /bin/ 13 | /built/ 14 | node_modules/ 15 | out/ 16 | target/ 17 | /web/dev/src/lib/ 18 | *.wasm 19 | /web/public/script 20 | __pycache__/ 21 | *.vsix 22 | /utils/ 23 | bin/ 24 | obj/ 25 | testdata/ 26 | *.profraw 27 | go_dump_env.bat 28 | /web/public/doc 29 | /web/public/example 30 | /web/doc/resources/_gen 31 | license_cache 32 | pkg/ 33 | stats.json 34 | zig-cache/ 35 | zig-out/ 36 | rebrgen/ 37 | wasmCopy.js -------------------------------------------------------------------------------- /.licensed.yml: -------------------------------------------------------------------------------- 1 | name: "brgen" # デフォルトはsource_pathの名前 2 | source_path: 3 | - "./web/dev" # デフォルトはカレントディレクトリ 4 | - "./lsp" 5 | - "./lsp/server" 6 | - "./lsp/client" 7 | cache_path: "./license_cache" # source_pathからの相対パス。デフォルトは .licenses 8 | 9 | sources: # 今回はnpmを使います 10 | npm: true 11 | 12 | allowed: # 以下のライセンスならOKとします 13 | - mit 14 | - apache-2.0 15 | - isc 16 | - bsd-3-clause 17 | - cc-by-4.0 18 | - other 19 | - gpl-2.0 20 | - bsd-2-clause 21 | - 0bsd 22 | -------------------------------------------------------------------------------- /.vscode/c_cpp_properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "name": "Win32", 5 | "includePath": [ 6 | "${workspaceFolder}/src/**", 7 | "C:/workspace/utils_backup/src/include", 8 | "${workspaceFolder}/built/native/Debug/_deps/googletest-src/googletest/include", 9 | ], 10 | "defines": [ 11 | "_DEBUG", 12 | "UNICODE", 13 | "_UNICODE" 14 | ], 15 | "windowsSdkVersion": "10.0.22000.0", 16 | "compilerPath": "C:/Program Files/LLVM/bin/clang++.exe", 17 | "cStandard": "c17", 18 | "cppStandard": "c++20", 19 | "intelliSenseMode": "windows-clang-x64" 20 | } 21 | ], 22 | "version": 4 23 | } -------------------------------------------------------------------------------- /CONTRIBUTE.md: -------------------------------------------------------------------------------- 1 | # List of Contributors 2 | 3 | write GitHub account 4 | 5 | [on-keyday](https://github.com/on-keyday) - repository owner 6 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | #license 2 | FROM ubuntu:devel 3 | 4 | RUN mkdir -p /workspace 5 | 6 | WORKDIR /workspace 7 | 8 | # if you are not in Japan region, you should comment out this line, or change `ftp.jaist.ac.jp/pub/Linux` to your region millor server address. 9 | RUN sed -i 's@archive.ubuntu.com@ftp.jaist.ac.jp/pub/Linux@g' /etc/apt/sources.list 10 | 11 | RUN /bin/bash -c "$(curl -s https://apt.llvm.org/llvm.sh)" 12 | 13 | 14 | 15 | RUN apt-get update && \ 16 | apt-get install -y\ 17 | clang\ 18 | libc++-dev\ 19 | golang-go\ 20 | lldb\ 21 | liblldb-dev\ 22 | lld\ 23 | git\ 24 | curl 25 | 26 | 27 | RUN apt-get update && \ 28 | apt-get install -y\ 29 | ninja-build\ 30 | cmake 31 | RUN apt-get update && \ 32 | apt-get install -y\ 33 | vim 34 | 35 | # RUN ln -s /lib/llvm-15/bin/clang++ /bin/clang++ 36 | # RUN ln -s /lib/llvm-15/bin/clang /bin/clang 37 | # RUN ln -s /bin/lldb-15 /bin/lldb 38 | RUN ln -s /usr/lib/x86_64-linux-gnu/libc++abi.so.1.0 /usr/lib/x86_64-linux-gnu/libc++abi.so 39 | RUN unlink /usr/bin/ld 40 | RUN ln -s /bin/lld /usr/bin/ld 41 | RUN ln -s /usr/bin/lldb-server-16 /usr/bin/lldb-server-16.0.6 42 | 43 | RUN apt-get update && \ 44 | apt-get install -y\ 45 | unzip 46 | 47 | RUN curl https://github.com/lldb-tools/lldb-mi/archive/refs/heads/main.zip \ 48 | -o /workspace/lldb-mi.zip -L 49 | 50 | 51 | RUN unzip /workspace/lldb-mi.zip -d /workspace 52 | RUN rm /workspace/lldb-mi.zip 53 | 54 | RUN (cd /workspace/lldb-mi-main;cmake -G Ninja -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER=clang .) 55 | RUN (cd /workspace/lldb-mi-main;cmake --build .) 56 | RUN cp /workspace/lldb-mi-main/src/lldb-mi /bin/lldb-mi 57 | 58 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023-2025 on-keyday (https://github.com/on-keyday) 4 | Copyright (c) 2024-2025 Contributors of brgen (https://github.com/on-keyday/brgen) 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | 問題は基本的にはこのリポジトリの GitHub Issue で報告してください。 4 | 5 | セキュリティ脆弱性については 6 | GitHub Security Advisories の機能を使って報告してください。 7 | 8 | v0.0.x 及び main ブランチやその他のブランチの最新版についてはこのリポジトリの中身を使ったことによるセキュリティ脆弱性があったとしても 9 | 作者は責任を負いません。(ライセンスとしても一切保証はありません) 10 | また、可能な限り Issue に対しては応答するよう努めますが、確実な対応は保証できません。 11 | 12 | v0.1.0 以降では別途ポリシーを定める予定です。 13 | 14 | Please report issues primarily on the GitHub Issue of this repository. 15 | 16 | For security vulnerabilities, please report using the GitHub Security Advisories feature. 17 | 18 | The author bears no responsibility for any security vulnerabilities resulting from the use of the contents of this repository in v0.0.x, main branch, or any other branches' latest versions. (There is no guarantee whatsoever, even in terms of licensing). 19 | Furthermore, while efforts will be made to respond to issues, it cannot be guaranteed that responses will be provided promptly or reliably. 20 | 21 | Separate policies will be established for v0.1.0 and onwards. 22 | -------------------------------------------------------------------------------- /arch.md: -------------------------------------------------------------------------------- 1 | # Architecture 2 | 3 | tool/brgen - code generator driver <- input is brgen.json 4 | | 5 | |--tool/src2json - parse source code then convert to json ast, dump type information of ast node, lexer etc... 6 | | 7 | |--tool/json2cpp - C++ code generator 8 | | 9 | |--tool/json2go - Go code generator 10 | -------------------------------------------------------------------------------- /astlib/ast2c/test.c: -------------------------------------------------------------------------------- 1 | /*license*/ 2 | 3 | #include "ast.h" 4 | 5 | int main(int argc, char *argv[]) { 6 | ast2c_json_handlers handlers; 7 | return 0; 8 | } -------------------------------------------------------------------------------- /astlib/ast2csharp/ast2csharp.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net7.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /astlib/ast2go/generate_nix.go: -------------------------------------------------------------------------------- 1 | //go:build !windows 2 | 3 | //go:generate ../tool/gen_ast2go ast/ast.go 4 | //go:generate gofmt -w ast/ast.go 5 | package ast2go 6 | -------------------------------------------------------------------------------- /astlib/ast2go/generate_win.go: -------------------------------------------------------------------------------- 1 | //go:build windows 2 | 3 | //go:generate ../tool/gen_ast2go.exe ast/ast.go 4 | //go:generate gofmt -w ast/ast.go 5 | package ast2go 6 | -------------------------------------------------------------------------------- /astlib/ast2go/request/exec.go: -------------------------------------------------------------------------------- 1 | package request 2 | 3 | import ( 4 | "io" 5 | "os" 6 | "os/exec" 7 | ) 8 | 9 | type ProcessClient struct { 10 | cmd *exec.Cmd 11 | SourceManager 12 | } 13 | 14 | // NewProcessClient creates a new process client 15 | // stdin and stdout are set to handle the communication 16 | // you should set stderr if you want to see the error 17 | func NewProcessClient(cmd *exec.Cmd) (*ProcessClient, error) { 18 | rp, ws, err := os.Pipe() 19 | if err != nil { 20 | return nil, err 21 | } 22 | rs, wp, err := os.Pipe() 23 | if err != nil { 24 | return nil, err 25 | } 26 | cmd.Stdin = rp 27 | cmd.Stdout = wp 28 | err = cmd.Start() 29 | if err != nil { 30 | return nil, err 31 | } 32 | c := NewRequestManager(rs, ws, func(err error) { 33 | if err != io.EOF { 34 | cmd.Process.Kill() 35 | } 36 | }) 37 | go func() { 38 | err := cmd.Wait() 39 | c.CloseWithError(err) 40 | }() 41 | return &ProcessClient{ 42 | cmd: cmd, 43 | SourceManager: c, 44 | }, nil 45 | } 46 | -------------------------------------------------------------------------------- /astlib/ast2py/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/on-keyday/brgen/950489741469a370ab244f44f59ae6732914cb37/astlib/ast2py/__init__.py -------------------------------------------------------------------------------- /astlib/ast2py/test.py: -------------------------------------------------------------------------------- 1 | import ast2py as ast 2 | import subprocess as sp 3 | import json 4 | 5 | if __name__ == "__main__": 6 | # execute tool/src2json(.exe) example/tree_test.bgn and get stdout 7 | # (stdout is json format) 8 | cmd = ["./tool/src2json.exe", "example/feature_test/tree_test.bgn"] 9 | proc = sp.Popen(cmd, stdout=sp.PIPE) 10 | stdout, stderr = proc.communicate() 11 | # create AstFile object 12 | d = json.loads(stdout.decode("utf-8")) 13 | file = ast.parse_AstFile(d) 14 | node = ast.ast2node(file.ast) 15 | assert isinstance(node, ast.Program) 16 | 17 | def walker(f, node): 18 | ast.walk(node, f) 19 | print(type(node)) 20 | 21 | ast.walk(node, walker) 22 | -------------------------------------------------------------------------------- /astlib/ast2rust/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | 3 | members = [ 4 | "core", 5 | "macros" 6 | ] 7 | -------------------------------------------------------------------------------- /astlib/ast2rust/core/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ast2rust" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | serde_json = "1.0.116" 10 | serde = "1.0.200" 11 | serde_derive = "1.0.200" 12 | bitflags = {version ="2.5.0",features=["serde"]} 13 | ast2rust_macro = {path = "../macros"} 14 | 15 | [features] 16 | default = ["std"] 17 | macros = [] 18 | std = [] 19 | -------------------------------------------------------------------------------- /astlib/ast2rust/core/src/lib.rs: -------------------------------------------------------------------------------- 1 | use std::{ 2 | cell::RefCell, 3 | hash::{Hash, Hasher}, 4 | rc::Rc, 5 | }; 6 | 7 | pub mod ast; 8 | pub mod eval; 9 | mod test; 10 | pub mod traverse; 11 | 12 | #[derive(Debug)] 13 | pub enum PtrUnwrapError { 14 | ExpiredWeakPtr(&'static str), 15 | Nullptr(&'static str), 16 | } 17 | 18 | impl std::fmt::Display for PtrUnwrapError { 19 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 20 | match self { 21 | PtrUnwrapError::ExpiredWeakPtr(s) => write!(f, "expired weak ptr: {}", s), 22 | PtrUnwrapError::Nullptr(s) => write!(f, "nullptr: {}", s), 23 | } 24 | } 25 | } 26 | 27 | impl std::error::Error for PtrUnwrapError {} 28 | 29 | pub struct PtrKey { 30 | ptr: *const T, 31 | _phantom: std::marker::PhantomData, 32 | } 33 | 34 | impl PtrKey { 35 | pub fn new(ptr: &Rc>) -> Self { 36 | PtrKey { 37 | ptr: ptr.as_ptr() as *const T, 38 | _phantom: std::marker::PhantomData, 39 | } 40 | } 41 | } 42 | 43 | impl PartialEq for PtrKey { 44 | fn eq(&self, other: &Self) -> bool { 45 | std::ptr::eq(self.ptr, other.ptr) 46 | } 47 | } 48 | 49 | impl Eq for PtrKey {} 50 | 51 | impl Hash for PtrKey { 52 | fn hash(&self, state: &mut H) { 53 | self.ptr.hash(state); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /astlib/ast2rust/core/src/test.rs: -------------------------------------------------------------------------------- 1 | use std::{env, path}; 2 | 3 | use crate::ast; 4 | use serde::Deserialize; 5 | 6 | pub fn exec_and_output(file: &str) -> std::io::Result { 7 | env::set_current_dir(path::Path::new("..")).unwrap(); 8 | println!("current dir: {:?}", env::current_dir().unwrap()); 9 | let cmd = env::current_dir() 10 | .unwrap() 11 | .join(path::Path::new("tool/src2json")); 12 | #[cfg(target_os = "windows")] 13 | let cmd = cmd.with_extension("exe"); 14 | println!("cmd: {:?}", cmd); 15 | let mut cmd = std::process::Command::new(cmd); 16 | cmd.arg(file).output() 17 | } 18 | 19 | pub fn load_test_file() -> ast::Node { 20 | let ch = exec_and_output("./example/feature_test/tree_test.bgn").unwrap(); 21 | let mut de = serde_json::Deserializer::from_slice(&ch.stdout); 22 | let file = ast::AstFile::deserialize(&mut de).unwrap(); 23 | let prog = ast::parse_ast(file.ast.unwrap()).unwrap(); 24 | prog.into() 25 | } 26 | -------------------------------------------------------------------------------- /astlib/ast2rust/core/src/traverse.rs: -------------------------------------------------------------------------------- 1 | use super::ast; 2 | use std::ops::Fn; 3 | 4 | pub fn traverse(n: &ast::Node, f: &F) 5 | where 6 | F: Fn(&ast::Node) -> (), 7 | { 8 | ast::walk_node(n, &|s: &dyn ast::Visitor, n: &ast::Node| -> bool { 9 | ast::walk_node(n, s); 10 | f(n); 11 | true 12 | }) 13 | } 14 | 15 | #[cfg(test)] 16 | mod tests { 17 | 18 | use super::super::ast; 19 | use super::super::test; 20 | use super::traverse; 21 | 22 | #[test] 23 | fn test_traverse() { 24 | let prog = test::load_test_file(); 25 | traverse(&prog, &mut |n: &ast::Node| { 26 | let t: ast::NodeType = n.into(); 27 | println!("node: {:?}", t); 28 | }); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /astlib/ast2rust/macros/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ast2rust_macro" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | syn = "2.0" 10 | quote = "1.0" 11 | proc-macro2 = "1.0.86" 12 | 13 | [lib] 14 | proc-macro=true 15 | 16 | [features] -------------------------------------------------------------------------------- /astlib/ast2ts/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ast2ts", 3 | "version": "0.0.1", 4 | "description": "brgen ast to typescript", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "build": "tsc" 9 | }, 10 | "author": "on-keyday (https://github.com/on-keyday)", 11 | "license": "MIT", 12 | "devDependencies": { 13 | "@types/node": "^22.0.0", 14 | "ts-node": "^10.9.1", 15 | "typescript": "^5.2.2" 16 | }, 17 | "dependencies": { 18 | "vscode-languageserver": "^9.0.1" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /astlib/ast2ts/src/index.ts: -------------------------------------------------------------------------------- 1 | 2 | 3 | export {ast2ts} from "./ast"; 4 | export {analyze} from "./analyze"; 5 | -------------------------------------------------------------------------------- /astlib/ast2ts/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "module": "commonjs", 5 | "declaration": true, 6 | "outDir": "./out", 7 | "strict": true, 8 | "esModuleInterop": true 9 | }, 10 | "include": [ 11 | "." 12 | ] 13 | } -------------------------------------------------------------------------------- /brgen.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.5.002.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ast2csharp", "ast2csharp\ast2csharp.csproj", "{5A3E00B5-19F5-4261-BBE8-9FD96BBE815B}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {5A3E00B5-19F5-4261-BBE8-9FD96BBE815B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {5A3E00B5-19F5-4261-BBE8-9FD96BBE815B}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {5A3E00B5-19F5-4261-BBE8-9FD96BBE815B}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {5A3E00B5-19F5-4261-BBE8-9FD96BBE815B}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {73FF9147-74B4-40D7-A9E4-C1CDE14F69B1} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /build.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | setlocal 3 | set S2J_LIB=1 4 | set BRGEN_RUST_ENABLED=1 5 | set BUILD_MODE=%1 6 | set BUILD_TYPE=%2 7 | set FUTILS_DIR=%3 8 | 9 | if "%BUILD_MODE%" == "" ( 10 | set BUILD_MODE=native 11 | ) 12 | if "%FUTILS_DIR%" == "" ( 13 | rem for developers 14 | set FUTILS_DIR=C:/workspace/utils_backup 15 | ) 16 | if not exist %FUTILS_DIR% ( 17 | call script\clone_utils.bat %BUILD_MODE% %BUILD_TYPE% 18 | set FUTILS_DIR=%CD%\utils 19 | ) 20 | 21 | if "%BUILD_TYPE%" == "" ( 22 | set BUILD_TYPE=Debug 23 | ) 24 | 25 | if "%EMSDK_PATH%" == "" ( 26 | set EMSDK_PATH=C:\workspace\emsdk\emsdk_env.bat 27 | ) 28 | 29 | set INSTALL_PREFIX=. 30 | if "%BUILD_MODE%" == "native" ( 31 | cmake -D CMAKE_CXX_COMPILER=clang++ -D CMAKE_C_COMPILER=clang -G Ninja -DCMAKE_INSTALL_PREFIX=%INSTALL_PREFIX% -D CMAKE_BUILD_TYPE=%BUILD_TYPE% -S . -B ./built/%BUILD_MODE%/%BUILD_TYPE% 32 | ) else if "%BUILD_MODE%" == "wasm-em" ( 33 | call %EMSDK_PATH% 34 | set GOOS=js 35 | set GOARCH=wasm 36 | call emcmake cmake -G Ninja -D CMAKE_BUILD_TYPE=%BUILD_TYPE% -DCMAKE_INSTALL_PREFIX=%INSTALL_PREFIX%/web/dev/src -S . -B ./built/%BUILD_MODE%/%BUILD_TYPE% 37 | ) else ( 38 | echo "Invalid build mode: %BUILD_MODE%" 39 | exit 1 40 | ) 41 | rem ninja -C ./built/%BUILD_MODE%/%BUILD_TYPE% 42 | ninja -C ./built/%BUILD_MODE%/%BUILD_TYPE% install 43 | 44 | if "%BUILD_MODE%" == "wasm-em" ( 45 | rem cd ./src/tool/json2rust 46 | rem wasm-pack build --target web 47 | rem copy ..\..\..\LICENSE .\pkg\LICENSE 48 | rem cd ../../../ 49 | python script/copy_bmgen_stub.py 50 | cd ./web/dev 51 | call tsc 52 | call webpack 53 | cd ../../ 54 | python script/copy_example.py 55 | ) 56 | -------------------------------------------------------------------------------- /build_all.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | setlocal 3 | set BUILD_MODE_BASE=%1 4 | call build.bat native %BUILD_MODE_BASE% 5 | if not %errorlevel% == 0 goto :error 6 | go env > script/go_dump_env.bat 7 | call script\go_dump_env.bat 8 | set WASMEXEC_FILE=%GOROOT%\lib\wasm\wasm_exec.js 9 | call build.bat wasm-em %BUILD_MODE_BASE% 10 | if not %errorlevel% == 0 goto :error 11 | python script/generate.py 12 | if not %errorlevel% == 0 goto :error 13 | cd web/dev 14 | call webpack.cmd 15 | set LEV=%errorlevel% 16 | cd ../.. 17 | rem if not %LEV% == 0 goto :error 18 | call script\install_lsp.bat 19 | :error 20 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | #license 2 | version: "3" 3 | services: 4 | brgen_linux: 5 | build: . 6 | container_name: brgen 7 | tty: true 8 | stdin_open: true 9 | volumes: 10 | - ./src:/workspace/src:cached 11 | - ./build.sh:/workspace/build.sh:cached 12 | - ./CMakeLists.txt:/workspace/CMakeLists.txt:cached 13 | - ./docker_vscode:/workspace/.vscode:cached 14 | - ./script:/workspace/script:cached 15 | - ./example:/workspace/example:cached 16 | - ./go.mod:/workspace/go.mod:cached 17 | - ./go.sum:/workspace/go.sum:cached 18 | - ./ast2go:/workspace/ast2go:cached 19 | - ./brgen.json:/workspace/brgen.json:cached 20 | - ./Dockerfile:/workspace/Dockerfile:cached 21 | - ./docker-compose.yml:/workspace/docker-compose.yml:cached 22 | - ./README.md:/workspace/README.md:cached 23 | - ./.devcontainer:/workspace/.devcontainer:cached 24 | cap_add: 25 | - SYS_PTRACE 26 | security_opt: 27 | - seccomp:unconfined 28 | ports: 29 | - "8090:8080" 30 | 31 | volumes: 32 | src: 33 | -------------------------------------------------------------------------------- /docker_vscode/c_cpp_properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "name": "Win32", 5 | "includePath": [ 6 | "${workspaceFolder}/**", 7 | "C:/workspace/utils_backup/src/include", 8 | "C:/workspace/shbrgen/brgen/build/_deps/googletest-src/googletest/include", 9 | "C:/workspace/llvm-project/clang/include" 10 | ], 11 | "defines": [ 12 | "_DEBUG", 13 | "UNICODE", 14 | "_UNICODE" 15 | ], 16 | "windowsSdkVersion": "10.0.22000.0", 17 | "compilerPath": "C:/Program Files/LLVM/bin/clang++.exe", 18 | "cStandard": "c17", 19 | "cppStandard": "c++20", 20 | "intelliSenseMode": "windows-clang-x64" 21 | } 22 | ], 23 | "version": 4 24 | } -------------------------------------------------------------------------------- /example/arp.bgn: -------------------------------------------------------------------------------- 1 | 2 | # ArpPacket 3 | # arp packet is used to resolve ip address to mac address 4 | # ------------- 5 | 6 | enum Operation: 7 | :u16 8 | Request = 1 9 | Reply = 2 10 | 11 | format ArpPacket: 12 | hardware_type :u16 13 | protocol_type :u16 14 | hardware_len :u8 15 | protocol_len :u8 16 | operation :Operation 17 | operation == Operation.Request || operation == Operation.Reply 18 | source_hardware_address :[hardware_len]u8 19 | source_protocol_address :[protocol_len]u8 20 | target_hardware_address :[hardware_len]u8 21 | target_protocol_address :[protocol_len]u8 22 | 23 | 24 | -------------------------------------------------------------------------------- /example/asn1.bgn: -------------------------------------------------------------------------------- 1 | enum Tag: 2 | :u8 3 | RESERVED 4 | BOOLEAN 5 | INTEGER 6 | BIT_STRING 7 | OCTET_STRING 8 | NULL 9 | OBJECT_IDENTIFIER 10 | 11 | # c ::=config.import("./arp.bgn") 12 | 13 | 14 | format Len: 15 | len :u64 16 | 17 | fn size() -> u8: 18 | if len < 0x80: 19 | return 1 20 | else: 21 | len_of_len := 0 22 | val := len 23 | for val > 0: 24 | len_of_len = len_of_len + 1 25 | val = val >> 8 26 | return len_of_len + 1 27 | 28 | fn encode(): 29 | if len < 0x80: 30 | output.put(u8(len)) 31 | return 32 | else: 33 | len_of_len := size() - 1 34 | output.put(u8(0x80 | len_of_len)) 35 | for len_of_len > 0: 36 | output.put(u8(len >> (len_of_len - 1) * 8)) 37 | len_of_len = len_of_len - 1 38 | 39 | fn decode(): 40 | input.endian = config.endian.little 41 | val := input.get() 42 | if val < 0x80: 43 | len = val 44 | else: 45 | len_of_len := val & 0x7f 46 | len = 0 47 | for len_of_len > 0: 48 | len = len << 8 49 | v ::= input.get() 50 | len = len | u64(v) 51 | len_of_len = len_of_len - 1 52 | 53 | fn u64() -> u64: # cast operator 54 | return len 55 | 56 | format TLV: # tag length value 57 | tag: Tag 58 | len: Len 59 | value :[len.len]u8 60 | 61 | format Integer: 62 | tlv :TLV 63 | tlv.tag == Tag.INTEGER 64 | 65 | 66 | -------------------------------------------------------------------------------- /example/ast_step/step1.bgn: -------------------------------------------------------------------------------- 1 | 0x100 -------------------------------------------------------------------------------- /example/ast_step/step2.bgn: -------------------------------------------------------------------------------- 1 | p := 200 2 | p&0xC0 >> 3 | 6 4 | -------------------------------------------------------------------------------- /example/ast_step/step3.bgn: -------------------------------------------------------------------------------- 1 | value := if 1 == (0 == 1 ? 1 : if 1!=0: 2 | 30 3 | else: 4 | 40 5 | ): 6 | 3 7 | else: 8 | 4 9 | 10 | value = - 10 11 | -------------------------------------------------------------------------------- /example/ast_step/step4.bgn: -------------------------------------------------------------------------------- 1 | config.debug = true 2 | for: 3 | if config.debug: 4 | trace() 5 | data = readfrom() 6 | input.buffer = data 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /example/ast_step/step5.bgn: -------------------------------------------------------------------------------- 1 | form :u1 2 | if form == 1: 3 | :LongPacket 4 | else: 5 | :ShortPacket 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/ast_step/step6.bgn: -------------------------------------------------------------------------------- 1 | format LongPacket: 2 | fixed :u1 3 | long_packet_type :u2 4 | reserved :u2 5 | packet_number_length :u2 6 | version :u32 7 | dst_conn_id :ConnectionID() 8 | src_conn_id :ConnectionID() 9 | 10 | -------------------------------------------------------------------------------- /example/ast_step/step7.bgn: -------------------------------------------------------------------------------- 1 | 2 | if input.remain < 9: 3 | val := input.get(u8) 4 | 5 | -------------------------------------------------------------------------------- /example/ast_step/step8.bgn: -------------------------------------------------------------------------------- 1 | 2 | format Data: 3 | data1 :u32 4 | data2 :u32 5 | data3 :u64 6 | 7 | format Data2: 8 | data1 :u64 9 | 10 | format Data3: 11 | data1 :u15 12 | data2 :u49 13 | 14 | format QUICLongPacket: 15 | form :u1 16 | fixed :u1 17 | packet_type :u2 18 | reserved :u2 19 | packet_number_len:u2 20 | version :u32 21 | -------------------------------------------------------------------------------- /example/ast_step/step9.bgn: -------------------------------------------------------------------------------- 1 | format Data: 2 | len :u8 3 | payload :[len]u8 4 | 5 | format 🎅サンタΑa: 6 | .. 7 | 8 | format A: 9 | cond :u8 10 | if cond == 8: 11 | a :u8 12 | else: 13 | b :u16 14 | 15 | 16 | 17 | format B: 18 | x :u8 19 | 20 | X ::= "dom dom" 21 | -------------------------------------------------------------------------------- /example/att.bgn: -------------------------------------------------------------------------------- 1 | 2 | config.url = "https://techweb.rohm.co.jp/product/wireless/bluetooth/bluetooth-basic/3367/" 3 | input.bit_order = config.bit_order.lsb 4 | 5 | 6 | format ATT_PDU: 7 | method :u6 8 | command :u1 9 | authentication_signature :u1 10 | if authentication_signature == 0: 11 | parameter :[..]u8 12 | else: 13 | parameter :[..]u8 14 | signature :[12]u8 15 | 16 | 17 | -------------------------------------------------------------------------------- /example/attestation_object.bgn: -------------------------------------------------------------------------------- 1 | cbor := config.import("cbor.bgn") 2 | 3 | format AuthFlags: # from msb 4 | ed :u1 5 | at :u1 6 | reserved1:u1(0) 7 | bs :u1 8 | be :u1 9 | uv :u1 10 | reserved2 :u1(0) 11 | up :u1 12 | 13 | format AuthenticatorData: 14 | rp_id_hash :[32]u8 15 | flags :AuthFlags 16 | counter :ub32 17 | if flags.at == 1: 18 | attested_credential_data :AuthenticatorDataAttestation 19 | if flags.ed == 1: 20 | extensions :[..]u8 21 | 22 | format AuthenticatorDataAttestation: 23 | aaguid :[16]u8 24 | credential_id_length :u16 25 | credential_id :[credential_id_length]u8 26 | credential_public_key :cbor.Value 27 | -------------------------------------------------------------------------------- /example/ax25.bgn: -------------------------------------------------------------------------------- 1 | 2 | config.url = "https://www.tapr.org/pdf/AX25.2.2.pdf" 3 | 4 | state ProtocolState: 5 | is_16bit_addressing: bool 6 | 7 | s :ProtocolState 8 | 9 | format AX25Frame: 10 | begin_magic: "\x7e" 11 | if s.is_16bit_addressing: 12 | address :u16 13 | else: 14 | address :u8 15 | control :u8 16 | pid :u8 17 | data :[..]u8 18 | fcs :u16 19 | end_magic: "\x7e" 20 | -------------------------------------------------------------------------------- /example/bmp.bgn: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | format BMPHeader: 5 | bfType :ul16 6 | bfSize :ul32 7 | bfReserved1 :ul16 8 | bfReserved2 :ul16 9 | bfOffBits :ul32 10 | biSize :ul32 11 | biWidth :sl32 12 | biHeight :sl32 13 | biPlanes :ul16 14 | biBitCount :ul16 15 | biCompression :ul32 16 | biSizeImage :ul32 17 | biXPelsPerMeter :sl32 18 | biYPelsPerMeter :sl32 19 | biClrUsed :ul32 20 | biClrImportant :ul32 21 | 22 | format RGB: 23 | b :u8 24 | g :u8 25 | r :u8 26 | 27 | format BMP: 28 | header :BMPHeader 29 | data :[header.biSizeImage]u8 30 | 31 | state LineState: 32 | width :u32 33 | bitSize :u32 34 | 35 | line_state :LineState 36 | 37 | format SingleLine: 38 | inByte ::= line_state.width * line_state.bitSize / 8 39 | #delta ::= 4 - inByte % 4 40 | len ::= inByte + (4 - inByte % 4) % 4 41 | data :[len]u8 42 | -------------------------------------------------------------------------------- /example/bmp.txt: -------------------------------------------------------------------------------- 1 | struct BMPHeader 2 | { 3 | uint16 bfType; 4 | uint32 bfSize; 5 | uint16 bfReserved1; 6 | uint16 bfReserved2; 7 | uint32 bfOffBits; 8 | uint32 biSize; 9 | int32 biWidth; 10 | int32 biHeight; 11 | uint16 biPlanes; 12 | uint16 biBitCount; 13 | uint32 biCompression; 14 | uint32 biSizeImage; 15 | int32 biXPelsPerMeter; 16 | int32 biYPelsPerMeter; 17 | uint32 biClrUsed; 18 | uint32 biClrImportant; 19 | }; -------------------------------------------------------------------------------- /example/brgen_help/game.bgn: -------------------------------------------------------------------------------- 1 | 2 | format FrameContainer: 3 | len :u32 4 | data :[len]u8 5 | 6 | enum GameType: 7 | :u8 8 | ID 9 | Move 10 | 11 | format GameFrame: 12 | type :GameType 13 | match type: 14 | GameType.ID => id :ID 15 | GameType.Move => move :MoveFrame 16 | .. => error("invalid GameType") 17 | 18 | format ID: 19 | id :[16]u8 20 | 21 | format LocationPath: 22 | world :ID 23 | region :ID 24 | area :ID 25 | field :ID 26 | position :Vector 27 | 28 | format Vector: 29 | x :f32 30 | y :f32 31 | z :f32 32 | 33 | format MoveFrame: 34 | position :Vector 35 | velocity :Vector 36 | acceleration :Vector 37 | 38 | format EventFlag: 39 | is_active :u1 40 | is_triggered :u1 41 | is_managed :u1 42 | reserved :u5(0) -------------------------------------------------------------------------------- /example/brgen_help/key.bgn: -------------------------------------------------------------------------------- 1 | format KeyExchangeInfo: 2 | sign :[16]u8 3 | client_id :[16]u8 4 | salt :[3][32]u8 5 | public_key :ECDHMaterial 6 | 7 | enum ECDHParam: 8 | :u8 9 | curve25519 = 0 10 | curve448 = 1 11 | p256 = 2 12 | p384 = 3 13 | p521 = 4 14 | 15 | format ECDHMaterial: 16 | param :ECDHParam 17 | match param: 18 | ECDHParam.curve25519: 19 | material :[32]u8 20 | ECDHParam.curve448: 21 | material :[56]u8 22 | ECDHParam.p256: 23 | material :[64]u8 24 | ECDHParam.p384: 25 | material :[96]u8 26 | ECDHParam.p521: 27 | material :[132]u8 28 | .. => error("invalid ECDHParam") 29 | -------------------------------------------------------------------------------- /example/brgen_help/lexer_enum.bgn: -------------------------------------------------------------------------------- 1 | 2 | config.cpp.namespace = "brgen::lexer" 3 | 4 | enum Tag: 5 | indent 6 | space 7 | line 8 | punct 9 | int_literal 10 | bool_literal 11 | str_literal 12 | regex_literal 13 | char_literal 14 | keyword 15 | ident 16 | comment 17 | error 18 | unknown 19 | partial_str_literal 20 | partial_char_literal 21 | partial_regex_literal 22 | 23 | -------------------------------------------------------------------------------- /example/brgen_help/segment_routing_header.bgn: -------------------------------------------------------------------------------- 1 | config.url = "https://www.rfc-editor.org/rfc/rfc8754" 2 | 3 | 4 | format RoutingHeader: 5 | next_header :u8 6 | hdr_ext_len :u8 7 | routing_type :u8 8 | segments_left :u8 9 | last_entry :u8 10 | flags :u8 11 | tag :u16 12 | 13 | format TLV: 14 | type :u8 15 | if type != 0: 16 | length :u8 17 | value :[length]u8 18 | 19 | format Routing: 20 | header :RoutingHeader 21 | match header.routing_type: 22 | 4: 23 | segments :[header.segments_left][16]u8 24 | ext_len ::= header.hdr_ext_len * 8 25 | segment_len ::= header.segments_left * 16 26 | ext_len > segment_len 27 | bytes_len ::= ext_len - segment_len 28 | tlv :[..]TLV(input =input.subrange(bytes_len)) 29 | -------------------------------------------------------------------------------- /example/brgen_help/ssa.bgn: -------------------------------------------------------------------------------- 1 | 2 | config.cpp.namespace = "brgen::ssa" 3 | config.go.package = "ssa" 4 | config.word.map("Ssa","SSA") 5 | 6 | enum SsaOp: 7 | :u8 8 | 9 | # arithmetic operations 10 | ADD = 0 11 | SUB = 1 12 | MUL = 2 13 | DIV = 3 14 | MOD = 4 15 | 16 | # bitwise operations 17 | AND = 5 18 | OR = 6 19 | XOR = 7 20 | SHL = 8 21 | SHR = 9 22 | 23 | # comparison operations 24 | EQ = 10 25 | NE = 11 26 | LT = 12 27 | LE = 13 28 | GT = 14 29 | GE = 15 30 | 31 | # logical operations 32 | LAND = 16 33 | LOR = 17 34 | 35 | # unary operations 36 | NEG = 18 37 | NOT = 19 38 | 39 | # phi function 40 | PHI = 20 41 | 42 | # memory operations 43 | LOAD = 21 44 | STORE = 22 45 | 46 | # call/ret operations 47 | CALL = 23 48 | RET = 24 49 | 50 | # branch operations 51 | BR = 25 # unconditional branch 52 | BRC = 26 # conditional branch 53 | 54 | # meta operations 55 | BEGIN_BLOCK = 27 56 | 57 | # special operations 58 | NOP = 28 59 | ASSIGN = 29 60 | 61 | format VarInt: 62 | config.type = u64 63 | prefix :u2 64 | match prefix: 65 | 0 => value :u6 66 | 1 => value :u14 67 | 2 => value :u30 68 | 3 => value :u62 69 | 70 | fn u64() -> u64: 71 | return value 72 | 73 | format SSA: 74 | op :SsaOp 75 | arg_len :VarInt 76 | args :[arg_len]u8 77 | 78 | format SsaBlock: 79 | id :u32 80 | ssas :[..]SSA 81 | -------------------------------------------------------------------------------- /example/can.bgn: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | config.url = "https://www.keyence.co.jp/ss/products/recorder/lab/candata/mechanism.jsp" 5 | config.url = "https://sunnygiken.jp/product/can-fd-tool/about_canfd/" 6 | fn extendedDataLength(r :u4) -> u8: 7 | x ::= match r: 8 | 0 => 0 9 | 1 => 1 10 | 2 => 2 11 | 3 => 3 12 | 4 => 4 13 | 5 => 5 14 | 6 => 6 15 | 7 => 7 16 | 8 => 8 17 | 9 => 12 18 | 10 => 16 19 | 11 => 20 20 | 12 => 24 21 | 13 => 32 22 | 14 => 48 23 | 15 => 64 24 | return x 25 | 26 | format ControlField: 27 | ide :u1 28 | if ide == 1: 29 | id_ext :u18 30 | rtr_or_rss :u1 31 | reserved1 :u1 32 | fdf :u1 33 | if fdf == 1: 34 | reserved2 :u1 35 | brs :u1 36 | esi :u1 37 | dlc :u4 38 | 39 | format CANFrame: 40 | sof :u1 41 | id :u11 42 | rtr_or_srr_or_rss :u1 43 | control :ControlField 44 | len ::= control.fdf == 1 ? extendedDataLength(control.dlc) : (control.dlc >= 9 ? 8 : control.dlc) 45 | data :[len]u8 46 | if control.fdf == 1: 47 | stuff_count :u4 48 | crc :u15 49 | crc_delimiter :u1 50 | ack :u1 51 | ack_delimiter :u1 52 | eof :u7 53 | intermission :u3 54 | 55 | 56 | -------------------------------------------------------------------------------- /example/capnproto.bgn: -------------------------------------------------------------------------------- 1 | 2 | config.url = "https://capnproto.org/encoding.html" 3 | input.endian = config.endian.little 4 | input.bit_order = config.bit_order.lsb 5 | # little endian and begin with lsb 6 | 7 | # for example, the following code 8 | # 9 | format StructPointer: 10 | config.type = u64 11 | magic :u2(0) 12 | offset :s30 13 | sizeOfDataInWord :u16 14 | sizeOfPointerInWord :u16 15 | 16 | enum SizeOfListElement: 17 | :u3 18 | void_ = 0 19 | bit = 1 20 | byte1 = 2 21 | byte2 = 3 22 | byte4 = 4 23 | byte8 = 5 24 | pointer8 = 6 25 | composite = 7 26 | 27 | format ListPointer: 28 | config.type = u64 29 | magic :u2(1) 30 | offset :u30 31 | sizeOfElement :SizeOfListElement 32 | # if sizeOfElemet == SizeOfListElement.composite 33 | # then sizeOfList is the word count in list 34 | # otehrwise element count 35 | sizeOfList :u29 36 | 37 | 38 | format InterSegmentPointer: 39 | config.type = u64 40 | magic :u2(2) 41 | padding2byte :u1 42 | offset :u29 43 | id :u32 44 | 45 | format Capabilities: 46 | config.type = u64 47 | magic :u2(3) 48 | reserved :u30(0) 49 | capabilityTable :u32 50 | -------------------------------------------------------------------------------- /example/ccsds.bgn: -------------------------------------------------------------------------------- 1 | 2 | format CCSDS: 3 | version :u3 4 | type :u1 5 | packet_secondary_header_flag :u1 6 | application_process_id :u11 7 | group_flags :u2 8 | soruce_sequence_count :u14 9 | packet_data_length :u16 10 | packet_data :[packet_data_length]u8 11 | -------------------------------------------------------------------------------- /example/chg.bgn: -------------------------------------------------------------------------------- 1 | 2 | format MonomakhSaprChg: 3 | title : [10]u8 4 | block :[..]Block 5 | 6 | format Block: 7 | title : [13]u8 8 | file_size :ul64 9 | data : [file_size]u8 10 | 11 | -------------------------------------------------------------------------------- /example/cmsg.bgn: -------------------------------------------------------------------------------- 1 | config.cpp.namespace = "futils::fnet" 2 | format CMsg: 3 | len :ul64 4 | level :ul32 5 | type :ul32 6 | msg :[len]u8 7 | -------------------------------------------------------------------------------- /example/core_can_proto.bgn: -------------------------------------------------------------------------------- 1 | config.url = "https://github.com/core-rocket/CCP" 2 | 3 | 4 | format Str: 5 | seconds :u16 6 | text :[6]u8 7 | 8 | format Int: 9 | milliseconds :u32 10 | value :u32 11 | 12 | format Float: 13 | milliseconds :u32 14 | value :f32 15 | 16 | format FastFloat: 17 | seconds :u16 18 | fp16 :[3]f16 19 | -------------------------------------------------------------------------------- /example/dccp.bgn: -------------------------------------------------------------------------------- 1 | 2 | config.url = "https://en.wikipedia.org/wiki/Datagram_Congestion_Control_Protocol" 3 | 4 | format GenericHeader: 5 | srcPort :u16 6 | dstPort :u16 7 | dataOffset :u8 8 | ccVal :u4 9 | csCov :u4 10 | checksum :u16 11 | res :u3 12 | type :u4 13 | x :u1 14 | if x == 1: 15 | reserved :u8 16 | seqNum :u48 17 | else: 18 | seqNum :u24 19 | -------------------------------------------------------------------------------- /example/dnssec.bgn: -------------------------------------------------------------------------------- 1 | 2 | dns ::= config.import("./dns.bgn") 3 | 4 | format DNSKeyRData: 5 | flags :u16 6 | protocol :u8 7 | algorithm :u8 8 | public_key :[..]u8 9 | 10 | format RRSIGRData: 11 | type_covered :u16 12 | algorithm :u8 13 | labels :u8 14 | original_ttl :u32 15 | signature_expiration :u32 16 | signature_inception :u32 17 | key_tag :u16 18 | signer_name :dns.DomainName 19 | signature :[..]u8 20 | 21 | # unsigned int 22 | # keytag ( 23 | # unsigned char key[], /* the RDATA part of the DNSKEY RR */ 24 | # unsigned int keysize /* the RDLENGTH */ 25 | # ) 26 | # { 27 | # unsigned long ac; /* assumed to be 32 bits or larger */ 28 | # int i; /* loop index */ 29 | # 30 | # for ( ac = 0, i = 0; i < keysize; ++i ) 31 | # ac += (i & 1) ? key[i] : key[i] << 8; 32 | # ac += (ac >> 16) & 0xFFFF; 33 | # return ac & 0xFFFF; 34 | # } 35 | 36 | fn keytag(key: []u8) -> u16: 37 | ac := u32(0) 38 | for i in key.length: 39 | if i & 1 == 1: 40 | ac += u32(key[i]) 41 | else: 42 | ac += u32(key[i]) << 8 43 | ac += (ac >> 16) & 0xFFFF 44 | return ac & 0xFFFF 45 | -------------------------------------------------------------------------------- /example/ether.bgn: -------------------------------------------------------------------------------- 1 | 2 | config.go.package = "ether" 3 | 4 | enum EtherType: 5 | :u16 6 | ipv4 = 0x0800 7 | arp = 0x0806 8 | vlan = 0x8100 9 | ipv6 = 0x86DD 10 | service_vlen = 0x88A8 11 | pppoe_discovery = 0x8863 12 | pppoe_session = 0x8864 13 | 14 | format OUI: 15 | high: u6 16 | local :u1 17 | multicast :u1 18 | low :[2]u8 19 | 20 | format MacAddress: 21 | oui :OUI 22 | nic :[3]u8 23 | 24 | format EthernetFrame: 25 | dstMac :[6]u8 26 | srcMac :[6]u8 27 | ether_type :u16 28 | if ether_type == u16(EtherType.vlan): 29 | vlan_tag :u16 30 | ether_type2 :u16 31 | elif ether_type == u16(EtherType.service_vlen): 32 | service_vlan_tag :u16 33 | dummy_ether_type :u16(u16(EtherType.vlan)) 34 | vlan_tag :u16 35 | ether_type2 :u16 36 | len ::= available(ether_type2) ? ether_type2 : ether_type 37 | len <= 0x5dc || len >= 0x600 38 | if len >= 0x600: 39 | data :[..]u8 40 | else: 41 | # peek :u16(input.peek = true) 42 | data :[len]u8 43 | 44 | format PPPoE: 45 | version :u4(1) 46 | type :u4(1) 47 | code :u8 48 | session_id :u16 49 | len :u16 50 | data :[len]u8 51 | -------------------------------------------------------------------------------- /example/etherip.bgn: -------------------------------------------------------------------------------- 1 | 2 | config.rfc = "https://www.rfc-editor.org/rfc/rfc3378" 3 | 4 | format EtherIP: 5 | version :u3 6 | reserved :u13 7 | -------------------------------------------------------------------------------- /example/feature_test/analyze_block_trait.bgn: -------------------------------------------------------------------------------- 1 | 2 | state S: 3 | is_ok :bool 4 | ok_bit :u1 5 | s :S 6 | 7 | format Nest: 8 | a :u32 9 | 10 | format None: 11 | .. 12 | 13 | format A: 14 | a :u1 15 | d :[a]u8 16 | if a == 1: 17 | q :[a]u8 18 | n :[22]u8 19 | if d.length > 0: 20 | if s.ok_bit != a: 21 | error("not output") 22 | s.ok_bit == 1 23 | v := input.get(u8) 24 | input.bit_order = v == 0 ? config.bit_order.lsb : config.bit_order.msb 25 | nest :Nest 26 | 27 | fn encode(): 28 | input.bit_order = config.bit_order.msb 29 | val := input.get(<[32]u1>) 30 | result := <[]A>() 31 | result[result.length] = A() 32 | for v in val: 33 | .. -------------------------------------------------------------------------------- /example/feature_test/assert_or_implicit_yeild.bgn: -------------------------------------------------------------------------------- 1 | 2 | format ImplicitYieldMatchPattern: 3 | type :u8 4 | len :u8 5 | data :[len]u8 6 | ok ::= match type: # match type is bool 7 | 0 => (data.length >= 10) # as boolean expression 8 | 1 => (data.length >= 20) 9 | .. => (data.length >= 30) 10 | ok == true 11 | 12 | format AssertMatchPattern: 13 | type :u8 14 | len :u8 15 | data :[len]u8 16 | match type: # match type is void 17 | 0 => data.length >= 10 # as assertion 18 | 1 => data.length >= 20 19 | .. => data.length >= 30 20 | 21 | format ImplicitYieldIfPattern: 22 | type :u8 23 | len :u8 24 | data :[len]u8 25 | ok ::= if type == 0: # if type is bool 26 | (data.length >= 10) # as boolean expression 27 | elif type == 1: 28 | (data.length >= 20) 29 | else: 30 | (data.length >= 30) 31 | ok == true 32 | 33 | format AssertIfPattern: 34 | type :u8 35 | len :u8 36 | data :[len]u8 37 | if type == 0: # if type is void 38 | data.length >= 10 # as assertion 39 | elif type == 1: 40 | data.length >= 20 41 | else: 42 | data.length >= 30 43 | 44 | -------------------------------------------------------------------------------- /example/feature_test/bit_fields.bgn: -------------------------------------------------------------------------------- 1 | 2 | format BitFields: 3 | a :u1 4 | b :u2 5 | c :u3 6 | d :u4 7 | e :u5 8 | f :u6 9 | g :u7 10 | h :u8 11 | i :u9 12 | j :u10 13 | k :u11 14 | l :u12 15 | m :u13 16 | n :u14 17 | o :u15 18 | 19 | # flag value is 1, data value is 0x1234, opaque1 value is 0x2678 20 | 21 | # msb lsb 22 | # |0 |1 |2 |3 23 | # |0|1|2|3|4|5|6|7|8|9|a|b|c|d|e|f|0|1|2|3|4|5|6|7|8|9|a|b|c|d|e|f| 24 | # 0 1|0 0 0 1 0 0 1 0 0 0 1 1 0 1 0 0|1 0 0 1 1 0 0 1 1 1 1 0 0 0| 25 | # |f|data |opaque1 | 26 | format DefaultLayout: 27 | flag :u2 28 | data :u16 29 | opaque1 :u14 30 | 31 | # msb lsb 32 | # |0 |1 |2 |3 33 | # |0|1|2|3|4|5|6|7|8|9|a|b|c|d|e|f|0|1|2|3|4|5|6|7|8|9|a|b|c|d|e|f| 34 | # 1 0 0 0 0 1|0 1|0 0 0 0 1 1 0 0| |0 1 35 | # | 36 | format LSBProiorLayout: 37 | input.bit_order = config.bit_order.lsb 38 | flag :u2 39 | data :u30 40 | opaque1 :u32 41 | -------------------------------------------------------------------------------- /example/feature_test/comma_match.bgn: -------------------------------------------------------------------------------- 1 | 2 | x := u1() 3 | match x: 4 | 0,1 => .. 5 | 6 | fn isHexDigit(c :u8) -> bool: 7 | return match c: 8 | '0'..='9','a'..='f','A'..='F' => true 9 | .. => false 10 | 11 | -------------------------------------------------------------------------------- /example/feature_test/const_length.bgn: -------------------------------------------------------------------------------- 1 | 2 | format A: 3 | T ::=30 4 | val :[T+1]u8 5 | -------------------------------------------------------------------------------- /example/feature_test/edge_case1.bgn: -------------------------------------------------------------------------------- 1 | 2 | format A: 3 | a :u8 b :u8 4 | b 5 | a 6 | b 7 | -------------------------------------------------------------------------------- /example/feature_test/for_in.bgn: -------------------------------------------------------------------------------- 1 | 2 | for x in 10: 3 | y ::= x + 1 4 | 5 | for x in 1..10: 6 | y ::= x + 1 7 | 8 | for x in "HELLO": 9 | y ::= x + 1 10 | 11 | arr :[]u8 12 | 13 | for x in arr: 14 | x = 0 15 | -------------------------------------------------------------------------------- /example/feature_test/import_and_use.bgn: -------------------------------------------------------------------------------- 1 | 2 | arp ::= config.import("../arp.bgn") 3 | ether ::=config.import("../ether.bgn") 4 | ip ::= config.import("../ip.bgn") 5 | 6 | format ArpProtocol: 7 | etherHeader :ether.EthernetFrame 8 | ipHeader :ip.IPv4Header 9 | arpHeader :arp.ArpPacket 10 | 11 | 12 | -------------------------------------------------------------------------------- /example/feature_test/loop_ref.bgn: -------------------------------------------------------------------------------- 1 | 2 | format A: 3 | c :C 4 | 5 | format B: 6 | a :A 7 | 8 | format C: 9 | b :B 10 | 11 | -------------------------------------------------------------------------------- /example/feature_test/nested_state.bgn: -------------------------------------------------------------------------------- 1 | 2 | 3 | state S: 4 | isA :bool 5 | 6 | sstate :S 7 | 8 | format A: 9 | len :u8 10 | if sstate.isA: 11 | a :u8 12 | else: 13 | b :u8 14 | 15 | format B: 16 | a :A 17 | 18 | -------------------------------------------------------------------------------- /example/feature_test/regexp.bgn: -------------------------------------------------------------------------------- 1 | 2 | format RegExp: 3 | reg : /\s/(input.skip = true) 4 | 5 | r ::= /r/gi 6 | 7 | "a" == r 8 | -------------------------------------------------------------------------------- /example/feature_test/simple_binary.bgn: -------------------------------------------------------------------------------- 1 | x := 1 + 1 2 | err := if true: 3 | 2 4 | else: 5 | 3 6 | n ::= 20 7 | V ::= if n < 10 && n > -10: 8 | 10 * n 9 | else: 10 | n / 2 11 | 12 | for i in 10: 13 | error("error!",i) 14 | -------------------------------------------------------------------------------- /example/feature_test/sort_test.bgn: -------------------------------------------------------------------------------- 1 | 2 | format A: 3 | x :u8 4 | y :B 5 | 6 | format B: 7 | x :u8 8 | y :u8 9 | z :u8 10 | 11 | format G: 12 | d :D 13 | 14 | format D: 15 | d :B 16 | s :G 17 | 18 | format E: 19 | e :D 20 | 21 | 22 | 23 | config.test.sort.expect(B,A,D,G,E) 24 | -------------------------------------------------------------------------------- /example/feature_test/state_variable.bgn: -------------------------------------------------------------------------------- 1 | 2 | state S: 3 | is_ok :bool 4 | 5 | s :S 6 | y :S 7 | 8 | format N: 9 | s.is_ok = true 10 | 11 | format X: 12 | if s.is_ok: 13 | a :u8 14 | else: 15 | if !s.is_ok: 16 | c :u8 17 | b :u8 18 | y.is_ok = true 19 | if y.is_ok: 20 | d :N 21 | v :N 22 | else: 23 | e :u8 -------------------------------------------------------------------------------- /example/feature_test/state_variable2.bgn: -------------------------------------------------------------------------------- 1 | state Condition: 2 | is_16bit :bool 3 | 4 | condition :Condition 5 | 6 | format Data: 7 | if condition.is_16bit: 8 | data :u16 9 | else: 10 | data :u32 -------------------------------------------------------------------------------- /example/feature_test/test_import.bgn: -------------------------------------------------------------------------------- 1 | 2 | format Import: 3 | x :u8 4 | 5 | a :u32 -------------------------------------------------------------------------------- /example/feature_test/trial_match.bgn: -------------------------------------------------------------------------------- 1 | 2 | match: 3 | .. => x :u8(0x90) 4 | .. => x :u8(0x80) 5 | .. => x :u8(0x81) 6 | -------------------------------------------------------------------------------- /example/feature_test/union.bgn: -------------------------------------------------------------------------------- 1 | # this type is union of a,b,c and x 2 | format UnionSample: 3 | tag :u8 4 | match tag: 5 | 1 => a :u8 6 | 2 : 7 | b :u16 8 | 3 => c :u32 9 | .. => x :u64 10 | 11 | format UnionExample: 12 | size :u8 13 | match size: 14 | 1 => len :u8 15 | 2 => len :u16 16 | 4 => len :u32 17 | 8 => len :u64 18 | .. => error("invalid size") 19 | data :[len]u8 20 | 21 | # but actually, this type is become like this 22 | # struct { uint8_t tag; union { uint8_t a; uint16_t b; uint32_t c; uint64_t x; }; 23 | 24 | enum EnumExample: 25 | A 26 | B 27 | C 28 | D 29 | 30 | format LEB128: 31 | value :u64 32 | fn encode(): 33 | data := value 34 | # encode value to LEB128 35 | for data > 0: 36 | output.put(0x80 | (data & 0x7f)) 37 | data = data >> 7 38 | 39 | fn decode(): 40 | # decode LEB128 to value 41 | i := 0 42 | for value < 0x80: 43 | byte := input.get() 44 | value = value | u64(byte & 0x7f) << (i * 7) 45 | i = i + 1 46 | 47 | fn u64(): 48 | return value 49 | 50 | 51 | format Magic: 52 | magic :"\xab\xcd\xef\x00" 53 | 54 | format FixedValue: 55 | fixed :u8(0x12) 56 | -------------------------------------------------------------------------------- /example/feature_test/varint_test.bgn: -------------------------------------------------------------------------------- 1 | 2 | q ::= config.import("../quic_varint.bgn") 3 | format Length: 4 | indicator :u1 5 | match indicator: 6 | 0 => len :u7 7 | 1 => len :u31 8 | 9 | format TestVarint: # total 16 field 10 | field_1 :q.VarInt # 8-bit data 11 | field_2 :q.VarInt # 8-bit data 12 | field_3 :q.VarInt # 8-bit data 13 | field_4 :q.VarInt # 8-bit data 14 | field_5 :q.VarInt # 16-bit data 15 | field_6 :q.VarInt # 16-bit data 16 | field_7 :q.VarInt # 16-bit data 17 | field_8 :q.VarInt # 16-bit data 18 | field_9 :q.VarInt # 32-bit data 19 | field_10 :q.VarInt # 32-bit data 20 | field_11 :q.VarInt # 32-bit data 21 | field_12 :q.VarInt # 32-bit data 22 | field_13 :q.VarInt # 64-bit data 23 | field_14 :q.VarInt # 64-bit data 24 | field_15 :q.VarInt # 64-bit data 25 | field_16 :q.VarInt # 64-bit data 26 | 27 | field_17 :Length # 8-bit data 28 | field_18 :Length # 32-bit data 29 | -------------------------------------------------------------------------------- /example/fido_u2f.bgn: -------------------------------------------------------------------------------- 1 | 2 | config.url = "https://fidoalliance.org/specs/fido-u2f-v1.2-ps-20170411/fido-u2f-raw-message-formats-v1.2-ps-20170411.html" 3 | 4 | enum U2FCommand: 5 | :u8 6 | Register = 0x01 7 | Authenticate = 0x02 8 | 9 | format U2FMessage: 10 | type :U2FCommand 11 | if type == U2FCommand.Register: 12 | register :RegisterRequest 13 | else: 14 | authenticate :AuthenticateRequest 15 | 16 | format RegisterRequest: 17 | challenge :[32]u8 18 | application :[32]u8 19 | 20 | format AuthenticateRequest: 21 | challenge :[32]u8 22 | application :[32]u8 23 | key_handle_len :u8 24 | key_handle :[key_handle_len]u8 25 | -------------------------------------------------------------------------------- /example/from_kaitai/btrfs_stream.bgn: -------------------------------------------------------------------------------- 1 | 2 | format SendStreamHeader: 3 | magic :"btrfs-stream\x00" 4 | version :ul32 5 | 6 | format TLV: 7 | type :ul16 8 | length :ul16 9 | value :[length]u8 10 | 11 | format SendCommand: 12 | len :ul32 13 | type :ul16 14 | checksum :ul32 15 | data :[len]TLV -------------------------------------------------------------------------------- /example/gen_step/step1.bgn: -------------------------------------------------------------------------------- 1 | # step 1 - can generate set of fundamental types 2 | format Step1: 3 | hello :u8 4 | world :u16 5 | is :u32 6 | cheap :u64 7 | -------------------------------------------------------------------------------- /example/gen_step/step2.bgn: -------------------------------------------------------------------------------- 1 | # step2 - fixed array of fundamental types 2 | format Step2: 3 | hello :[16]u8 4 | world :[8]u16 5 | is :[4]u32 6 | cheap :[2]u64 7 | -------------------------------------------------------------------------------- /example/gen_step/step3.bgn: -------------------------------------------------------------------------------- 1 | # step3 - dynamic length byte array 2 | format Step3: 3 | len :u8 4 | data :[len]u8 5 | -------------------------------------------------------------------------------- /example/gen_step/step4.bgn: -------------------------------------------------------------------------------- 1 | # step4 - dynamic length byte array (length is used with operator) 2 | format Step4: 3 | len1 :u8 4 | data1 :[len1*2]u8 5 | len2 :u8 6 | data2 :[len2/2]u8 7 | len3 :u8 8 | data3 :[len3 << 2]u8 9 | -------------------------------------------------------------------------------- /example/gen_step/step4_a.bgn: -------------------------------------------------------------------------------- 1 | # step4.a - dynamic length byte array (length is used with operator) 2 | config.cpp.vector_mode = "pointer" 3 | format Step4: 4 | len1 :u8 5 | data1 :[len1*2]u8 6 | len2 :u8 7 | data2 :[len2/2]u8 8 | true || false 9 | -------------------------------------------------------------------------------- /example/gen_step/step4_b.bgn: -------------------------------------------------------------------------------- 1 | # step4.a - dynamic length byte array (length is used with operator) 2 | config.cpp.vector_mode = "pointer" 3 | # asymmetric length treatment 4 | # when decode, decode length as is 5 | # when encode, length is actual buffer length 6 | config.cpp.vector_pointer.asymmetric = true 7 | format Step4: 8 | len1 :u8 9 | data1 :[len1*2]u8 10 | len2 :u8 11 | data2 :[len2/2]u8 12 | -------------------------------------------------------------------------------- /example/gen_step/step5.bgn: -------------------------------------------------------------------------------- 1 | # step5 - bit field 2 | format Step5: 3 | reserved: u1 4 | code :u2 5 | offset :u1 6 | len :u4 7 | -------------------------------------------------------------------------------- /example/gen_step/step6.bgn: -------------------------------------------------------------------------------- 1 | 2 | # step6 - bit field (with length) 3 | format Step6: 4 | reserved: u1 5 | code :u2 6 | offset :u1 7 | len :u4 8 | data :[len]u8 9 | -------------------------------------------------------------------------------- /example/gen_step/step7.bgn: -------------------------------------------------------------------------------- 1 | format Step7: 2 | len :u8 3 | match len: 4 | 0 => value :u8 5 | 1 => value :u16 6 | 2 => value :u32 7 | 3 => value :u64 8 | -------------------------------------------------------------------------------- /example/gif.bgn: -------------------------------------------------------------------------------- 1 | 2 | format GifHeader: 3 | gif :"GIF" 4 | version :[3]u8 5 | 6 | format LogicalScreen: 7 | width :ul16 8 | height :ul16 9 | flags :u8 10 | backgroundColorIndex :u8 11 | pixelAspectRatio :u8 12 | 13 | format Gif: 14 | header :GifHeader 15 | logicalScreen :LogicalScreen 16 | globalColorTable :[256]ColorTable 17 | blocks :[..]Block 18 | :";" 19 | 20 | format ColorTable: 21 | colors :[3]u8 22 | 23 | format Block: 24 | blockType :u8 25 | data :[..]u8 26 | 27 | format ImageDescriptor: 28 | left :ul16 29 | top :ul16 30 | width :ul16 31 | height :ul16 32 | flags :u8 33 | -------------------------------------------------------------------------------- /example/gzip.bgn: -------------------------------------------------------------------------------- 1 | config.url = "https://www.rfc-editor.org/rfc/rfc1952" 2 | input.endian = config.endian.little 3 | input.bit_order = config.bit_order.lsb 4 | 5 | format GZipHeader: 6 | magic :"\x1f\x8b" 7 | method :CompressionMethod 8 | flags :GZipFlag 9 | mtime :u32 10 | xfl :u8 11 | os :OS 12 | if flags.extra ==1: 13 | extra :GZipExtra 14 | if flags.fname ==1: 15 | fname :CString 16 | if flags.fcomment ==1: 17 | fcomment :CString 18 | if flags.crc ==1: 19 | crc16 :u16 20 | 21 | format GZipExtra: 22 | xlen :u16 23 | data :[xlen]u8 24 | 25 | format CString: 26 | data :[..]u8 27 | :"\x00" 28 | 29 | format GZipFlag: 30 | text :u1 31 | crc :u1 32 | extra :u1 33 | fname :u1 34 | fcomment :u1 35 | reserved :u3 36 | reserved == 0 37 | 38 | enum CompressionMethod: 39 | :u8 40 | deflate = 8 41 | 42 | enum OS: 43 | :u8 44 | fat = 0 45 | amiga = 1 46 | vms = 2 47 | unix_ = 3 48 | vm_cms = 4 49 | atari = 5 50 | hpfs = 6 51 | machintosh = 7 52 | z_system = 8 53 | cp_m = 9 54 | tops_20 = 10 55 | ntfs = 11 56 | qdos = 12 57 | acorn_risc_os = 13 58 | vfat = 14 59 | mvs = 15 60 | beos = 16 61 | -------------------------------------------------------------------------------- /example/hci.bgn: -------------------------------------------------------------------------------- 1 | config.url = "https://www.wdic.org/w/WDIC/HCI%20%28Bluetooth%29" 2 | config.url = "https://www.bluetooth.org/DocMan/handlers/DownloadDoc.ashx?doc_id=521059" 3 | input.endian = config.endian.little 4 | input.bit_order = config.bit_order.msb 5 | 6 | format HCIHeader: 7 | indicator :u8 8 | 9 | format HCICommand: 10 | opcode_group_field :u6 11 | opcode_command_field :u10 12 | length :u8 13 | parameters :[length]u8 14 | 15 | format ACLData: 16 | conn_handle :u12 17 | packet_boundary :u2 18 | broadcast :u2 19 | length :u8 20 | data :[length]u8 21 | 22 | format HCIEvent: 23 | event_code :u16 -------------------------------------------------------------------------------- /example/http.bgn: -------------------------------------------------------------------------------- 1 | 2 | format RequestLine: 3 | method :[..]u8 4 | :" " 5 | path :[..]u8 6 | :" " 7 | version :[..]u8 8 | :"\r\n" 9 | 10 | format ResponseLine: 11 | version :[..]u8 12 | :" " 13 | status :[..]u8 14 | :" " 15 | reason :[..]u8 16 | :"\r\n" 17 | 18 | format Field: 19 | name :[..]u8 20 | :": " 21 | value :[..]u8 22 | :"\r\n" 23 | 24 | format RequestHeader: 25 | line :RequestLine 26 | fields :[..]Field 27 | :"\r\n" 28 | 29 | format ResponseHeader: 30 | line :ResponseLine 31 | fields :[..]Field 32 | :"\r\n" 33 | -------------------------------------------------------------------------------- /example/icn.bgn: -------------------------------------------------------------------------------- 1 | config.url = "https://datatracker.ietf.org/doc/rfc8609/" 2 | enum TLVType: 3 | T_ORG 4 | 5 | format TLV: 6 | type :u16 7 | length :u16 8 | data :[length]u8 9 | 10 | enum PacketType: 11 | :u8 12 | Interest = 0x00 13 | Content = 0x01 14 | Return = 0x02 15 | 16 | enum ReturnCode: 17 | :u8 18 | NoRoute = 0x01 19 | LimitExceeded = 0x02 20 | NoResources = 0x03 21 | PathError = 0x04 22 | ReturnProhibited = 0x05 23 | Congested = 0x06 24 | ReturnMtuTooLarge = 0x07 25 | ReturnUnsupportedHashRestriction = 0x08 26 | MalformedInterest = 0x09 27 | 28 | format CCNxPacketHeader: 29 | version :u8 30 | packet_type :PacketType 31 | packet_length :u16 32 | packet_specific :u24 33 | header_length :u8 34 | 35 | format CCNxPacket: 36 | header :CCNxPacketHeader 37 | header.packet_length >= u16(header.header_length) 38 | header_tlvs :[..]TLV(input = input.subrange(header.header_length)) 39 | payload_tlvs :[..]TLV(input = input.subrange(header.packet_length - header.header_length)) 40 | -------------------------------------------------------------------------------- /example/ico.bgn: -------------------------------------------------------------------------------- 1 | config.url ="https://en.wikipedia.org/wiki/ICO_(file_format)" 2 | input.endian = config.endian.little 3 | 4 | enum Type: 5 | :u16 6 | ICON = 1 7 | CURSOR = 2 8 | 9 | format ICONDir: 10 | reserved :u16(0) 11 | type :Type 12 | count :u16 13 | 14 | format ICONDirEntry: 15 | width :u8 16 | height :u8 17 | colors :u8 18 | reserved :u8 19 | planes :u16 20 | bitcount :u16 21 | size :u32 22 | offset :u32 23 | 24 | format ICOHeader: 25 | dir :ICONDir 26 | entries : [dir.count]ICONDirEntry 27 | -------------------------------------------------------------------------------- /example/ieee802_11.bgn: -------------------------------------------------------------------------------- 1 | config.url = "https://www.n-study.com/wlan-detail/802-11-frame-type-subtype/" 2 | enum FrameType: 3 | :u2 4 | Management = 0 5 | Control = 1 6 | Data = 2 7 | Extension = 3 8 | 9 | 10 | format FrameControl: # msb to lsb 11 | protocol_version :u2 12 | frame_type: FrameType 13 | sub_type: u4 14 | to_ds: u1 15 | from_ds: u1 16 | more_frag: u1 17 | retry: u1 18 | power_mgmt: u1 19 | more_data: u1 20 | protected_frame: u1 21 | order: u1 22 | 23 | format IEEE802_11: 24 | frame_control: FrameControl 25 | duration_id: u16 26 | addr1 : [6]u8 27 | addr2 : [6]u8 28 | addr3 : [6]u8 29 | sequence_control: u16 30 | addr4 : [6]u8 31 | payload: [..]u8 32 | 33 | format IEEE802_11FCS: 34 | frame_control: u16 35 | duration_id: u16 36 | addr1 : [6]u8 37 | addr2 : [6]u8 38 | addr3 : [6]u8 39 | sequence_control: u16 40 | addr4 : [6]u8 41 | payload: [..]u8 42 | fcs: u32 43 | -------------------------------------------------------------------------------- /example/ietf_hackathon/bgp_ls.bgn: -------------------------------------------------------------------------------- 1 | 2 | format ServiceChaining: 3 | type :u16 4 | length :u16 5 | service_type :u16 6 | flags :u8 7 | traffic_type :u8 8 | reserved :u16 9 | 10 | format OpaqueMetadata: 11 | type :u16 12 | length :u16 13 | opaque_type :u16 14 | flags :u8 15 | data :[length * 8 + 1]u8 16 | -------------------------------------------------------------------------------- /example/ietf_hackathon/initial_registory.bgn: -------------------------------------------------------------------------------- 1 | config.url = "https://www.rfc-editor.org/rfc/rfc8986#name-initial-registrations" 2 | 3 | enum RegistrationProcedures: 4 | :u16 5 | reserved = 0x0 6 | first_come_first_served_begin = 0x1 7 | first_come_first_served_end = 0x7fff 8 | private_use_begin = 0x8000 9 | private_use_end = 0x87ff 10 | reserved2_begin = 0x8800 11 | reserved2_end = 0xfffe 12 | opaque = 0xffff 13 | 14 | enum EndpointBehavior: 15 | :u16 16 | reserved 17 | end 18 | end_with_psp 19 | end_with_usp 20 | end_with_psp_and_usp 21 | end_x 22 | end_x_with_psp 23 | end_x_with_usp 24 | end_x_with_psp_and_usp 25 | end_t 26 | end_t_with_psp 27 | end_t_with_usp 28 | end_t_with_psp_and_usp 29 | unassigned 30 | end_b6_encaps 31 | end_bm 32 | end_dx6 33 | end_dx4 34 | end_dt6 35 | end_dt4 36 | end_dt46 37 | end_dx2 38 | end_dx2v 39 | end_dx2u 40 | end_dx2m 41 | reserved2 42 | unassigned2 43 | end_b6_encaps_red 44 | end_with_usd 45 | end_with_psp_and_usd 46 | end_with_usp_and_usd 47 | end_x_with_usd 48 | end_x_with_psp_and_usd 49 | end_x_with_usp_and_usd 50 | end_x_with_psp_usp_and_usd 51 | end_t_with_psp_and_usd 52 | end_t_with_usp_and_usd 53 | end_t_with_psp_usp_and_usd 54 | 55 | sid_defined_in_rfc8754 = 0x7fff 56 | reserved_for_private_use_begin = 0x8000 57 | reserved_for_private_use_end = 0xfffe 58 | opaque = 0xffff 59 | -------------------------------------------------------------------------------- /example/ietf_hackathon/sid.bgn: -------------------------------------------------------------------------------- 1 | config.url = "https://www.rfc-editor.org/rfc/rfc8986#name-sid-format" 2 | state Lengths: 3 | F :u16 4 | L :u16 5 | A :u16 6 | 7 | lengths :Lengths 8 | 9 | format SID: # msb to lsb 10 | lengths.L + lengths.F + lengths.A <= 128 11 | loc :[lengths.L]u1 12 | func :[lengths.F]u1 13 | args :[lengths.A]u1 14 | padding :[128 - lengths.L - lengths.F - lengths.A]u1 15 | -------------------------------------------------------------------------------- /example/ike.bgn: -------------------------------------------------------------------------------- 1 | 2 | format IKEHeader: 3 | initiators_spi :u64 4 | responders_spi :u64 5 | next_payload :u8 6 | major_version :u4 7 | minor_version :u4 8 | exchange_type :u8 9 | reserved1 :u2 10 | response :u1 11 | version :u1 12 | initiator :u1 13 | reserved2 :u3 14 | message_id :u32 15 | length :u32 16 | 17 | format GenericPayloadHeader: 18 | next_payload :u8 19 | critical :u1 20 | reserved :u7 21 | payload_length :u16 22 | 23 | format GenericPayload: 24 | header :GenericPayloadHeader 25 | payload :[header.payload_length - 4]u8 26 | -------------------------------------------------------------------------------- /example/il.bgn: -------------------------------------------------------------------------------- 1 | 2 | config.url = "https://doc.cat-v.org/plan_9/4th_edition/papers/il/" 3 | 4 | enum ILType: 5 | :u8 6 | sync = 0 7 | data = 1 8 | dataquery = 2 9 | ack = 3 10 | query = 4 11 | state_ = 5 12 | close = 6 13 | 14 | format InternetLinkHeader: 15 | checkSum :u16 16 | length :u16 17 | type :ILType 18 | special :u8 19 | srcPort :u16 20 | dstPort :u16 21 | seqNum :u32 22 | ackNum :u32 23 | -------------------------------------------------------------------------------- /example/impromptu_app_protocol.bgn: -------------------------------------------------------------------------------- 1 | 2 | enum AppProtocolStatus: 3 | :u8 4 | start = 0 5 | middle = 1 6 | end = 2 7 | once = 3 8 | control = 4 9 | fileWatch = 5 10 | fileRequestList = 6 11 | fileRequestWrite = 7 12 | fileRequestRead = 8 13 | fileAcceptWrite = 9 14 | fileAcceptRead = 10 15 | fileError = 11 16 | 17 | format AppProtocolHeader: 18 | id :u32 19 | status :AppProtocolStatus 20 | order :u32 21 | 22 | format AppProtocol: 23 | header :AppProtocolHeader 24 | data :[..]u8 25 | 26 | -------------------------------------------------------------------------------- /example/ipsec.bgn: -------------------------------------------------------------------------------- 1 | 2 | format AuthenticationHeader: 3 | next_header :u8 4 | payload_length :u8 5 | reserved :u16 6 | security_parameters_index :u32 7 | sequence_number :u32 8 | len ::= (payload_length + 2) * 9 | 4 - # per RFC 4302, the length field is in 4-byte units 10 | 12 # length of fixed part of header 11 | integrity_check_value :[len]u8 12 | 13 | state SPIState: 14 | spi :u32 15 | integrity_check_value_length :u8 16 | 17 | spi_state :SPIState 18 | config.url = "https://www.rfc-editor.org/rfc/rfc4303" 19 | format EncapsulingSecurityPayload: 20 | security_parameters_index :u32 21 | sequence_number :u32 22 | offset ::= input.offset 23 | payload_and_padding :[..]u8 24 | pad_length :u8 25 | payload :[..]u8(input = input.subrange(payload_and_padding.length - pad_length,offset)) 26 | next_header :u8 27 | integrity_check_value :[spi_state.integrity_check_value_length]u8 28 | -------------------------------------------------------------------------------- /example/ipv6addr.bgn: -------------------------------------------------------------------------------- 1 | 2 | state PrefixInfo: 3 | global :u8 4 | subnet :u8 5 | 6 | pinfo :PrefixInfo 7 | 8 | # 2000::/3 9 | format GlobalUnicast: 10 | prefix :u3(1) 11 | global_routing_prefix :[pinfo.global]u1 12 | subnet :[pinfo.subnet]u1 13 | pinfo.global + pinfo.subnet <= 64 14 | interface_id :[125 - pinfo.global - pinfo.subnet]u1 15 | 16 | # fe80::/10 17 | format LinkLocalUnicast: 18 | prefix :u10(0x3fa) 19 | subnet :[54]u1 20 | interface_id :[64/8]u8 21 | 22 | # fc00::/7 || fd00::/8 23 | format UniqueLocalUnicast: 24 | prefix :u7(0x7e) 25 | local_subnet :u1 26 | globalID :[40/8]u8 27 | subnetID :[16/8]u8 28 | interface_id :[64]u1 29 | 30 | # ff00::/8 31 | format Multicast: 32 | prefix :u8(0xff) 33 | flags :u4 34 | scope :u4 35 | group_id :[14]u8 36 | 37 | # fe80::/10 38 | format SolicitedMulticast: 39 | prefix :u104(0xff0200000000000000000001) 40 | addr :[3]u8 41 | 42 | # ::1/128 43 | format Loopback: 44 | prefix :u128(0x1) 45 | 46 | # ::/128 47 | format Unspecified: 48 | prefix :u128(0x0) 49 | 50 | # ::ffff:0:0/96 51 | format IPv4Mapped: 52 | prefix :u96(0x0000000000ffff) 53 | addr :[4]u8 54 | 55 | -------------------------------------------------------------------------------- /example/isis.bgn: -------------------------------------------------------------------------------- 1 | 2 | config.url = "https://datatracker.ietf.org/doc/html/rfc5307" 3 | 4 | enum ProtectionCapability: 5 | :u8 6 | extra_traffic = 0x01 7 | unidirectional = 0x02 8 | shared = 0x04 9 | dedicated_1_per_1 = 0x08 10 | dedicated_1_plus_1 = 0x10 11 | enhanced = 0x20 12 | 13 | format LinkProtectionType: 14 | protection_cap :u8 15 | reserved :u8 16 | 17 | enum SwitchingCapability: 18 | :u8 19 | psc_1 = 1 20 | psc_2 = 2 21 | psc_3 = 3 22 | psc_4 = 4 23 | l2_sc = 51 24 | tdm = 100 # time division multiplexing 25 | lsc = 150 # lambda switching 26 | fsc = 200 # fiber switching 27 | 28 | 29 | format InterfaceSwitchingCapabilityDescriptor: 30 | switch_cap :u8 31 | encoding :u8 32 | reserved :u16 33 | max_lsp_bandwidth_per_priority :[8]u32 34 | switching_capabilty_specific_info :[..]u8 35 | 36 | format SRLG: 37 | system_id :[6]u8 38 | pseudonode_num :u8 39 | flags :u8 40 | ipv4_interface_address :[4]u8 41 | ipv4_neighbor_address :[4]u8 42 | shared_risk_link_group_value :[..]u32 43 | -------------------------------------------------------------------------------- /example/l2cap.bgn: -------------------------------------------------------------------------------- 1 | config.url = "https://www.wdic.org/w/WDIC/L2CAP" 2 | format L2CAP: 3 | length :u16 4 | channel_id :ChannelID 5 | payload :[length]u8 6 | 7 | enum ChannelID: 8 | :u16 9 | null = 0x0000 10 | l2cap_signaling = 0x0001 11 | connectionless = 0x0002 12 | -------------------------------------------------------------------------------- /example/l2tp.bgn: -------------------------------------------------------------------------------- 1 | 2 | format L2TPHeader: 3 | type :u1 4 | has_len :u1 5 | reserved1 :u2 6 | has_seq :u1 7 | reserved2 :u1 8 | has_offset :u1 9 | priority :u1 10 | reserved3 :u4 11 | version :u4 12 | 13 | version == 2 || version == 3 14 | if version == 3: 15 | has_len == 1 && has_seq == 1 && has_offset == 0 16 | 17 | if has_len == 1: 18 | length :u16 19 | 20 | id :u32 21 | if has_seq == 1: 22 | ns :u16 23 | nr :u16 24 | 25 | if has_offset == 1: 26 | ofsset :u16 27 | padding :[ofsset]u8 28 | 29 | format AVP: 30 | mandatory :u1 31 | hidden :u1 32 | reserved :u4 33 | length :u10 34 | length >= 6 35 | vendor_id :u16 36 | type :u16 37 | value :[length - 6]u8 38 | -------------------------------------------------------------------------------- /example/llama2.bgn: -------------------------------------------------------------------------------- 1 | 2 | config.url = "https://github.com/karpathy/llama2.c/blob/master/run.c" 3 | input.endian = config.endian.little 4 | 5 | format Llama2Tokenizer: 6 | max_token_length :u32 7 | vocabularies :[..]Vocabulary 8 | 9 | format Vocabulary: 10 | score: f32 11 | len :u32 12 | token :[len]u8 13 | 14 | format Llama2Config: 15 | dim :u32 16 | hidden_dim :u32 17 | num_layers :u32 18 | num_heads :u32 19 | num_kv_heads :u32 20 | shared_weights :u1 21 | vocab_size :u31 22 | seq_len :u32 23 | 24 | state Llama2State: 25 | conf :Llama2Config 26 | 27 | llama2_state :Llama2State 28 | 29 | format Llama2Weights: 30 | conf ::= llama2_state.conf 31 | head_size ::= conf.dim / conf.num_heads 32 | token_embedding_table :[conf.dim][conf.vocab_size]f32 33 | rms_att_weight :[conf.num_layers][conf.dim]f32 34 | wq :[conf.num_layers][conf.dim][conf.num_heads * head_size]f32 35 | wk :[conf.num_layers][conf.dim][conf.num_kv_heads * head_size]f32 36 | wv :[conf.num_layers][conf.dim][conf.num_kv_heads * head_size]f32 37 | wo :[conf.num_layers][conf.num_heads * head_size][conf.dim]f32 38 | rms_ffn_weight :[conf.num_layers][conf.dim]f32 39 | w1 :[conf.num_layers][conf.dim][conf.hidden_dim]f32 40 | w2 :[conf.num_layers][conf.hidden_dim][conf.dim]f32 41 | w3 :[conf.num_layers][conf.dim][conf.hidden_dim]f32 42 | rms_final_weight :[conf.dim]f32 43 | freq_cis_real :[conf.seq_len][head_size/2]f32 44 | freq_cis_imag :[conf.seq_len][head_size/2]f32 45 | 46 | 47 | format Llama2Model: 48 | conf :Llama2Config 49 | llama2_state.conf = conf 50 | weights :Llama2Weights 51 | 52 | -------------------------------------------------------------------------------- /example/mach-o.bgn: -------------------------------------------------------------------------------- 1 | 2 | format MachOHeader: 3 | magic :u32(0xfeedface) 4 | cputype :u32 5 | cpusubtype :u32 6 | filetype :u32 7 | ncmds :u32 8 | sizeofcmds :u32 9 | flags :u32 10 | reserved :u32 11 | 12 | format LoadCommandHeader: 13 | cmd :u32 14 | cmdsize :u32 15 | data :[cmdsize - 8]u8 16 | -------------------------------------------------------------------------------- /example/mp3.bgn: -------------------------------------------------------------------------------- 1 | 2 | format MP3Header: 3 | sync :u11 4 | version :u2 5 | layer :u2 6 | protection :u1 7 | bitrate :u4 8 | sampling_frequency :u2 9 | padding :u1 10 | private_ :u1 11 | mode :u2 12 | intensity_stereo :u1 13 | ms_stereo :u1 14 | copy_right :u1 15 | original :u1 16 | emphasis :u2 17 | -------------------------------------------------------------------------------- /example/mp4.bgn: -------------------------------------------------------------------------------- 1 | 2 | format Box: 3 | size :u32 4 | type :[4]u8 5 | if size == 1: 6 | large_size :u64 7 | 8 | if type == "uuid": 9 | usertype :[16]u8 10 | 11 | if size == 0: 12 | data :[..]u8 13 | else: 14 | data :[size-8]u8 15 | 16 | -------------------------------------------------------------------------------- /example/mpls.bgn: -------------------------------------------------------------------------------- 1 | 2 | format MPLS: 3 | label :u20 4 | tc :u3 5 | s :u1 6 | ttl :u8 7 | -------------------------------------------------------------------------------- /example/mqtt.bgn: -------------------------------------------------------------------------------- 1 | 2 | enum PacketType: 3 | :u4 4 | reserved 5 | connect 6 | connack 7 | publish 8 | puback 9 | pubrec 10 | pubrel 11 | pubcomp 12 | subscribe 13 | suback 14 | unsubscribe 15 | unsuback 16 | pingreq 17 | pingresp 18 | disconnect 19 | auth 20 | 21 | format FixedHeader: 22 | packet_type: PacketType 23 | if packet_type == PacketType.publish: 24 | dup : u1 25 | qos : u2 26 | retain : u1 27 | elif packet_type == PacketType.pubrel || packet_type == PacketType.unsubscribe: 28 | reserved :u4(0x2) 29 | else: 30 | reserved : u4(0x0) 31 | remaining_length : u8 32 | 33 | 34 | format MQTTPacket: 35 | header :FixedHeader 36 | input.remain == u64(header.remaining_length) 37 | -------------------------------------------------------------------------------- /example/ntp.bgn: -------------------------------------------------------------------------------- 1 | 2 | enum Leap: 3 | :u2 4 | NoWarning 5 | LastMinute61 6 | LastMinute59 7 | Unsyncronized 8 | 9 | enum Mode: 10 | :u3 11 | Reserved 12 | SymmetricActive 13 | SymmetricPassive 14 | Client 15 | Server 16 | Broadcast 17 | ReservedForNtpControlMessage 18 | ReservedForPrivateUse 19 | 20 | format ShortFormat: 21 | seconds :u16 22 | fraction :u16 23 | 24 | format Timestamp: 25 | seconds :u32 26 | fraction :u32 27 | 28 | format Extension: 29 | type :u16 30 | length :u16 31 | value :[length]u8 32 | 33 | format ReferenceID: 34 | id :[4]u8 35 | 36 | format Auth: 37 | key_id :u32 38 | digest :[..24]u8 39 | 40 | format NtpPacket: 41 | leap :Leap 42 | version :u3 43 | mode :Mode 44 | stratum :u8 45 | poll :u8 46 | precision :s8 47 | root_delay :ShortFormat 48 | root_dispersion :ShortFormat 49 | reference_id :ReferenceID 50 | reference_timestamp :Timestamp 51 | origin_timestamp :Timestamp 52 | receive_timestamp :Timestamp 53 | transmit_timestamp :Timestamp 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /example/pcap.bgn: -------------------------------------------------------------------------------- 1 | 2 | format PcapHeader: 3 | magic :u32 4 | magic == 0xa1b2c3d4 || magic == 0xa1b2cd34 5 | version_major :u16 6 | version_minor :u16 7 | thiszone :s32 8 | sigfigs :u32 9 | snaplen :u32 10 | network :u32 11 | if magic == 0xa1b2cd34: 12 | ifindex :u32 13 | protocol :u16 14 | pkt_type :u8 15 | pad :u8 16 | 17 | format PcapRecord: 18 | ts_sec :u32 19 | ts_usec :u32 20 | incl_len :u32 21 | orig_len :u32 22 | data :[incl_len]u8 23 | 24 | -------------------------------------------------------------------------------- /example/pcapng.bgn: -------------------------------------------------------------------------------- 1 | 2 | format PcapNGBlock: 3 | block_type: u32 4 | block_total_length: u32 5 | block_body :[block_total_length -12]u8 6 | block_total_length2: u32 7 | block_total_length == block_total_length2 8 | 9 | format SectionHeaderBlock: 10 | byte_order_magic: u32(0x1A2B3C4D) 11 | major_version: u16 12 | minor_version: u16 13 | section_length: u64 14 | section_options: [section_length - 28]u8 15 | 16 | format EnhancedPacketBlock: 17 | interface_id: u32 18 | timestamp_high: u32 19 | timestamp_low: u32 20 | captured_packet_length: u32 21 | original_packet_length: u32 22 | packet_data: [captured_packet_length]u8 23 | options : [..]u8 24 | 25 | format InterfaceDescriptionBlock: 26 | link_type: u16 27 | reserved: u16 28 | snap_len: u32 29 | options: [..]u8 30 | 31 | format SimplePacketBlock: 32 | packet_len :u32 33 | packet_data: [packet_len]u8 34 | options : [..]u8 35 | 36 | format Record: 37 | record_type: u16 38 | record_length: u16 39 | record_data: [record_length]u8 40 | 41 | format NameResolutionBlock: 42 | record: [..]Record 43 | :"\x00" 44 | options : [..]u8 45 | -------------------------------------------------------------------------------- /example/pcep.bgn: -------------------------------------------------------------------------------- 1 | config.url = "https://tex2e.github.io/rfc-translater/html/rfc5440.html#7-1--PCEP-TLV-Format" 2 | 3 | format CommonHeader: 4 | version :u3 5 | flags :u5 6 | message_type :u8 7 | message_length :u16 8 | 9 | format ObjectTLV: 10 | type :u16 11 | length :u16 12 | value :[length]u8 13 | 14 | format CommonObjectHeader: 15 | object_class :u8 16 | object_type :u4 17 | reserved :u2 18 | p :u1 19 | ignore :u1 20 | object_length :u16 21 | 22 | format PCEPOpen: 23 | version :u3 24 | flags :u5 25 | keep_alive :u8 26 | dead_timer :u8 27 | sid :u8 28 | object :[..]ObjectTLV 29 | 30 | format PCEPRequestParameters: 31 | flags :u26 32 | loose :u1 # O 33 | bidirectional :u1 # B 34 | re_optimization :u1 # R 35 | priority :u3 36 | request_id :u32 37 | tlvs :[..]ObjectTLV 38 | 39 | enum PCEPNatureOfIssue: 40 | :u8 41 | NoPath = 0 42 | PCEChainBroken = 1 43 | 44 | format PCEPNoPath: 45 | nature_of_issue :PCEPNatureOfIssue 46 | -------------------------------------------------------------------------------- /example/pefile_map.json: -------------------------------------------------------------------------------- 1 | { 2 | "WORD": "u16", 3 | "LONG": "u32", 4 | "MAGIC_MZ": "\"Mz\"", 5 | "DWORD": "u32", 6 | "UINT16": "u16", 7 | "UINT32": "u32", 8 | "UINT64": "u64", 9 | "CHAR8": "u8", 10 | "UINT8": "u8", 11 | "uint8_t": "u8", 12 | "uint16_t": "u16", 13 | "uint32_t": "u32", 14 | "uint64_t": "u64", 15 | "uint48_t": "u48", 16 | "char16_t": "u16", 17 | "uint32": "u32", 18 | "uint64": "u64", 19 | "uint16": "u16", 20 | "uint8": "u8", 21 | "int32": "s32", 22 | "int64": "s64", 23 | "int16": "s16", 24 | "int8": "s8", 25 | "time_t": "u64", 26 | "size_t": "u32", 27 | "int": "u32", 28 | "char": "u8" 29 | } -------------------------------------------------------------------------------- /example/ppp.bgn: -------------------------------------------------------------------------------- 1 | 2 | format PPP: 3 | flag :u8(0x7e) 4 | address :u8(0xff) 5 | control :u8(0x03) 6 | protocol :u16 7 | data :[..]u8 8 | checksum :u16 9 | flag2 :u8(0x7e) 10 | 11 | format LCP: 12 | code :u8 13 | identifier :u8 14 | length :u16 15 | data :LCPData 16 | 17 | format LCPData: 18 | type :u8 19 | length :u8 20 | data :[length]u8 21 | 22 | format IPCP: 23 | data :LCP 24 | -------------------------------------------------------------------------------- /example/protobuf.bgn: -------------------------------------------------------------------------------- 1 | 2 | format Varint: 3 | value :u64 4 | 5 | fn decode(): 6 | for: 7 | v := input.get() 8 | if v < 0x80: 9 | value = v 10 | return 11 | value = (value << 7) | u64(v & 0x7f) 12 | 13 | 14 | fn encode(): 15 | for: 16 | v := u8(value & 0x7f) 17 | value = value >> 7 18 | if value == 0: 19 | output.put(v) 20 | return 21 | output.put(v | 0x80) 22 | 23 | enum WireType: 24 | Varint = 0 25 | Fixed64 = 1 26 | LengthDelimited = 2 27 | StartGroup = 3 28 | EndGroup = 4 29 | Fixed32 = 5 30 | 31 | format Field: 32 | id :Varint 33 | fn type() -> WireType: 34 | return WireType(id.value & 0x7) 35 | fn number() -> u64: 36 | return id.value >> 3 37 | 38 | match type(): 39 | WireType.Varint => value :Varint 40 | WireType.Fixed64 => value :u64 41 | WireType.LengthDelimited: 42 | length :Varint 43 | value :[length]u8 44 | WireType.StartGroup => .. 45 | WireType.EndGroup => .. 46 | WireType.Fixed32 => value :u32 47 | -------------------------------------------------------------------------------- /example/quic_transport_parameter.bgn: -------------------------------------------------------------------------------- 1 | 2 | qpkt ::= config.import("quic_varint.bgn") 3 | 4 | enum TransportParameterID: 5 | original_destination_connection_id = 0x0000 6 | max_idle_timeout = 0x0001 7 | stateless_reset_token = 0x0002 8 | max_packet_size = 0x0003 9 | initial_max_data = 0x0004 10 | initial_max_stream_data_bidi_local = 0x0005 11 | initial_max_stream_data_bidi_remote = 0x0006 12 | initial_max_stream_data_uni = 0x0007 13 | initial_max_streams_bidi = 0x0008 14 | initial_max_streams_uni = 0x0009 15 | ack_delay_exponent = 0x000a 16 | max_ack_delay = 0x000b 17 | disable_active_migration = 0x000c 18 | preferred_address = 0x000d 19 | active_connection_id_limit = 0x000e 20 | initial_source_connection_id = 0x000f 21 | retry_source_connection_id = 0x0010 22 | max_datagram_frame_size = 0x0011 23 | 24 | 25 | format TransportParameter: 26 | parameter_id: qpkt.VarInt 27 | length: qpkt.VarInt 28 | value: [length]qpkt.VarInt 29 | -------------------------------------------------------------------------------- /example/quic_varint.bgn: -------------------------------------------------------------------------------- 1 | 2 | format VarInt: 3 | prefix :u2 4 | match prefix: 5 | 0 => value :u6 6 | 1 => value :u14 7 | 2 => value :u30 8 | 3 => value :u62 9 | 10 | fn u64() -> u64: 11 | return value 12 | -------------------------------------------------------------------------------- /example/radius.bgn: -------------------------------------------------------------------------------- 1 | 2 | config.url = "https://datatracker.ietf.org/doc/html/rfc8044" 3 | 4 | enum RadiusDataType: 5 | integer = 1 6 | enum_ = 2,"enum" 7 | time = 3 8 | text = 4 9 | string = 5 10 | concat = 6 11 | ifid = 7 12 | ipv4addr = 8 13 | ipv6addr = 9 14 | ipv6prefix = 10 15 | ipv4prefix = 11 16 | integer64 = 12 17 | tlv = 13 18 | vsa = 14 19 | extended = 15 20 | long_extended = 16 21 | evs = 17 22 | 23 | 24 | 25 | format Integer: 26 | value :u32 27 | 28 | format Enum: 29 | value :u32 -------------------------------------------------------------------------------- /example/rdp.bgn: -------------------------------------------------------------------------------- 1 | config.url = "https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/5073f4ed-1e93-45e1-b039-6e30c385867c" 2 | input.endian = config.endian.little 3 | 4 | format ClientX224ConnectionRequest: 5 | tpktHeader :TPKTHeader 6 | x224Crq: X224Crq 7 | routing_token :LineEnded 8 | cookie :LineEnded 9 | rdp_neg_req :RDPNegReq 10 | if rdp_neg_req.flags.correlation_info_present == 1: 11 | rdp_correlation_info :RDPCorrelationInfo 12 | 13 | 14 | format LineEnded: 15 | data :[..]u8 16 | :"\r\n" 17 | 18 | 19 | format TPKTHeader: 20 | unknown :u32 21 | 22 | format X224Crq: 23 | data :[7]u8 24 | 25 | format RDPNegReq: 26 | type :u8(0x01) 27 | flags :RDPNegReqFlags 28 | length :u16 29 | requested_protocols :RDPNegReqRequestedProtocols 30 | 31 | enum RDPNegReqRequestedProtocols: 32 | :u32 33 | RDP = 0x00000000 34 | SSL = 0x00000001 35 | HYBRID = 0x00000002 36 | RDSTLS = 0x00000004 37 | HYBRIDEX = 0x00000008 38 | RDSAAD = 0x00000010 39 | 40 | 41 | format RDPNegReqFlags: # from lsb 42 | restricted_admin :u1 43 | restricted_authentication :u1 44 | correlation_info_present :u1 45 | reserved :u5 46 | 47 | format RDPCorrelationInfo: 48 | type :u8(0x06) 49 | flags :u8(0) 50 | length :u16(0x24) 51 | correlation_id :[16]u8 52 | reserved :[16]u8 53 | 54 | # TODO: add support for the other messages -------------------------------------------------------------------------------- /example/rtp.bgn: -------------------------------------------------------------------------------- 1 | 2 | format RTPHeader: 3 | version :u2 4 | padding :u1 5 | extension :u1 6 | csrc_count :u4 7 | marker :u1 8 | payload_type :u7 9 | sequence_number :u16 10 | timestamp :u32 11 | ssrc :u32 12 | csrc_list :[csrc_count]u32 13 | 14 | 15 | format RTPExtensionHeader: 16 | profile :u16 17 | length :u16 18 | data :[length]u8 19 | -------------------------------------------------------------------------------- /example/safetensor.bgn: -------------------------------------------------------------------------------- 1 | 2 | input.endian = config.endian.little 3 | 4 | config.url = "https://github.com/huggingface/safetensors/blob/main/safetensors/src/tensor.rs#L510" 5 | 6 | format SafeTensorHeader: 7 | header_len :ul64 8 | json_header :[header_len]u8 9 | 10 | format SafeTensor: 11 | header :SafeTensorHeader 12 | data :[..]u8 13 | 14 | # json serialized but this not supports json parsing 15 | state TensorInfo: 16 | dtype :DType 17 | shape :[]u64 18 | data_offset_begin :u64 19 | data_offset_end :u64 20 | 21 | 22 | fn getTensorSize(tensor: TensorInfo) -> u64: 23 | perElem := getByteSize(tensor.dtype) 24 | total := u64(1) 25 | for dim in tensor.shape: 26 | total *= dim 27 | return total * u64(perElem) 28 | 29 | enum DType: 30 | BOOL 31 | U8 32 | I8 33 | F8_E5M2 34 | F8_E4M3 35 | I16 36 | U16 37 | F16 38 | BF16 39 | I32 40 | U32 41 | F32 42 | F64 43 | I64 44 | U64 45 | 46 | fn getByteSize(dtype: DType) -> u8: 47 | return match dtype: 48 | DType.BOOL => 1 49 | DType.U8 => 1 50 | DType.I8 => 1 51 | DType.F8_E5M2 => 1 52 | DType.F8_E4M3 => 1 53 | DType.I16 => 2 54 | DType.U16 => 2 55 | DType.F16 => 2 56 | DType.BF16 => 2 57 | DType.I32 => 4 58 | DType.U32 => 4 59 | DType.F32 => 4 60 | DType.F64 => 8 61 | DType.I64 => 8 62 | DType.U64 => 8 63 | 64 | -------------------------------------------------------------------------------- /example/simple.bgn: -------------------------------------------------------------------------------- 1 | 2 | format Data: 3 | data :[32]u8 4 | -------------------------------------------------------------------------------- /example/srv6.bgn: -------------------------------------------------------------------------------- 1 | enum EndpointBehavior: 2 | :u16 3 | reserved 4 | end 5 | end_with_psp 6 | end_with_usp 7 | end_with_psp_and_usp 8 | end_x 9 | end_x_with_psp 10 | end_x_with_usp 11 | end_x_with_psp_and_usp 12 | end_t 13 | end_t_with_psp 14 | end_t_with_usp 15 | end_t_with_psp_and_usp 16 | unassigned 17 | end_b6_encaps 18 | end_bm 19 | end_dx6 20 | end_dx4 21 | end_dt6 22 | end_dt4 23 | end_dt46 24 | end_dx2 25 | end_dx2v 26 | end_dx2u 27 | end_dx2m 28 | reserved2 29 | unassigned2 30 | end_b6_encaps_red 31 | end_with_usd 32 | end_with_psp_and_usd 33 | end_with_usp_and_usd 34 | end_x_with_usd 35 | end_x_with_psp_and_usd 36 | end_x_with_usp_and_usd 37 | end_x_with_psp_usp_and_usd 38 | end_t_with_psp_and_usd 39 | end_t_with_usp_and_usd 40 | end_t_with_psp_usp_and_usd 41 | 42 | sid_defined_in_rfc8754 = 0x7fff 43 | reserved_for_private_use_begin = 0x8000 44 | reserved_for_private_use_end = 0xfffe 45 | opaque = 0xffff -------------------------------------------------------------------------------- /example/stl.bgn: -------------------------------------------------------------------------------- 1 | 2 | format STL: 3 | header :[80]u8 4 | num_triangles :u32 5 | triangles :[num_triangles]Triangle 6 | 7 | 8 | format Triangle: 9 | normal :[3]f32 10 | vertices :[3]Vertex 11 | attr :u16 12 | 13 | format Vertex: 14 | x :f32 15 | y :f32 16 | z :f32 17 | -------------------------------------------------------------------------------- /example/stp.bgn: -------------------------------------------------------------------------------- 1 | # spaning tree protocol 2 | 3 | format BridgeID: 4 | priority :u16 5 | mac :u48 6 | 7 | format BDPU: 8 | protocol_id :u16 9 | version :u8 10 | bpdu_type :u8 11 | flags :u8 12 | root_id :BridgeID 13 | root_path_cost :u32 14 | bridge_id :BridgeID 15 | port_id :u16 16 | message_age :u16 17 | max_age :u16 18 | hello_time :u16 19 | forward_delay :u16 20 | -------------------------------------------------------------------------------- /example/stub.bgn: -------------------------------------------------------------------------------- 1 | 2 | format TEST_CLASS: 3 | data :[..]u8 4 | -------------------------------------------------------------------------------- /example/stun.bgn: -------------------------------------------------------------------------------- 1 | 2 | enum MessageType: 3 | :u16 4 | BindingRequest = 0x0001 5 | BindingResponse = 0x0101 6 | BindingErrorResponse = 0x0111 7 | SharedSecretRequest = 0x0002 8 | SharedSecretResponse = 0x0102 9 | SharedSecretErrorResponse = 0x0112 10 | 11 | enum StunAddrFamily: 12 | :u8 13 | IPv4 = 0x01 14 | IPv6 = 0x02 15 | 16 | format StunHeader: 17 | type :u16 18 | length :u16 19 | magic_cookie :u32(0x2112A442) 20 | transaction_id :[12]u8 21 | 22 | format Attribute: 23 | type :AttributeType 24 | length :u16 25 | value :[length]u8 26 | 27 | format MappedAddress: 28 | family :StunAddrFamily 29 | family == StunAddrFamily.IPv4 || family == StunAddrFamily.IPv6 30 | port :u16 31 | address :[family == StunAddrFamily.IPv4 ? 4: 16]u8 32 | 33 | format ChangeRequest: 34 | reserved1 :u29 35 | change_ip :u1 36 | change_port :u1 37 | reserved2 :u1 38 | 39 | format ErrorCode: 40 | reserved :u22 41 | class :u3 42 | number :u7 43 | 44 | enum AttributeType: 45 | :u16 46 | reserved = 0x0000 47 | mapped_address = 0x0001 48 | response_address = 0x0002 49 | change_request = 0x0003 50 | source_address = 0x0004 51 | changed_address = 0x0005 52 | user_name = 0x0006 53 | password = 0x0007 54 | message_integrity = 0x0008 55 | error_code = 0x0009 56 | unknown_attribute = 0x000a 57 | reflected_from = 0x000b 58 | realm = 0x0014 59 | nonce = 0x0015 60 | xor_mapped_address = 0x0020 61 | -------------------------------------------------------------------------------- /example/swf_rect.bgn: -------------------------------------------------------------------------------- 1 | 2 | format SWFRect: 3 | len :u5 # maximum is 2^5-1 = 31 4 | x_min : [len]u1(config.type = u32) 5 | x_max : [len]u1(config.type = u32) 6 | y_min : [len]u1(config.type = u32) 7 | y_max : [len]u1(config.type = u32) 8 | padding :[(5 + len *4)%8]u1(input.align = 8) # padding to next byte 9 | 10 | 11 | -------------------------------------------------------------------------------- /example/tar.bgn: -------------------------------------------------------------------------------- 1 | 2 | fn oct2int(oct :[]u8) -> u64: 3 | res := u64(0) 4 | for i := u64(0); i < oct.length; i = i + 1: 5 | oct[i] >= '0' && oct[i] <= '7' 6 | res = res * 8 + u64(oct[i] - u8('0')) 7 | return res 8 | 9 | 10 | format TarFile: 11 | name :[100]u8 12 | mode :[8]u8 13 | uid :[8]u8 14 | gid :[8]u8 15 | size :[12]u8 16 | mtime :[12]u8 17 | chksum :[8]u8 18 | type :u8 19 | linkname :[100]u8 20 | magic :"ustar\0" 21 | version :[2]u8 22 | uname :[32]u8 23 | gname :[32]u8 24 | devmajor :[8]u8 25 | devminor :[8]u8 26 | prefix :[155]u8 27 | padding :[12]u8 28 | len ::= oct2int(<[]u8>(size)) 29 | data :[len]u8 30 | -------------------------------------------------------------------------------- /example/tftp.bgn: -------------------------------------------------------------------------------- 1 | 2 | enum OpCode: 3 | :u16 4 | RRQ = 1 # Read Request 5 | WRQ = 2 # Write Request 6 | DATA = 3 # Data 7 | ACK = 4 # Acknowledgment 8 | ERROR = 5 # Error 9 | 10 | format Packet: 11 | op :OpCode 12 | match op: 13 | OpCode.RRQ => rrq :Request 14 | OpCode.WRQ => wrq :Request 15 | OpCode.DATA => data :Data 16 | OpCode.ACK => ack :Ack 17 | OpCode.ERROR => error :Error 18 | 19 | format Request: 20 | fileName :[..]u8 21 | :"\0" 22 | mode :[..]u8 23 | :"\0" 24 | 25 | format Data: 26 | blockNumber :u16 27 | data :[..]u8 28 | 29 | format Ack: 30 | blockNumber :u16 31 | 32 | format Error: 33 | errorCode :u16 34 | errorMsg :[..]u8 35 | :"\0" 36 | -------------------------------------------------------------------------------- /example/tor_prop220.bgn: -------------------------------------------------------------------------------- 1 | config.url = "https://gitlab.torproject.org/tpo/core/trunnel/-/blob/main/examples/prop220.trunnel?ref_type=heads" 2 | format TorEdCert: 3 | version :u8(1) 4 | cert_type :u8 5 | exp_field :u32 6 | cert_key_type :u8 7 | certified_key :[32]u8 8 | n_extensions :u8 9 | extensions :[n_extensions]TorEdCertExt 10 | signature :[64]u8 11 | 12 | CERTEXT_SIGNED_WITH_KEY ::= 4 13 | 14 | format TorEdCertExt: 15 | ext_len :u16 16 | ext_type :u8 17 | ext_flags :u8 18 | if ext_type == CERTEXT_SIGNED_WITH_KEY: 19 | signing_key :[32]u8 20 | else: 21 | ext_data :[ext_len]u8 22 | 23 | format CertRevocation: 24 | prefix :[8]u8 25 | version :u8(1) 26 | key_type :u8 27 | identity_key :[32]u8 28 | revoked_key :[32]u8 29 | published_time :u64 30 | n_extensions :u8 31 | extensions :[n_extensions]TorEdCertExt 32 | signature :[64]u8 33 | 34 | format CrossCertEdRSA: 35 | ed_key :[32]u8 36 | expiring_date :u32 37 | signature :[64]u8 38 | 39 | enum LinkSpecifierType: 40 | :u8 41 | IPv4 = 0x00 42 | IPv6 = 0x01 43 | LEGACY_ID = 0x02 44 | ED25519_ID = 0x03 45 | 46 | format LinkSpecifier: 47 | type :LinkSpecifierType 48 | len :u8 49 | if type == LinkSpecifierType.IPv4: 50 | ipv4 :[4]u8 51 | port :u16 52 | elif type == LinkSpecifierType.IPv6: 53 | ipv6 :[16]u8 54 | port :u16 55 | elif type == LinkSpecifierType.LEGACY_ID: 56 | legacy_id :[20]u8 57 | elif type == LinkSpecifierType.ED25519_ID: 58 | ed25519_id :[32]u8 59 | -------------------------------------------------------------------------------- /example/tor_rend.bgn: -------------------------------------------------------------------------------- 1 | config.url = "https://gitlab.torproject.org/tpo/core/trunnel/-/blob/main/examples/tor-rend.trunnel?ref_type=heads" 2 | 3 | 4 | format EstablishIntroBody: 5 | key_len :u16 6 | key :[key_len]u8 7 | session_hash :[20]u8 8 | signature :[..]u8 9 | 10 | format IntroducelCell: 11 | pk_id :u8 12 | encrypted_part :[..]u8 13 | 14 | format IntroducelCellPlainText: 15 | version :u8 16 | match version: 17 | 1 => v1 :IntroducelCellBodyV1 18 | 2 => v2 :IntroducelCellBodyV2 19 | 3 => v3 :IntroducelCellBodyV3 20 | 4..=32 => error("invalid version") 21 | .. => v0 :IntroducelCellBodyV0 22 | 23 | format IntroducelCellBodyV0: 24 | rest_of_nickname :[19]u8 25 | rc :[20]u8 26 | dh_data :[128]u8 27 | 28 | format IntroducelCellBodyV1: 29 | rp_id :[42]u8 30 | rc :[20]u8 31 | dh_data :[128]u8 32 | 33 | format IntroducelCellBodyV2: 34 | rp_ip :u32 35 | rp_port :u16 36 | rp_id :[20]u8 37 | klen :u16 38 | onion_key :[klen]u8 39 | rc :[20]u8 40 | dh_data :[128]u8 41 | 42 | format IntroducelCellBodyV3: 43 | auth_type :u8 44 | if auth_type != 0: 45 | auth_len :u16 46 | auth_data :[auth_len]u8 47 | timestamp :u32 48 | rp_ip :u32 49 | rp_port :u16 50 | rp_id :[20]u8 51 | klen :u16 52 | onion_key :[klen]u8 53 | rc :[20]u8 54 | dh_data :[128]u8 55 | 56 | format Rendezvous1CellBody: 57 | rc :[20]u8 58 | dh :[128]u8 59 | kh :[20]u8 60 | 61 | format Rendezvous2CellBody: 62 | dh :[128]u8 63 | kh :[20]u8 64 | -------------------------------------------------------------------------------- /example/tzdb.bgn: -------------------------------------------------------------------------------- 1 | 2 | format TZHeader: 3 | tzMagic: "TZif" 4 | tzVersion: u8 5 | tzReserved: [15]u8 6 | tzTimeIsUTCCount: u32 7 | tzTimeIsStdCount: u32 8 | tzTimeLeapCount: u32 9 | tzTimeCount :u32 10 | tzTypeCount: u32 11 | tzCharCount: u32 12 | 13 | format TZTime: 14 | tzTime: u32 15 | 16 | format TZType: 17 | tzGmtOffset: u32 18 | tzIsDst: u8 19 | tzAbbrIndex: u8 20 | 21 | format TZChar: 22 | tzChar: [..]u8 23 | :"\0" 24 | 25 | format TZLeap: 26 | tzLeapTime: u32 27 | tzLeapGmtOffset: u32 28 | 29 | -------------------------------------------------------------------------------- /example/udp.bgn: -------------------------------------------------------------------------------- 1 | 2 | 3 | format UDPHeader: 4 | config.rfc = "https://datatracker.ietf.org/doc/html/rfc768" 5 | src_port :u16 6 | dst_port :u16 7 | length :u16 8 | checksum :u16 9 | 10 | format UDPDatagram: 11 | header :UDPHeader 12 | data :[header.length-8]u8 13 | 14 | -------------------------------------------------------------------------------- /example/usb.bgn: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | format USBPacket: 5 | sync :u8 6 | pid :u4 7 | pid_reverse :u4 8 | !pid == pid_reverse 9 | match pid: 10 | 0b0001 => data :StartOfFrame 11 | 12 | 13 | format StartOfFrame: 14 | frame :u11 15 | crc :u5 16 | 17 | format TokenPacket: 18 | addr :u7 19 | endp :u4 20 | crc :u5 21 | -------------------------------------------------------------------------------- /example/vm_test/udp_test.bgn: -------------------------------------------------------------------------------- 1 | 2 | udp ::= config.import("../udp.bgn") 3 | quic ::= config.import("../quic_packet.bgn") 4 | varint ::= config.import("../quic_varint.bgn") 5 | 6 | format Test: 7 | quic.qstate.encrypted = true 8 | # UDP Header (rfc 768) 9 | udpHeader :udp.UDPHeader 10 | quicPacket :quic.QUICPackets(input = input.subrange(udpHeader.length - 8)) 11 | 12 | format Test2: 13 | v1 :varint.VarInt 14 | v2 :varint.VarInt 15 | v3 :varint.VarInt 16 | v4 :varint.VarInt 17 | input.remain == 0 18 | -------------------------------------------------------------------------------- /example/vrrp.bgn: -------------------------------------------------------------------------------- 1 | config.url = "https://tex2e.github.io/rfc-translater/html/rfc9568.html#5-1--VRRP-Packet-Format" 2 | format VRRPPacket: 3 | version :u4 4 | type :u4 5 | vrid :u8 6 | priority :u8 7 | addr_count :u8 8 | reserved :u4 9 | max_advertise_interval :u20 10 | checksum :u16 11 | 12 | 13 | format IPv4VrrpPacket: 14 | header :VRRPPacket 15 | addr :[header.addr_count][4]u8 16 | 17 | format IPv6VrrpPacket: 18 | header :VRRPPacket 19 | addr :[header.addr_count][16]u8 20 | 21 | enum VRRPState: 22 | INIT 23 | ACTIVE 24 | BACKUP 25 | -------------------------------------------------------------------------------- /example/wasmos_def.txt: -------------------------------------------------------------------------------- 1 | struct tcpip_connect_fields { 2 | uint32_t dst_addr; 3 | uint16_t dst_port; 4 | }; 5 | struct tcpip_connect_reply_fields { 6 | uint32_t sock; 7 | }; 8 | 9 | struct tcpip_write_fields { 10 | int sock; 11 | uint8_t data[1024]; 12 | size_t data_len; 13 | }; 14 | struct tcpip_write_reply_fields { 15 | }; 16 | 17 | struct tcpip_read_fields { 18 | int sock; 19 | }; 20 | struct tcpip_read_reply_fields { 21 | uint8_t data[1024]; 22 | size_t data_len; 23 | }; 24 | 25 | struct echo_fields { 26 | uint8_t data[1024]; 27 | size_t data_len; 28 | }; 29 | struct echo_reply_fields { 30 | uint8_t data[1024]; 31 | size_t data_len; 32 | }; 33 | 34 | struct tcpip_data_fields { 35 | int sock; 36 | }; 37 | 38 | struct tcpip_closed_fields { 39 | int sock; 40 | }; 41 | 42 | struct tcpip_dns_resolve_fields { 43 | char hostname[256]; 44 | }; 45 | struct tcpip_dns_resolve_reply_fields { 46 | uint32_t addr; 47 | }; -------------------------------------------------------------------------------- /example/wave.bgn: -------------------------------------------------------------------------------- 1 | 2 | format WaveHeader: 3 | magic :"RIFF" 4 | chunkSize :u32 5 | magic2 :"WAVE" 6 | subChunk1Id :"fmt " 7 | subChunk1Size :u32 8 | audioFormat :u16 9 | numChannels :u16 10 | sampleRate :u32 11 | byteRate :u32 12 | blockAlign :u16 13 | bitsPerSample :u16 14 | subChunk2Id :"data" 15 | subChunk2Size :u32 16 | 17 | format Wave: 18 | header :WaveHeader 19 | data :[header.subChunk2Size]u8 20 | -------------------------------------------------------------------------------- /example/webauthn_cosepubkey.bgn: -------------------------------------------------------------------------------- 1 | 2 | config.go.package="webauthn" 3 | config.word.map("Cose","COSE") 4 | 5 | enum COSEKeyType: 6 | Reserved = 0 7 | OctetKey = 1 8 | EllipticKey = 2 9 | RSAKey = 3 10 | Symmetric = 4 11 | HSSLMS = 5 12 | 13 | 14 | COSE_KEY_KEY_TYPE ::= 1 15 | COSE_KEY_ALGORITHM_IDENTIFIER ::= 3 16 | 17 | COSE_OKP_KEY_X_COORDINATE ::= -2 18 | 19 | COSE_EC_KEY_CRV ::= -1 20 | COSE_EC_KEY_X_COORDINATE ::= -2 21 | COSE_EC_KEY_Y_COORDINATE ::= -3 22 | 23 | COSE_RSA_KEY_N ::= -1 24 | COSE_RSA_KEY_E ::= -2 25 | -------------------------------------------------------------------------------- /example/websocket.bgn: -------------------------------------------------------------------------------- 1 | 2 | enum OpCode: 3 | :u4 4 | ContinuationFrame = 0x0 5 | TextFrame = 0x1 6 | BinaryFrame = 0x2 7 | ConnectionClose = 0x8 8 | Ping = 0x9 9 | Pong = 0xA 10 | 11 | format Frame: 12 | FIN :u1 13 | RSV1 :u1 14 | RSV2 :u1 15 | RSV3 :u1 16 | Opcode :OpCode 17 | Mask :u1 18 | PayloadLength :u7 19 | match PayloadLength: 20 | 126 => ExtendedPayloadLength :u16 21 | 127 => ExtendedPayloadLength :u64 22 | 23 | if Mask == 1: 24 | MaskingKey :[4]u8 25 | 26 | len ::= available(ExtendedPayloadLength) ? # if ExtendedPayloadLength (u16 or u64) is available 27 | ExtendedPayloadLength : # use ExtendedPayloadLength 28 | PayloadLength # otherwise use PayloadLength 29 | Payload :[len]u8(input.xor = MaskingKey) 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /example/wire_data/capnproto.dat: -------------------------------------------------------------------------------- 1 | # Cap'n Proto format 2 | # little endian format 3 | # 0b00 /*magic*/ 0x0001 /*offset*/ 4 | # 0x0002 /*sizeof data*/ 0x0003 /*sizeof pointer*/ 5 | 0300 0200 0100 0000 6 | 0000 0000 0000 0000 # skip offset 7 | 6865 6c6c 6f20 776f # struct data? 8 | 726c 6420 0000 0000 9 | -------------------------------------------------------------------------------- /example/wire_data/udp.dat: -------------------------------------------------------------------------------- 1 | # UDP Header 2 | ef12 01bb 3 | 0023 0000 4 | # Data 5 | c0 6 | 00 00 00 01 # version 7 | 00 # dst connection id 8 | # no data 9 | 00 # src connection id 10 | # no data 11 | 00 # token length 12 | # no token 13 | 12 # length 14 | 00 # packet number 15 | 01 # ping frame 16 | # Message Authentication Code (16 byte) 17 | 00 11 22 33 44 55 66 77 88 99 aa bb cc dd ee ff 18 | 19 | -------------------------------------------------------------------------------- /example/wire_data/unknwon_raspi.bgn: -------------------------------------------------------------------------------- 1 | format UnknownHeader: 2 | thirty_three :[2]u8 3 | three_zero :[3]u8 4 | seven_random :[7]u8 5 | eight_six_dd :[2]u8 6 | sixty :u8 7 | seven_random2 :[7]u8 8 | fe_byte_and_zero :[8]u8 9 | nine_random :[9]u8 10 | two :u8 11 | twenty_six_zero :[26]u8 12 | 13 | format UnknownHeader2: 14 | nine_header :[9]u8 15 | two_zero :[2]u8 16 | eight_four :[2]u8 17 | four_zero :[4]u8 18 | one :u8 19 | four_maybe_type_of_packet :[4]u8 20 | twenty_one_random :[21]u8 21 | maybe_flag :u8 22 | one2 :u8 23 | two_zero2 :[2]u8 24 | unknown_but_different_two :[2]u8 25 | two_three :u8 26 | two_same_thirty_five_random :[2][35]u8 -------------------------------------------------------------------------------- /example/wire_data/varint.dat: -------------------------------------------------------------------------------- 1 | # quic varint 2 | # prefix = 0 (8-bit data) 3 | 3A 4 | 12 5 | 24 6 | 3f 7 | 8 | # prefix = 1 (16-bit data) 9 | 40 85 10 | 40 F3 11 | 40 9B 12 | 7F FF 13 | 14 | # prefix = 2 (32-bit data) 15 | 80 01 2B 3D 16 | 80 04 E6 7F 17 | 80 00 AB CD 18 | BF FF FF FF 19 | 20 | # prefix = 3 (64-bit data) 21 | C0 12 34 56 78 9A BC DE 22 | C0 00 12 34 56 78 9A BC 23 | C0 98 76 54 32 1F ED CB 24 | 25 | FF FF FF FF FF FF FF FF 26 | 27 | # fastcgi varint 28 | # prefix = 0 (8-bit data) 29 | 7f 30 | # prefix = 1 (32-bit data) 31 | FF FF FF FF 32 | -------------------------------------------------------------------------------- /example/wire_data/websocket.dat: -------------------------------------------------------------------------------- 1 | # WebSocket Frame 2 | 8 # fin=true rsv1-rsv3 3 | 1 # text frame 4 | 0 # mask = false 5 | f # payload len = 15 6 | # no extended len 7 | # no mask 8 | # payload 15 byte 9 | 68 65 6c 6c 6f 20 77 6f 72 6c 64 20 21 21 21 10 | -------------------------------------------------------------------------------- /example/wireguard.bgn: -------------------------------------------------------------------------------- 1 | 2 | AEAD_LEN ::= 16 3 | 4 | format handshake_initiation: 5 | message_type :u8 6 | reserved_zero :[3]u8 7 | sender_index :u32 8 | unencrypted_ephemeral :[32]u8 9 | encrypted_static :[32+AEAD_LEN]u8 10 | encrypted_timestamp :[12+AEAD_LEN]u8 11 | mac1 :[16]u8 12 | mac2 :[16]u8 13 | 14 | format handshake_response: 15 | message_type :u8 16 | reserved_zero :[3]u8 17 | sender_index :u32 18 | receiver_index :u32 19 | unencrypted_ephemeral :[32]u8 20 | encrypted_nothing :[0+AEAD_LEN]u8 21 | mac1 :[16]u8 22 | mac2 :[16]u8 23 | 24 | # packet_data { 25 | # u8 message_type 26 | # u8 reserved_zero[3] 27 | # u32 receiver_index 28 | # u64 counter 29 | # u8 encrypted_encapsulated_packet[] 30 | # } 31 | 32 | format packet_data: 33 | message_type :u8 34 | reserved_zero :[3]u8 35 | receiver_index :u32 36 | counter :ul64 37 | encrypted_encapsulated_packet :[..]u8 38 | 39 | # packet_cookie_reply { 40 | # u8 message_type 41 | # u8 reserved_zero[3] 42 | # u32 receiver_index 43 | # u8 nonce[24] 44 | # u8 encrypted_cookie[AEAD_LEN(16)] 45 | # } 46 | 47 | format packet_cookie_reply: 48 | message_type :u8 49 | reserved_zero :[3]u8 50 | receiver_index :u32 51 | nonce :[24]u8 52 | encrypted_cookie :[16+AEAD_LEN]u8 53 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/on-keyday/brgen 2 | 3 | go 1.24 4 | 5 | require github.com/iancoleman/strcase v0.3.0 6 | 7 | require golang.org/x/net v0.40.0 8 | 9 | require ( 10 | golang.org/x/sys v0.33.0 11 | sigs.k8s.io/yaml v1.4.0 12 | ) 13 | -------------------------------------------------------------------------------- /lsp/.vscodeignore: -------------------------------------------------------------------------------- 1 | **/src/** 2 | **/tsconfig.json 3 | **/*.ts 4 | 5 | -------------------------------------------------------------------------------- /lsp/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 on-keyday (https://github.com/on-keyday) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /lsp/client/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "client", 3 | "version": "0.0.1", 4 | "description": "brgen language server client", 5 | "main": "./out/extension.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "watch": "tsc -b -w", 9 | "compile": "tsc -b", 10 | "vscode:prepublish": "npm run compile" 11 | }, 12 | "author": "", 13 | "license": "MIT", 14 | "dependencies": { 15 | "vscode-languageclient": "^9.0.0" 16 | }, 17 | "devDependencies": { 18 | "@types/node": "^22.0.0" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /lsp/server/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "server", 3 | "version": "0.0.1", 4 | "description": "brgen language server", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "watch": "tsc -b -w", 9 | "compile": "tsc -b", 10 | "vscode:prepublish": "npm run compile" 11 | }, 12 | "author": "", 13 | "license": "MIT", 14 | "dependencies": { 15 | "vscode-languageserver": "^9.0.0", 16 | "vscode-languageserver-textdocument": "^1.0.8" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": ["config:recommended", "group:allNonMajor"] 4 | } 5 | -------------------------------------------------------------------------------- /script/clean.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | setlocal 3 | rmdir /Q /S %CD%\built 4 | -------------------------------------------------------------------------------- /script/clone_utils.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | setlocal 3 | git clone https://github.com/on-keyday/utils --depth 1 4 | cd utils 5 | if "%2" == "" ( 6 | set BUILD_TYPE=Debug 7 | ) else ( 8 | set BUILD_TYPE=%2 9 | ) 10 | if "%1" == "wasm-em" ( 11 | call build wasm-em %BUILD_TYPE% futils 12 | ) else ( 13 | call build shared %BUILD_TYPE% futils 14 | if "%S2J_USE_NETWORK%" == "1" ( 15 | call build shared %BUILD_TYPE% fnet 16 | call build shared %BUILD_TYPE% fnetserv 17 | ) 18 | ) 19 | cd .. 20 | -------------------------------------------------------------------------------- /script/clone_utils.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/bash 2 | git clone https://github.com/on-keyday/utils --depth 1 3 | cd utils || exit 1 4 | BUILD_TYPE=$2 5 | if [ ! $BUILD_TYPE ]; then 6 | BUILD_TYPE=Debug 7 | fi 8 | if [ $1 = "wasm-em" ]; then 9 | . build wasm-em $BUILD_TYPE futils 10 | else 11 | . build shared $BUILD_TYPE futils 12 | if [ "$S2J_USE_NETWORK" = "1" ]; then 13 | . build shared $BUILD_TYPE fnet 14 | . build shared $BUILD_TYPE fnetserv 15 | fi 16 | fi 17 | cd .. 18 | -------------------------------------------------------------------------------- /script/cmptest_debug.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | FUTILS_DIR=/c/workspace/utils_backup 3 | export FUTILS_DIR=$FUTILS_DIR 4 | ./build.sh 5 | tool/brgen -config test-brgen.json 6 | tool/cmptest -f ./ignore/example/test_info.json -c ./testkit/cmptest.json --print-fail-command --save-tmp-dir --as-vscode --clean-tmp 7 | 8 | -------------------------------------------------------------------------------- /script/collect_licenses.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | licensed cache 3 | licensed status 4 | if [ $? -eq 0 ]; then 5 | echo "licensed status: OK" 6 | else 7 | echo "licensed status: FAIL" 8 | return 1 9 | fi 10 | if [ ! -d ./license_cache ]; then 11 | mkdir ./license_cache 12 | fi 13 | if [ ! -d ./license_cache/go ]; then 14 | mkdir ./license_cache/go 15 | fi 16 | if [ ! -d ./license_cache/web ]; then 17 | mkdir ./license_cache/web 18 | fi 19 | GOCREDITS=`go env GOPATH`/bin/gocredits 20 | $GOCREDITS -skip-missing > ./license_cache/go/credits.txt 21 | if [ $? -eq 0 ]; then 22 | echo "gocredits save: OK" 23 | else 24 | echo "gocredits save: FAIL" 25 | return 1 26 | fi 27 | cd web/doc 28 | $GOCREDITS -skip-missing > ../../license_cache/web/credits.txt 29 | RESULT=$? 30 | cd ../.. 31 | if [ $RESULT -eq 0 ]; then 32 | echo "gocredits save: OK" 33 | else 34 | echo "gocredits save: FAIL" 35 | return 1 36 | fi 37 | cp ./script/license_note.txt ./license_cache/ 38 | if [ $? -eq 0 ]; then 39 | echo "license_note.txt copy: OK" 40 | else 41 | echo "license_note.txt copy: FAIL" 42 | return 1 43 | fi 44 | -------------------------------------------------------------------------------- /script/copy_bmgen_stub.py: -------------------------------------------------------------------------------- 1 | import pathlib as pl 2 | import shutil as sh 3 | 4 | if not pl.Path("./web/dev/src/lib/bmgen").exists(): 5 | sh.copytree("./web/dev/stub/bmgen", "./web/dev/src/lib/bmgen") 6 | -------------------------------------------------------------------------------- /script/copy_example.py: -------------------------------------------------------------------------------- 1 | import shutil 2 | 3 | shutil.copytree("./example", "./web/public/example", dirs_exist_ok=True) 4 | 5 | # list copied files recursively and filter by suffix .bgn and 6 | # write ./web/public/example/index.txt 7 | import os 8 | import pathlib 9 | 10 | with open("./web/public/example/index.txt", "w") as f: 11 | for root, dirs, files in os.walk("./web/public/example"): 12 | for file in files: 13 | if file.endswith(".bgn"): 14 | path = pathlib.Path(os.path.join(root, file)) 15 | path = path.relative_to("./web/public") 16 | f.write(path.as_posix() + "\n") 17 | -------------------------------------------------------------------------------- /script/dirty_patch.py: -------------------------------------------------------------------------------- 1 | TARGET = "src/tool/json2rust/pkg/json2rust.d.ts" 2 | with open(TARGET, "r") as f: 3 | text = f.read() 4 | 5 | text = text.replace("=> Array", "=> number[]") 6 | 7 | with open(TARGET, "w") as f: 8 | f.write(text) 9 | -------------------------------------------------------------------------------- /script/export_tag.sh: -------------------------------------------------------------------------------- 1 | 2 | read RELEASE_TAG < ./script/tag.txt 3 | 4 | if [ -z "$RELEASE_TAG" ]; then 5 | echo "No tag found" 6 | exit 1 7 | fi 8 | 9 | echo "Exporting tag $RELEASE_TAG" 10 | export RELEASE_TAG 11 | -------------------------------------------------------------------------------- /script/gen_deep.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | setlocal 3 | set OUTPUT_DIR=src/ 4 | set DEEP_GEN=go run ./src/tool/gen/cpp_deep_copy 5 | 6 | tool\src2json --dump-types | %DEEP_GEN% /dev/stdout | clang-format > %OUTPUT_DIR%/core/ast/node/deep_copy.h 7 | -------------------------------------------------------------------------------- /script/gen_enum.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | setlocal 3 | set INPUT_DIR=example/brgen_help 4 | set OUTPUT_DIR=src/ 5 | set ENUM_GEN=go run ./src/tool/gen/enum_gen 6 | 7 | tool\src2json example/brgen_help/ast_enum.bgn | %ENUM_GEN% > %OUTPUT_DIR%/core/ast/node/ast_enum.h 8 | tool\src2json example/brgen_help/lexer_enum.bgn | %ENUM_GEN% > %OUTPUT_DIR%/core/lexer/lexer_enum.h 9 | tool\src2json example/brgen_help/vm_enum.bgn | %ENUM_GEN% > %OUTPUT_DIR%/vm/vm_enum.h 10 | -------------------------------------------------------------------------------- /script/gen_large.py: -------------------------------------------------------------------------------- 1 | BASE_TEXT = """ 2 | format Step%s: 3 | name: "step%s" 4 | value :u64 5 | step :u%s 6 | 7 | """ 8 | import sys 9 | import textwrap 10 | 11 | 12 | def gen_large(count): 13 | for i in range(1, count): 14 | print(BASE_TEXT % (i, i, i)) 15 | 16 | 17 | def gen_indent(count): 18 | indent = " " 19 | print(BASE_TEXT % (1, 1, 1)) 20 | for i in range(2, count): 21 | print(textwrap.indent(BASE_TEXT % (i, i, i), indent)) 22 | indent += " " 23 | 24 | 25 | if __name__ == "__main__": 26 | count = int(sys.argv[2]) 27 | mode = sys.argv[1] 28 | match mode: 29 | case "flat": 30 | gen_large(count) 31 | case "nest": 32 | gen_indent(count) 33 | case _: 34 | raise ValueError("unknown mode") 35 | -------------------------------------------------------------------------------- /script/gen_sample.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | setlocal 3 | tool\src2json %1 > ignore\sample.json 4 | -------------------------------------------------------------------------------- /script/gen_samples.sh: -------------------------------------------------------------------------------- 1 | for file in example/*.bgn; do 2 | name=`basename $file` 3 | tool/src2json $file > example/s2j_test/${name}.json 4 | done -------------------------------------------------------------------------------- /script/generate.py: -------------------------------------------------------------------------------- 1 | import subprocess as sp 2 | 3 | ret = sp.call( 4 | ["./tool/gen_ast2go", "./astlib/ast2go/ast/ast.go"], 5 | executable="./tool/gen_ast2go.exe", 6 | ) 7 | print(ret) 8 | ret = sp.call( 9 | ["gofmt", "-w", "./astlib/ast2go/ast/ast.go"], 10 | ) 11 | print(ret) 12 | ret = sp.call( 13 | ["./tool/gen_ast2ts", "./astlib/ast2ts/src/ast.ts"], 14 | executable="./tool/gen_ast2ts.exe", 15 | ) 16 | print(ret) 17 | ret = sp.call(["tsc"], cwd="./astlib/ast2ts", shell=True) 18 | print(ret) 19 | if ret == 0: 20 | import shutil 21 | 22 | shutil.copy("./LICENSE", "./astlib/ast2ts/out/LICENSE") 23 | ret = sp.call( 24 | ["./tool/gen_ast2rust", "./astlib/ast2rust/core/src/ast.rs"], 25 | executable="./tool/gen_ast2rust.exe", 26 | ) 27 | print(ret) 28 | ret = sp.call( 29 | ["./tool/gen_ast2py", "./astlib/ast2py/ast.py"], 30 | executable="./tool/gen_ast2py.exe", 31 | ) 32 | print(ret) 33 | 34 | ret = sp.call( 35 | ["./tool/gen_ast2c", "./astlib/ast2c/ast.h", "./astlib/ast2c/ast.c"], 36 | executable="./tool/gen_ast2c.exe", 37 | ) 38 | 39 | print(ret) 40 | 41 | ret = sp.call( 42 | ["./tool/gen_ast2csharp", "./astlib/ast2csharp/ast.cs"], 43 | executable="./tool/gen_ast2csharp.exe", 44 | ) 45 | 46 | print(ret) 47 | 48 | ret = sp.call( 49 | ["./tool/gen_ast2dart", "./astlib/ast2dart/lib/ast.dart"], 50 | executable="./tool/gen_ast2dart.exe", 51 | ) 52 | 53 | print(ret) 54 | -------------------------------------------------------------------------------- /script/install_lsp.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | cd lsp 3 | call vsce package 4 | call code --install-extension ./brgen-lsp-0.0.1.vsix 5 | cd ../ 6 | -------------------------------------------------------------------------------- /script/license_note.txt: -------------------------------------------------------------------------------- 1 | This bundle contains license information for web, LSP, and Golang dependencies. 2 | Some are exclusively used in development or build processes (such as compilers), 3 | while others are integrated into the binary. 4 | However, counting and categorizing all dependencies based on their usage has proven challenging for me. 5 | The licenses for these libraries have been gathered using tools 6 | like licensed (https://github.com/github/licensed) and gocredits (https://github.com/Songmu/gocredits), 7 | and the author has personally verified them. 8 | It's important to note that the author is not a lawyer, 9 | so there might be gaps in the consideration of licenses. 10 | If any issues with the licenses are identified, 11 | please report them through GitHub Issues at https://github.com/on-keyday/brgen. 12 | -------------------------------------------------------------------------------- /script/link_path.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | export LD_LIBRARY_PATH=`pwd`/tool:$LD_LIBRARY_PATH 4 | -------------------------------------------------------------------------------- /script/make_ast_doc.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | 4 | ER_DIAGRAM=`./tool/gen_ast2mermaid stdout` 5 | FLOW_CHART=`./tool/gen_ast2mermaid -flow stdout | grep derive` 6 | JSON=`./tool/src2json --dump-types | jq` 7 | 8 | 9 | #echo "$ER_DIAGRAM" 10 | #echo "$FLOW_CHART" 11 | #echo "$JSON" 12 | 13 | #return 14 | 15 | DOC=$(cat <}} 71 | 72 | EOF 73 | ) 74 | 75 | 76 | echo "$DOC" > ./web/doc/content/docs/ast.md 77 | -------------------------------------------------------------------------------- /script/make_cpp_tests.sh: -------------------------------------------------------------------------------- 1 | 2 | if [ $# -lt 1 ]; then 3 | echo "Usage: $0 [run]" 4 | exit 1 5 | fi 6 | 7 | TEST_TARGETS=`cat $1 | jq -r '.generated_files[] | select(.suffix==".hpp") | "\(.dir) \(.base)"'` 8 | 9 | if [ `uname -o` == 'Msys' ]; then 10 | # replace \r\n to \n 11 | TEST_TARGETS=`echo -n "$TEST_TARGETS" | sed -e "s@\r\n@\n@"` 12 | fi 13 | 14 | MAKE_CPP_TEST_PATH=`cd $(dirname ${0}) && pwd`/make_cpp_test.sh 15 | 16 | echo "$MAKE_CPP_TEST_PATH" 17 | RUN_BUILD=$2 18 | IFS=$'\n' 19 | for TEST_TARGET in $TEST_TARGETS; do 20 | DIR=`echo $TEST_TARGET | cut -d ' ' -f 1` 21 | BASE=`echo $TEST_TARGET | cut -d ' ' -f 2` 22 | echo "make test for $DIR/$BASE.hpp" 23 | bash -C $MAKE_CPP_TEST_PATH $DIR $BASE $RUN_BUILD & 24 | done 25 | wait 26 | echo "all tests are done" 27 | -------------------------------------------------------------------------------- /script/push_and_watch.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | setlocal 3 | git push 4 | ping -n 4 127.0.0.1>nul 5 | gh run watch -i1 6 | -------------------------------------------------------------------------------- /script/tag.txt: -------------------------------------------------------------------------------- 1 | v0.0.7 -------------------------------------------------------------------------------- /script/tag_release.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | setlocal 3 | 4 | for /f %%a in (./script/tag.txt) do set RELEASE_TAG=%%a 5 | if "%RELEASE_TAG%"=="" ( 6 | echo "tag.txt" not found 7 | exit /b 1 8 | ) 9 | rem test 10 | echo %RELEASE_TAG% 11 | git tag -d %RELEASE_TAG% 12 | git push origin --delete %RELEASE_TAG% 13 | git add . 14 | git commit -m "release %RELEASE_TAG% %date% %time%" 15 | git tag %RELEASE_TAG% 16 | git push 17 | git push origin %RELEASE_TAG% 18 | -------------------------------------------------------------------------------- /spec/brgen_test_info_schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "type": "object", 4 | "description": "brgen(BinaRy encoder/decoder GENerator driver) output information file schema", 5 | "properties": { 6 | "total_count": { 7 | "type": "integer", 8 | "description": "Total count of output files" 9 | }, 10 | "error_count": { 11 | "type": "integer", 12 | "description": "Count of output files with errors" 13 | }, 14 | "time": { 15 | "type": "string", 16 | "description": "Time taken to generate output files" 17 | }, 18 | "generated_files": { 19 | "type": "array", 20 | "description": "List of generated output files", 21 | "items": { 22 | "type": "object", 23 | "properties": { 24 | "dir": { 25 | "type": "string", 26 | "description": "Directory containing the output file" 27 | }, 28 | "base": { 29 | "type": "string", 30 | "description": "Output file name without extension" 31 | }, 32 | "suffix": { 33 | "type": "string", 34 | "description": "Output file extension" 35 | } 36 | } 37 | } 38 | } 39 | }, 40 | "additionalProperties": false 41 | } 42 | -------------------------------------------------------------------------------- /src/core/ast/ast.h: -------------------------------------------------------------------------------- 1 | /*license*/ 2 | #pragma once 3 | #include "node/base.h" 4 | #include "node/expr.h" 5 | #include "node/statement.h" 6 | #include "node/type.h" 7 | #include "node/translated.h" 8 | #include "node/scope.h" 9 | 10 | namespace brgen::ast { 11 | 12 | template 13 | constexpr T* as(auto&& t) { 14 | Node* v = std::to_address(t); 15 | if constexpr (std::is_same_v) { 16 | return v; 17 | } 18 | else if constexpr (std::is_same_v || std::is_same_v || 19 | std::is_same_v || std::is_same_v || 20 | std::is_same_v) { 21 | if (v && (int(v->node_type) & int(T::node_type_tag)) == int(T::node_type_tag)) { 22 | return static_cast(v); 23 | } 24 | } 25 | else { 26 | if (v && v->node_type == T::node_type_tag) { 27 | return static_cast(v); 28 | } 29 | } 30 | return nullptr; 31 | } 32 | 33 | template 34 | constexpr auto cast_to(auto&& t) { 35 | assert(as(t) != nullptr); 36 | using T = std::decay_t; 37 | if constexpr (futils::helper::is_template_instance_of) { 38 | using V = typename futils::helper::template_instance_of_t::template param_at<0>; 39 | return std::static_pointer_cast(std::forward(t)); 40 | } 41 | else { 42 | return static_cast(t); 43 | } 44 | } 45 | 46 | } // namespace brgen::ast 47 | -------------------------------------------------------------------------------- /src/core/ast/kill_node.h: -------------------------------------------------------------------------------- 1 | /*license*/ 2 | #pragma once 3 | 4 | #include "traverse.h" 5 | 6 | namespace brgen::ast { 7 | // for large scale of AST 8 | // destructor call stack is too deep that makes stack overflow 9 | // so we need to use this 10 | void kill_node(const std::shared_ptr& node) { 11 | if (auto p = ast::as(node); p && p->global_scope) { 12 | std::vector> stack; 13 | stack.push_back(std::move(p->global_scope)); 14 | p->global_scope = nullptr; 15 | while (!stack.empty()) { 16 | auto s = std::move(stack.back()); 17 | stack.pop_back(); 18 | if (s->next) { 19 | if (s->next->prev.lock() == s) { 20 | stack.push_back(std::move(s->next)); 21 | } 22 | s->next = nullptr; 23 | } 24 | if (s->branch) { 25 | stack.push_back(std::move(s->branch)); 26 | s->branch = nullptr; 27 | } 28 | } 29 | } 30 | std::vector> stack; 31 | stack.push_back(node); 32 | while (!stack.empty()) { 33 | auto n = std::move(stack.back()); 34 | stack.pop_back(); 35 | traverse(n, [&](auto& v) { 36 | stack.push_back(std::move(v)); 37 | v = nullptr; 38 | }); 39 | } 40 | } 41 | } // namespace brgen::ast 42 | -------------------------------------------------------------------------------- /src/core/ast/line_map.h: -------------------------------------------------------------------------------- 1 | /*license*/ 2 | #pragma once 3 | #include 4 | 5 | namespace brgen::ast { 6 | struct LineMap { 7 | brgen::lexer::Loc loc; 8 | size_t line; 9 | }; 10 | 11 | void as_json(LineMap& mp, auto&& obj) { 12 | auto field = obj.object(); 13 | field("loc", mp.loc); 14 | field("line", mp.line); 15 | } 16 | 17 | } // namespace brgen::ast -------------------------------------------------------------------------------- /src/core/ast/parse.h: -------------------------------------------------------------------------------- 1 | /*license*/ 2 | #pragma once 3 | #include "ast.h" 4 | #include "stream.h" 5 | 6 | namespace brgen::ast { 7 | struct ParseOption { 8 | bool collect_comments = false; 9 | bool error_tolerant = false; 10 | }; 11 | std::shared_ptr parse(Stream& stream, LocationError* err_or_warn, ParseOption option = {}); 12 | } // namespace brgen::ast 13 | -------------------------------------------------------------------------------- /src/core/ast/tool/metadata.h: -------------------------------------------------------------------------------- 1 | /*license*/ 2 | #pragma once 3 | #include "../ast.h" 4 | 5 | namespace brgen::ast::tool { 6 | std::optional lookup_str_metadata(std::string_view name, std::vector>& md) { 7 | for (auto& m : md) { 8 | auto p = m.lock(); 9 | if (p && p->name == name && p->values.size() == 1) { 10 | if (auto s = ast::as(p->values[0])) { 11 | auto input = s->value.substr(1, s->value.size() - 2); 12 | return futils::escape::unescape_str(input); 13 | } 14 | } 15 | } 16 | return std::nullopt; 17 | } 18 | } // namespace brgen::ast::tool 19 | -------------------------------------------------------------------------------- /src/core/ast/tool/tmp_ident.h: -------------------------------------------------------------------------------- 1 | /*license*/ 2 | #pragma once 3 | #include 4 | 5 | namespace brgen::ast::tool { 6 | void set_tmp_field_ident(size_t seq, const std::shared_ptr& f, const char* name_prefix = "tmp") { 7 | if (f->ident) return; 8 | auto ident = std::make_shared(f->loc, brgen::concat(name_prefix, brgen::nums(seq))); 9 | ident->base = f; 10 | f->ident = ident; 11 | f->ident->usage = IdentUsage::define_field; 12 | f->ident->constant_level = ConstantLevel::variable; 13 | } 14 | } // namespace brgen::ast::tool 15 | -------------------------------------------------------------------------------- /src/core/common/debug.h: -------------------------------------------------------------------------------- 1 | /*license*/ 2 | #pragma once 3 | #include "util.h" 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace brgen { 11 | 12 | #define sdebugf(name) field_(#name, name) 13 | #define sdebugf_omit(name) field_(#name, name) 14 | 15 | using JSONWriter = futils::json::Stringer<>; 16 | } // namespace brgen 17 | -------------------------------------------------------------------------------- /src/core/common/expected.h: -------------------------------------------------------------------------------- 1 | /*license*/ 2 | #pragma once 3 | #include 4 | 5 | namespace brgen { 6 | using namespace futils::helper::either; 7 | namespace either = futils::helper::either; 8 | 9 | constexpr auto unexpect(auto&&... e) { 10 | return either::unexpected(e...); 11 | } 12 | 13 | } // namespace brgen 14 | -------------------------------------------------------------------------------- /src/core/common/util.h: -------------------------------------------------------------------------------- 1 | /*license*/ 2 | #pragma once 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace brgen { 10 | auto nums(auto v, int radix = 10) { 11 | return futils::number::to_string(v, radix); 12 | } 13 | 14 | using futils::strutil::append, futils::strutil::appends; 15 | 16 | inline std::optional unescape(std::string_view str_lit) { 17 | std::string mid; 18 | if (!futils::escape::unescape_str(str_lit.substr(1, str_lit.size() - 2), mid)) { 19 | return std::nullopt; 20 | } 21 | return mid; 22 | } 23 | 24 | template 25 | inline std::optional unescape_count(std::string_view str_lit) { 26 | futils::helper::CountPushBacker pb; 27 | futils::helper::IPushBacker ipb{pb}; 28 | if (!futils::escape::unescape_str(str_lit.substr(1, str_lit.size() - 2), ipb)) { 29 | return std::nullopt; 30 | } 31 | return pb.count; 32 | } 33 | 34 | inline std::string escape(std::string_view str_lit) { 35 | return futils::escape::escape_str(str_lit, futils::escape::EscapeFlag::utf16 | futils::escape::EscapeFlag::hex); 36 | } 37 | 38 | inline std::string concat(auto&&... msg) { 39 | std::string buf; 40 | appends(buf, msg...); 41 | return buf; 42 | } 43 | 44 | } // namespace brgen 45 | -------------------------------------------------------------------------------- /src/core/lexer/token.h: -------------------------------------------------------------------------------- 1 | /*license*/ 2 | #pragma once 3 | #include 4 | #include 5 | #include "lexer_enum.h" 6 | #include 7 | 8 | namespace brgen::lexer { 9 | using Pos = futils::comb2::Pos; 10 | 11 | using FileIndex = std::uint64_t; 12 | 13 | constexpr FileIndex builtin = 0; 14 | 15 | struct Loc { 16 | Pos pos; 17 | FileIndex file = 0; // file index 18 | size_t line = 0; 19 | size_t col = 0; 20 | }; 21 | 22 | constexpr bool operator==(const Loc& lhs, const Loc& rhs) { 23 | return lhs.pos == rhs.pos && lhs.file == rhs.file && lhs.line == rhs.line && lhs.col == rhs.col; 24 | } 25 | 26 | constexpr void as_json(Loc l, auto&& buf) { 27 | auto field = buf.object(); 28 | field("pos", [&] { 29 | auto field = buf.object(); 30 | field("begin", l.pos.begin); 31 | field("end", l.pos.end); 32 | }); 33 | field("file", l.file); 34 | field("line", l.line); 35 | field("col", l.col); 36 | } 37 | 38 | struct Token { 39 | Tag tag = Tag::unknown; 40 | std::string token; 41 | Loc loc; 42 | }; 43 | 44 | constexpr void as_json(const Token& token, auto&& buf) { 45 | auto field = buf.object(); 46 | field("tag", token.tag); 47 | field("token", token.token); 48 | field("loc", token.loc); 49 | } 50 | 51 | } // namespace brgen::lexer 52 | -------------------------------------------------------------------------------- /src/core/middle/analyze_block_trait.h: -------------------------------------------------------------------------------- 1 | /*license*/ 2 | #pragma once 3 | #include 4 | 5 | namespace brgen::middle { 6 | void analyze_block_trait(const std::shared_ptr&); 7 | } -------------------------------------------------------------------------------- /src/core/middle/type_attribute.h: -------------------------------------------------------------------------------- 1 | /*license*/ 2 | #pragma once 3 | #include 4 | 5 | namespace brgen::middle { 6 | void mark_recursive_reference(const std::shared_ptr& node); 7 | void analyze_bit_size_and_alignment(const std::shared_ptr& node); 8 | void detect_non_dynamic_type(const std::shared_ptr& node); 9 | } 10 | -------------------------------------------------------------------------------- /src/core/middle/typing.h: -------------------------------------------------------------------------------- 1 | /*license*/ 2 | #pragma once 3 | #include "../common/file.h" 4 | #include "../common/error.h" 5 | #include "../ast/ast.h" 6 | 7 | namespace brgen::middle { 8 | result analyze_type(std::shared_ptr& node, LocationError* warnings); 9 | } 10 | -------------------------------------------------------------------------------- /src/test/core/ast_test.cpp: -------------------------------------------------------------------------------- 1 | #include "ast_test_component.h" 2 | #include 3 | #include 4 | #include 5 | using namespace brgen; 6 | 7 | int main(int argc, char** argv) { 8 | set_test_handler([](auto& prog, auto i, auto& fs) { 9 | JSONWriter d; 10 | d.value(prog); 11 | add_result(std::move(d)); 12 | }); 13 | ::testing::InitGoogleTest(&argc, argv); 14 | auto res = RUN_ALL_TESTS(); 15 | save_result("ast_test_result.json"); 16 | return res; 17 | } 18 | -------------------------------------------------------------------------------- /src/test/core/ast_test_component.h: -------------------------------------------------------------------------------- 1 | /*license*/ 2 | #pragma once 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | extern futils::wrap::UtfOut& cerr; 11 | 12 | using Continuation = void (*)(std::shared_ptr& prog, brgen::File* input, brgen::FileSet& fs); 13 | 14 | // Function declarations with the AST_TEST_COMPONENT_API macro 15 | void set_test_handler(Continuation cont); 16 | void add_result(brgen::JSONWriter&& d); 17 | void save_result(const char* file); 18 | -------------------------------------------------------------------------------- /src/test/core/derive_test.cpp: -------------------------------------------------------------------------------- 1 | /*license*/ 2 | 3 | #include 4 | #include 5 | 6 | using namespace brgen; 7 | 8 | TEST(DeriveTest, Test1) { 9 | struct Dummy : ast::Member { 10 | Dummy() 11 | : ast::Member({}, ast::NodeType::member) {} 12 | }; 13 | Dummy d; 14 | ASSERT_NE(ast::as(&d), nullptr); 15 | ASSERT_NE(ast::as(&d), nullptr); 16 | ASSERT_NE(ast::as(&d), nullptr); 17 | 18 | 19 | struct Dummy2 : ast::Literal { 20 | Dummy2() 21 | : ast::Literal({}, ast::NodeType::literal) {} 22 | }; 23 | 24 | Dummy2 d2; 25 | ASSERT_NE(ast::as(&d2), nullptr); 26 | ASSERT_NE(ast::as(&d2), nullptr); 27 | ASSERT_NE(ast::as(&d2), nullptr); 28 | } 29 | -------------------------------------------------------------------------------- /src/test/core/from_json_test.cpp: -------------------------------------------------------------------------------- 1 | /*license*/ 2 | #include "ast_test_component.h" 3 | #include "middle_test.h" 4 | #include 5 | #include 6 | #include 7 | using namespace brgen; 8 | 9 | int main(int argc, char** argv) { 10 | set_test_handler([](auto a, auto in, auto fs) { 11 | LocationError warns; 12 | middle::test::apply_middle(warns, a) 13 | .transform_error(to_source_error(fs)) 14 | .value(); 15 | ast::JSONConverter m; 16 | m.encode(a); 17 | auto base = m.obj.out(); 18 | add_result(std::move(m.obj)); 19 | auto parsed = futils::json::parse(base); 20 | auto d = m.decode(parsed) 21 | .transform_error(to_source_error(fs)) 22 | .value(); 23 | m.encode(d); 24 | ASSERT_EQ(base, m.obj.out()); 25 | }); 26 | ::testing::InitGoogleTest(&argc, argv); 27 | auto res = RUN_ALL_TESTS(); 28 | save_result("from_json_test_result.json"); 29 | return res; 30 | } 31 | -------------------------------------------------------------------------------- /src/test/core/lexer_test.cpp: -------------------------------------------------------------------------------- 1 | /*license*/ 2 | #include 3 | #include 4 | 5 | TEST(LexerTest, LexerTest) { 6 | GTEST_ASSERT_TRUE(brgen::lexer::internal::check_lexer()); 7 | } 8 | -------------------------------------------------------------------------------- /src/test/core/middle_test.cpp: -------------------------------------------------------------------------------- 1 | /*license*/ 2 | #include "ast_test_component.h" 3 | #include "middle_test.h" 4 | #include 5 | using namespace brgen; 6 | 7 | int main(int argc, char** argv) { 8 | set_test_handler([](auto a, auto in, auto fs) { 9 | LocationError warns; 10 | middle::test::apply_middle(warns, a) 11 | .transform_error(to_source_error(fs)) 12 | .value(); 13 | JSONWriter d; 14 | d.value(a); 15 | add_result(std::move(d)); 16 | }); 17 | ::testing::InitGoogleTest(&argc, argv); 18 | auto res = RUN_ALL_TESTS(); 19 | save_result("middle_test_result.json"); 20 | return res; 21 | } 22 | -------------------------------------------------------------------------------- /src/test/core/middle_test.h: -------------------------------------------------------------------------------- 1 | /*license*/ 2 | #pragma once 3 | #include 4 | #include 5 | 6 | namespace brgen::middle::test { 7 | result apply_middle(LocationError& warn, std::shared_ptr& node) { 8 | middle::replace_assert(node); 9 | return middle::analyze_type(node, &warn).and_then([&] { 10 | brgen::middle::collect_unused_warnings(node, warn); 11 | return result{}; 12 | }); 13 | } 14 | } // namespace brgen::middle::test 15 | -------------------------------------------------------------------------------- /src/test/core/typing_test.cpp: -------------------------------------------------------------------------------- 1 | /*license*/ 2 | #include "ast_test_component.h" 3 | #include 4 | #include 5 | #include 6 | using namespace brgen; 7 | 8 | int main(int argc, char** argv) { 9 | set_test_handler([](auto& a, File* input, FileSet& fs) { 10 | middle::analyze_type(a, nullptr).transform_error(to_source_error(fs)).value(); 11 | JSONWriter d; 12 | d.value(*a); 13 | add_result(std::move(d)); 14 | }); 15 | ::testing::InitGoogleTest(&argc, argv); 16 | auto res = RUN_ALL_TESTS(); 17 | save_result("typing_test_result.json"); 18 | return res; 19 | } -------------------------------------------------------------------------------- /src/test/test_tool/test_log_server/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "net/http" 5 | "os" 6 | 7 | "golang.org/x/net/websocket" 8 | ) 9 | 10 | func logging(fp *os.File, log chan string) { 11 | for { 12 | msg := <-log 13 | fp.WriteString(msg) 14 | } 15 | } 16 | 17 | func main() { 18 | file := os.Args[1] 19 | fp, err := os.Create(file) 20 | if err != nil { 21 | panic(err) 22 | } 23 | defer fp.Close() 24 | log := make(chan string) 25 | go logging(fp, log) 26 | serv := &websocket.Server{} 27 | serv.Handler = func(ws *websocket.Conn) { 28 | for { 29 | var msg string 30 | err := websocket.Message.Receive(ws, &msg) 31 | if err != nil { 32 | break 33 | } 34 | log <- msg 35 | } 36 | } 37 | http.Handle("/log", serv) 38 | http.ListenAndServe(":8080", nil) 39 | } 40 | -------------------------------------------------------------------------------- /src/tool/brgen/config.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "encoding/json" 4 | 5 | type ArrayOrString []string 6 | 7 | func (a *ArrayOrString) UnmarshalJSON(b []byte) error { 8 | var arr []string 9 | if err := json.Unmarshal(b, &arr); err == nil { 10 | *a = arr 11 | return nil 12 | } 13 | var str string 14 | if err := json.Unmarshal(b, &str); err != nil { 15 | return err 16 | } 17 | *a = []string{str} 18 | return nil 19 | } 20 | 21 | type Output struct { 22 | Generator ArrayOrString `json:"generator"` 23 | OutputDir string `json:"output_dir"` 24 | Args []string `json:"args"` 25 | IgnoreMissing bool `json:"ignore_missing"` 26 | } 27 | 28 | type Warnings struct { 29 | DisableUntypedWarning bool `json:"disable_untyped"` 30 | DisableUnusedWarning bool `json:"disable_unused"` 31 | } 32 | 33 | type Config struct { 34 | Source2Json *string `json:"src2json"` 35 | LibSource2Json *string `json:"libs2j"` 36 | Suffix *string `json:"suffix"` 37 | TargetDirs []string `json:"input_dir"` 38 | Warnings Warnings `json:"warnings"` 39 | Output []*Output `json:"output"` 40 | TestInfo *string `json:"test_info_output"` 41 | } 42 | -------------------------------------------------------------------------------- /src/tool/brgen/stdin_stream.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "io" 6 | "os/exec" 7 | "path" 8 | "path/filepath" 9 | 10 | "github.com/on-keyday/brgen/astlib/ast2go/request" 11 | ) 12 | 13 | func (g *Generator) initStdinStream() error { 14 | cmdline := g.cmdline() 15 | cmd := exec.CommandContext(g.ctx, cmdline[0], cmdline[1:]...) 16 | cl, err := request.NewProcessClient(cmd) 17 | if err != nil { 18 | return err 19 | } 20 | g.stdinStream = cl 21 | return nil 22 | } 23 | 24 | func (g *Generator) handleStdinStreamRequest(req *Result) { 25 | stream := g.stdinStream.CreateStream() 26 | ext := filepath.Ext(req.Path) 27 | base := filepath.Base(req.Path) 28 | baseWithoutExt := base[:len(base)-len(ext)] 29 | err := stream.SendRequest(baseWithoutExt, req.Data) 30 | if err != nil { 31 | req.Err = err 32 | g.sendResult(req) 33 | return 34 | } 35 | for { 36 | resp, err := stream.ReceiveResponse() 37 | if err != nil { 38 | if err == io.EOF { 39 | break 40 | } 41 | req.Err = err 42 | g.sendResult(req) 43 | return 44 | } 45 | if resp.Status == request.ResponseStatus_Error { 46 | req.Err = errors.New(string(resp.ErrorMessage)) 47 | g.sendResult(req) 48 | continue 49 | } 50 | if len(resp.Name) == 0 { 51 | req.Data = resp.Code 52 | req.Err = errors.New("empty name") 53 | g.sendResult(req) 54 | continue 55 | } 56 | if path.Ext(string(resp.Name)) == "" { 57 | req.Data = resp.Code 58 | req.Err = errors.New("no extension") 59 | g.sendResult(req) 60 | continue 61 | } 62 | g.sendGenerated(string(resp.Name), resp.Code) 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/tool/cmptest/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "cmptest" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | clap = { version = "4.5.4", features = ["derive"] } 10 | serde = { version="1.0.200" ,features = ["derive"]} 11 | serde_json = "1.0.116" 12 | ast2rust = {path ="../../../astlib/ast2rust/core" } 13 | regex = "1.10.4" 14 | rand = "0.9.0" 15 | tokio = { version = "1.37.0", features = ["full"] } 16 | colored = "3.0.0" 17 | -------------------------------------------------------------------------------- /src/tool/common/em_main.h: -------------------------------------------------------------------------------- 1 | /*license*/ 2 | #pragma once 3 | #include 4 | #include 5 | #include 6 | 7 | int em_main(const char* cmdline, auto main_, auto... additional_args) { 8 | auto args = futils::view::make_cpy_splitview(cmdline, " "); 9 | futils::wrap::ArgvVector vec; 10 | for (size_t i = 0; i < args.size(); ++i) { 11 | std::string out; 12 | if (!futils::urlenc::decode(args[i], out)) { 13 | return 2; 14 | } 15 | vec.push_back(std::move(out)); 16 | } 17 | int argc; 18 | char** argv; 19 | vec.arg(argc, argv); 20 | return main_(argc, argv, additional_args...); 21 | } 22 | -------------------------------------------------------------------------------- /src/tool/common/generate.h: -------------------------------------------------------------------------------- 1 | /*license*/ 2 | #pragma once 3 | #include "load_json.h" 4 | #include 5 | #include 6 | 7 | template 8 | int do_generate(const auto& flags, brgen::request::GenerateSource& req, T&& input, auto&& cb) { 9 | auto res = load_json(req.id, req.name, std::forward(input)); 10 | if (!res) { 11 | return 1; 12 | } 13 | return cb(flags, req, res); 14 | } 15 | 16 | int generate_from_file(const auto& flags, auto&& cb) { 17 | if (flags.args.empty()) { 18 | print_error("no input file"); 19 | return 1; 20 | } 21 | if (flags.args.size() > 1) { 22 | print_error("too many input files"); 23 | return 1; 24 | } 25 | auto name = flags.args[0]; 26 | futils::file::View view; 27 | if (!view.open(name)) { 28 | print_error("cannot open file ", name); 29 | return 1; 30 | } 31 | std::filesystem::path path{name}; 32 | auto u8name = path.filename().replace_extension().generic_u8string(); 33 | brgen::request::GenerateSource req; 34 | req.id = 0; 35 | req.name = std::string(reinterpret_cast(u8name.data()), u8name.size()); 36 | send_as_text = true; 37 | return do_generate(flags, req, view, cb); 38 | } 39 | -------------------------------------------------------------------------------- /src/tool/common/load_json.h: -------------------------------------------------------------------------------- 1 | /*license*/ 2 | #pragma once 3 | #include "send.h" 4 | #include 5 | #include 6 | 7 | std::shared_ptr load_json(std::uint64_t id, auto&& name, auto&& input) { 8 | auto js = futils::json::parse(input); 9 | if (js.is_undef()) { 10 | send_error_and_end(id, "cannot parse json file: ", name); 11 | return nullptr; 12 | } 13 | brgen::ast::AstFile file; 14 | if (!futils::json::convert_from_json(js, file)) { 15 | send_error_and_end(id, "cannot convert json file to ast: ", name); 16 | return nullptr; 17 | } 18 | if (!file.ast) { 19 | send_error_and_end(id, "cannot convert json file to ast: ast is null: ", name); 20 | return nullptr; 21 | } 22 | brgen::ast::JSONConverter c; 23 | auto res = c.decode(*file.ast); 24 | if (!res) { 25 | send_error_and_end(id, "cannot decode json file: ", res.error().locations[0].msg); 26 | return nullptr; 27 | } 28 | if (!*res) { 29 | send_error_and_end(id, "cannot decode json file: ast is null: ", name); 30 | return nullptr; 31 | } 32 | return *res; 33 | } -------------------------------------------------------------------------------- /src/tool/json2go/js.go: -------------------------------------------------------------------------------- 1 | //go:build js && wasm 2 | 3 | package main 4 | 5 | import ( 6 | js "github.com/on-keyday/brgen/astlib/ast2go/js" 7 | ) 8 | 9 | type makeGenerator struct{} 10 | 11 | func (m *makeGenerator) New() js.Generator { 12 | return NewGenerator() 13 | } 14 | 15 | func (m *makeGenerator) ResetFlag() { 16 | ResetFlag() 17 | } 18 | 19 | func setFunc() { 20 | js.SetGoFunc(&makeGenerator{}) 21 | } 22 | 23 | func main() { 24 | c := make(chan struct{}) 25 | setFunc() 26 | <-c 27 | } 28 | -------------------------------------------------------------------------------- /src/tool/json2kaitai/js.go: -------------------------------------------------------------------------------- 1 | //go:build js && wasm 2 | 3 | package main 4 | 5 | import ( 6 | js "github.com/on-keyday/brgen/astlib/ast2go/js" 7 | ) 8 | 9 | type makeGenerator struct{} 10 | 11 | func (m *makeGenerator) New() js.Generator { 12 | return &Generator{} 13 | } 14 | 15 | func (m *makeGenerator) ResetFlag() { 16 | 17 | } 18 | 19 | func setFunc() { 20 | js.SetGoFunc(&makeGenerator{}) 21 | } 22 | 23 | func main() { 24 | c := make(chan struct{}) 25 | setFunc() 26 | <-c 27 | } 28 | -------------------------------------------------------------------------------- /src/tool/json2kaitai/main.go: -------------------------------------------------------------------------------- 1 | //go:build !js || !wasm 2 | 3 | package main 4 | 5 | import ( 6 | "encoding/json" 7 | "flag" 8 | "fmt" 9 | "os" 10 | 11 | "github.com/on-keyday/brgen/astlib/ast2go/ast" 12 | ) 13 | 14 | func main() { 15 | flag.Parse() 16 | if *f { 17 | fmt.Println(`{ 18 | "langs" : ["kaitai-struct"], 19 | "input" : "stdin", 20 | "suffix" : [".ksy"] 21 | }`) 22 | return 23 | } 24 | file := ast.AstFile{} 25 | if *filename != "" { 26 | f, err := os.Open(*filename) 27 | if err != nil { 28 | fmt.Fprintln(os.Stderr, err) 29 | os.Exit(1) 30 | return 31 | } 32 | defer f.Close() 33 | err = json.NewDecoder(f).Decode(&file) 34 | if err != nil { 35 | fmt.Fprintln(os.Stderr, err) 36 | os.Exit(1) 37 | return 38 | } 39 | } else { 40 | err := json.NewDecoder(os.Stdin).Decode(&file) 41 | if err != nil { 42 | fmt.Fprintln(os.Stderr, err) 43 | os.Exit(1) 44 | return 45 | } 46 | } 47 | 48 | g := &Generator{} 49 | out, err := g.GenerateAndFormat(&file) 50 | if err != nil { 51 | fmt.Fprintln(os.Stderr, err) 52 | os.Exit(1) 53 | return 54 | } 55 | 56 | os.Stdout.Write(out) 57 | } 58 | -------------------------------------------------------------------------------- /src/tool/json2llvm/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "json2llvm" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | inkwell = { version="0.6.0", features = ["llvm17-0","llvm17-0-no-llvm-linking"] } 10 | ast2rust = { path ="../../../astlib/ast2rust/core" } 11 | serde = "1.0.200" 12 | serde_json = "1.0.116" 13 | 14 | -------------------------------------------------------------------------------- /src/tool/json2llvm/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | println!("cargo:rustc-link-search=C:/workspace/LLVM/lib"); 3 | println!("cargo:rustc-link-lib=LLVM-C"); 4 | } 5 | -------------------------------------------------------------------------------- /src/tool/json2llvm/src/main.rs: -------------------------------------------------------------------------------- 1 | mod generate; 2 | use ast2rust::ast; 3 | use generate::Error; 4 | use serde::Deserialize; 5 | use std::process::ExitCode; 6 | 7 | fn main() -> Result<(), Error> { 8 | let mut deserializer = serde_json::Deserializer::from_reader(std::io::stdin()); 9 | let file = ast::AstFile::deserialize(&mut deserializer); 10 | if let Err(e) = file { 11 | return Err(Error::JSONError(e)); 12 | } 13 | let file = file.unwrap(); 14 | let prog = ast::parse_ast(file.ast.unwrap()); 15 | if let Err(e) = prog { 16 | return Err(Error::ParseError(e)); 17 | } 18 | let prog = prog.unwrap(); 19 | let gen = generate::Generator::new(&prog); 20 | gen.generate()?; 21 | Ok(()) 22 | } 23 | -------------------------------------------------------------------------------- /src/tool/json2rust/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "json2rust" 3 | version = "0.1.0" 4 | edition = "2021" 5 | repository = "https://github.com/on-keyday/brgen" 6 | license = "MIT" 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [lib] 10 | crate-type = ["cdylib", "rlib"] 11 | 12 | [dependencies] 13 | anyhow = "1.0.86" 14 | ast2rust = {path ="../../../astlib/ast2rust/core" } 15 | ast2rust_macro = {path="../../../astlib/ast2rust/macros"} 16 | clap = { version = "4.5.4", features = ["derive"] } 17 | serde = "1.0.200" 18 | serde_json = "1.0.116" 19 | wasm-bindgen = "0.2.92" 20 | 21 | -------------------------------------------------------------------------------- /src/tool/json2rust/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod generator; 2 | use ast2rust::ast; 3 | use serde::Deserialize; 4 | use wasm_bindgen::prelude::wasm_bindgen; 5 | 6 | #[wasm_bindgen] 7 | pub fn json2rust(input: &str) -> String { 8 | let mut deserializer = serde_json::Deserializer::from_str(input); 9 | let file = ast::AstFile::deserialize(&mut deserializer); 10 | if let Err(e) = file { 11 | return format!("error: {:?}", e); 12 | } 13 | let file = file.unwrap(); 14 | let prog = ast::parse_ast(file.ast.unwrap()); 15 | if let Err(e) = prog { 16 | return format!("error: {:?}", e); 17 | } 18 | let mut gen = generator::Generator::new(Vec::new()); 19 | let prog = prog.unwrap(); 20 | let b = gen.write_program(prog); 21 | if let Err(e) = b { 22 | return format!("error: {:?}", e); 23 | } 24 | let w = gen.get_mut_writer(); 25 | String::from_utf8(w.clone()).unwrap() 26 | } 27 | -------------------------------------------------------------------------------- /src/tool/json2spicy/spicy.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | 4 | func main() { 5 | 6 | } -------------------------------------------------------------------------------- /src/tool/json2ts/generate.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | namespace json2ts { 4 | struct Flags { 5 | bool use_bigint = false; 6 | bool no_resize = false; 7 | bool javascript = false; 8 | bool enum_to_string = false; 9 | }; 10 | std::string generate(const std::shared_ptr& p, Flags flags); 11 | } // namespace json2ts 12 | -------------------------------------------------------------------------------- /src/tool/s2jgo/capability.go: -------------------------------------------------------------------------------- 1 | package s2jgo 2 | 3 | /* 4 | #define S2J_CAPABILITY_STDIN (1 << 0) 5 | #define S2J_CAPABILITY_NETWORK (1 << 1) 6 | #define S2J_CAPABILITY_FILE (1 << 2) 7 | #define S2J_CAPABILITY_ARGV (1 << 3) 8 | #define S2J_CAPABILITY_CHECK_AST (1 << 4) 9 | #define S2J_CAPABILITY_LEXER (1 << 5) 10 | #define S2J_CAPABILITY_PARSER (1 << 6) 11 | #define S2J_CAPABILITY_IMPORTER (1 << 7) 12 | #define S2J_CAPABILITY_AST_JSON (1 << 8) 13 | */ 14 | 15 | type Capability uint64 16 | 17 | const ( 18 | CAPABILITY_STDIN Capability = 1 << 0 19 | CAPABILITY_NETWORK Capability = 1 << 1 20 | CAPABILITY_FILE Capability = 1 << 2 21 | CAPABILITY_ARGV Capability = 1 << 3 22 | CAPABILITY_CHECK_AST Capability = 1 << 4 23 | CAPABILITY_LEXER Capability = 1 << 5 24 | CAPABILITY_PARSER Capability = 1 << 6 25 | CAPABILITY_IMPORTER Capability = 1 << 7 26 | CAPABILITY_AST_JSON Capability = 1 << 8 27 | 28 | CAPABILITY_ALL Capability = 0xffffffffffffffff 29 | ) 30 | -------------------------------------------------------------------------------- /src/tool/s2jgo/s2j_stub.go: -------------------------------------------------------------------------------- 1 | //go:build !windows && (!cgo || !linux && !darwin && !freebsd) 2 | package s2jgo 3 | 4 | import "errors" 5 | 6 | func Available() bool { 7 | return false 8 | } 9 | 10 | type src2JSON struct{} 11 | 12 | func load(_ string) (*src2JSON, error) { 13 | return nil, errors.New("not implemented") 14 | } 15 | 16 | func (s *src2JSON) CallIOCallback(args []string, cap Capability, cb func(data []byte, isStdErr bool)) error { 17 | return errors.New("not implemented") 18 | } 19 | -------------------------------------------------------------------------------- /src/tool/s2jgo/s2j_test.go: -------------------------------------------------------------------------------- 1 | package s2jgo_test 2 | 3 | import ( 4 | "io" 5 | "net/http" 6 | "os" 7 | "strings" 8 | "sync" 9 | "testing" 10 | 11 | "github.com/on-keyday/brgen/src/tool/s2jgo" 12 | ) 13 | 14 | func TestLoad(t *testing.T) { 15 | os.Chdir("C:/workspace/shbrgen/brgen/tool") 16 | s2j, err := s2jgo.Load("C:/workspace/shbrgen/brgen/tool/libs2j.dll") 17 | if err != nil { 18 | t.Fatal(err) 19 | } 20 | var s sync.WaitGroup 21 | s.Add(1) 22 | go func() { 23 | err := s2j.CallIOCallback([]string{"src2json", "--via-http"}, s2jgo.CAPABILITY_ALL, 24 | func(data []byte, isStdErr bool) { 25 | if isStdErr { 26 | os.Stderr.Write(data) 27 | } else { 28 | os.Stdout.Write(data) 29 | } 30 | }) 31 | if err != nil { 32 | return 33 | } 34 | s.Done() 35 | }() 36 | r, err := http.Get("http://localhost:8080/stat") 37 | if err != nil { 38 | t.Fatal(err) 39 | } 40 | io.Copy(os.Stdout, r.Body) 41 | r.Body.Close() 42 | r, err = http.Post("http://localhost:8080/parse", "application/json", strings.NewReader(`{"args":["../example/udp.bgn"]}`)) 43 | if err != nil { 44 | t.Fatal(err) 45 | } 46 | io.Copy(os.Stdout, r.Body) 47 | r.Body.Close() 48 | r, err = http.Get("http://localhost:8080/stop") 49 | if err != nil { 50 | t.Fatal(err) 51 | } 52 | io.Copy(os.Stdout, r.Body) 53 | r.Body.Close() 54 | s.Wait() 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/tool/src2json/capi_export.h: -------------------------------------------------------------------------------- 1 | #if _WIN32 2 | #define S2J_EXPORT __declspec(dllexport) 3 | #else 4 | #define S2J_EXPORT 5 | #endif 6 | -------------------------------------------------------------------------------- /src/tool/src2json/entry.h: -------------------------------------------------------------------------------- 1 | /*license*/ 2 | #pragma once 3 | #include "capi.h" 4 | 5 | int src2json_main(int argc, char** argv, const Capability& cap); 6 | -------------------------------------------------------------------------------- /src/tool/src2json/hook.h: -------------------------------------------------------------------------------- 1 | /*license*/ 2 | #pragma once 3 | #include "../common/print.h" 4 | 5 | inline bool& is_worker_thread() { 6 | static thread_local bool is_worker = false; 7 | return is_worker; 8 | } 9 | 10 | inline futils::wrap::write_hook_fn& worker_hook() { 11 | static thread_local futils::wrap::write_hook_fn hook = nullptr; 12 | return hook; 13 | } 14 | 15 | inline std::string& worker_stdout_buffer() { 16 | static thread_local std::string buffer; 17 | return buffer; 18 | } 19 | 20 | inline std::string& worker_stderr_buffer() { 21 | static thread_local std::string buffer; 22 | return buffer; 23 | } 24 | 25 | inline futils::file::file_result cout_hook(futils::wrap::UtfOut& out, futils::view::rvec v) { 26 | if (is_worker_thread()) { 27 | worker_stdout_buffer().append(v.as_char(), v.size()); 28 | return {}; 29 | } 30 | if (worker_hook()) { 31 | return worker_hook()(out, v); 32 | } 33 | return out.write_no_hook(v); 34 | } 35 | 36 | inline futils::file::file_result cerr_hook(futils::wrap::UtfOut& out, futils::view::rvec v) { 37 | if (is_worker_thread()) { 38 | worker_stderr_buffer().append(v.as_char(), v.size()); 39 | return {}; 40 | } 41 | if (worker_hook()) { 42 | return worker_hook()(out, v); 43 | } 44 | return out.write_no_hook(v); 45 | } -------------------------------------------------------------------------------- /src/tool/src2json/test.h: -------------------------------------------------------------------------------- 1 | /*license*/ 2 | #pragma once 3 | #include 4 | #include 5 | 6 | namespace brgen::test { 7 | // simplified version of src2json 8 | // this only parse success case, otherwise throw exception 9 | std::shared_ptr src2json(FileSet& fs); 10 | } // namespace brgen::test 11 | -------------------------------------------------------------------------------- /src/tool/src2json/version.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | #include "capi.h" 4 | 5 | #ifndef BRGEN_VERSION 6 | #define BRGEN_VERSION "0.0.0 (unversioned)" 7 | #endif 8 | 9 | #ifndef SRC2JSON_VERSION 10 | #define SRC2JSON_VERSION BRGEN_VERSION 11 | #endif 12 | 13 | constexpr auto lang_version = BRGEN_VERSION; 14 | constexpr auto src2json_version = SRC2JSON_VERSION; 15 | 16 | constexpr auto exit_ok = 0; 17 | constexpr auto exit_err = 1; 18 | constexpr auto err_invalid = 2; 19 | 20 | int src2json_main(int argc, char** argv, const Capability& cap); 21 | 22 | #ifdef S2J_USE_NETWORK 23 | int network_main(const char* port, bool unsafe_escape, const Capability& cap); 24 | #endif 25 | -------------------------------------------------------------------------------- /src/tool/ssagen/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | -------------------------------------------------------------------------------- /src/tool/ssagen/ssa/compile.go: -------------------------------------------------------------------------------- 1 | package ssa 2 | 3 | import ( 4 | "github.com/on-keyday/brgen/astlib/ast2go/ast" 5 | ) 6 | 7 | type Compiler struct { 8 | ssa []*Ssa 9 | } 10 | 11 | func (c *Compiler) Compile(p *ast.Program) { 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/vm/compile.h: -------------------------------------------------------------------------------- 1 | /*license*/ 2 | #pragma once 3 | #include 4 | #include "vm.h" 5 | 6 | namespace brgen::vm { 7 | Code compile(const std::shared_ptr& prog); 8 | void print_code(futils::helper::IPushBacker<> out, const Code& code); 9 | } // namespace brgen::vm 10 | -------------------------------------------------------------------------------- /src/vm/vm2/compile.h: -------------------------------------------------------------------------------- 1 | /*license*/ 2 | #pragma once 3 | #include 4 | #include 5 | 6 | namespace brgen::vm2 { 7 | 8 | void compile(const std::shared_ptr& node, futils::binary::writer& dst); 9 | } -------------------------------------------------------------------------------- /src/writer/config.h: -------------------------------------------------------------------------------- 1 | /*license*/ 2 | #pragma once 3 | 4 | namespace brgen::writer { 5 | struct Config { 6 | bool test_main = false; 7 | bool insert_bit_pos_debug_code = false; 8 | }; 9 | } // namespace brgen::writer 10 | -------------------------------------------------------------------------------- /src/writer/context.h: -------------------------------------------------------------------------------- 1 | /*license*/ 2 | #pragma once 3 | #include "config.h" 4 | #include 5 | 6 | namespace brgen::writer { 7 | enum class WriteMode { 8 | unspec, 9 | encode, 10 | decode, 11 | }; 12 | struct Context { 13 | WriteMode mode = WriteMode::unspec; 14 | bool def_done = false; 15 | Config config; 16 | 17 | private: 18 | auto do_exchange(auto& m, auto v) { 19 | auto old = m; 20 | m = v; 21 | return futils::helper::defer([=, &m] { 22 | m = old; 23 | }); 24 | } 25 | 26 | public: 27 | auto set_write_mode(WriteMode m) { 28 | return do_exchange(mode, m); 29 | } 30 | }; 31 | } // namespace brgen::writer 32 | -------------------------------------------------------------------------------- /src/writer/writer.h: -------------------------------------------------------------------------------- 1 | /*license*/ 2 | #pragma once 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace brgen::writer { 11 | using Writer = futils::code::CodeWriter; 12 | 13 | } // namespace brgen::writer 14 | -------------------------------------------------------------------------------- /test.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | setlocal 3 | set BASE_PATH=%CD% 4 | set CTEST_OUTPUT_ON_FAILURE=1 5 | call build.bat 6 | ninja -C built/native/Debug test 7 | -------------------------------------------------------------------------------- /testkit/cmptest.json: -------------------------------------------------------------------------------- 1 | { 2 | "inputs": [ 3 | { 4 | "binary": "./example/wire_data/websocket.dat", 5 | "format_name": "Frame", 6 | "file_base": "websocket", 7 | "failure_case": false, 8 | "hex": true 9 | }, 10 | { 11 | "binary": "./example/wire_data/websocket.dat", 12 | "format_name": "Frame", 13 | "file_base": "websocket", 14 | "failure_case": true, 15 | "hex": false 16 | }, 17 | { 18 | "binary": "./example/wire_data/varint.dat", 19 | "format_name": "TestVarint", 20 | "file_base": "varint_test", 21 | "failure_case": false, 22 | "hex": true 23 | } 24 | ], 25 | "runners": [ 26 | { 27 | "file": "./testkit/cpp/config.json" 28 | }, 29 | { 30 | "file": "./testkit/go/config.json" 31 | }, 32 | { 33 | "file": "./testkit/rust/config.json" 34 | } 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /testkit/cpp/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | enable_testing() 3 | 4 | project(GeneratedCodeTest CXX) 5 | 6 | set(CMAKE_CXX_STANDARD 20) 7 | 8 | include_directories("${FUTILS_DIR}/src/include") 9 | link_directories("${FUTILS_DIR}/lib") 10 | 11 | -------------------------------------------------------------------------------- /testkit/cpp/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "suffix": "hpp", 3 | "test_template": "./testkit/cpp/test_template.cpp", 4 | "replace_file_name": "stub.hpp", 5 | "replace_struct_name": "TEST_CLASS", 6 | "build_input_name": "test.cpp", 7 | "build_output_name": "test.exe", 8 | "build_command": [ 9 | "python", 10 | "./testkit/cpp/setup.py", 11 | "$INPUT", 12 | "$OUTPUT", 13 | "$ORIGIN", 14 | "$TMPDIR", 15 | "$DEBUG" 16 | ], 17 | "run_command": ["$EXEC", "$INPUT", "$OUTPUT"] 18 | } 19 | -------------------------------------------------------------------------------- /testkit/cpp/stub.hpp: -------------------------------------------------------------------------------- 1 | //Code generated by json2cpp2 2 | #pragma once 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | struct TEST_CLASS { 11 | ::futils::view::rvec data; 12 | bool encode(::futils::binary::writer& w) const ; 13 | bool decode(::futils::binary::reader& r); 14 | }; 15 | inline bool TEST_CLASS::encode(::futils::binary::writer& w) const { 16 | if (!w.write(this->data)) { 17 | return false; 18 | } 19 | return true; 20 | } 21 | inline bool TEST_CLASS::decode(::futils::binary::reader& r) { 22 | if (r.remain().size() < 0) { 23 | return false; 24 | } 25 | if (!r.read(this->data, (r.remain().size() - 0))) { 26 | return false; 27 | } 28 | return true; 29 | } 30 | 31 | -------------------------------------------------------------------------------- /testkit/go/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "suffix": "go", 3 | "test_template": "./testkit/go/test_template.go", 4 | "replace_file_name": "stub.go", 5 | "replace_struct_name": "TEST_CLASS", 6 | "build_input_name": "test.go", 7 | "build_output_name": "test.exe", 8 | "build_command": [ 9 | "python", 10 | "./testkit/go/setup.py", 11 | "$INPUT", 12 | "$OUTPUT", 13 | "$ORIGIN", 14 | "$TMPDIR", 15 | "$DEBUG" 16 | ], 17 | "run_command": ["$EXEC", "$INPUT", "$OUTPUT"] 18 | } 19 | -------------------------------------------------------------------------------- /testkit/go/setup.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import shutil 3 | import subprocess as sp 4 | import re 5 | 6 | INPUT = sys.argv[1] 7 | OUTPUT = sys.argv[2] 8 | ORIGIN = sys.argv[3] 9 | TMPDIR = sys.argv[4] 10 | DEBUG = True if sys.argv[5] == "true" else False 11 | 12 | # replace `package xxx\n` (xxx is any string) with `package main\n` 13 | COMPILED = re.compile("package .*\n") 14 | 15 | with open(INPUT, "r") as fp: 16 | TEXT = fp.read() 17 | if DEBUG: 18 | print(INPUT, "before replace") 19 | print(TEXT) 20 | TEXT = COMPILED.sub("package main", TEXT) 21 | if DEBUG: 22 | print(INPUT, "after replace") 23 | print(TEXT) 24 | 25 | with open(INPUT, "w") as fp: 26 | fp.write(TEXT) 27 | 28 | # copy test target 29 | shutil.copyfile(ORIGIN, TMPDIR + "/target.go") 30 | CMDLINE = ["go", "build", "-o", OUTPUT, "."] 31 | print(f"Run go mod") 32 | code = sp.call( 33 | ["go", "mod", "init", "test"], 34 | stdout=sys.stdout, 35 | stderr=sys.stderr, 36 | cwd=TMPDIR, 37 | ) 38 | if code != 0: 39 | exit(code) 40 | print(f"Compiling {INPUT} to {OUTPUT} with {CMDLINE} ") 41 | code = sp.call( 42 | CMDLINE, 43 | stdout=sys.stdout, 44 | stderr=sys.stderr, 45 | cwd=TMPDIR, 46 | ) 47 | if code != 0: 48 | exit(code) 49 | -------------------------------------------------------------------------------- /testkit/go/test_class.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type TEST_CLASS struct { 4 | } 5 | 6 | func (t *TEST_CLASS) Decode(data []byte) (int, error) { 7 | return 0, nil 8 | } 9 | 10 | func (t *TEST_CLASS) Encode() ([]byte, error) { 11 | return nil, nil 12 | } 13 | -------------------------------------------------------------------------------- /testkit/go/test_template.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | "os" 6 | ) 7 | 8 | func main() { 9 | inputFile := os.Args[1] 10 | outputFile := os.Args[2] 11 | 12 | input, err := os.ReadFile(inputFile) 13 | if err != nil { 14 | log.Println(err) 15 | os.Exit(2) 16 | } 17 | 18 | var t TEST_CLASS 19 | 20 | n, err := t.Decode(input) 21 | 22 | if err != nil { 23 | log.Println(err) 24 | os.Exit(1) 25 | } 26 | 27 | if n != len(input) { 28 | log.Printf("expect length %d but actual %d", len(input), n) 29 | os.Exit(1) 30 | } 31 | 32 | enc, err := t.Encode() 33 | if err != nil { 34 | log.Println(err) 35 | os.Exit(2) 36 | } 37 | 38 | err = os.WriteFile(outputFile, enc, 0o777) 39 | if err != nil { 40 | log.Println(err) 41 | os.Exit(2) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /testkit/rust/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "test" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /testkit/rust/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "test" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | 10 | 11 | -------------------------------------------------------------------------------- /testkit/rust/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "suffix": "rs", 3 | "test_template": "./testkit/rust/src/main.rs", 4 | "replace_file_name": "stub.hpp", 5 | "replace_struct_name": "TEST_CLASS", 6 | "build_input_name": "main.rs", 7 | "build_output_name": "test.exe", 8 | "build_command": [ 9 | "python", 10 | "./testkit/rust/setup.py", 11 | "$INPUT", 12 | "$OUTPUT", 13 | "$ORIGIN", 14 | "$TMPDIR", 15 | "$DEBUG", 16 | "$CONFIG" 17 | ], 18 | "run_command": ["$EXEC", "$INPUT", "$OUTPUT"] 19 | } 20 | -------------------------------------------------------------------------------- /testkit/rust/setup.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os 3 | import subprocess as sp 4 | import pathlib as pl 5 | import shutil 6 | import platform as plt 7 | 8 | if len(sys.argv) != 7: 9 | exit(1) 10 | 11 | INPUT = sys.argv[1] 12 | OUTPUT = sys.argv[2] 13 | ORIGIN = sys.argv[3] 14 | TMPDIR = sys.argv[4] 15 | DEBUG = True if sys.argv[5] == "true" else False 16 | CONFIG = sys.argv[6] 17 | 18 | CONFIG_DIR = pl.Path(CONFIG).parent 19 | 20 | 21 | # run compiler for the test target 22 | # compiler output will be redirected to stdout and stderr 23 | os.mkdir(TMPDIR + "/src") 24 | shutil.copyfile(ORIGIN, TMPDIR + "/src/target.rs") 25 | shutil.copyfile(INPUT, TMPDIR + "/src/main.rs") 26 | shutil.copyfile( 27 | CONFIG_DIR.joinpath("Cargo.toml").absolute().as_posix(), TMPDIR + "/Cargo.toml" 28 | ) 29 | 30 | # run cargo build 31 | suffix = ".exe" if plt.system() == "Windows" else "" 32 | build_mode = "Debug" if plt.system() == "Windows" else "debug" 33 | ret = sp.call( 34 | ["cargo", "build", "--manifest-path", TMPDIR + "/Cargo.toml"], 35 | stdout=sys.stdout, 36 | stderr=sys.stderr, 37 | ) 38 | 39 | if ret != 0: 40 | exit(ret) 41 | print("Build successful") 42 | 43 | 44 | print("Copying", TMPDIR + f"/target/{build_mode}/test" + suffix, OUTPUT) 45 | shutil.copyfile(TMPDIR + f"/target/{build_mode}/test" + suffix, OUTPUT) 46 | os.chmod(OUTPUT, 0o755) 47 | exit(0) 48 | -------------------------------------------------------------------------------- /testkit/rust/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::{fs, process::ExitCode}; 2 | 3 | mod target; 4 | 5 | fn main() -> ExitCode { 6 | let args: Vec = std::env::args().collect(); 7 | let input = match std::fs::read(&args[1]) { 8 | Ok(input) => input, 9 | Err(e) => { 10 | eprintln!("Error reading file: {}", e); 11 | return ExitCode::from(2); 12 | } 13 | }; 14 | let decoded = match target::TEST_CLASS::decode_exact(&input[..]) { 15 | Ok(x) => x, 16 | Err(e) => { 17 | eprintln!("Error decoding: {}", e); 18 | return ExitCode::from(1); 19 | } 20 | }; 21 | let mut output = Vec::new(); 22 | match decoded.encode(&mut output) { 23 | Ok(_) => (), 24 | Err(e) => { 25 | eprintln!("Error encoding: {}", e); 26 | return ExitCode::from(2); 27 | } 28 | } 29 | fs::write(&args[2], &output).unwrap(); 30 | ExitCode::from(0) 31 | } 32 | -------------------------------------------------------------------------------- /web/dev/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "@monaco-editor/react": "^4.6.0", 4 | "@types/emscripten": "^1.39.8", 5 | "@types/node": "^22.0.0", 6 | "assert": "^2.1.0", 7 | "ast2ts": "file:../../astlib/ast2ts/out", 8 | "destyle.css": "^4.0.0", 9 | "highlight.js": "^11.9.0", 10 | "json2rust": "file:../../src/tool/json2rust/pkg", 11 | "monaco-editor": "^0.52.0", 12 | "puppeteer": "^24.0.0", 13 | "react": "^19.0.0", 14 | "react-dom": "^19.0.0", 15 | "vscode-languageserver": "^9.0.1", 16 | "wasm-loader": "^1.3.0" 17 | }, 18 | "devDependencies": { 19 | "@types/react": "^19.0.0", 20 | "@types/react-dom": "^19.0.0", 21 | "css-loader": "^7.0.0", 22 | "style-loader": "^4.0.0", 23 | "webpack": "^5.94.0", 24 | "webpack-bundle-analyzer": "^4.10.1", 25 | "webpack-cli": "^6.0.0" 26 | }, 27 | "scripts": { 28 | "build": "tsc & webpack" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /web/dev/src/compiler-explorer/api.ts: -------------------------------------------------------------------------------- 1 | import { Configuration } from "./types" 2 | 3 | export const compileCpp = async (sourceCode :string) => { 4 | let config :Configuration = { 5 | source: sourceCode, 6 | options: { 7 | userArguments: "-O3 --std=c++20", 8 | compilerOptions: { 9 | skipAsm: false, 10 | executorRequest: false 11 | }, 12 | filters: { 13 | binary: false, 14 | binaryObject: false, 15 | commentOnly: false, 16 | demangle: false, 17 | directives: false, 18 | execute: false, 19 | intel: false, 20 | labels: false, 21 | libraryCode: false, 22 | trim: false, 23 | debugCalls: false 24 | }, 25 | tools: [], 26 | libraries: [] 27 | }, 28 | lang: "c++", 29 | allowStoreCodeDebug: false 30 | } 31 | console.log(config); 32 | const compiler = "clang1701"; 33 | const compilerExplorerUrl = `https://godbolt.org/api/compiler/${compiler}/compile`; 34 | const response = await fetch(compilerExplorerUrl , { 35 | method: "POST", 36 | headers: { 37 | "Content-Type": "application/json", 38 | "Accept": "application/json" 39 | }, 40 | body: JSON.stringify(config) 41 | }); 42 | return await response.json(); 43 | } -------------------------------------------------------------------------------- /web/dev/src/compiler-explorer/types.ts: -------------------------------------------------------------------------------- 1 | export interface CompilerOptions { 2 | skipAsm: boolean; 3 | executorRequest: boolean; 4 | } 5 | 6 | export interface Filters { 7 | binary: boolean; 8 | binaryObject: boolean; 9 | commentOnly: boolean; 10 | demangle: boolean; 11 | directives: boolean; 12 | execute: boolean; 13 | intel: boolean; 14 | labels: boolean; 15 | libraryCode: boolean; 16 | trim: boolean; 17 | debugCalls: boolean; 18 | } 19 | 20 | export interface Tool { 21 | id: string; 22 | args: string; 23 | } 24 | 25 | export interface Library { 26 | id: string; 27 | version: string; 28 | } 29 | 30 | export interface Options { 31 | userArguments: string; 32 | compilerOptions: CompilerOptions; 33 | filters: Filters; 34 | tools: Tool[]; 35 | libraries: Library[]; 36 | } 37 | 38 | export interface Configuration { 39 | source: string; 40 | options: Options; 41 | lang?: string; 42 | allowStoreCodeDebug: boolean; 43 | } 44 | -------------------------------------------------------------------------------- /web/dev/src/cpp_include.ts: -------------------------------------------------------------------------------- 1 | import { clear } from "console"; 2 | 3 | 4 | const RAW_GIT_URL='https://raw.githubusercontent.com/on-keyday/utils/main/src/include' 5 | 6 | const fetchRawGitContent = async (path :string,progress :(t:string)=>void) => { 7 | const url = `${RAW_GIT_URL}/${path}`; 8 | const timer = setTimeout(() => { 9 | progress(path); 10 | },100); 11 | let res = await fetch(url); 12 | if(!res.ok) { 13 | clearTimeout(timer); 14 | throw new Error(`failed to fetch ${url}`); 15 | } 16 | const source = await res.text(); 17 | clearTimeout(timer); 18 | return source; 19 | } 20 | 21 | const resolveInclude = async (text :string,progress :(path :string)=>void,included:string[] = []):Promise => { 22 | const include = /#include\s*<(.*\/.*)>/g; 23 | const matched = include.exec(text); 24 | if(!matched) return text; 25 | const path = matched[1]; 26 | if(included.includes(path)) { 27 | console.log("duplicated include",path) 28 | const replaced = text.replace(matched[0],''); 29 | return await resolveInclude(replaced,progress,included); 30 | } 31 | const content = await fetchRawGitContent(path,progress); 32 | const removePragmaOnce = content.replace("#pragma once",''); 33 | const replaced = text.replace(matched[0], removePragmaOnce); 34 | return await resolveInclude(replaced,progress, [...included, path]); 35 | } 36 | 37 | export {resolveInclude,RAW_GIT_URL} 38 | -------------------------------------------------------------------------------- /web/dev/src/s2j/dummy_fs.ts: -------------------------------------------------------------------------------- 1 | import { MyEmscriptenModule } from "./emscripten_mod" 2 | 3 | export const fetchImportFile = async(mod :MyEmscriptenModule,sourceCode :string) => { 4 | const regex = /config\s*\.\s*import\s*\(.*\"(.*)\".*\)/g 5 | const matched = sourceCode.matchAll(regex); 6 | for(const match of matched) { 7 | const path = match[1]; 8 | const check = decodeURIComponent(path); 9 | if(!check.endsWith(".bgn")|| check.includes("..")){ 10 | continue; 11 | } 12 | const p = await fetch("../example/"+path); 13 | if(!p.ok){ 14 | continue; // ignore non exist file 15 | } 16 | const text = await p.text(); 17 | console.log("write",path); 18 | mod.FS.writeFile(path,text); 19 | } 20 | const actualOpen = mod.FS.open 21 | mod.FS.open = (path :string,...args) => { 22 | console.log("open",path); 23 | const got = actualOpen(path,...args); 24 | console.log("got",got); 25 | return got; 26 | } 27 | const actualMmap = mod.FS.mmap 28 | mod.FS.mmap = (...args) => { 29 | console.log("mmap",args); 30 | const got = actualMmap(...args); 31 | console.log("got",got); 32 | return got; 33 | } 34 | const actualStat = mod.FS.stat 35 | mod.FS.stat = (path :string) => { 36 | console.log("stat",path); 37 | const got = actualStat(path); 38 | console.log("got",got); 39 | return got; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /web/dev/src/s2j/emscripten_mod.ts: -------------------------------------------------------------------------------- 1 | /// 2 | export interface MyEmscriptenModule extends EmscriptenModule { 3 | ccall: typeof ccall; 4 | FS :typeof FS 5 | } 6 | 7 | -------------------------------------------------------------------------------- /web/dev/src/s2j/file_select.ts: -------------------------------------------------------------------------------- 1 | 2 | import * as stub from "./inputServiceStub.js" 3 | 4 | 5 | 6 | 7 | export interface FileCandidates { 8 | placeHolder :string; 9 | candidates :string[]; 10 | } 11 | 12 | const registerFileSelectionCallback = (candidates :()=>Promise,select :(p :string)=>void) => { 13 | stub.cacheRef.fileCandidates = candidates; 14 | stub.cacheRef.fileSelected = (a: any) => { 15 | select(a?.id); 16 | }; 17 | } 18 | 19 | export {registerFileSelectionCallback} 20 | -------------------------------------------------------------------------------- /web/dev/src/s2j/job_mgr.ts: -------------------------------------------------------------------------------- 1 | 2 | import {JobRequest,JobResult, RequestLanguage } from "./msg.js"; 3 | 4 | export type TraceID = number|null; 5 | export class JobManager { 6 | #worker :Worker; 7 | #resolverMap = new Map void, reject : (reason :any) => void}>(); 8 | #jobID = 0; 9 | constructor(worker :Worker){ 10 | this.#worker = worker; 11 | this.#worker.onmessage = this.#onmessage.bind(this); 12 | this.#worker.onerror = this.#onerror.bind(this); 13 | } 14 | 15 | #onerror(e :ErrorEvent) { 16 | console.error(e); 17 | } 18 | 19 | #onmessage(e :MessageEvent) { 20 | const msg = e.data as JobResult; 21 | const resolver = this.#resolverMap.get(msg.jobID); 22 | if(resolver){ 23 | this.#resolverMap.delete(msg.jobID); 24 | if(msg.code===0){ 25 | resolver.resolve(msg); 26 | }else{ 27 | resolver.reject(msg); 28 | } 29 | } 30 | } 31 | 32 | getRequest(traceID :TraceID,lang :RequestLanguage,sourceCode :string) :JobRequest { 33 | const id = this.#jobID; 34 | this.#jobID++; 35 | const req :JobRequest = { 36 | lang, 37 | traceID, 38 | jobID :id, 39 | sourceCode 40 | }; 41 | return req; 42 | } 43 | 44 | doRequest(req :JobRequest) :Promise { 45 | return new Promise((resolve,reject) => { 46 | this.#resolverMap.set(req.jobID,{resolve,reject}); 47 | this.#worker.postMessage(req); 48 | }); 49 | } 50 | } -------------------------------------------------------------------------------- /web/dev/src/s2j/request_queue.ts: -------------------------------------------------------------------------------- 1 | 2 | import { JobRequest, JobResult } from "./msg" 3 | 4 | export class RequestQueue { 5 | readonly #msgQueue: JobRequest[] = []; 6 | handler: ()=>void = ()=>{}; 7 | 8 | constructor(requestHandler: ()=>void) { 9 | globalThis.onmessage = this.#onmessage.bind(this); 10 | this.handler = requestHandler; 11 | } 12 | 13 | #onmessage(e :MessageEvent) { 14 | this.#postRequest(e.data as JobRequest); 15 | this.handler(); 16 | } 17 | 18 | #postRequest(ev: JobRequest) { 19 | console.time(`msg queueing ${ev.traceID}.${ev.jobID}`) 20 | this.#msgQueue.push(ev); 21 | } 22 | 23 | repostRequest(ev: JobRequest) { 24 | console.timeEnd(`msg handling ${ev.traceID}.${ev.jobID}`) // cancel previous 25 | console.log(`requeueing ${ev.traceID}.${ev.jobID}`) 26 | console.time(`msg queueing ${ev.traceID}.${ev.jobID}`) 27 | this.#msgQueue.push(ev); 28 | } 29 | 30 | popRequest(): JobRequest | undefined { 31 | const r = this.#msgQueue.shift(); 32 | if(r !== undefined){ 33 | console.timeEnd(`msg queueing ${r.traceID}.${r.jobID}`) 34 | console.time(`msg handling ${r.traceID}.${r.jobID}`) 35 | } 36 | return r; 37 | } 38 | 39 | postResult(msg: JobResult) { 40 | console.timeEnd(`msg handling ${msg.traceID}.${msg.jobID}`) 41 | console.time(`msg posting ${msg.traceID}.${msg.jobID}`) 42 | //this.#postQueue.push(msg); 43 | globalThis.postMessage(msg); 44 | console.timeEnd(`msg posting ${msg.traceID}.${msg.jobID}`) 45 | } 46 | } -------------------------------------------------------------------------------- /web/dev/src/s2j/update.tsx: -------------------------------------------------------------------------------- 1 | import { JobResult } from "./msg"; 2 | 3 | export class UpdateTracer{ 4 | #traceID: number = 0; 5 | getTraceID(){ 6 | return ++this.#traceID; 7 | } 8 | editorAlreadyUpdated (s :JobResult) { 9 | if(this.#traceID !== s.traceID){ 10 | console.log(`already updated traceID: ${s.traceID} jobID: ${s.jobID}`); 11 | return true; 12 | } 13 | return false; 14 | } 15 | }; 16 | -------------------------------------------------------------------------------- /web/dev/src/s2j/worker/bmgen/bmgen_worker.ts: -------------------------------------------------------------------------------- 1 | import * as bmgen from "../../../lib/bmgen/bmgen.js"; 2 | import { JobRequest, RequestLanguage } from "../../msg.js"; 3 | import { EmWorkContext} from "../../em_work_ctx.js"; 4 | import { MyEmscriptenModule } from "../../emscripten_mod.js"; 5 | 6 | const bmgenModule = bmgen.default as EmscriptenModuleFactory; 7 | 8 | const requestCallback = (e:JobRequest, m:MyEmscriptenModule) => { 9 | switch (e.lang) { 10 | case RequestLanguage.BINARY_MODULE: 11 | m.FS.writeFile("/editor.json", e.sourceCode); 12 | if(e.arguments?.includes("--print-instructions")) { 13 | return ["bmgen","-i", "/editor.json"]; 14 | } 15 | else { 16 | return ["bmgen","-i", "/editor.json","--base64","-o","-"]; 17 | } 18 | default: 19 | return new Error("unknown message type"); 20 | } 21 | } 22 | 23 | const bmgenWorker = new EmWorkContext(bmgenModule,requestCallback, () => { 24 | console.log("bmgen worker is ready"); 25 | }); 26 | 27 | -------------------------------------------------------------------------------- /web/dev/src/s2j/worker/bmgen/util.ts: -------------------------------------------------------------------------------- 1 | export const base64ToUint8Array = (base64: string) => { 2 | const base64Characters = 3 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; 4 | //const base64URLCharacters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_'; 5 | 6 | let cleanedBase64 = base64.replace(/-/g, "+").replace(/_/g, "/").trim(); 7 | const padding = (4 - (cleanedBase64.length % 4)) % 4; 8 | cleanedBase64 += "=".repeat(padding); 9 | 10 | const rawLength = cleanedBase64.length; 11 | const decodedLength = (rawLength * 3) / 4 - padding; 12 | 13 | const uint8Array = new Uint8Array(decodedLength); 14 | 15 | let byteIndex = 0; 16 | for (let i = 0; i < rawLength; i += 4) { 17 | const encoded1 = base64Characters.indexOf(cleanedBase64[i]); 18 | const encoded2 = base64Characters.indexOf(cleanedBase64[i + 1]); 19 | const encoded3 = base64Characters.indexOf(cleanedBase64[i + 2]); 20 | const encoded4 = base64Characters.indexOf(cleanedBase64[i + 3]); 21 | 22 | if(encoded1 < 0 || encoded2 < 0 || encoded3 < 0 || encoded4 < 0) { 23 | return new Error("invalid base64 string"); 24 | } 25 | 26 | const decoded1 = (encoded1 << 2) | (encoded2 >> 4); 27 | const decoded2 = ((encoded2 & 15) << 4) | (encoded3 >> 2); 28 | const decoded3 = ((encoded3 & 3) << 6) | encoded4; 29 | 30 | uint8Array[byteIndex++] = decoded1; 31 | if (encoded3 !== 64) uint8Array[byteIndex++] = decoded2; 32 | if (encoded4 !== 64) uint8Array[byteIndex++] = decoded3; 33 | } 34 | 35 | return uint8Array; 36 | }; 37 | -------------------------------------------------------------------------------- /web/dev/src/s2j/worker/json2c_worker.ts: -------------------------------------------------------------------------------- 1 | import * as json2c from "../../lib/json2c.js"; 2 | import { JobRequest, RequestLanguage } from "../msg.js"; 3 | import { EmWorkContext} from "../em_work_ctx.js"; 4 | import { MyEmscriptenModule } from "../emscripten_mod.js"; 5 | 6 | 7 | const json2cModule = json2c.default as EmscriptenModuleFactory; 8 | 9 | 10 | const requestCallback = (e:JobRequest, m:MyEmscriptenModule) => { 11 | switch (e.lang) { 12 | case RequestLanguage.C: 13 | m.FS.writeFile("/editor.json", e.sourceCode); 14 | return ["json2c", "/editor.json", "--no-color"]; 15 | default: 16 | return new Error("unknown message type"); 17 | } 18 | } 19 | 20 | 21 | const j2c_ctx = new EmWorkContext(json2cModule,requestCallback, () => { 22 | console.log("json2c worker is ready"); 23 | }); -------------------------------------------------------------------------------- /web/dev/src/s2j/worker/json2cpp2_worker.ts: -------------------------------------------------------------------------------- 1 | import * as json2cpp2 from "../../lib/json2cpp2.js"; 2 | import { JobRequest, RequestLanguage } from "../msg.js"; 3 | import { EmWorkContext} from "../em_work_ctx.js"; 4 | import { MyEmscriptenModule } from "../emscripten_mod.js"; 5 | 6 | const json2cpp2Module = json2cpp2.default as EmscriptenModuleFactory; 7 | 8 | const requestCallback = (e:JobRequest, m:MyEmscriptenModule) => { 9 | switch (e.lang) { 10 | case RequestLanguage.CPP: 11 | m.FS.writeFile("/editor.json", e.sourceCode); 12 | return ["json2cpp2", "/editor.json", "--no-color"]; 13 | default: 14 | return new Error("unknown message type"); 15 | } 16 | } 17 | 18 | const j2c2_ctx = new EmWorkContext(json2cpp2Module,requestCallback, () => { 19 | console.log("json2cpp2 worker is ready"); 20 | }); 21 | 22 | -------------------------------------------------------------------------------- /web/dev/src/s2j/worker/json2go_worker.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | export { }; 4 | 5 | import { JobRequest, RequestLanguage } from "../msg.js"; 6 | import { GoWorkContext} from "../go_work_ctx.js"; 7 | 8 | 9 | 10 | 11 | const requestCallback = (e:JobRequest) => { 12 | switch (e.lang) { 13 | case RequestLanguage.GO: 14 | return e.sourceCode; 15 | default: 16 | return new Error("unknown message type"); 17 | } 18 | } 19 | 20 | 21 | const j2go_ctx = new GoWorkContext( 22 | fetch(new URL("../../lib/json2go.wasm",import.meta.url)).then((r) => r.arrayBuffer()), 23 | requestCallback, () => { 24 | console.log("json2go worker is ready"); 25 | }); -------------------------------------------------------------------------------- /web/dev/src/s2j/worker/json2kaitai_worker.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | export { }; 4 | 5 | import { JobRequest, RequestLanguage } from "../msg.js"; 6 | import { GoWorkContext} from "../go_work_ctx.js"; 7 | 8 | 9 | 10 | 11 | const requestCallback = (e:JobRequest) => { 12 | switch (e.lang) { 13 | case RequestLanguage.KAITAI_STRUCT: 14 | return e.sourceCode; 15 | default: 16 | return new Error("unknown message type"); 17 | } 18 | } 19 | 20 | 21 | const j2go_ctx = new GoWorkContext( 22 | fetch(new URL("../../lib/json2kaitai.wasm",import.meta.url)).then((r) => r.arrayBuffer()), 23 | requestCallback, () => { 24 | console.log("json2go worker is ready"); 25 | }); -------------------------------------------------------------------------------- /web/dev/src/s2j/worker/json2rust_worker.ts: -------------------------------------------------------------------------------- 1 | 2 | import _wbg_init, { InitOutput, json2rust } from "json2rust" 3 | import { JobRequest, JobResult } from "../msg"; 4 | 5 | let _mod :InitOutput | null = null; 6 | 7 | const getWasmModule = async () => { 8 | if (_mod) return _mod; 9 | const mod = await _wbg_init(); 10 | if(_mod !== null) return _mod; 11 | _mod = mod; 12 | return _mod; 13 | } 14 | 15 | globalThis.onmessage = async(ev) => { 16 | const data = ev.data as JobRequest; 17 | await getWasmModule(); 18 | try { 19 | const result = json2rust(data.sourceCode); 20 | const res :JobResult = { 21 | lang: data.lang, 22 | jobID: data.jobID, 23 | traceID: data.traceID, 24 | originalSourceCode: data.sourceCode, 25 | code: 0, 26 | stdout: result, 27 | stderr: "" 28 | } 29 | globalThis.postMessage(res); 30 | } catch(e) { 31 | console.error(e) 32 | const res :JobResult = { 33 | lang: data.lang, 34 | jobID: data.jobID, 35 | traceID: data.traceID, 36 | originalSourceCode: data.sourceCode, 37 | code: 1, 38 | stdout: "", 39 | stderr: (e as any).toString() 40 | } 41 | globalThis.postMessage(res); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /web/dev/src/s2j/worker/json2ts_worker.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | import * as json2ts from "../../lib/json2ts.js"; 4 | import { JobRequest, RequestLanguage } from "../msg.js"; 5 | import { EmWorkContext} from "../em_work_ctx.js"; 6 | import { MyEmscriptenModule } from "../emscripten_mod.js"; 7 | 8 | 9 | const json2tsModule = json2ts.default as EmscriptenModuleFactory; 10 | 11 | 12 | const requestCallback = (e:JobRequest, m:MyEmscriptenModule) => { 13 | switch (e.lang) { 14 | case RequestLanguage.TYPESCRIPT: 15 | m.FS.writeFile("/editor.json", e.sourceCode); 16 | return ["json2ts", "/editor.json", "--no-color"]; 17 | default: 18 | return new Error("unknown message type"); 19 | } 20 | }; 21 | 22 | const j2ts_ctx = new EmWorkContext(json2tsModule,requestCallback, () => { 23 | console.log("json2ts worker is ready"); 24 | }); 25 | 26 | -------------------------------------------------------------------------------- /web/dev/src/s2j/worker/src2json_worker.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | export { }; 4 | 5 | import * as src2json from "../../lib/src2json.js"; 6 | import { RequestLanguage, JobRequest } from "../msg.js"; 7 | import { EmWorkContext} from "../em_work_ctx.js"; 8 | import { MyEmscriptenModule } from "../emscripten_mod.js"; 9 | import { fetchImportFile } from "../dummy_fs.js"; 10 | 11 | 12 | 13 | const src2jsonModule = src2json.default as EmscriptenModuleFactory; 14 | 15 | 16 | const requestCallback = async (e:JobRequest, m:MyEmscriptenModule) => { 17 | switch(e.lang) { 18 | case RequestLanguage.JSON_AST: 19 | await fetchImportFile(m,e.sourceCode); 20 | return ["src2json","--argv",e.sourceCode,"--no-color","--print-json","--print-on-error"]; 21 | case RequestLanguage.JSON_DEBUG_AST: 22 | await fetchImportFile(m,e.sourceCode); 23 | return ["src2json","--argv",e.sourceCode,"--no-color","--print-json","--print-on-error","--debug-json"]; 24 | case RequestLanguage.TOKENIZE: 25 | return ["src2json","--argv",e.sourceCode,"--no-color","--print-json","--print-on-error","--lexer"]; 26 | default: 27 | return new Error("unknown message type"); 28 | } 29 | } 30 | 31 | const ctx = new EmWorkContext(src2jsonModule,requestCallback,() => { 32 | console.log("src2json worker is ready") 33 | }); 34 | 35 | 36 | -------------------------------------------------------------------------------- /web/dev/src/save-data/save.ts: -------------------------------------------------------------------------------- 1 | 2 | export const save =async (baseUrl :string,sourceCode :string,config :any) => { 3 | const data = JSON.stringify({ 4 | sourceCode, 5 | config 6 | }); 7 | return await fetch(`${baseUrl}/save`,{ 8 | method: 'POST', 9 | body: data, 10 | headers: { 11 | 'Content-Type': 'application/json' 12 | } 13 | }).then(response => { 14 | if (!response.ok) { 15 | throw new Error('not saved correctly'); 16 | } 17 | return; 18 | }) 19 | } 20 | 21 | export const load = async (baseUrl :string) => { 22 | return await fetch(`${baseUrl}/load`).then(response => { 23 | if (!response.ok) { 24 | throw new Error('not loaded correctly'); 25 | } 26 | return response.json() as Promise<{sourceCode: string, config: any}>; 27 | }) 28 | } 29 | -------------------------------------------------------------------------------- /web/dev/src/types.ts: -------------------------------------------------------------------------------- 1 | export const enum ElementID { 2 | CONTAINER1 = "container1", 3 | CONTAINER2 = "container2", 4 | TITLE_BAR = "title_bar", 5 | LANGUAGE_SELECT = "language-select", 6 | COPY_BUTTON = "copy-button", 7 | GITHUB_LINK = "github-link", 8 | BALL = "ball", 9 | BALL_BOUND = "ball-bound", 10 | INPUT_LIST = "input-list", 11 | } 12 | 13 | export const enum ConfigKey { 14 | COMMON_FILE_NAME ="file_name", 15 | COMMON_SAVE_LOCATION = "save_url", 16 | CPP_SOURCE_MAP = "source_map", 17 | CPP_EXPAND_INCLUDE = "expand_include", 18 | CPP_USE_ERROR = "use_error", 19 | CPP_USE_RAW_UNION = "use_raw_union", 20 | CPP_CHECK_OVERFLOW = "check_overflow", 21 | CPP_COMPILE_VIA_API = "compile_via_api", 22 | CPP_USE_CONSTEXPR = "use_constexpr", 23 | CPP_ENUM_STRINGER = "enum_stringer", 24 | CPP_ADD_VISIT = "add_visit", 25 | GO_OMIT_MUST_ENCODE = "omit_must_encode", 26 | GO_OMIT_DECODE_EXACT = "omit_decode_exact", 27 | GO_OMIT_VISITOR= "omit_visitors", 28 | GO_OMIT_MARSHAL_JSON = "omit_marshal_json", 29 | TS_JAVASCRIPT = "javascript", 30 | C_MULTI_FILE = "multi_file", 31 | C_OMIT_ERROR_CALLBACK = "omit_error", 32 | C_USE_MEMCPY = "use_memcpy", 33 | C_ZERO_COPY = "zero_copy", 34 | 35 | BM_PRINT_INSTRUCTION = "print_instruction", 36 | RUST2_USE_ASYNC = "use_async", 37 | RUST2_USE_COPY_ON_WRITE_VEC = "copy_on_write_vec", 38 | } -------------------------------------------------------------------------------- /web/dev/stub/bmgen/bm2cpp.js: -------------------------------------------------------------------------------- 1 | export default function bmgen() { 2 | throw new Error("Not implemented"); 3 | } 4 | -------------------------------------------------------------------------------- /web/dev/stub/bmgen/bm2rust.js: -------------------------------------------------------------------------------- 1 | export default function bmgen() { 2 | throw new Error("Not implemented"); 3 | } 4 | -------------------------------------------------------------------------------- /web/dev/stub/bmgen/bm_caller.js: -------------------------------------------------------------------------------- 1 | export const BM_LANGUAGES = []; 2 | 3 | export const generateBMCode = (ui, traceID, lang, sourceCode) => {}; 4 | 5 | export const setBMUIConfig = (config) => {}; 6 | 7 | export const BM_LSP_LANGUAGES = {}; 8 | -------------------------------------------------------------------------------- /web/dev/stub/bmgen/bmgen.js: -------------------------------------------------------------------------------- 1 | export default function bmgen() { 2 | throw new Error("Not implemented"); 3 | } 4 | -------------------------------------------------------------------------------- /web/dev/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2022", 4 | "module": "ES2022", 5 | "sourceMap": true, 6 | "outDir": "./out", 7 | "rootDir": "./src", 8 | "allowJs": true, 9 | "strict": true, 10 | "lib": ["ES2022","DOM"], 11 | "paths": {}, 12 | "moduleResolution": "Node", 13 | "jsx": "react-jsx" 14 | }, 15 | "include": ["**/*.ts", "**/*.tsx"], 16 | } -------------------------------------------------------------------------------- /web/dev/wasmCopy.js.txt: -------------------------------------------------------------------------------- 1 | const { copyFile } = require("fs"); 2 | const path = require("path"); 3 | const copyWasm = (p) => { 4 | copyFile( 5 | path.resolve(__dirname, "src/lib/", p), 6 | path.resolve(__dirname, "out/lib/", p), 7 | (err) => { 8 | if (err) { 9 | console.log(err); 10 | } 11 | } 12 | ); 13 | }; 14 | 15 | copyWasm("src2json.wasm"); 16 | //copyWasm("json2cpp.wasm"); 17 | copyWasm("json2cpp2.wasm"); 18 | copyWasm("json2go.wasm"); 19 | copyWasm("json2c.wasm"); 20 | copyWasm("json2ts.wasm"); 21 | copyWasm("json2kaitai.wasm"); 22 | 23 | // for rebrgen 24 | copyWasm("bmgen/bmgen.wasm"); 25 | -------------------------------------------------------------------------------- /web/dev/webpack.config.js: -------------------------------------------------------------------------------- 1 | const process = require("process"); 2 | const path = require("path"); 3 | 4 | require("./wasmCopy"); 5 | 6 | let mode = "development"; 7 | if (process.env.WEB_PRODUCTION === "production") { 8 | mode = "production"; 9 | } 10 | 11 | module.exports = { 12 | mode: mode, 13 | entry: path.resolve(__dirname, "out/index.js"), 14 | resolve: { 15 | extensions: [".ts", ".tsx", ".js"], 16 | }, 17 | module: { 18 | rules: [ 19 | { 20 | test: /\.(ts|tsx)$/, 21 | loader: "ts-loader", 22 | }, 23 | { 24 | test: /\.css$/, 25 | use: ["style-loader", "css-loader"], 26 | }, 27 | ], 28 | }, 29 | output: { 30 | filename: "index.js", 31 | path: path.resolve(__dirname, "../public/script"), 32 | assetModuleFilename: "[name][ext]", 33 | }, 34 | stats: { 35 | errorDetails: true, 36 | }, 37 | }; 38 | 39 | if (mode === "development") { 40 | module.exports.devtool = "hidden-source-map"; 41 | } 42 | -------------------------------------------------------------------------------- /web/doc/.hugo_build.lock: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/on-keyday/brgen/950489741469a370ab244f44f59ae6732914cb37/web/doc/.hugo_build.lock -------------------------------------------------------------------------------- /web/doc/archetypes/default.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = '{{ replace .File.ContentBaseName "-" " " | title }}' 3 | date = {{ .Date }} 4 | draft = true 5 | +++ 6 | -------------------------------------------------------------------------------- /web/doc/content/_index.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = 'Brgen Document' 3 | date = 2023-12-29T13:20:08+09:00 4 | draft = false 5 | +++ 6 | 7 | # Brgen Document 8 | 9 | brgen - BinaRy encoder/decoder GENerator のドキュメントです 10 | 11 | TODO(on-keyday): ドキュメント整備 12 | 13 | [開発ページ(GitHub)](https://github.com/on-keyday/brgen) 14 | 15 | [Web Playground](https://on-keyday.github.io/brgen) 16 | 17 | [Overview](https://on-keyday.github.io/brgen/doc/docs/overview) 18 | [Setup](https://on-keyday.github.io/brgen/doc/docs/setup) 19 | 20 | ドキュメントに間違いを見つけた場合や追加したい場合は GitHub Issue で報告するか、修正して Pull Request をしてください。 21 | PR する場合はブランチ名に`doc/`というプリフィックスをつけてください。 22 | -------------------------------------------------------------------------------- /web/doc/content/docs/change.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Language Change" 3 | weight: 1 4 | # bookFlatSection: false 5 | # bookToc: true 6 | # bookHidden: false 7 | # bookCollapseSection: false 8 | # bookComments: false 9 | # bookSearchExclude: false 10 | --- 11 | 12 | # 言語仕様変更記録 13 | 14 | 言語仕様の変更記録 (24/02/07 ~) 15 | 16 | # 24/01/23 (転記) 17 | 18 | - resolve_primitive_cast を parser の機能に移動、それに伴い --not-resolve-cast オプションを 削除 19 | 20 | ## 24/02/07 21 | 22 | - const_variable を immutable_variable に変更 23 | - 語の意味の明確化 24 | 25 | ## 24/3/?? 26 | 27 | - loop 文を for 文に 28 | - for 文に for in 構文を追加 29 | 30 | ## 24/5 31 | 32 | - match 文の条件節において`,`を使ったものを特別扱いする構文を追加 33 | -------------------------------------------------------------------------------- /web/doc/content/docs/for_ai.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "For AI write" 3 | weight: 1 4 | # bookFlatSection: false 5 | # bookToc: true 6 | # bookHidden: false 7 | # bookCollapseSection: false 8 | # bookComments: false 9 | # bookSearchExclude: false 10 | --- 11 | 12 | # For AI write 13 | 14 | 生成系 AI に brgen フォーマットで書かせるためのテンプレート(TODO(on-keyday): お試し、要改善) 15 | 16 | ## 仕様ベース 17 | 18 | ``` 19 | 上記の仕様を元に以下の形式でフォーマットを記述してください。 20 | 21 | # これはコメントです 22 | format A: # これはフォーマット宣言です。Aはフォーマット名を表します。より仕様にあった名前をつけることが推奨されます。 23 | .. # フィールドが何も無い場合はインデントして`..`を書いてください 24 | 25 | format B: 26 | a :u8 # フィールドは「変数名 :型名」で定義します。これは符号なし8bit整数型のフィールドを定義しています。 27 | b :s16 # これは符号あり16ビット整数型のフィールドです。なお次に述べる例外のない限りはビッグエンディアンとして解釈します 28 | c :ul32 # これはリトルエンディアン符号なし32bit整数型のフィールドです。整数型は[us][bl]?[0-9]* 29 | 30 | format C: 31 | fixed_array :[32]u8 # これは配列型のフィールドです。この配列はバイナリデータ表現上では長さ情報を含まず単に32バイトのバイト列のみに変換されます 32 | len :u8 33 | data :[len]u8 # これも配列型です。配列型の長さには単純な数値のみでなく他のフィールドや後述する変数、四則演算やビット演算などの式を使えます。 34 | 35 | format D: 36 |   type :u8 37 | if type == 1: # これは条件分岐です。条件分岐を用いることでさまざまな 38 | len :u8 39 | else: 40 | len :u32 41 | 42 | data :[len]u32 # また条件分岐内で定義したフィールドはunionとなり、外側のスコープで使用することも可能です 43 | 44 | match type: # こちらも同じく条件分岐として使えます 45 | 1 => additional_data :u8 # =>を使った形式では単一のフィールドのみを記せます 46 | 2: # :を使った形式では複数のフィールドを記せます 47 | additional_data_len :u8 48 | additional_data :[additional_data_len]u8 49 | 50 | format E: 51 | prefix :u8 52 | data [..]u8 # これは末尾終端パターンです。この場合、dataは入力終端までのデータを表します 53 | 54 | format F: 55 | prefix :u16 56 | data :[..]u8 # このような場合、dataは末尾2バイトを除いた入力データすべてを表します 57 | authentication_code :u16 58 | 59 | ``` 60 | -------------------------------------------------------------------------------- /web/doc/content/docs/generator_dev.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Generator Dev" 3 | weight: 1 4 | # bookFlatSection: false 5 | # bookToc: true 6 | # bookHidden: false 7 | # bookCollapseSection: false 8 | # bookComments: false 9 | # bookSearchExclude: false 10 | --- 11 | 12 | # Generator の開発 13 | 14 | ジェネレーターの開発に関するメモ 15 | 16 | ジェネレーターは必ずしも brgen(lang)の全機能に対応している必要はない。 17 | このリポジトリ付属のジェネレーターはひととおりできるよう対応していくつもりではあるが、 18 | いくつかのパターンには対応できない可能性もある。 19 | その場合は、ぜひ自分でジェネレーターを書いて、その要件を満たすコードを生成できるようにしてほしい。 20 | 21 | ## 基本的な流れ 22 | 23 | 以下擬似コード 24 | 25 | ```py 26 | import ast2py as ast 27 | 28 | def generate_root(prog :ast.Program): 29 | for element in prog.elements: 30 | if isinstance(element,ast.Format): 31 | generate_format(element) 32 | 33 | def generate_format(fmt :ast.Format) 34 | generate_definition(fmt.struct_type) 35 | if fmt.encode_fn is not None: 36 | generate_encoder(fmt.encode_fn.body) 37 | else: 38 | generate_encoder(fmt.body) 39 | 40 | if fmt.decode_fn is not None: 41 | generate_decoder(fmt.decode_fn.body) 42 | else: 43 | generate_decoder(fmt.body) 44 | 45 | def generate_definition(block :ast.IndentBlock): 46 | ... 47 | ``` 48 | 49 | ## 開発用ツール 50 | 51 | core/ast/tool(C++)や ast2go/gen(Go) ディレクトリ内にいくつか便利なツールが用意されている 52 | 53 | tool/stringer.h/Stringer クラス(C++)|gen/gen.go/ExprStringer クラス(Go) - Expr 型ノードをその言語の式の文字列に変換する 54 | 55 | tool/sort.h/FormatSorter クラス - Format を AST から抽出して依存関係の順に並び替える(トポロジカルソート) 56 | 57 | ## その他メモ 58 | 59 | Union 実装時にブロックに入ったところで場合分けしたい場合、 60 | IndentBlock(もしくは ScopedStatement)の StructType が StructUnion に登録されているものになるのでそこから対応を探すというように実装するとよい。 61 | -------------------------------------------------------------------------------- /web/doc/content/docs/metadata.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Metadata" 3 | weight: 1 4 | # bookFlatSection: false 5 | # bookToc: true 6 | # bookHidden: false 7 | # bookCollapseSection: false 8 | # bookComments: false 9 | # bookSearchExclude: false 10 | --- 11 | 12 | # メタデータ 13 | 14 | ジェネレーター共通のメタデータについて述べる。 15 | 16 | ## 共通 17 | 18 | ### 元の URL のメタデータ 19 | 20 | ``` 21 | config.url = "https://example.com" 22 | ``` 23 | 24 | ### RFC を指定する。 25 | 26 | ``` 27 | config.rfc = "https://example.com/url/to/rfc" 28 | ``` 29 | 30 | `config.url`を推奨する 31 | 32 | ### 文字列マッピングを指定する 33 | 34 | 生成先コードで特別扱いしたい文字列のマッピング情報を追加する。 35 | 識別子の名前で使われる。 36 | 37 | ``` 38 | config.word.map("Id","ID") 39 | ``` 40 | 41 | ### フォーマットの順序を変更する 42 | 43 | C++などコード生成時に言語が識別子の宣言順序を厳密に気にするような言語(~~C か C++くらいしかもはやそんな言語は存在しないが~~)のために 44 | ジェネレーター側でトポロジカルソートもどきで順序をソートしているが、再帰的な型などはどうしても正しい順序で生成できないことがあるためそれを補正するためのもの。 45 | 46 | ``` 47 | format After: 48 | config.order.after = "Object" 49 | y :Object 50 | 51 | format Object: 52 | x :u8 53 | ``` 54 | 55 | この場合定義が`format Object`で生成されたものの直後に挿入される 56 | 57 | ## 言語固有 58 | 59 | ### C++ 60 | 61 | #### 名前空間名を指定 62 | 63 | ``` 64 | config.cpp.namespace = "namespace name" 65 | ``` 66 | 67 | 名前空間名の整合性については保証しない 68 | 69 | #### バイト列の型を指定 70 | 71 | ``` 72 | config.cpp.bytes_type = "byte type name" 73 | ``` 74 | 75 | バイト列(`[]u8`)の型を指定。デフォルトは`::futils::view::rvec` 76 | 77 | #### 動的配列の型を指定 78 | 79 | ``` 80 | config.cpp.vector_type = "vector type" 81 | ``` 82 | 83 | 動的配列(`[]T`(T は u8 以外の任意の型))の型を指定。デフォルトは`std::vector` 84 | 85 | ### Go 86 | 87 | #### パッケージ名を指定 88 | 89 | ``` 90 | config.go.package = "package name" 91 | ``` 92 | -------------------------------------------------------------------------------- /web/doc/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/on-keyday/brgen/web/doc 2 | 3 | go 1.21 4 | 5 | require github.com/alex-shpak/hugo-book v0.0.0-20241009212754-7c78a39c531a // indirect 6 | -------------------------------------------------------------------------------- /web/doc/go.sum: -------------------------------------------------------------------------------- 1 | github.com/alex-shpak/hugo-book v0.0.0-20231204233341-118997fa920e h1:vOzQO2BCcgZ+M5W5KkhRHWiryNX/4RuA0iJprMrMUH4= 2 | github.com/alex-shpak/hugo-book v0.0.0-20231204233341-118997fa920e/go.mod h1:L4NMyzbn15fpLIpmmtDg9ZFFyTZzw87/lk7M2bMQ7ds= 3 | github.com/alex-shpak/hugo-book v0.0.0-20241009212754-7c78a39c531a h1:GiRJQYc9Bt8H59/e0w/97i46Ql39CUIdDQjHikd9scA= 4 | github.com/alex-shpak/hugo-book v0.0.0-20241009212754-7c78a39c531a/go.mod h1:L4NMyzbn15fpLIpmmtDg9ZFFyTZzw87/lk7M2bMQ7ds= 5 | -------------------------------------------------------------------------------- /web/doc/hugo.toml: -------------------------------------------------------------------------------- 1 | baseURL = 'https://on-keyday.github.io/brgen/doc' 2 | languageCode = 'en-us' 3 | title = 'Brgen Document' 4 | publishDir = '../public/doc' 5 | 6 | enableGitInfo = true 7 | 8 | [param] 9 | BookRepo = 'https://on-keyday.github.io/brgen/doc' 10 | 11 | [module] 12 | [[module.imports]] 13 | path = 'github.com/alex-shpak/hugo-book' 14 | 15 | [security] 16 | [security.funcs] 17 | getenv = ['^HUGO_', '^CI$','^RELEASE_TAG$'] 18 | -------------------------------------------------------------------------------- /web/doc/layouts/shortcodes/mermaid.html: -------------------------------------------------------------------------------- 1 | 16 | 38 | --------------------------------------------------------------------------------