JavaScript
出力されるコード
.lps 一つにつき ES モジュールが一つ出力されます。ソースマップも出力されます。型が分かっている算術は演算子に、クラスへのメッセージ送信はメソッド呼び出しになります。
static fact$(n) {
return ((n <= 1) ? 1 : (n * Calc.fact$((n - 1))));
}
$.Http.get$("orders.json");
$.Json.parse$($.send(r, "body", []));
組み込み型への操作は $.send を通ります。Str は JavaScript の文字列、Array は JavaScript の配列そのもので、, や collect: に相当するメソッドが無いためです。プロトタイプにメソッドを追加することはしません。実際の画面では、メッセージ送信の大半がこれです。
一描画のうち $.send が占める時間は 1% 未満です。
ブラウザの機能を使う
.d.ts はありません。使う機能を自分で宣言します。OCaml の external や Haskell の FFI と同じ方式です。
Extern subclass: #Session global: 'sessionStorage'.
Session class >> getItem: Str -> Maybe[Str].
Session class >> setItem: Str with: Str -> Unit.
Extern subclass: #Ctx.
Ctx >> fillRect: Int y: Int w: Int h: Int -> Unit.
Ctx >> fillStyle := Str.
宣言できるのは、グローバル変数、モジュール(from: 'node:path')、コンストラクタ(new:)、プロパティの読み出し、プロパティへの代入です。localStorage、WebSocket、canvas、location、requestAnimationFrame はいずれもこの方式で使います。言語には組み込まれていません。
メソッド呼び出しとプロパティの読み出しは () の有無で区別します。Sock >> close() -> Unit. は呼び出し、Sock >> close -> Unit. はプロパティの読み出しです。後者を誤って書くと、関数オブジェクトを読んで捨てるだけになり、型検査もビルドも通ります。そのため、Unit を返すプロパティの読み出しは警告になります。
"close" is declared as a property read, so it answers the function without
calling it — write `close()` if it is meant to run
警告は標準エラー出力に出ます。終了ステータスは変わりません。エディタにも警告として届きます。
境界での型変換
宣言した型に従って変換します。型の内側(Array[Date] の要素など)も変換します。
| 型 | JavaScript へ | JavaScript から |
|---|---|---|
Int Float Str Bool | そのままの値 | $.int など |
Date | '2026-08-12' | $.date |
Time | '09:30' または '09:30:45' | $.time |
DateTime | '2026-09-05T09:30' | $.dateTime |
Maybe[T] | 値または null。中身も変換 | $.maybe |
Dict[Str V] | オブジェクト。値も変換 | $.dict |
Array[T] | T が変換不要ならそのまま | 複製して凍結 |
Future[T] | そのまま(Future は Promise) | そのまま |
Date Time DateTime を文字列で渡すのは、JavaScript の Date にするとタイムゾーンが付いてしまうためです。
JavaScript から戻る値は検査します。時刻として読めない文字列が来た場合、境界でエラーになります。コンパイル時の型が Time で実行時の値が文字列、という状態にはなりません。
変換方法が一つに決まらない型は、宣言の時点でコンパイルエラーになります。
"take:" cannot cross to JavaScript: JavaScript has no decimal, and which way to
lose that is the caller's to choose — send `asString` to keep the digits,
`asFloat` to compute with it
ActorRef と Bytes も同様にコンパイルエラーです。ActorRef は LPScript のランタイム外では意味を持たず、Bytes は JavaScript 側の型が決まっていないためです。
minify
名前を短縮するツール(terser や uglify の mangle)を出力された JavaScript にかけると動作しません。理由は二つあります。
- メッセージ送信はセレクタを文字列で運びます。
$.send(o, "at:put:", [...])の"at:put:"はランタイムのメソッド名と一致している必要があります Html clone:は CSS セレクタで HTML と照合します。文字列を短縮すると照合に失敗します
安全に短縮できる部分は、コンパイラが短縮します。
lpsc build orders.lps --minify
局所変数はメソッドごとに a、b、… になり、字下げとコメントは除去されます。メソッド名、クラス名、$.send のセレクタ文字列、CSS セレクタは変更しません。コンパイラの中で処理するので、ビルドに必要なものは lpsc だけです。同梱の例は全部 --minify でも同じ出力になることをテストしています。ソースマップも出力されます。
デプロイ時の注意
lpsc build は .mjs と一緒に .mjs.map を出力します。ソースマップには .lps の全文(コメントを含む)が入っています。デプロイするのは .mjs だけにしてください。
出力された JavaScript は読める形のままです。権限の判断(単価を見せてよいか、受注を進めてよいか)はサーバで行ってください。サーバで判断していれば、クライアントのコードが読めても問題は起きません。