Skip to content

SotaTamura/blockscript

Repository files navigation

BlockScript (bs)

TypeScript と Node.js で構築された、シンプルで軽量なプログラミング言語インタープリターです。

特徴

  • 演算子の多重定義: 多くの演算子が数値以外(文字列、配列、オブジェクト)に対しても直感的な動作をします。
    • + (加算):
      • 配列 + 配列: 配列の結合。
      • オブジェクト + オブジェクト: プロパティの結合(右辺で上書き)。
    • - (減算):
      • 文字列 - 文字列: 一致した部分文字列の削除。
      • 配列 - 配列: 右辺の配列に含まれる要素を左辺から削除。
      • オブジェクト - オブジェクト: 右辺のオブジェクトとキー・値の両方が一致するプロパティを削除。
    • * (乗算):
      • 文字列 * 数値: 文字列の繰り返し。
      • 配列 * 数値: 配列の要素を繰り返した新しい配列。
    • 比較演算 (<, >, <=, >=):
      • 文字列: 包含関係 ("a" < "abc" は true)。
      • 配列: 部分集合・包含関係。
      • オブジェクト: プロパティの包含関係(部分集合判定)。
  • 論理演算: AND (&), OR (|), NOT (!) 。
  • 比較演算: ==値の等価), !=, <, <=, >, >=
  • 変数: 自由な変数名への代入と更新。レキシカルスコープをサポート。
  • 関数: function キーワードによる第一級関数の定義。return による値の返却(値なしも可)。
  • 基本型: 数値 (Number)、文字列 (String)、ブール値 (Boolean: true/false)、および undefined
  • 配列 (List): [...] による配列の作成。インデックスによる要素の取得と更新(1始まり)。
  • ブロック: ( ... ) による処理のグループ化。最後に評価された値を返し、新しいスコープを作成します。
  • 制御構文(式): すべての制御構文は値を返す「式」として扱われます。
    • 条件分岐: if (条件) 式 else 式
    • 繰り返し: while (条件) 式 。各ループの結果を配列として返します。
    • 反復: for (変数 in 配列) 式 。配列の各要素を順に処理し、各ループの結果を配列として返します。
    • 関数脱出: return 式 。関数から値を返して即座に終了します。
  • ジャンプ文: break, continue による制御。
    • break, continue はオプションで値を返すことができ、ループの結果リストに含まれます。
    • 値を指定しない continue は、そのイテレーションの結果をスキップ(フィルタリング)するために使用できます。
  • オブジェクト (Object): { key: value, ... } によるオブジェクトの作成。ドット記法 (obj.key) やブラケット記法 (obj["key"]) によるプロパティの取得と更新。
  • this キーワード: オブジェクトのメソッド内で、そのオブジェクト自身を参照します。
  • 組み込み関数:
    • print(値): 値を標準出力に表示します。
    • range(開始, 終了): 開始から終了までの数値を含む配列(例:range(1, 3)[1, 2, 3])を生成します。
    • parseNumber: 文字列を数値に変換します。
    • parseString: 数値を文字列に変換します。
  • コメント: # で囲まれたテキストはコメントとして無視されます。

インストール

bs コマンドをグローバルに使用できるようにするには、リポジトリをクローンして以下を実行します:

npm install
npm link

使い方

.bs 拡張子のファイルを bs コマンドで実行します:

bs ファイルのパス

実行すると以下のファイルが生成されます:

  • tokens.json: 字句解析されたコードが記述されます。
  • ast.json: 構文解析されたコードが記述されます。

ターミナルに結果が出力されます。

コード例

#出力#
print("Hello World!")

#多重定義された演算子#
# 文字列 #
print("HelloWorld" - "World") #Hello#
print("Go" * 3)               #GoGoGo#
print("bc" < "abc")           #true (包含)#

# 配列 #
print([1, 2] + [3, 4])        #[1, 2, 3, 4]#
print([1, 2, 3] - [2])        #[1, 3]#
print([1, 2] * 2)             #[1, 2, 1, 2]#
print([1] < [1, 2])           #true (部分集合)#

# オブジェクト #
print({a: 1} + {b: 2})        #{a: 1, b: 2}#
print({a: 1, b: 2} - {a: 1})  #{b: 2}#
print({a: 1} < {a: 1, b: 2})  #true (部分集合)#

#変数#
mysteriousNumber = 0
mysteriousNumber = 2
print(mysteriousNumber)  #2#

#ブール値と論理演算#
print(true)
print(!false)       #true#
print(true & false) #false#
print(true | false) #true#

#比較演算子#
age = 14
print(age == 15) #false#
print(age == 14) #true#
print([1, 2] == [1, 2]) #true#

#ブロック#
v = (
  a = 1
  b = 2
  a + b
)
print(v) #3#

#関数#
add = function (a, b) (
  sum = a + b
  return sum
)
print(add(3, 4)) #7#

divide = function (a, b) (
  if (b == 0) return;
  return a / b
)

print(divide(10, 2)) #5#
print(divide(10, 0)); #undefined#

#即時関数#
(function () (
  print("Hello!")
))()

#条件分岐#
age = 16
if (age >= 18) (
  print("大人です")
) else (
  print("子供です")
) #子供です#

beverage = if (age >= 20) "ビール" else "ジュース"
print(beverage) #ジュース#

#再帰#
fact = function (n) (
  if (n == 0) (
    return 1
  )

  return n * fact(n - 1)
)

print(fact(5)) #120#

#while文#
i = 0
while (i < 5) (
  print(i)
  i = i + 1
) #0 1 2 3 4#

i = 0

print(while (i < 6) (
  if (i == 3) break;
  i = i + 1
)) #[1, 2, 3]#

#配列#
studentNames = ["田中", "佐藤", "鈴木"]
print(studentNames[1]) #田中#
studentNames[2] = "内藤"
print(studentNames[2]) #内藤#

#for文#
text = ""

for (i in range(0, 9)) (
  if (i == 3) continue;
  text = text + i
)

print(text) #012456789#

evens = for (i in range(1, 10)) if (i % 2 == 0) i
print(evens) #[2, 4, 6, 8, 10]#

#オブジェクト#
student = {
  name: "山田太郎",
  age: 15,
  scores: {japanese: 90, math: 70, english: 80}
}

subject = "math"
student.scores[subject] = 100
print(student.scores) #{japanese: 90, math: 100, english: 80}#

#クラスもどき#
Student = function (name, age) {
    name: name
    age: age
    introduceSelf: function () (
        print("私の名前は" + this.name + "です。" + this.age + "歳です。")
    )
}

tanaka = Student("田中", 18)
tanaka.introduceSelf() #私の名前は田中です。18歳です。#

#継承もどき#
FreshmanStudent = function (name, age, selectedLanguage) (
    super = Student(name, age)

    return super + {
        selectedLanguage: selectedLanguage
        introduceSelf: function () (
            super.introduceSelf()
            print(this.selectedLanguage + "選択です。")
        )
    }
)

tanaka = FreshmanStudent("田中", 18, "ドイツ語")
tanaka.introduceSelf() #私の名前は田中です。18歳です。ドイツ語選択です。#

#応用例: 3の倍数と3がつく数字の時だけアホになる関数#
nabeatsu = function (start, end) (
    for (i in range(start, end)) (
        iStr = parseString(i)
        if (i % 3 == 0 | iStr >= "3") (
            print(iStr + "~~~!!!")
        ) else (
            print(i)
        )
    )
)

nabeatsu(1, 100) #1 2 3~~~!!! ...#

#応用例: 素数フィルタ#
getPrimes = function (max) (
    for (n in range(2, max)) (
        is_prime = true
        for (i in range(2, n - 1)) (
            if (n % i == 0) (
                is_prime = false
                break
            )
        )
        if (is_prime) n else continue
    )
)

print(getPrimes(30)) #[2, 3, 5, 7, 11, 13, 17, 19, 23, 29]#

内部アーキテクチャ

  1. Tokenizer (tokenizer.ts): ソースコードをトークンのストリームに変換します。
  2. Parser (parser.ts): トークンを抽象構文木 (AST) に変換します。
  3. Evaluator (evaluator.ts): AST を再帰的に走査し、プログラムを実行します。
  4. Interpreter (interpreter.mts): 各コンポーネントを統合するエントリポイントです。

About

A programming language.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors