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 にかけると動作しません。理由は二つあります。

安全に短縮できる部分は、コンパイラが短縮します。

lpsc build orders.lps --minify

局所変数はメソッドごとに a、b、… になり、字下げとコメントは除去されます。メソッド名、クラス名、$.send のセレクタ文字列、CSS セレクタは変更しません。コンパイラの中で処理するので、ビルドに必要なものは lpsc だけです。同梱の例は全部 --minify でも同じ出力になることをテストしています。ソースマップも出力されます。

デプロイ時の注意

lpsc build は .mjs と一緒に .mjs.map を出力します。ソースマップには .lps の全文(コメントを含む)が入っています。デプロイするのは .mjs だけにしてください。

出力された JavaScript は読める形のままです。権限の判断(単価を見せてよいか、受注を進めてよいか)はサーバで行ってください。サーバで判断していれば、クライアントのコードが読めても問題は起きません。