CLI#

Xarpiteはコマンドラインインターフェース(CLI)を通じて実行できます。

ブラウザ版にはない、CLI版限定の機能や概念がいくつか存在します。

ランチャーとランタイム#

CLI上でXarpiteを実行する際には、ランチャーとランタイムという 2 つのレイヤーが存在します。


ランチャーとはxarpiteコマンドを直接受け付けるシェルスクリプトを指します。

ランチャーは環境変数や引数などに基づいて実際に起動すべきランタイムの決定とその起動を行います。


ランタイムとはXarpiteスクリプトを実際に動作させるプログラムを指します。

ランタイムには複数のプラットフォームによる異なる実装があり、これはXarpiteエンジンと呼ばれます。

Xarpiteを実行するコマンド#

xarpite: Xarpiteを実行する基本的なコマンド#

xarpiteコマンドはXarpiteを実行するための最も基本的なコマンドです。

$ xarpite -h | tail -n +2
# Usage: xarpite <Launcher Options> <Runtime Options> [--] [scriptfile] <arguments>
# Launcher Options:
#   --native                 Use the native engine
#   --jvm                    Use the JVM engine
#   --node                   Use the Node.js engine
# Runtime Options:
#   -h, --help               Show this help
#   -v, --version            Show version
#   -q                       Run script as a runner
#   --verbose                Display Kotlin stack traces
#   -A <apiversion>          Set the API version
#   -f <scriptfile>          Read script from file
#                            Use '-' to read from stdin
#                            Omit [scriptfile]
#   -e <script>              Evaluate script directly
#                            Omit [scriptfile]
#   -E                       Interpret the entire script as an embedded string literal
#
# Repository: https://github.com/MirrgieRiana/xarpite

Launcher Optionsはランチャー側で、Runtime Optionsはランタイム側で解釈されます。

このため、両者は順序を入れ替えて指定することはできません。


xarpiteコマンドはシバン行によってXarpiteスクリプトを直接実行するためにも利用できます。

$ {
  echo '#!/usr/bin/env xarpite' > script.xa1
  echo '100 + 20 + 3' >> script.xa1
  chmod +x script.xa1

  ./script.xa1

  rm script.xa1
}
# 123

xa: Xarpiteを手元で実行する便利なショートカット#

xaコマンドはxarpiteコマンドのショートカットです。

$ xa -h | tail -n +2
# Usage: xa <Launcher Options> <Runtime Options> [--] [script] <arguments>
# Launcher Options:
#   --native                 Use the native engine
#   --jvm                    Use the JVM engine
#   --node                   Use the Node.js engine
# Runtime Options:
#   -h, --help               Show this help
#   -v, --version            Show version
#   -q                       Run script as a runner
#   --verbose                Display Kotlin stack traces
#   -A <apiversion>          Set the API version
#   -f <scriptfile>          Read script from file
#                            Use '-' to read from stdin
#                            Omit [script]
#   -e <script>              Evaluate script directly
#                            Omit [script]
#   -E                       Interpret the entire script as an embedded string literal
#
# Repository: https://github.com/MirrgieRiana/xarpite

xarpiteコマンドと概ね同じ仕様ですが、以下の点で重要な違いがあります。

  • 文字数が2文字と非常に短い。
  • 第一引数がデフォルトでXarpiteスクリプトファイルではなくXarpiteスクリプトそのものとして解釈される。
  • Xarpite2などが出た場合、同じxaコマンドが使われる可能性がある。

大雑把に言えば、人間が手元のコンソール上で使うための便利なコマンドです。

xaコマンドを使えば非常に少ない記述量で簡単な計算をすることができます。

$ xa '100 + 20 + 3'
# 123

一方で、xaコマンドはシェルスクリプトなどのファイル内に記述する利用法を想定していません。

その目的には代わりにxarpiteコマンドを使用してください。

ヘルプ系のオプション#

-h, --help: ヘルプの表示#

-hまたは--helpオプションを指定するとヘルプメッセージが表示されます。

-v, --version: バージョン情報の表示#

-vまたは--versionオプションを指定するとXarpiteのバージョンが表示されます。

Xarpiteエンジンの指定#

XARPITE_ENGINE: Xarpiteエンジンを指定する環境変数#

XARPITE_ENGINE環境変数はXarpiteの実行エンジンを指定します。

  • native: ネイティブ実装を使用
  • jvm: JVMを使用
  • node: Node.jsを使用

一部の機能は特定のエンジンでのみ利用可能です。


XARPITE_ENGINE環境変数が指定されていない場合、設定ファイルdefault_engineの内容が使用されます。

通常、この設定ファイルはXarpiteのインストール時に作成されます。

この設定ファイルも存在しない場合、デフォルトでnativeエンジンが使用されます。


コマンドラインオプションによるXarpiteエンジンの指定は環境変数による指定よりも優先されます。

Xarpiteエンジンを指定するコマンドラインオプション#

Xarpiteエンジンを指定するコマンドラインオプションは排他的であり、複数を同時に指定することはできません。

--native: ネイティブ実装エンジンを使用#

ネイティブコンパイルされたXarpiteエンジンを使用します。

--jvm: JVMエンジンを使用#

JVM上で動作するXarpiteエンジンを使用します。

--node: Node.jsエンジンを使用#

Node.js上で動作するXarpiteエンジンを使用します。

スタックサイズの指定#

XARPITE_STACK_SIZE: スタックサイズを指定する環境変数#

XARPITE_STACK_SIZE環境変数はXarpiteの実行スタックのサイズの上限を指定します。

ランタイムによってはこの上限を尊重します。


値は数値と単位を表す接尾辞を連結した形式で指定します。

  • K: キビバイト単位
  • M: メビバイト単位
  • G: ギビバイト単位

戻り値の出力#

CLI版Xarpiteでは、標準の動作としてプログラム全体の戻り値を標準出力に出力します。


この際、出力値の文字列化が行われます。

$ xa '
  Object := {
    new: () -> Object{}
    `&_`: _ -> "Hello, World"
  }
  Object.new()
'
# Hello, World

コードの値がストリームだった場合、各要素を1行ずつ出力します。

$ xa '1 .. 3'
# 1
# 2
# 3

コードの戻り値が空ストリームである場合、何も出力されません。

$ xa '1 + 2; ,'

-q: 戻り値の出力の抑制#

-qオプションを指定すると、戻り値の出力が行われなくなります。

出力を行うには別途OUT関数などを使う必要があります。

$ xa -q '
  OUT << "apple"
  OUT << "banana"
  "orange"
'
# apple
# banana

厳密には、このオプションはソースコード全体を文(runner)コンテキストとして解釈することを指定するオプションです。

このため末尾式の部分に変数宣言文などの文が書けるようになります。

APIバージョン#

-A: APIバージョンの指定#

-A <apiversion>

ランタイムのAPIバージョンを指定します。

$ xa -A 4 'API_VERSION'
# 4

-Aオプションを指定しない場合、APIバージョンはXarpite自身のメジャーバージョンと同じ値になります。


ランタイムが提供していないAPIバージョンを指定した場合、スクリプトの実行前にエラーとなります。

スクリプトの指定#

実行するXarpiteスクリプトの指定方法は起動コマンドと指定方法で6通りに別れます。

起動コマンド スクリプトの指定方法 記述例 扱い
xarpite 第一引数 xarpite script.xa1 arg1 ... スクリプトファイル
xarpite -f xarpite -f script.xa1 arg1 ... スクリプトファイル
xarpite -e xarpite -e '1 + 2' arg1 ... スクリプト
xa 第一引数 xa '1 + 2' arg1 ... スクリプト
xa -f xa -f script.xa1 arg1 ... スクリプトファイル
xa -e xa -e '1 + 2' arg1 ... スクリプト

-f: ファイルからスクリプトを読み込む#

-f <scriptfile>

-fオプションを指定すると、指定したXarpiteスクリプトファイルからXarpiteスクリプトを読み込んで実行します。

USE関数とは異なり、scriptfileが相対パスで指定された場合、カレントディレクトリを起点として解決されます。

$ {
  echo '100 + 20 + 3' > script.xa1
  xa -f script.xa1
  rm script.xa1
}
# 123

scriptfile-を指定すると、標準入力からスクリプトを読み込みます。

$ echo '100 + 20 + 3' | xa -f -
# 123

-fオプションが指定された場合、第1引数はスクリプトに渡す引数の一部として解釈されます。

$ {
  echo 'ARGS()' > script.xa1
  xa -f script.xa1 '100 + 20 + 3' apple banana cherry
  rm script.xa1
}
# 100 + 20 + 3
# apple
# banana
# cherry

-fオプションと-eオプションは排他的であり、同時に指定することはできません。

-e: スクリプトを直接実行#

-e <script>

-eオプションを指定すると、指定したXarpiteスクリプトを直接実行します。

$ xarpite -e '100 + 20 + 3'
# 123

-eオプションが指定された場合、第1引数はスクリプトに渡す引数の一部として解釈されます。

$ xa -e 'ARGS()' '100 + 20 + 3' apple banana cherry
# 100 + 20 + 3
# apple
# banana
# cherry

-fオプションと-eオプションは排他的であり、同時に指定することはできません。

埋め込み文字列リテラルとしての解釈#

-E: スクリプト全体を埋め込み文字列リテラルとして解釈#

-Eオプションを指定すると、エントリポイントであるスクリプト全体を埋め込み文字列リテラル%> <%の中身として解釈します。

これにより、テンプレートエンジンのように、テキストの中にXarpiteの式を埋め込んだスクリプトを記述できます。

スクリプトの先頭行が#!で開始する場合は、末尾の改行ごと無視されます。

$ {
  touch script.xa1
  echo '#!/usr/bin/env -S xarpite -E' >> script.xa1
  echo '<h1><%= 100 + 20 + 3 %></h1>' >> script.xa1
  chmod +x script.xa1

  ./script.xa1

  rm script.xa1
}
# <h1>123</h1>

エラーによる終了#

捕捉されないエラーによってプログラムが終了した場合、その値は標準エラーに出力されます。

エラーで終了した場合のプロセスの終了コードは、以下に従います。

  • 0 - APIバージョン4以前かつ、ネイティブでないエラーで終了した場合
  • 1 - それ以外の場合
$ xa -A 5 ' !! "error" ' 2>/dev/null; echo $?
# 1

$ xa -A 4 ' !! "error" ' 2>/dev/null; echo $?
# 0

その他のコマンド#

xarpite-update: Xarpiteを最新版に更新する#

現在実行中のXarpiteを最新版に更新します。

このコマンドにはインストールディレクトリに書き込みを行う権限が必要です。

-hオプションを指定すると、使い方を表示して終了します。

-yオプションを指定すると、確認プロンプトをスキップして自動的に更新を適用します。

CLI版限定組み込み定数・関数#

ARGS: コマンドライン引数を取得#

コマンドライン引数が配列で格納されています。

最初の引数が添え字0に対応し、xaコマンドやワンライナーのソースコードは含まれません。

$ xa 'ARGS' 1 2 3
# [1;2;3]

PWD: カレントディレクトリを取得#

PWD: STRING

現在のワーキングディレクトリのパスです。

このパスは正規化(...である階層を含みません)されており、絶対パスです。


この定数は以下の優先順位に基づいて値を決定します。

  1. 環境変数XARPITE_PWD
    • この環境変数はLinux版のランチャースクリプト内で自動的に付与されます。
    • シンボリックリンクの解決はされません。
  2. 環境変数PWD
    • この環境変数は多くの場合Linuxシェルが自動的に付与します。
    • シンボリックリンクの解決はされません。
  3. プラットフォーム固有の取得方法
    • どちらの環境変数も利用できなかった場合、プラットフォームごとに固有の方法でカレントディレクトリを取得します。
    • シンボリックリンクの解決が行われる場合があります。

Windows上でJVM版ランタイムを起動した場合は3に該当しますが、ジャンクションの解決は行われないことが判明しています。


ルートディレクトリでは/になることに注意してください。

例えば、次のような文字列結合を行うと異常なパス文字列が生成されます。

この問題の解決としてRESOLVE関数が利用できます。

$ cd / && xa ' "$PWD/apple.txt" '
# //apple.txt

$ cd / && xa ' PWD::RESOLVE("apple.txt") '
# /apple.txt

LOCATION: 実行中のスクリプトのパスを取得#

LOCATION: STRING

現在実行中のXarpiteスクリプトのパスです。

LOCATIONは正規化(...である階層の除去)済みの絶対パスであり、ファイルパスもしくはURLを表します。


ファイル名に相当する末尾の部分が-である場合、-eコマンドラインオプションなどの手段によって動的に与えられたスクリプトであることを示します。

$ cd /usr/local/bin && xa -e 'LOCATION'
# /usr/local/bin/-

ENV: 環境変数を取得#

環境変数がオブジェクトとして格納されています。

$ FOO=bar xa 'ENV.FOO'
# bar

存在しない変数にアクセスした場合はNULLが返ります。

INC: モジュール検索パスの配列#

INC: ARRAY<STRING>

モジュールをUSEする際に検索されるディレクトリパスやURLの配列です。

http://またはhttps://で始まる文字列はURLとして解釈されます。

相対ディレクトリパスを指定した場合、そのパスはPWDに基づいて解決されます。

デフォルトでは./.xarpite/lib./.xarpite/maven、および Maven Central (https://repo1.maven.org/maven2) が含まれています。


この配列をプログラムから実行中に変更することで、モジュールの検索対象を動的に変更することができます。

$ {
  mkdir module-fruits

  echo ' "Apple" ' > module-fruits/apple.xa1

  xa '
    INC += "module-fruits"
    USE("apple")
  '

  rm -r module-fruits
}
# Apple

MAJOR, MINOR, PATCH: Xarpiteのバージョン番号を取得#

MAJOR: INT

MINOR: INT

PATCH: INT

実行中のXarpiteのバージョン番号を、メジャー・マイナー・パッチの各要素ごとに数値で取得します。

$ xa 'MAJOR ?= INT'
# TRUE

バージョン番号を取得できない場合や、メジャー.マイナー.パッチの数値形式で解釈できない場合は、参照時にエラーが発生します。

API_VERSION: 現在提供されているAPIバージョンを取得#

API_VERSION: INT

現在のランタイムが提供しているAPIバージョンが整数で格納されています。

$ xa -A 4 'API_VERSION'
# 4

API: APIバージョンのチェック#

API(apiVersion: INT): NULL

現在のランタイムのAPIバージョンがapiVersionと厳密に一致しない場合、エラーをスローします。

$ xa -A 4 -q '
  API(4)
  OUT << "Hello"
'
# Hello

$ xa -A 4 -q '
  API(5)
  OUT << "Hello"
'
# ERROR: Script requires API version 5, but the environment API version is 4
#   at -:2:6             API(5)
#   at -:1:1

IN, I, INL: コンソールから文字列を1行ずつ読み取る#

IN: STREAM<STRING>

標準入力から文字列を1行ずつ読み取るストリームです。

IおよびINLINの別名です。

$ { echo 123; echo 456; } | xa 'IN'
# 123
# 456

APIバージョン5からは、INのみ、これらの別名ではなくなり、標準入力全体を1個の文字列として読み取るようになります。

このとき、INは改行文字を一切改変せず、入力された文字列をそのまま返します。


ストリームは逐次的であるため、非常に大きな反復も少ないメモリ消費で行うことができます。

$ xa '1 .. 10000 | "#" * 10000' | xa 'IN | $#_ >> SUM'
# 100000000

コンソールから1行だけ読み取るには、FIRST関数を使用します。

$ {
  echo 123
  echo 456
} | xa -q '
  OUT << "1: $(FIRST(IN))"
  OUT << "2: $(FIRST(IN))"
'
# 1: 123
# 2: 456

INを一度でも使用した場合、INBを使用することはできません。

INB: コンソールからバイトデータを読み取る#

INB: STREAM<BLOB>

標準入力からバイトデータをBLOBとしてすべて読み取るストリームです。

BLOBは最大8192バイトの長さに分割されます。

$ echo -n "abc" | xa 'INB'
# BLOB.of([97;98;99])

INBを一度でも使用した場合、INを使用することはできません。

OUT, O, OUTL: 標準出力に出力#

OUT(value: VALUE): NULL

標準出力に出力します。

OおよびOUTLOUTの別名です。

この関数はしばしば左実行パイプ<<によって呼び出されます。

$ xa -q '
  OUT(123)
  OUT << 456
'
# 123
# 456

ストリームが指定された場合、各要素を1行ずつ出力します。

$ xa -q '
  OUT(1 .. 3)
'
# 1
# 2
# 3

OUT関数自体はNULLを返します。

OUTB: バイトデータを標準出力に出力#

OUTB(blobLike: BLOB_LIKE): NULL

blobLikeをバイト列に変換し、バイト列のまま標準出力に出力します。

ストリームが与えられた場合は各要素を順にバイト列に変換し、順に出力します。

改行は自動的には付与されません。

$ xa -q 'OUTB(BLOB.of([65, 66, 67, 10]), BLOB.of([68, 69, 70, 10]))'
# ABC
# DEF

それ以外の部分は概ねOUT関数の仕様に準じます。


Xarpiteでは通常、プログラム全体の戻り値を自動的に標準出力に出力することに注意してください。

以下のような場合、-qオプションを忘れると、バイト列の最初に「NULL改行」などのゴミが付きます。

$ xa -q '65, 66, 67, 10 >> OUTB'
# ABC

$ xa '65, 66, 67, 10 >> OUTB'
# ABC
# NULL

ERR: 標準エラー出力に出力#

ERR(value: VALUE): NULL

標準エラー出力に出力します。

この関数は概ねCLI版OUT関数と共通の動作をしますが、標準出力ではなく標準エラー出力に出力します。

$ xa -q 'ERR("Error!")' > /dev/null
# Error!

ERRB: バイトデータを標準エラー出力に出力#

ERRB(blobLike: BLOB_LIKE): NULL

blobLikeをバイト列に変換し、バイト列のまま標準エラー出力に出力します。

この関数は概ねOUTB関数と共通の動作をしますが、標準出力ではなく標準エラー出力に出力します。

$ xa -q '65, 66, 67, 10 >> ERRB' > /dev/null
# ABC

EXISTS: ファイルの存在の確認#

EXISTS(file: STRING): BOOLEAN

fileで指定されたパスにファイルが存在する場合はTRUEを、存在しない場合はFALSEを返します。

パスがディレクトリを指す場合もTRUEを返します。

$ {
  touch tmp.txt
  xa 'EXISTS("tmp.txt")'
  xa 'EXISTS("no_such_file.txt")'
  rm tmp.txt
}
# TRUE
# FALSE

FILES / FILE_NAMES: ディレクトリ内のファイルの一覧を取得#

FILES(dir: STRING): STREAM<STRING>

dirで指定されたディレクトリ直下のファイル名のストリームを取得します。

FILE_NAMESFILESの別名であり、同一の動作を持ちます。

ファイル名にはディレクトリのパスは含まれません。

APIバージョン5からは、これらは別名ではなくなり、FILESの方のみ、dirを先頭に含むパスを返すようになります。

返されるファイルには...は含まれず、ディレクトリやその他の特殊なファイルは含まれます。

返されるファイル名は辞書順にソートされます。

$ {
  mkdir tmp
  touch tmp/file.txt
  mkdir tmp/dir
  xa 'FILES("tmp")'
  rm -r tmp
}
# dir
# file.txt

TREE: ディレクトリ配下のすべてのファイルとディレクトリを取得#

TREE(dir: STRING): STREAM<STRING>

dirの配下にあるすべてのディレクトリとファイルのパスを再帰的に検索するストリームを返します。

返されるパス文字列の先頭にはdirが含まれます。

返されるパスにはdir自身は含まれません。

各ディレクトリ内の項目は名前順にソートされます。

ただし、ディレクトリ内の項目は親ディレクトリの直後に報告されます。

$ {
  mkdir tmp
  mkdir tmp/dir1
  mkdir tmp/dir1/dir2
  touch tmp/dir1/dir2/file2.txt
  touch tmp/dir1/file1.txt
  mkdir tmp/empty-dir
  xa 'TREE("tmp")'
  rm -r tmp
}
# tmp/dir1
# tmp/dir1/dir2
# tmp/dir1/dir2/file2.txt
# tmp/dir1/file1.txt
# tmp/empty-dir

FILE_TREE: ディレクトリ配下のすべてのファイルを取得#

FILE_TREE(dir: STRING): STREAM<STRING>

dirの配下にあるすべてのファイルのパスを再帰的に検索するストリームを返します。

ディレクトリのパスは報告されません。

返されるパス文字列の先頭にはdirが含まれます。

返されるパスにはdir自身は含まれません。

各ディレクトリ内の項目は名前順にソートされます。

ただし、ディレクトリ内の項目は親ディレクトリの直後に報告されます。

$ {
  mkdir tmp
  mkdir tmp/dir1
  mkdir tmp/dir1/dir2
  touch tmp/dir1/dir2/file2.txt
  touch tmp/dir1/file1.txt
  mkdir tmp/empty-dir
  xa 'FILE_TREE("tmp")'
  rm -r tmp
}
# tmp/dir1/dir2/file2.txt
# tmp/dir1/file1.txt

READ / READL: テキストファイルから読み込み#

READ(file: STRING): STREAM<STRING>

fileで指定されたテキストファイルの内容を文字列として1行ずつ読み取ります。

READLREADの別名であり、同一の動作を持ちます。

改行コードは除去されます。

$ {
  echo "apple" > tmp.txt
  echo "banana" >> tmp.txt
  xa 'READ("tmp.txt")'
  rm tmp.txt
}
# apple
# banana

APIバージョン5からは、これらは別名ではなくなり、READの方のみ、ファイル全体を単一の文字列として返すようになります。

改行の調整は行いません。

READB: バイナリファイルから読み込み#

READB(file: STRING): STREAM<BLOB>

fileで指定されたバイナリファイルの内容をBLOBとしてすべて読み取ります。

BLOBは最大8192バイトの長さに分割されます。

$ {
  echo -en '\x20\x21\x22' > tmp.bin
  xa 'READB("tmp.bin")'
  rm tmp.bin
}
# BLOB.of([32;33;34])

WRITE: テキストファイルに書き込み#

WRITE(file: STRING; string: STRING): NULL

fileで指定されたファイルにstringをUTF-8エンコードして書き込みます。

改行の付与や正規化は行われません。

ファイルが既に存在する場合は上書きされます。

$ {
  xa -q 'WRITE("tmp.txt"; "apple")'
  printf '%s\n' "$(cat tmp.txt | tr '\n' ',')"
  rm tmp.txt
}
# apple

WRITEL: テキストファイルに行単位で書き込み#

WRITEL(file: STRING; lines: STREAM<STRING>): NULL

fileで指定されたファイルにlinesの各行を書き込みます。

最後の行も含め、各行の末尾には\nが付与されます。

ファイルが既に存在する場合は上書きされます。

$ {
  xa -q 'WRITEL("tmp.txt"; "apple", "banana", "cherry")'
  printf '%s\n' "$(cat tmp.txt | tr '\n' ',')"
  rm tmp.txt
}
# apple,banana,cherry,

ファイルはlinesのストリームを読み始める前に空にされます。

このため、書き込み先と同じファイルをlinesの中で読み取ると、内容が失われます。

このような自己参照を行う場合は、CACHEで入力を先に確定させてください。

$ {
  printf 'apple\nbanana\ncherry\n' > tmp.txt
  xa -q 'WRITEL["tmp.txt"] << CACHE << READL("tmp.txt")'
  printf '%s\n' "$(cat tmp.txt | tr '\n' ',')"
  rm tmp.txt
}
# apple,banana,cherry,

WRITEB: バイナリファイルに書き込み#

WRITEB(file: STRING; blobLike: BLOB_LIKE): NULL

fileで指定されたファイルにblobLikeを書き込みます。

ファイルが既に存在する場合は上書きされます。

$ {
  xa -q 'WRITEB("tmp.bin"; 97, 112, 112, 108, 101)'
  printf '%s\n' "$(cat tmp.bin | tr '\n' ',')"
  rm tmp.bin
}
# apple

ファイルはblobLikeを読み始める前に空にされます。

このため、書き込み先と同じファイルをblobLikeの中で読み取ると、内容が失われます。

このような自己参照を行う場合は、CACHEで入力を先に確定させてください。

$ {
  printf 'apple' > tmp.bin
  xa -q 'WRITEB["tmp.bin"] << CACHE << READB("tmp.bin")'
  printf '%s\n' "$(cat tmp.bin | tr '\n' ',')"
  rm tmp.bin
}
# apple

USE: モジュールの呼び出し#

USE(reference: STRING): VALUE

referenceで指定されたXarpiteスクリプトを評価した結果を返します。

USEされるXarpiteスクリプトをモジュールと呼びます。

referenceには、絶対ローカルファイルパス、URL、相対パス、INCを起点とした相対パス、Maven座標の指定方法があります。

モジュールの文化的位置付け#

モジュールは多くの場合マウント用のオブジェクトを返すことでAPIを公開しますが、そうでない場合もあります。

モジュールの提供するAPIは、組み込みマウント風に大文字で書かれる場合もあれば、そうでない場合もあります。


@USE("fruit")のようにUSE関数の戻り値をそのままマウントすることで、ディレクティブのような使用感を実現できます。

INCに基づくロケーションの解決#

referenceは検索場所を与えるINCビルトイン定数に基づいて実際のロケーションに解決されます。

原則としてINC配列内で末尾に近いパスに属するモジュールが優先されます。

ただし、ローカルファイルパスであるINCエントリーは、URLであるエントリーよりも優先的に検索されます。


ディレクトリの区切り文字は、それが実行されるOSに関わらず/を使用することができます。

ローカルファイルパスの末尾の.xa1/main.xa1は省略可能です。

-eコマンドラインオプションによって起動されたコンテキストでは、ロケーションはPWD直下の-という名前のファイルとして扱われます。


ロケーションがURLである場合、通信によって非同期的にスクリプトが取得され、その間はサスペンドされます。

オンライン上にある多数のモジュールを使用する場合、LAUNCH関数などでコルーチンを起動することで並列化ができます。

同一ロケーションにあるスクリプトの再利用#

同一ロケーションに対するUSE関数の結果は再利用されます。

返されるインスタンスは常に同一となり、読み込み時の副作用も1度だけ生じます。

スクリプトの結果がストリームである場合、そのストリームは解決されます。

シンボリックリンクなどによって異なるロケーションにある場合は、ファイル実体が同一でもそれぞれ別に評価されます。

$ {
  echo 'IN' > input.xa1

  xa '1 .. 3' | xa -q '
    OUT << USE("./input.xa1") >> TO_ARRAY
    OUT << USE("./input") >> TO_ARRAY
    OUT << USE("$PWD/input.xa1") >> TO_ARRAY
    OUT << USE("$PWD/input") >> TO_ARRAY
  '

  rm input.xa1
}
# [1;2;3]
# [1;2;3]
# [1;2;3]
# [1;2;3]

絶対ローカルファイルパスによるreferenceの指定#

referenceが絶対ローカルファイルパスである場合、そのファイルを呼び出します。

$ {
  echo ' "Apple" ' > fruit.xa1

  xa 'USE("$PWD/fruit.xa1")'

  rm fruit.xa1
}
# Apple

URLによるreferenceの指定#

referenceがURLである場合、そこからスクリプトを取得して呼び出します。

http://またはhttps://で始まるreferenceがURLとして解釈されます。

相対パスによるreferenceの指定#

reference.または..の階層で始まる相対パスである場合、USE関数の呼び出しを行ったスクリプトのロケーションからの相対パスとして解決されます。


以下はカレントディレクトリ直下にあるファイルを呼び出す例です。

$ {
  echo ' "Apple" ' > fruit.xa1

  xa 'USE("./fruit.xa1")'
  xa 'USE("./fruit")'

  rm fruit.xa1
}
# Apple
# Apple

以下は、main.xa1ファイルを持つディレクトリを呼び出す例です。

$ {
  mkdir fruit

  echo ' "Apple" ' > fruit/main.xa1

  xa 'USE("./fruit")'

  rm -r fruit
}
# Apple

以下はmodulesサブディレクトリ内にあるファイルを呼び出し、更にそこから同階層の別のファイルを呼び出す例です。

$ {
  mkdir modules

  echo '
    {
      getApple: () -> "Apple"
    }
  ' > modules/apple.xa1
  echo '
    @USE("./apple.xa1")
    {
      getFruit: () -> getApple()
    }
  ' > modules/fruit.xa1

  xa '
    @USE("./modules/fruit.xa1")
    getFruit()
  '

  rm -r modules
}
# Apple

INCを起点とした相対パスによるreferenceの指定#

reference.または..の階層で始まらない相対パスである場合、対応するモジュールをINCから検索します。

$ {
  mkdir -p modules/fruit

  echo ' "Apple" ' > modules/fruit/main.xa1

  xa -q '
    INC += "modules"
    OUT << USE("fruit/main.xa1")
    OUT << USE("fruit/main")
    OUT << USE("fruit")
  '

  rm -r modules
}
# Apple
# Apple
# Apple

Maven座標によるreferenceの指定#

referenceがMaven座標である場合、対応するモジュールをINCから検索します。

Maven座標はgroup:artifact:versionの形式で指定します。

拡張子には.xa1が自動的に付与されます。

例えば、com.example.fruit:apple:1.0.0というMaven座標の場合、INCの各エントリーに対してcom/example/fruit/apple/1.0.0/apple-1.0.0.xa1というサブパスが検索されます。

$ {
  mkdir -p .xarpite/maven/com/example/fruit/apple/1.0.0

  echo ' "Apple" ' > .xarpite/maven/com/example/fruit/apple/1.0.0/apple-1.0.0.xa1

  xa 'USE("com.example.fruit:apple:1.0.0")'

  rm -r .xarpite
}
# Apple

XA: Xarpiteスクリプトの実行#

XA(script: STRING[; reference: reference: STRING]): VALUE

scriptで与えられたXarpiteスクリプトを評価した結果を返します。

USEと異なり、同じ入力に対しても評価結果は再利用されず、ストリームの解決も行われません。

$ xa 'XA("8 * 100 + 77")'
# 877

reference引数#

reference引数は、scriptのロケーションに使われます。

referenceは、URL、絶対パス、または...の階層で始まる相対パスで指定できます。

相対パスはXA関数を呼び出したスクリプトのロケーションを起点として解決されます。

referenceを省略した場合、XA関数を呼び出したスクリプトのロケーションのディレクトリ直下の-という名前のファイルとして扱われます。

$ cd /usr/local/bin && xa 'XA("LOCATION"; reference: "./fruit.xa1")'
# /usr/local/bin/fruit.xa1

$ cd /usr/local/bin && xa 'XA("LOCATION")'
# /usr/local/bin/-

EXEC / EXECL: 外部コマンドを実行 [EXPERIMENTAL]#

EXEC(command: STREAM<STRING>[; env: OBJECT<STRING>]): STREAM<STRING>

外部コマンドを実行します。

EXECLEXECの別名であり、同一の動作を持ちます。

commandにはプロセスおよびその引数を1要素ずつ指定します。

戻り値はそのプロセスの標準出力を1行ずつ読み取るストリームです。

$ xa 'EXEC("echo", "Hello, World!")'
# Hello, World!
$ xa 'EXEC("bash", "-c", "seq 1 30 | grep 3")'
# 3
# 13
# 23
# 30

APIバージョン5からは、これらは別名ではなくなり、EXECの方のみ、標準出力全体をUTF-8としてデコードした文字列を返すようになります。


env引数を指定すると、プロセスの環境変数を指定できます。

環境変数は呼び出したXarpiteプロセスの環境変数を継承した上で追加・上書きされます。

$ xa 'EXEC("bash", "-c", %>echo $FOO<%; env: {FOO: "BAR"})'
# BAR

空文字列もしくはNULLを指定すると、既存の環境変数を削除できます。

$ A=APPLE B=ANNA xa '
  EXEC("bash", "-c", %>
    echo "A=$A"
    echo "B=$B"
    echo "C=$C"
  <%; env: {
    B: NULL
    C: "CHERRY"
  })
'
# A=APPLE
# B=
# C=CHERRY

呼び出したプロセスが0以外の終了コードで終了した場合、エラーをスローします。

$ xa 'EXEC("bash", "-c", "exit 1") !? "ERROR"'
# ERROR

呼び出したプロセスの標準エラー出力はXarpiteの標準エラー出力にリダイレクトされます。

$ xa -q 'EXEC("bash", "-c", "echo 'ERROR' 1>&2")' 2>&1
# ERROR

呼び出したプロセスは別のスレッドで管理され、メインスレッドはブロッキングせずにサスペンドします。


この関数は実験的な機能であり、将来的に仕様が変更される可能性があります。

戻り値は、プロセスの標準出力を逐次的に読み取るストリームではなく、プロセスの終了後にその標準出力を行分割したものです。

また、この関数は現状JVM版とNative版でのみ提供されます。

EXECB: 外部コマンドを実行しBLOBで返す [EXPERIMENTAL]#

EXECB(command: STREAM<STRING>[; env: OBJECT<STRING>]): STREAM<BLOB>

外部コマンドを実行し、その標準出力のバイト列をBLOBのストリームとして返します。

外部コマンドの実行状態と出力のタイミングの間には、今のところ何の保証もありません。

これ以外の動作は概ねEXEC関数の仕様に準じます。

$ xa 'EXECB("printf", "abc")'
# BLOB.of([97;98;99])

BASH: Bashスクリプトを実行#

BASH(script: STRING[; args: STREAM<STRING>]): STRING

scriptをBashスクリプトとして実行し、その標準出力をUTF-8としてデコードし、文字列として返します。

出力の末尾の改行は取り除かれます。

これはBashの"$(...)"の動作と似ています。

$ xa '
  result := BASH("echo Hello")
  "[$result]"
'
# [Hello]

args引数を指定すると、Bashスクリプトに引数を渡せます。

$ xa '
  result := BASH(%>
    echo "$1"
    echo "$2"
  <%; "The fruit is:", "apple")
  "[$result]"
'
# [The fruit is:
# apple]

この関数は内部的にbashコマンドを実行します。

bashコマンドが利用できない環境ではエラーが発生します。


これ以外の動作は概ねEXEC関数の仕様に準じます。

この関数は現状JVM版とNative版でのみ提供されます。

EXIT: 指定した終了コードでプロセスを終了#

EXIT(code: INT): NOTHING

指定した終了コードでXarpiteプロセスを終了します。

$ xa 'EXIT(0)'; echo $?
# 0

$ xa 'EXIT(1)'; echo $?
# 1

$ xa 'EXIT(42)'; echo $?
# 42