Skip to content

Commit

Permalink
Merge pull request #442 from aiscript-dev/aiscript-next
Browse files Browse the repository at this point in the history
AiScript Next
  • Loading branch information
FineArchs authored Jul 29, 2024
2 parents ac1510e + 80b1473 commit 0fc741a
Show file tree
Hide file tree
Showing 53 changed files with 6,712 additions and 4,865 deletions.
3 changes: 3 additions & 0 deletions docs/builtin-props.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ Core:range(0,2).push(4) //[0,1,2,4]
### @(_x_: num).to_str(): str
数値を文字列に変換します。

### @(_x_: num).to_hex(): str
数値から16進数の文字列を生成します。

## 文字列
### #(_v_: str).len
Expand Down Expand Up @@ -198,6 +200,7 @@ _fromIndex_が負値の時は末尾からの位置(配列の長さ+_fromIndex_
### @(_v_: arr).sort(_comp_: @(_a_: value, _b_: value)): arr
**【この操作は配列を書き換えます】**
配列の並べ替えをします。第1引数 _comp_ として次のような比較関数を渡します。
安定ソートです。
* _a__b_ より順番的に前の時、負の値を返す
* _a__b_ より順番的に後の時、正の値を返す
* _a__b_ と順番的に同等の時、0を返す
Expand Down
42 changes: 20 additions & 22 deletions docs/get-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ print("Hello, world!")
`"~"`は文字列リテラルです。`"`で囲ったものが文字列になります。

ちなみに、`print( ~ )`には糖衣構文があり、次のようにも書けます:
```
```js
<: "Hello, world!"
```

Expand Down Expand Up @@ -86,13 +86,13 @@ print(message)
## 配列
`[]`の中に式をスペースで区切って列挙します。
```
["ai" "chan" "kawaii"]
["ai", "chan", "kawaii"]
```

配列の要素にアクセスするときは、`[<index>]`と書きます。
インデックスは0始まりです。
```
let arr = ["ai" "chan" "kawaii"]
let arr = ["ai", "chan", "kawaii"]
<: arr[0] // "ai"
<: arr[2] // "kawaii"
```
Expand Down Expand Up @@ -130,21 +130,7 @@ let obj = {foo: "bar", answer: 42}
```
Core:add(1, 1)
```

<table>
<tr><th>演算子</th><th>標準関数</th><th>意味</th></tr>
<tr><td><code>+</code></td><td><code>Core:add</code></td><td>加算</td></tr>
<tr><td><code>-</code></td><td><code>Core:sub</code></td><td>減算</td></tr>
<tr><td><code>*</code></td><td><code>Core:mul</code></td><td>乗算</td></tr>
<tr><td><code>^</code></td><td><code>Core:pow</code></td><td>冪算</td></tr
<tr><td><code>/</code></td><td><code>Core:div</code></td><td>除算</td></tr>
<tr><td><code>%</code></td><td><code>Core:mod</code></td><td>剰余</td></tr>
<tr><td><code>==</code></td><td><code>Core:eq</code></td><td>等しい</td></tr>
<tr><td><code>&&</code></td><td><code>Core:and</code></td><td>かつ</td></tr>
<tr><td><code>||</code></td><td><code>Core:or</code></td><td>または</td></tr>
<tr><td><code>></code></td><td><code>Core:gt</code></td><td>大きい</td></tr>
<tr><td><code><</code></td><td><code>Core:lt</code></td><td>小さい</td></tr>
</table>
詳しくは→[syntax.md](/docs/syntax.md#%E6%BC%94%E7%AE%97%E5%AD%90)

## ブロック式
ブロック式 `eval { ~ }` を使うと、ブロック内で最後に書かれた式が値として返されます。
Expand Down Expand Up @@ -216,7 +202,7 @@ for (100) {
## 繰り返し(配列)
`each`を使うと、配列の各アイテムに対し処理を繰り返すことができます:
```
let items = ["a" "b" "c"]
let items = ["a", "b", "c"]
each (let item, items) {
<: item
}
Expand Down Expand Up @@ -260,17 +246,29 @@ AiScriptファイルにメタデータを埋め込める機能です。
### {
name: "example"
version: 42
keywords: ["foo" "bar" "baz"]
keywords: ["foo", "bar", "baz"]
}
```

## エラー型
一部の標準関数は実行失敗時にエラー型の値を返します。
これによりエラー処理を行うことができます。
一部の標準関数は実行失敗時にエラー型の値を返します。
これによりエラー処理を行うことができます。
```
@validate(str){
let v=Json:parse(str)
if (Core:type(v)=='error') print(v.name)
else print('successful')
}
```

## エラーメッセージ
進行不能なエラーが発生するとエラーメッセージが表示されます。
```
let scores=[10, 8, 5, 5]
let 3rd=scores[2] // unexpected token: NumberLiteral (Line 2, Column 5)
```
```
let arr=[]
arr[0] // Runtime: Index out of range. Index: 0 max: -1 (Line 2, Column 4)
```
行(Line)、列(Column)は1始まりです。
8 changes: 4 additions & 4 deletions docs/keywords.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
## 予約語について
AiScriptにおける予約語とは、変数や関数の名前として使用することが禁止されている単語のことを言います。
使用するとSyntax Errorとなります。
```
```js
// matchとforは予約語
let match=null // エラー
@for(){ print('hoge')} // エラー
@for(){ print('hoge') } // エラー
```

## 使用中の語と使用予定の語
Expand All @@ -18,7 +18,7 @@ let match=null // エラー
## 一覧
以下の単語が予約語として登録されています。
### 使用中の語
`null`, `true`, `false`, `each`, `for`, `loop`, `break`, `continue`, `match`, `if`, `elif`, `else`, `return`, `eval`, `var`, `let`, `exists`
`null`, `true`, `false`, `each`, `for`, `loop`, `break`, `continue`, `match`, `case`, `default`, `if`, `elif`, `else`, `return`, `eval`, `var`, `let`, `exists`

### 使用予定の語
`fn`, `namespace`, `meta`, `attr`, `attribute`, `static`, `class`, `struct`, `module`, `while`, `import`, `export`
`as`, `async`, `attr`, `attribute`, `await`, `catch`, `class`, `component`, `constructor`, `dictionary`, `do`, `enum`, `export`, `finally`, `fn`, `hash`, `in`, `interface`, `out`, `private`, `public`, `ref`, `static`, `struct`, `table`, `this`, `throw`, `trait`, `try`, `undefined`, `use`, `using`, `when`, `while`, `yield`, `import`, `is`, `meta`, `module`, `namespace`, `new`
41 changes: 26 additions & 15 deletions docs/literals.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,14 @@ false
`'`または`"`が使用可能な通常の文字列リテラルと、`` ` ``を使用し文中に式を含むことができるテンプレートリテラルがあります。

#### エスケープについて
構文の一部として使われている文字は`\`を前置することで使うことができます。
`'...'`では`\'`
`"..."`では`\"`
`` `...` ``では`` \` ```\{``\}`のエスケープがサポートされています。
改行やタブ文字等のエスケープは未サポートです。
`\`を前置した文字は、構文の一部ではなく一つの文字として解釈されます。
例えば`'\''``'`
`"\""`では`"`
``` `\`` ````` ` ``
`` `\{` ```{`、として解釈されます。
特に構文としての意味を持たない文字の場合、単に`\`が無視されます。例:`'\n'``n`
文字`\`を使用したい場合は`'\\'`のように2つ繋げてください。
エスケープシーケンスは未サポートです。

#### 文字列リテラル
```js
Expand Down Expand Up @@ -69,29 +72,37 @@ Previous statement is { !true }.`
### 配列
```js
[] // 空の配列
[1 2 3] // 空白区切り(将来的に廃止予定)
[1, 1+1, 1+1+1] // ,で区切ることも出来る
[ // 改行可
[1, 1+1, 1+1+1] // コロンで区切ることも出来る
[1, 1+1, 1+1+1,] // 最後の項に,をつけてもよい
[ // 改行区切りも可
'hoge'
'huga'
'piyo'
]
[ // コロンと改行の併用可
'hoge',
'huga',
'piyo', // 最後の項に,をつけてもよい
'piyo',
]
```
```js
[1 2 3] // 空白区切りは廃止済み
```

### オブジェクト
```js
{} // 空のオブジェクト
{
{ // 改行区切り
a: 12
b: 'hoge'
}
{a: 12,b: 'hoge'} // ワンライナー
{a: 12 b: 'hoge'} // 空白区切りは将来的に廃止予定
{a: 12;b: 'hoge'} // セミコロン区切りは将来的に廃止予定
{a: 12,b: 'hoge'} // コロン区切り
```
```js
// :の後に空白必須
{a:12,b:'hoge'} // Syntax Error
// 空白区切りは廃止済み
{a: 12 b: 'hoge'} // Syntax Error
// セミコロン区切りは廃止済み
{a: 12; b: 'hoge'} // Syntax Error
```

### 関数
Expand Down
16 changes: 16 additions & 0 deletions docs/parser/overview.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# AiScriptパーサーの全体像

AiScriptのパーサーは2つの段階を経て構文ツリーに変換される。

1. ソースコードをトークン列に分割する
2. トークン列を順番に読み取って構文ツリー(AST)を構築する

ソースコードをトークン列に分割する処理(トークナイズと呼ばれる)は「Scanner」というモジュールが担当する。
トークン列から構文ツリーを構築する処理(パース)は、syntaxesディレクトリ以下にあるパース関数が担当する。名前がparseから始まっている関数がパース関数。

AiScriptのパーサーではトークナイズはまとめて行われない。
パース関数が次のトークンを要求すると、下位モジュールであるScannerが次のトークンを1つだけ読み取る。

Scannerによって現在の読み取り位置(カーソル位置)が保持される。
また、Scannerの各種メソッドで現在のトークンが期待されたものと一致するかどうかの確認やトークンの種類の取得などを行える。
これらの機能を利用することにより、パース関数を簡潔に記述できる。
12 changes: 12 additions & 0 deletions docs/parser/scanner.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Scanner 設計資料

## 現在のトークンと先読みされたトークン
_tokensの0番には現在のトークンが保持される。また、トークンが先読みされた場合は1番以降にそれらのトークンが保持されていくことになる。
例えば、次のトークンを1つ先読みした場合は0番に現在のトークンが入り1番に先読みされたトークンが入る。

nextメソッドで現在位置が移動すると、それまで0番にあったトークン(現在のトークン)は配列から削除され、1番にあった要素は現在のトークンとなる。
配列から全てのトークンが無くなった場合はトークンの読み取りが実行される。

## CharStream
ScannerはCharStreamを下位モジュールとして利用する。
CharStreamは入力文字列から一文字ずつ文字を取り出すことができる。
11 changes: 11 additions & 0 deletions docs/parser/token-streams.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# TokenStreams
各種パース関数はITokenStreamインターフェースを実装したクラスインスタンスを引数にとる。

実装クラス
- Scanner
- TokenStream

## TokenStream
読み取り済みのトークン列を入力にとるストリーム。
テンプレート構文の式部分ではトークン列の読み取りだけを先に行い、式の内容の解析はパース時に遅延して行われる。
この時の読み取り済みのトークン列はTokenStremとしてパース関数に渡される。
3 changes: 0 additions & 3 deletions docs/std.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,9 +105,6 @@ _time_offset_ を渡していない場合はローカルのものを参照しま
数が多いため専用のページになっています。→[std-math.md](std-math.md)

## :: Num
### @Num:to_hex(_x_: num): str
数値から16進数の文字列を生成します。

### @Num:from_hex(_hex_: str): num
16進数の文字列から数値を生成します。

Expand Down
101 changes: 97 additions & 4 deletions docs/syntax.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,29 @@ let add2 = @(x, y) {
) {
x + y
}
@add5(x,y){x+y} // ワンライナー
// 省略可能引数
@func1(a, b?) {
<: a
<: b // 省略されるとnullになる
}
func1('hoge') // 'hoge' null
// 初期値を設定された引数(省略可能引数と組み合わせて使用可能)
@func2(a, b?, c = 'piyo', d?) {
<: a
<: b
<: c
<: d
}
func2('hoge', 'fuga') // 'hoge' 'fuga' 'piyo' null
// 初期値には変数を使用可能(値は宣言時点で固定)
var v = 'hoge'
@func3(a = v) {
<: a
}
v = 'fuga'
func3() // 'hoge'
// ワンライナー
@func4(a,b?,c=1){<:a;<:b;<:c}
```
```js
// match等の予約語は関数名として使用できない
Expand All @@ -87,6 +109,8 @@ var func = null
@func() { // Runtime Error
'hoge'
}
// 省略可能引数構文と初期値構文は併用できない
@func(a? = 1) {} // Syntax Error
```
### 代入
Expand Down Expand Up @@ -182,6 +206,36 @@ each let v, arr{ // Syntax Error
}
```
### while
条件がtrueの間ループを続けます。
条件が最初からfalseの場合はループは実行されません。
```js
var count = 0
while count < 42 {
count += 1
}
<: count // 42
// 条件が最初からfalseの場合
while false {
<: 'hoge'
} // no output
```
### do-while
条件がtrueの間ループを続けます。
条件が最初からfalseであってもループは一度実行されます。
```js
var count = 0
do {
count += 1
} while count < 42
<: count // 42
// 条件が最初からfalseの場合
do {
<: 'hoge'
} while false // hoge
```
### loop
`break`されるまで無制限にループを行います。
```js
Expand Down Expand Up @@ -230,6 +284,42 @@ Ai:kun() // kawaii
値をスクリプト中に直接書き込むことができる構文です。
詳しくは→[literals.md](./literals.md)
### 演算子
主要な演算を表現します。
#### 単項演算子
式に前置して使用します。論理否定(`!`)、正数符号(`+`)、負数符号(`-`)の三種があります。
#### 二項演算子
2つの式の間に置いて使用します。四則演算とその派生(`+`,`-`,`*`,`^`,`/`,`%`)、比較演算(`==`,`!=`,`<`,`<=`,`>`,`>=`)、論理演算(`&&`,`||`)があります。
#### 演算子の優先度
例えば`1 + 2 * 3`などは`2 * 3`が先に計算されてから`1 +`が行われます。これは`*`の優先度が`+`より高いことによるものです。優先度の一覧は下の表をご覧下さい。
この優先度は`(1 + 2) * 3`のように`(` `)`で括ることで変えることができます。
#### 二項演算子の糖衣構文性
二項演算子は構文解析の過程でそれぞれ対応する組み込み関数に置き換えられます。
(単項演算子である`!`にも対応する関数`Core:not`が存在しますが、置き換えは行われていません)
何の関数に置き換えられるかは下の表をご覧下さい。
### 演算子一覧
上から順に優先度が高くなっています。(一部優先度が同じものもあります)
<table>
<tr><th>演算子</th><th>対応する関数</th><th>意味</th></tr>
<tr><td><code>^</code></td><td><code>Core:pow</code></td><td>冪算</td></tr>
<tr><td><code>+(単項)</code></td><td>なし</td><td>正数</td></tr>
<tr><td><code>-(単項)</code></td><td>なし</td><td>負数</td></tr>
<tr><td><code>!(単項)</code></td><td>なし</td><td>否定</td></tr>
<tr><td><code>*</code></td><td><code>Core:mul</code></td><td>乗算</td></tr>
<tr><td><code>/</code></td><td><code>Core:div</code></td><td>除算</td></tr>
<tr><td><code>%</code></td><td><code>Core:mod</code></td><td>剰余</td></tr>
<tr><td><code>+</code></td><td><code>Core:add</code></td><td>加算</td></tr>
<tr><td><code>-</code></td><td><code>Core:sub</code></td><td>減算</td></tr>
<tr><td><code>></code></td><td><code>Core:gt</code></td><td>大きい</td></tr>
<tr><td><code>>=</code></td><td><code>Core:gteq</code></td><td>以上</td></tr>
<tr><td><code><</code></td><td><code>Core:lt</code></td><td>小さい</td></tr>
<tr><td><code><=</code></td><td><code>Core:lteq</code></td><td>以下</td></tr>
<tr><td><code>==</code></td><td><code>Core:eq</code></td><td>等しい</td></tr>
<tr><td><code>!=</code></td><td><code>Core:neq</code></td><td>等しくない</td></tr>
<tr><td><code>&&</code></td><td><code>Core:and</code></td><td>かつ</td></tr>
<tr><td><code>||</code></td><td><code>Core:or</code></td><td>または</td></tr>
</table>
### if
キーワード`if`に続く式がtrueに評価されるかfalseに評価されるかで条件分岐を行います。
式として扱うことができ、最後の文の値を返します。
Expand Down Expand Up @@ -283,11 +373,14 @@ let foo = eval {
```js
let x = 1
let y = match x {
1 => "yes"
0 => "no"
* => "other"
case 1 => "yes"
case 0 => "no"
default => "other"
}
<: y // "yes"

// ワンライナー
<:match x{case 1=>"yes",case 0=>"no",default=>"other"} // "yes"
```
### exists
Expand Down
Loading

0 comments on commit 0fc741a

Please sign in to comment.