Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .github/workflows/asf-allowlist.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,13 @@ name: ASF GitHub Actions Allowlist

on:
push:
paths-ignore:
- "kotoba/**"
- ".github/workflows/kotoba*.yml"
pull_request:
paths-ignore:
- "kotoba/**"
- ".github/workflows/kotoba*.yml"

permissions:
contents: read
Expand Down
14 changes: 12 additions & 2 deletions .github/workflows/build-containerized-pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,20 @@
name: Build Containerized PR Wheels
on:
pull_request:
paths: [ci/**, python/**, .github/workflows/**]
paths:
- ci/**
- python/**
- .github/workflows/**
- "!kotoba/**"
- "!.github/workflows/kotoba*.yml"
push:
branches: [main]
paths: [ci/**, python/**, .github/workflows/**]
paths:
- ci/**
- python/**
- .github/workflows/**
- "!kotoba/**"
- "!.github/workflows/kotoba*.yml"

jobs:
build:
Expand Down
14 changes: 12 additions & 2 deletions .github/workflows/build-native-pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,20 @@
name: Build Native PR Wheels
on:
pull_request:
paths: [ci/**, python/**, .github/workflows/**]
paths:
- ci/**
- python/**
- .github/workflows/**
- "!kotoba/**"
- "!.github/workflows/kotoba*.yml"
push:
branches: [main]
paths: [ci/**, python/**, .github/workflows/**]
paths:
- ci/**
- python/**
- .github/workflows/**
- "!kotoba/**"
- "!.github/workflows/kotoba*.yml"

jobs:
build-windows:
Expand Down
5 changes: 5 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
Expand Down Expand Up @@ -33,6 +33,9 @@
- "test*"
tags:
- v*
paths-ignore:
- "kotoba/**"
- ".github/workflows/kotoba*.yml"
pull_request:
paths-ignore:
- "**/*.md"
Expand All @@ -42,6 +45,8 @@
- "licenses/**"
- "DISCLAIMER"
- "NOTICE"
- "kotoba/**"
- ".github/workflows/kotoba*.yml"
types: ["opened", "reopened", "synchronize"]

permissions:
Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/clean-pr-body.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ on:
pull_request_target:
types:
- opened
paths-ignore:
- "kotoba/**"
- ".github/workflows/kotoba*.yml"

permissions:
pull-requests: write
Expand Down
42 changes: 42 additions & 0 deletions .github/workflows/kotoba.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.

name: Kotoba v1

on:
push:
paths:
- "kotoba/**"
- ".github/workflows/kotoba.yml"
pull_request:
paths:
- "kotoba/**"
- ".github/workflows/kotoba.yml"

permissions:
contents: read

jobs:
checks:
name: Header and one-record fixture
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
with:
persist-credentials: false
- name: Run Kotoba v1 checks
run: bash kotoba/checks.sh
5 changes: 5 additions & 0 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,18 @@ on:
pull_request:
branches:
- main
paths-ignore:
- "kotoba/**"
- ".github/workflows/kotoba*.yml"
push:
branches:
- main
paths:
- "**.md"
- "**.yml"
- "**.yaml"
- "!kotoba/**"
- "!.github/workflows/kotoba*.yml"

permissions:
contents: read
Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/pr-lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ on:
- opened
- edited
- synchronize
paths-ignore:
- "kotoba/**"
- ".github/workflows/kotoba*.yml"

permissions:
pull-requests: read
Expand Down
1 change: 1 addition & 0 deletions kotoba/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.cache/
62 changes: 62 additions & 0 deletions kotoba/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Kotoba v1 Fory binding

Honest v1 only. This tree is a first-class sibling of `java/`, `python/`,
`go/`, and the other runtimes **on this fork**. It is not a replacement for
those implementations and it is not robotics-ready.

The module compiles with [Kotoba](https://github.com/kotoba-lang/kotoba) CLI
**0.7.2** to `wasm32-kotoba-v1` under the `i64-v1` value profile: no FFI, no
IEEE floats, no vector or externref ABI.

## What this implements

One vendored xlang record and the Fory header bitmap that precedes it.

| Byte | Value | Meaning |
| ---- | ------ | ------------------------------------------------------ |
| 0 | `0x01` | xlang bit set; oob clear; reserved bits 2-7 zero |
| 1 | `0xFF` | `NOT_NULL_VALUE_FLAG` (root ref tracking is null-only) |
| 2 | `0x07` | `VARINT64` type id |
| 3 | `0x54` | zigzag(`42`) as a one-byte unsigned varint |

The fixture is `fixtures/varint64-42.hex`. `fory.kotoba` encodes that same
integer and decodes those same four bytes. It does not implement the rest of
the xlang serializer: no structs, collections, strings, metadata, references
beyond this null-only flag, or a general varint loop.

Layout source: `docs/specification/xlang_serialization_spec.md` (Fory header,
reference flags, type id table, signed varint64 / zigzag).

## What this is not

- Not a Java, Python, Go, Rust, or other Fory runtime.
- Not cross-language integration coverage.
- Not schema evolution, codegen, or row format.
- Not a claim that Kotoba can exchange arbitrary Fory payloads.

## Checks

`checks.sh` downloads Kotoba 0.7.2 (or uses `KOTOBA_BIN`), compiles
`fory.kotoba` to wasm, and requires a real compiler receipt:

- `value-profile` is `i64-v1`
- target is `wasm32-kotoba-v1`
- `value-abi` is `direct-v1`
- `wasm-features` is empty
- the artifact starts with wasm magic and carries `wasm32-kotoba-v1`

It then runs the module and requires runtime value `1`. The script fails if
the fixture, module comment, or byte literals drift. It does not invent a
pass.

```sh
bash kotoba/checks.sh
```

## Upstream

This binding lives on `kotoba-lang/fory`. It is not an Apache Fory release
surface. An eventual pull request to `apache/fory` may require an ASF ICLA.
This tree does not file that ICLA.

Fork operator: [awai.network](https://awai.network) / Ryo Awai.
162 changes: 162 additions & 0 deletions kotoba/checks.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
#!/usr/bin/env bash

# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.

# Compile the Kotoba v1 Fory header/record module with CLI 0.7.2 and
# assert the vendored fixture. Do not invent a pass: every gate reads
# a real compiler receipt or runtime value.

set -euo pipefail

ROOT="$(cd "$(dirname "$0")" && pwd)"
MODULE="${ROOT}/fory.kotoba"
FIXTURE="${ROOT}/fixtures/varint64-42.hex"
EXPECTED_HEX="01ff0754"

KOTOBA_VERSION="0.7.2"
KOTOBA_TARBALL="kotoba-linux-amd64.tar.gz"
KOTOBA_URL="https://github.com/kotoba-lang/kotoba/releases/download/v${KOTOBA_VERSION}/${KOTOBA_TARBALL}"
KOTOBA_SHA256="95e225461e1b8a21849b251e8c8b654693d2c8a516b258532771651e978e1977"

fail() {
echo "FAIL: $*" >&2
exit 1
}

need_cmd() {
command -v "$1" >/dev/null 2>&1 || fail "required command not found: $1"
}

need_cmd python3
need_cmd curl
need_cmd tar
need_cmd sha256sum
need_cmd grep

[[ -f "${MODULE}" ]] || fail "missing module ${MODULE}"
[[ -f "${FIXTURE}" ]] || fail "missing fixture ${FIXTURE}"

FILE_HEX="$(tr -d ' \n\t\r' <"${FIXTURE}" | tr 'A-F' 'a-f')"
[[ "${FILE_HEX}" == "${EXPECTED_HEX}" ]] || fail "fixture hex is ${FILE_HEX}, expected ${EXPECTED_HEX}"

MODULE_HEX="$(sed -n 's/^;; Vendored fixture bytes (hex): //p' "${MODULE}" | tr -d ' \n\t\r' | tr 'A-F' 'a-f')"
[[ "${MODULE_HEX}" == "${EXPECTED_HEX}" ]] || fail "module fixture comment is ${MODULE_HEX}, expected ${EXPECTED_HEX}"

python3 - "${MODULE}" "${EXPECTED_HEX}" <<'PY'
import pathlib
import re
import sys

module = pathlib.Path(sys.argv[1]).read_text()
expected = sys.argv[2]
wanted = {
"fixture-b0": "0x01",
"fixture-b1": "0xFF",
"fixture-b2": "0x07",
"fixture-b3": "0x54",
}
for name, lit in wanted.items():
if not re.search(rf"\(defn {name} \[\] {lit}\)", module):
raise SystemExit(f"module is missing ({name} {lit})")
lits = "".join(wanted[name][2:] for name in ("fixture-b0", "fixture-b1", "fixture-b2", "fixture-b3"))
if lits.lower() != expected:
raise SystemExit(f"module literals {lits.lower()} != fixture {expected}")
PY

HEADER_BYTE="$(python3 -c "print(int('${EXPECTED_HEX}'[0:2], 16))")"
[[ "${HEADER_BYTE}" == "1" ]] || fail "fixture header byte is ${HEADER_BYTE}, expected 1"

if [[ -n "${KOTOBA_BIN:-}" ]]; then
KOTOBA="${KOTOBA_BIN}"
[[ -x "${KOTOBA}" ]] || fail "KOTOBA_BIN is not executable: ${KOTOBA}"
else
CACHE="${KOTOBA_CACHE:-${ROOT}/.cache/kotoba-${KOTOBA_VERSION}}"
mkdir -p "${CACHE}"
TARBALL="${CACHE}/${KOTOBA_TARBALL}"
if [[ ! -x "${CACHE}/kotoba" ]]; then
echo "downloading Kotoba CLI ${KOTOBA_VERSION}"
curl -fsSL -o "${TARBALL}" "${KOTOBA_URL}"
echo "${KOTOBA_SHA256} ${TARBALL}" | sha256sum -c -
tar -xzf "${TARBALL}" -C "${CACHE}" kotoba
fi
KOTOBA="${CACHE}/kotoba"
[[ -x "${KOTOBA}" ]] || fail "downloaded kotoba binary missing at ${KOTOBA}"
fi

WORKDIR="$(mktemp -d)"
trap 'rm -rf "${WORKDIR}"' EXIT
WASM="${WORKDIR}/fory.wasm"
COMPILE_JSON="${WORKDIR}/compile.json"
RUN_JSON="${WORKDIR}/run.json"

echo "compile ${MODULE} with ${KOTOBA}"
"${KOTOBA}" compile "${MODULE}" --target wasm -o "${WASM}" --json >"${COMPILE_JSON}"

python3 - "${COMPILE_JSON}" "${WASM}" <<'PY'
import json
import pathlib
import sys

receipt = json.loads(pathlib.Path(sys.argv[1]).read_text())
wasm = pathlib.Path(sys.argv[2]).read_bytes()
if receipt.get("kotoba.cli/ok?") is not True:
raise SystemExit(f"compile ok? {receipt.get('kotoba.cli/ok?')}: {receipt}")
if receipt.get("kotoba.cli/code") != "emitted":
raise SystemExit(f"compile code {receipt.get('kotoba.cli/code')}: {receipt}")
data = receipt.get("kotoba.cli/data") or {}
if data.get("value-profile") != "i64-v1":
raise SystemExit(f"value-profile {data.get('value-profile')!r}, expected i64-v1")
compat = data.get("compatibility") or {}
if compat.get("target") != "wasm32-kotoba-v1":
raise SystemExit(f"target {compat.get('target')!r}, expected wasm32-kotoba-v1")
if data.get("value-abi") != "direct-v1":
raise SystemExit(f"value-abi {data.get('value-abi')!r}, expected direct-v1")
features = data.get("wasm-features") or []
if features:
raise SystemExit(f"wasm-features {features!r}, expected none for i64-v1")
if wasm[:4] != b"\x00asm":
raise SystemExit("compiled artifact is not a wasm module")
if b"wasm32-kotoba-v1" not in wasm:
raise SystemExit("compiled artifact is missing wasm32-kotoba-v1 target mark")
print("compile receipt: i64-v1 wasm32-kotoba-v1 direct-v1")
PY

echo "run ${MODULE}"
"${KOTOBA}" run "${MODULE}" --json >"${RUN_JSON}"

python3 - "${RUN_JSON}" <<'PY'
import json
import pathlib
import sys

receipt = json.loads(pathlib.Path(sys.argv[1]).read_text())
if receipt.get("kotoba.cli/ok?") is not True:
raise SystemExit(f"run ok? {receipt.get('kotoba.cli/ok?')}: {receipt}")
if receipt.get("kotoba.cli/code") != "completed":
raise SystemExit(f"run code {receipt.get('kotoba.cli/code')}: {receipt}")
data = receipt.get("kotoba.cli/data") or {}
result = data.get("kotoba.runtime/result") or {}
if result.get("kotoba.runtime/ok?") is not True:
raise SystemExit(f"runtime ok? {result.get('kotoba.runtime/ok?')}: {receipt}")
value = result.get("kotoba.runtime/value")
if value != 1:
raise SystemExit(f"runtime value {value!r}, expected 1")
print("run result: 1")
PY

echo "PASS: Kotoba v1 Fory header and VARINT64=42 fixture"
1 change: 1 addition & 0 deletions kotoba/fixtures/varint64-42.hex
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
01ff0754
Loading
Loading