C# サブセットから Lua 5.5 ソースコードへのトランスパイラ。ゲームスクリプティング向け。
Roslyn で C# を解析し、Lua のテーブル + メタテーブル OOP に変換する。 型チェックは C# コンパイラが行い、Lua 側は型消去で動作する。
- .NET 10 SDK (版は
global.jsonで固定。導入はdotnet-install.sh --jsonfile global.jsonを推奨 — distro package は workload と版がずれるため混ぜない) - CMake 3.12+ (Lua ビルド用)
- C コンパイラ (MSVC / GCC / Clang)
git clone --recursive https://github.com/neguse/tcs.git
cd tcsサブモジュールを取得し忘れた場合:
git submodule update --init --recursivedeps/lua は Lua 5.5 ソースの git submodule として固定する。
更新する場合は submodule commit を明示的に進め、deps/lua/lua -v が Lua 5.5 で始まることを run-tests で確認する。
CMake でクロスプラットフォームビルド:
cmake -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build --config ReleaseWindows (MSVC) の場合も同じ。Visual Studio の Developer Command Prompt か PowerShell で実行する。
CMake は Linux / Windows / macOS / iOS-family / Emscripten / BSD / generic Unix で Lua の compile definitions と system libs を分岐する。
ビルド成果物は deps/lua/lua (Unix) または deps/lua/lua.exe (Windows) に出力される。
dotnet testLinux:
./run-tests.shWindows (PowerShell):
.\run-tests.ps1Lua が未ビルド、CMake 入力より古い、または Lua 5.5 ではない場合は自動で cmake を呼んでビルドしてからテストを実行する。
テスト時は deps/lua/lua -v が Lua 5.5 で始まることも検証する。
run-tests は dotnet test に加え、代表 sample の tcs check、Rider helper script、analyzer-demo build の expected diagnostics、analyzer nupkg の PackageReference consumer と .editorconfig severity override を検査する。
GitHub Actions (.github/workflows/ci.yml) でも同じ gate を実行する。
NuGet package は floating version を使わず .csproj に明示 version を pin し、packages.lock.json で transitive dependency も固定する。
依存を更新する場合は対象 package version と lock file を同時に更新する。
CLI publish:
dotnet publish Transpiler/Transpiler.csproj -c Release -o publish/tcspublish 出力には runtime/tinysystem.lua が runtime/ 配下に同梱される。
通常の CLI 出力はこの runtime を読み込んで Lua prelude に埋め込むため、publish ディレクトリ単体で変換できる。
# ヘルプ / バージョン
dotnet run --project Transpiler -- --help
dotnet run --project Transpiler -- --version
# stdout に出力
dotnet run --project Transpiler -- samples/hello.cs
# ファイルに出力
dotnet run --project Transpiler -- samples/hello.cs -o out.lua-oの出力と--sourcemapのmapは、input / --ref / --preludeと
同じパスにはできない。Windows / Linux / macOSではsymlinkやhardlink等で
同じ実体を指す場合も含め、衝突時は書き込み前にエラーとなり、入力を変更しない。
衝突しない既存の出力linkはlink先へ書かず、出力entryを通常ファイルへ置換する。
既存出力が書き込み不可なら従来どおりエラーにし、Linux / macOSでは置換前の
Unix permission bitsを維持する。
CLI 生成 Lua はデフォルトで TinySystem runtime prelude を埋め込む。
List / Dict / Math / String / Random は生成物だけで利用できる。
エンジン側で runtime を供給する場合は --no-runtime を付ける。
dotnet run --project Transpiler -- samples/hello.cs -o out.lua --no-runtime--entry <Class> を付けると出力末尾に emitted 名の return を追記し、
require / dofile が class table を返す Lua module として使える
(host が module の callback を呼ぶ engine 組み込み向け)。
指定は metadata 名 (Game.App) と一意な simple 名 (App) の両方を解決し、
interface / --ref 型 / 曖昧な simple 名はエラーになる。
--module を付けると出力末尾に定義した型 (--ref を除く) の table を返す
return { Counter = Counter, ... } を追記し、ライブラリを
local m = require("lib") で読む Lua module として使える (--entry /
--snapshot とは併用しない)。
--prelude <shim.lua> は任意のユーザー Lua (host API を tcs stub の形に
橋渡しする shim など) を出力の先頭に前置する。
output / source map のパスが入力・--ref・--prelude と同じ実体
(symlink / hardlink 含む) になる場合は、書き込み前にエラーにして
入力破壊を防ぐ (watch の各 rebuild でも再検証)。
dotnet run --project Transpiler -- game.cs -o game.lua --entry Game --prelude engine-shim.lualub エンジンで動かす実例は samples/lub/ (run-lub.sh) と
doc/lub-gap-analysis.md を参照。
Lua を出力せず、C# compile error と TinyC# 準拠診断だけを返す。
警告またはエラーがあれば exit 1、問題がなければ exit 0。
TinyC#固有の例外はenumと数値整数 (charを除く) の変換・等値比較、および
互換public fieldによるinterface property facadeだけで、同じC#エラーIDの
通常の型不一致は失敗する。
Lua 出力のメンバ名は C# 名から規則で写す (BeginPass → begin_pass、enum
メンバ DontCare → DONT_CARE、--ref 型の static アクセスは
Lub.Gfx → lub.gfx)。host の wire format が snake_case なら C# 側は通常の
naming convention で書ける (規則は doc/support-matrix.md の
「Lua 出力の名前規則」)。--no-naming-check は naming convention warning
だけを抑制する。
dotnet run --project Transpiler -- check samples/hello.cs
dotnet run --project Transpiler -- check game.cs --ref engine-stub.csdotnet run --project Transpiler -- src/Player.cs src/Enemy.cs src/Game.cs -o game.lua同一 Compilation でコンパイルするので、ファイル間のクラス参照が解決される。
Lua に出力しない型チェック専用ファイルは --ref で渡す。
外部エンジン API や host 提供 API の最小 stub を置く用途。
dotnet run --project Transpiler -- game.cs --ref engine-stub.cs -o game.luaこの repo では engine 固有名に依存しない例として、
samples/host_api_game.cs と samples/host_api_stub.cs を用意している。
dotnet run --project Transpiler -- samples/host_api_game.cs --ref samples/host_api_stub.cs -o host_api_game.luadotnet run --project Transpiler -- game.cs -o game.lua --sourcemapgame.lua.map が生成される。Lua 行番号 → C# ファイル:行番号 の JSON マッピング。
runtime prelude を埋め込む通常出力でも、map の Lua 行番号は生成された .lua ファイル上の行番号に合わせて offset 済み。
.lua.map の形式:
{
"version": 1,
"mappings": {
"42": {"file": "game.cs", "line": 12}
}
}Lua runtime error の stack trace は SourceMap で注釈できる:
deps/lua/lua game.lua 2> trace.txt
dotnet run --project Transpiler -- --map-stacktrace game.lua.map trace.txttrace.txt を省略した場合は stdin から読む。SourceMap の exact 行が無い場合は直前の mapping を使う。
dotnet run --project Transpiler -- src/*.cs -o out.lua --watchsrc/*.cs は shell が展開する例。shell が glob 展開しない環境ではファイルを個別に渡す。
ファイル変更を検知して自動で再トランスパイルする。Ctrl+C で停止。
Rider などの C# IDE 上で tcs 非準拠コードを警告するための Roslyn Analyzer PoC。
現時点では struct, record struct, partial 型, lock, nameof, try/catch, throw, local function, list pattern、未対応 BCL API / 未対応 core library member、collection への null 保存を TCS1001 / TCS1002 / TCS1003 として報告する。
同じ共有ルールを tcs check と transpiler warning でも使う。
dotnet test TinyCs.Analyzers.Tests
dotnet build samples/analyzer-demo/analyzer-demo.csprojdemo project 固有の expected diagnostics と Rider 確認手順は
samples/analyzer-demo/README.md にも残している。
run-tests は analyzer nupkg を pack し、一時 project から PackageReference で参照して同じ診断が出ることと、.editorconfig で TCS1001 / TCS1002 / TCS1003 を error にした build が失敗することも検証する。
samples/analyzer-demo/verify-inspectcode.sh で JetBrains InspectCode 2026.1.3 の headless 実行でも、ProjectReference と local nupkg PackageReference consumer の両方で TCS1001 x5 / TCS1002 x1 / TCS1003 x1 が SARIF に出ることを確認できる。さらに PackageReference consumer の .editorconfig で TCS1001 / TCS1002 / TCS1003 を error にした場合、InspectCode が同じ件数の error を返すことも検証する。
通常の C# project から package として参照する場合:
dotnet pack TinyCs.Analyzers/TinyCs.Analyzers.csproj -c Release -o .nupkgs
dotnet restore your-project.csproj --source .nupkgs --source https://api.nuget.org/v3/index.json<PackageReference Include="TinyCs.Analyzers"
Version="0.1.0"
PrivateAssets="all" />NuGet 公開は当面行わず、local nupkg の配布のみとする。
TinyCs.Analyzers/TinyCs.Analyzers.csprojのPackageVersionを上げるrun-tests.sh内の consumer 検証と本 README のPackageReference例のVersionを同じ値に更新するdotnet pack TinyCs.Analyzers/TinyCs.Analyzers.csproj -c Release -o .nupkgsで再生成するbash run-tests.shを実行し、nupkg consumer build と.editorconfigseverity override の検証が通ることを確認する
repository 内で直接参照する場合:
<ProjectReference Include="..\TinyCs.Analyzers\TinyCs.Analyzers.csproj"
OutputItemType="Analyzer"
ReferenceOutputAssembly="false"
PrivateAssets="all" />.editorconfig で重要度を変更できる:
dotnet_diagnostic.TCS1001.severity = warning
dotnet_diagnostic.TCS1002.severity = error
dotnet_diagnostic.TCS1003.severity = warningRider 実機確認の手順:
- 必要なら
samples/analyzer-demo/open-rider-demo.shで pre-check 後に demo project を Rider で開く。Windows では.\samples\analyzer-demo\open-rider-demo.ps1を使う。Rider command を自動検出できない場合はTCS_RIDER_COMMAND=/path/to/rider.sh、Windows では$env:TCS_RIDER_COMMAND = "C:\path\to\rider64.exe"を指定する samples/analyzer-demo/analyzer-demo.csprojを含む solution/project を Rider で開く- Restore 後、
samples/analyzer-demo/Program.csを開く struct, local function,try,throw,values is [1, 2],System.IO.File.ReadAllText,List<string?> { null }に Roslyn inspection の squiggle が出ることを確認する- Build tool window で
TCS1001が5件、TCS1002が1件、TCS1003が1件出ることを確認する .editorconfigのdotnet_diagnostic.TCS1001/TCS1002/TCS1003.severityをerrorへ変え、Rider 表示が追従するか確認する(build 上の severity override はrun-testsで検証済み)samples/analyzer-demo/RIDER_VERIFICATION_TEMPLATE.mdに沿って、結果をq.mdに go / no-go として記録する
class, enum, interface(型チェックのみ), 継承, コンストラクタ, auto/custom プロパティ,
static/instance メソッド, if/else/while/for/foreach/switch, ラムダ,
List<T>, Dictionary<K,V>, LINQ (Where/Select/Any/All/First/Last/OrderBy/OrderByDescending/Take/Skip/Min/Max/Sum/Count/ToDictionary),
文字列補間, null 条件演算子 (?.), is パターン, switch 式 など。
詳細は doc/support-matrix.md 参照。
tcs/
Transpiler/ # トランスパイラ本体 (Roslyn → Lua)
Transpiler.Tests/ # xUnit テスト
TinyCs.Analyzers/ # Roslyn Analyzer PoC
TinyCs.Analyzers.Tests/
TinySystem/ # C# 側の型定義/facade (コンパイル・補完用)
runtime/
tinysystem.lua # Lua ランタイムライブラリ (List/Dict/String/Math)
deps/
lua/ # Lua 5.5 ソース (git submodule)
samples/ # サンプル C# コード
doc/
support-matrix.md # サポートマトリクス
CMakeLists.txt # Lua クロスプラットフォームビルド
MIT