;;
;; 概要
;;
;; 前置記法/ポーランド記法を採用したプログラミング言語。
+ 1 2 ; ポーランド記法
1 2 + ; 逆ポーランド記法
1 + 2 ; 中置記法
;;
;; サンプル(プログラミング言語)
;;
:str "hello" ; var str = "hello"
ary: ["world" "end"] ; var ary = ["world", "end"]
print str ary.0 ; print("hello", "world")
:v + 1 2
print v ; 3
- + 1 2 2 ; 1
- (+ 1 2 2) ; -5
if = "hello" str
print "yes"
print "no"
print (if = "hello" str "yes" "no")
[print [if cond:[= "hello" str]
then:"yes"
else:"no"]]
switch Align.Left
:Left echo "Left"
:Right echo "Right"
:Center echo "Center"
[1 2 3].head ; 1
[1 2 3].rest ; [2 3]
sort [3 2 1] {|a b| < a b} ; [1 2 3]
[3 2 1].sort {< $0 $1} ; [1 2 3]
[3 2 1].sort (<) ; [1 2 3]
sort{<} [3 2 1] ; [1 2 3]
filter<& 1> [3 2 1] ; [1 3]
func counter ()
:c 0
~~ = c (+ c 1)
= f counter
f ; 1
f ; 2
func fact n
if = n 0
1
* n
this - n 1
fact 3 ; 6
fact 4 ; 24
func sum list
+ list.car
if list.cdr
sum list.cdr
0
sum [1 2] ; 3
times<3 i> {print i} ; "012"
times<3 i> print i ; "012"
times 3 print _ ; "012"
times 3 print ; "012"
len "str" ; 3
"str".len ; 3
["str"].0 len ; 3
1.+ 2 ; 3 ;; 1.+(2)
1 + 2 ; 3 ;; 1.+ 2
+(1 2) ; 3
join "-", map{to_s}\reverse\sort [1 3 2] ; "3-2-1"
"-".join map{to_s} \ sort<a b>{- a b} [1 3 2] ; "3-2-1"
assert (= yes true 1)
~~ sum (a b) + a b
print-sum 1 2 ; "3"
main: {
object:
:v 99
:f ~~ print (+ $0.k " " v)
object.f {k: "Shop"}
}
main() ; Shop 99
main.object ; 99
print main..object ; Shop 99\n99
;;
;; 設計方針
;;
;; インタプリタまたはハイブリッド
;; 型システムなし。eval相当機能あり
;; for文if文等の基本機能はライブラリ関数として実装
;; コア言語側である程度の組み込み型を用意する
;; - Number型、String型、List型、Map型、Key型、Function型
;; - 組み込み型のメンバ関数はライブラリ側で実装可能とする
;; 組み込みの糖衣構文は極力宣言しない
;; - 前置記法を活かした構文をベースとする
;; - 予約済みのキーワードは極力定義しない
;; DSLの実現を可能とする汎用的な言語仕様
;; - 多様性を受け入れる寛容プログラミング言語
;; - 設定ファイルの構文やマックアップ言語への応用を可能とする
;; - ライブラリ次第でまったく異なる構文の利用が可能となる(方言の実現)
;; - 中置記法、Lisp風記法、Smalltalk風のオブジェクト指向機構、等々
;; - 未定義動作や処理系依存の動作を方言側で制御可能とする(実引数の評価順序等)
;; - リアルタイム・インタプリタインタプリタ(インタプリタジェネレータ)
;;
;;
;; 仕様
;;
;; 2016年12月24日 公開
;; 2017年01月28日 更新
;; 2017年04月28日 更新
;; 2017年09月28日 更新
;; 2018年02月28日 更新
;; 2018年10月28日 更新
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; 基本構文
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; 代入・比較
;;
= i 3 ; var i = 3
== i 3 ; i == 3
;;
;; 四則演算
;;
+ 1 2 ; 1 + 2
- 1 2 ; 1 - 2
+ 1 2 3 ; 1 + 2 + 3
+ 1, 2, 3 ; 1 + 2 + 3
(+ 1 2 3) ; 1 + 2 + 3
+(1 2 3) ; 1 + 2 + 3 ;; 要検討(糖衣構文)
+ (1 2 3) 4 ; [1, 2, 3] + 4 ;; 要検証
;;
;; 二項演算優先の原則(保留・廃止予定)
;;
; + 1 2 3 ; 1 + 2; 3;
; + + 1 2 3 ; (1 + 2) + 3
; * + 1 2 - 6 3 ; (1 + 2) * (6 - 3)
; 1 + 2 ; 1 (+ 2 nil)
; if == nil v return 0 ; if (nil == v) return 0
;;
;; リテラル
;;
99 ; Number
"abc" ; String
[1 2 3] ; List
(1 2 3) ; List ;; 要検討
[:key 99] ; Map
[key: 99] ; Map ;; 要検討(糖衣構文)
{:key 99} ; Map ;; 要検討
;;
;; 配列/リスト
;;
= ary [1 2 3]
ary 0 ; 1
ary[1] ; 2 ;; 糖衣構文
ary.2 ; 3 ;; メンバアクセス
ary(2) ; 3 ;; 転送
*ary ; 1
+ary ; [2 3]
ary.car ; 1
ary.cdr ; [2 3]
ary.first ; 1
ary.head ; 1
ary.last ; 3
ary.tail ; 3
ary.rest ; [2 3]
ary.begin ; &[1 2 3][0]
ary.end ; &[1 2 3][[1 2 3].size]
ary.from(1) ; [2 3]
ary(to: 2) ; [1 2]
to(ary, 2) ; [1 2]
ary[1:] ; [2 3]
ary[:2] ; [1 2]
ary[1:2] ; [2]
ary-0 ; 1
ary-1: ; [2 3]
ary:2 ; [1 2]
ary-1:2 ; [2]
ary.take 2 ; [1 2]
ary.before 2 ; [1 2]
ary.prefix 2 ; [1 2]
ary.drop 2 ; [3]
ary.after 2 ; [3]
ary.suffix 2 ; [3]
ary.chop 2 ; [1]
ary.dropLast 2 ; [1]
;;
;; 辞書/連想配列
;;
= dic [:key 99 :may 5]
dic "key" ; 99
dic["key"] ; 99 ;; 糖衣構文
dic.key ; 99
dic(:key) ; 99
dic[:key] ; 99
;;
;; 関数
;;
;; 関数定義式の採用は保留
;; - 無名関数を変数へ代入することで代用
;;
= add fn (a b) + a b ; function add(a, b) { a + b }
add 1 2 ; 3
add 1, 2 ; 3
add(1 2) ; 3
;;
;; 無名関数
;;
= sub ~ (a b) - a b ;; 要検討(糖衣構文または基本構文とする)
= mul ~~ * $0 $1 ;; 案2-1
= div ~~ / _0 _1 ;; 案2-2
= add ~~ + _ _ ;; 案2-3
= rem ^(a b) % a b ;; 案3
= add {(a b) + a b} ;; 案4-1
= add {+ _0 _1} ;; 案4-2(仮引数省略時専用)
= add {[a b] + a b} ;; 案4-3(案4-2との混在が可能)-- 参考:[#引数リスト]
= add [a b]{+ a b} ;; 案4-4(案4-2との混在が可能)-- 参考:[#引数リスト] [#前置引数リスト] #1%
= add [a b] {+ a b} ;; 案4-5(不可: 配列型引数と解釈 -- `sort [2 1] {<}`)
= add {a b| + a b} ;; 案5 [#ラムダ宣言式の追加]
sort [2 1] {<} ;; sort([2 1] (<))
[2 1].sort |a b| < a b
[2 1].sort {a b| < a b}
[2 1].sort(|a b| < a b)
[2 1].sort([a b]{< a b}) ;; 煩雑
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; オブジェクト指向
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; メソッド
;;
"s".len nil ; "s".len()
"s".len() ; 糖衣構文
"s" len ; "s"(:len)
len "s" ; 転送 --> "s".len()
"R".sub "R", "r" ; "R".sub("R", "r")
;;
;; クラス
;;
class Number
fn init (v) = self.intValue v
fn is, eq (v) == v self.intValue
fn pow (v) Math.pow(self.intValue v)
fn (+) (v) + self.intValue v
fn get ( ) return self.intValue
;; 案2
= is fn (v) == self v
= pow fn (v) Math.pow self v
= pow {[v]
Math.pow self v
}
;; fn VS func
;; 無名関数との区別のためにfuncの採用を検討
;; func name(a b) + a b ; メソッド宣言式
;; fn (a b) + a b ; ラムダ式
;; Objective-C風
- instanceMethod() + 1 2
+ classMethod() + 1 2
;;
;; インスタンス化
;;
= v (Number 99)
;;
;; メソッド呼び出し
;;
get v ; 9
v get ; 9
v.get() ; 9
v.get ; func Number::get
v.get nil ; 9
(9.get) ; 9
v.eq 2 ; v.eq(2)
10.pow 3 ; 1000
v is 4 ; v.is(4)
eq v 2 ; v.eq(2) ;; [#代理関数呼び出し]
;; #domain-specific
2(3) ; 6
= x 4
2(x) ; 8
= f(x) 2(x)
f(5) ; 10
;;
;; 糖衣構文
;;
"".split(",") ; ("".split ",")
"".len() ; ("".len void)
print("") ; (print "")
+ v 2 ; v.+(2)
;;
;; オブジェクト
;;
;; あらゆる値はオブジェクトで表現される
;; 各演算子の挙動は被演算子側のオブジェクト実装に依存する
;;
= (+) ~~ (a b) (a.+ b)
+ 1 2 ; 3
class String
func `+`(s) _s.copy.append s
+ "a" "b" ; "ab"
"a".+("b") ; "ab"
;;
;; Anyクラス
;; 全てのオブジェクトはAnyプロトコルに準拠する
;;
class Any
func (==) (b) __UNIMPLEMENTED__ b
func (!=) (b) ! self.==(b)
class Object :Any
func eq (b) == self b
class String
func (!=) (b) ! (__builtin__["string.h"].strcmp
self.__raw__
b.__raw__)
!= "a" "b" ; true
eq "a" "b" ; <<<error String:Any("a") eq String:Any("b")>>>
extension Number :Object
func `==`() (== self.__raw__ $0)
!= 9 8 ; true
eq 9 9 ; true
;;
;; 中置記法
;;
class Number
func __call__ (op ...)
if == (+) op
+ self ...
__UNIMPLEMENTED__ this
1 + 2 ; (1 + 2) --> 1(+, 2) --> 1.+(2)
+ 1 2 + 3 ; + 1 (2.+ 3) ;; 要検討(糖衣構文に対する優先順位)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; コア機能
;;
;; 参考:
;; #用語の意味
;; #予約語
;; #備考
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; ブロックの解釈
;;
;; インデントで式の繋がりを表現する
;; - 複文の実現が可能になる(関数の処理部やクラスのメソッド宣言部で使用)
;; - 入れ子された式の延長用途にも使われる
;;
;; 深さ1:
;; 一つ前の階層の式に対応する要素式であることを意味する
;; 深さ2以上:
;; 前の行の最後の式に続く要素式であることを意味する
;; 特性
;; インデントされた要素式は単一の式として解釈される
;;
;;
;; 例(深さ1) ※ インデント幅は空白2つと仮定
;;
; + 1 2
+
1
2
; + 1 2
+ 1
2
; + 1 (2 3)
+ 1
2 3 ;; 3は`+`関数の第三引数にならない
; (+ 1 2 3)
+ 1
2
3
; + 1 (+ 2 3)
+ 1
+ 2 3
; + (+ 1 2) 3
+
+ 1 2
3
; - (+ 1 2 3) 4
-
+ 1 2
3
4
; = v (+ 1 2)
= v
+ 2 3
;;
;; 例(深さ2以上)
;;
; + 1 (+ 2 3)
+ 1 + 2
3
; + 1 (+ 2 3)
+ 1 + 2
3
; = v (+ 1 (+ 2 3) 4)
= v
+ 1 + 2 ;; 関連: [#演算子の結合規則]
3
4
; = add {[a b] (+ a b)}
= add fn (a b)
+ a b
if == true yes
then:
print "true ="
print "= yes"
else:
print "true !"
print "= yes"
if
cond: == true yes
then: "yes"
else:
echo "n"
echo "o"
; if yes (echo "yes") (echo "no")
if yes
echo "yes"
echo "no"
; if yes (do (echo "ye") (echo "s")) (echo "no")
if yes do
echo "ye"
echo "s"
echo "no"
;; ブロック補完(深さ2以上) -- #TODO
; if yes (do (echo "ye") (echo "s")) (echo "no")
if yes
echo "ye"
echo "s"
echo "no"
;; ブロック補完(深さ1) -- 後置Keyの結合規則 #TODO
; if yes (then: (echo "ye") (echo "s"))
if yes then:
echo "ye"
echo "s"
; if yes (do (echo "ye") (echo "s")) -- 関連: [#ブロック内包式の結合規則#ブロック内包式の演算子結合]
if (yes):
echo "ye"
echo "s"
;;
;; ブロック内包式の結合規則
;;
;; #コア機能 #拡張機能 #重要度 50% #影響度 100%
;;
;; ブロックを内包する式の結合規則に例外を設ける
;;
;; ブロック内包式の例外
;; ブロックが出現するまでのオペランドの並びを要素式として解釈する
;;
;; #関連 [#演算子の結合規則(拡張)]
;;
;; インデントの深さに関する例外 #拡張機能
;; インデントの深さはオペレーターの位置を考慮した形で計算される
;; 深さ1と深さ2、3を区別する
;; わかりやすさを考慮し、インデントの深さではなくオペレータの位置関係を基準に統一する必要がある
;;
;; #関連 [#ブロックの解釈]
;;
;; ブロック内包式の演算子結合 #[重要度 25%] #TODO
;; 演算子がオペランドを必要とする場合
;; 内包するブロックをその演算子のオペランドと解釈する
;;
; if (== "String" (typeof String)) "yes"
if == "String" typeof String
"yes"
; if (== "String" typeof) (String) ("yes")
if == "String" typeof String "yes"
; if (== "String" (typeof String "yes"))
if == "String" typeof String
"yes"
echo, add 1 2 ; echo (add 1 2) 3
3
echo, add 1 2 ; echo (add 1 2 3)
3
echo, add 1 2 ; echo add (1 2 3) ;; ???: オペレーターの位置を考慮した場合
3
echo, add 1 2 ; echo (add (1 2 3)) 4 ;; ???: 矯正インデント
3
4
echo, add 1 2 ; echo (add 1 2 3) 4 ;; ???
3
4
+ * 1 ;; (+ (* 1 2) 3) ;; (+ (* 1 2 3)) ;; (+ (* 1) 2 3)
2
3
if (yes):
"ye"
"s"
;;
;; ブロックの明示
;;
;; #コア機能 #拡張機能 #重要度 75% #影響度 0%
;;
;; ブロックを`()`, `[]`, `{}`で明示する
;; if-else構文の実現に必要
;;
; = v (+ 1 2)
= v (
+ 1 2
)
; = v (+ 1 2)
= v (
+ 1 2)
; = v (# (= a 1) (+ a 2))
= v {
= a 1
+ a 2
}
do v ; 3
if yes (
echo "yes"
) (
echo "no"
)
if yes (
= r "yes"
print r
) else: [
print "no"
]
func hello (world) {
= str "hello"
print str " " world
}
hello "world" ; "hello world"
;;
;; ブロックの明示(拡張)
;;
;; 開始括弧`(`, `[`, `{`を関数式として解釈するコア機能
;; 終わり括弧までを一つの式として解釈させる
;; ヒアドキュメントの実現に必要
;; ユーザ定義を可能とするために必要
;; 可変長演算子への応用・統合も視野に入れる
;;
; var v = "<h1>heading</h1>\n<p>paragraph</p>";
= v """
<h1>heading</h1>
<p>paragraph</p>
"""
; var v = [{name: "bob", age: 65}, {name: "tom", age: 9}];
= v ((
---
name: "bob"
age: 65
---
name: "tom"
age: 9
))
= __builtin__.fn_paired["{}"] (~~)
{echo "a"} ; ~~ echo "a"
;;
;; 遅延評価式のスコープ
;; - 案1:遅延評価式の動的スコープは元スコープ基準
;; - 案2:遅延評価式の動的スコープは式評価時のスコープ
= that (if yes this)
== that this ; true (案1)
== that this ; false(案2)
(fn ()
{echo _0} 2 ; 1(案1)
{echo _0} 2 ; 2(案2)
)(1)
;; 影響(案1)
;; - DSLの実現が困難
func markdown (...)
= ary []
= (#) fn (head) ary.push (+ "<h1>" Serialize(head) "</h1>")
= (-) fn (item) ary.push (+ "<li>" Serialize(item) "</li>")
for.each(i ...)
= (#i).__prototype__["#"] (#)
= (#i).__prototype__["-"] (-)
i()
join separator:"\n"
terminator:""
items:ary
; "<h1>Heading</h1>\n<li>list item</li>"
markdown
# Heading
- list item
;;
;; カテゴリー式、グループ式
;;
;; #コア機能 #重要度 50% #影響度 25%(演算子の構文規則)
;; #関連 [#チェインケース]
;;
;; 式のサブ機能を実現する
;;
;; `-`演算子をカテゴリ参照演算子として活用
;; クラスのクラスメソッドを呼び出す(案1)
;; `::`との競合
;; クラスのインスタンスメソッドを呼び出す(案2)
;;
;; 同等の機能はメンバ参照演算子`.`を活用して実現することもできる #重要度 -25%
;; ただしファンクタによる実装が必要
;;
loop-3 echo "a" ; "aaa"
while-infinite
for-in i [1 2]
if (= i 1) for-continue
if (= i 2) while-break
class assert
:eq(a b) __builtin__.assert(= a b)
func assert(#expr) __builtin__.assert(expr)
assert = 1 2
assert-eq 1 2
;; フリー関数への転送
"a"-print ;; print(self) ;; self == "a"
"a"-print "b" ;; print(self, "b")
"s"-length ; 9
"s".length ; 1
fn length(s) 9
fn Any::__doesNotUnderstand__(msg ...args)
if-eq "Function" typeof-msg
msg(self ...args)
__UNIMPLEMENTED__(self msg ...args)
;; 関数呼び出し式としての応用
typeof-"a" ; "String"
typeof-999 ; "Number"
; 影響範囲 ; 整合性 ; 合成関数への応用も視野に入れる #TODO
typeof-print ; "(Operator name:'typeof')" ;; print(typeof) ;; ???
print-typeof ; "(Function name:'print')" ;; print(typeof) ;; ???
typeof=print ; "(Function name:'print')" ;; typeof(print) ;; ???
:print "a"
typeof-print ;; "String" ;; ???
typeof=print ;; "Function" ;; ???
; 代替記法 ;; 関連: [#インライン・インデント #`|`演算子, `\`演算子の用途考察]
assert\eq 1 2
assert~eq 1 2
assert:eq 1 2 ; `Key:Any`型と競合
assert|eq 1 2
assert.eq 1 2 ; TODO: 名前衝突と優先順位
;; 関数オブジェクトへの応用
[97 98].map{toUpperCase-toCharacter} ; ['A' 'B']
[97 98].map{toCharacter/toUpperCase} ; ['A' 'B']
[97 98].map{toUpperCase\toCharacter} ; ['A' 'B']
join '-' map<toS>\reverse\sort [2 1] ; "1-2"
'-'.join (sort/reverse/map<toS> [2 1]) ; "1-2" ;; 逐次呼び出しの遅延評価
join '-', sort/reverse/map<toS> [2 1]
join '-' (map<toS>..reverse..sort [2 1]) ; "1-2"
expression `\(expr)..\(expr)` (a b) ~~(x) a (b x)
;; パイプライン
:pipes toCharacter|toUpperCase
9 pipes|print ; "A"
9 toCharacter/toUpperCase/print ; "A"
;; 変数への応用
= margin-left 25
= margin-right 25
assert-eq margin {:left 25 :right 25}
assert-eq margin- {margin-left: 25 margin-right: 25}
;; メンバ関数への応用
func String-size () self.length
func String-substr () self[$0, $1]
func String-substring () self[$0..$1]
"12345".size ; 5
"12345".substr(2 3) ; 345
"12345".substring(2 3) ; 3
;;
;; 暗黙のブロック
;;
;; #拡張機能 #重要度 25% #影響度 10%
;;
;; オペランドを必要とするオペレータが単独で使用された場合、
;; 次の行の式をそのオペレータに対応するオペランドとして解釈する
;; オペランドの探索は空行や同一オペランドが出現するまで繰り返される
;;
; + 1 2
+
1
2
; (if 1 "then" "else") (if 0 "then" "else")
if
1
"then"
"else"
if
0
"then"
"else"
; {members: [{name:"bob" age:65} {name:"tom" age:9}]}
members:
------------
name: "bob"
age: 65
------------
name: "tom"
age: 9
;;
;; 遅延評価
;;
;; 実引数は式として渡される
;; 式は関数側で遅延評価される
;; 式の評価は仮引数側で自動的に行われる
;; 仮引数名に前置`#`を付与することで式の評価を保留することができる
;; - 式中に仮引数名が出現した段階で評価される
;; - 式中に出現した仮引数名が前置`#`されていた場合は式を返す
;;
= foo fn (a) ; この段階でaが評価される
a ; aには評価結果が格納されている
foo + 1 2 ; 3
;; 仮引数の先頭が`#`で始まる場合は式の評価を保留する
= foo fn (#a) ; 評価されない
#a ; aは式
foo + 1 2 ; + 1 2
;; 本文中で#が省略された場合は式の展開・評価が行われる
= foo fn (#a) ; 評価されない
a ; 評価される
foo + 1 2 ; 3
;; if文はこの仕組みを用いて実装することができる
func if (cond #then #else)
? cond #then #else
if nil (print "a") (print "b") ; "b"
;; この仕組みで独自のキーワードを処理することも可能になる
= if fn (c #then #t #else #e)
? c
? (= #then then:) #t #then)
? (= #else else:) #e #else)
if nil
then: print "yes"
else: print "no"
;; この仕組みで短絡評価の実現が可能になる
func logicalAND (#a #b) if a #b #a
func logicalOR (#a #b) if a #a #b
logicalOR (logicalAND (echo "1") no) (echo "2") ; 12
logicalOR (logicalAND (echo "1") yes) (echo "2") ; 1
;; この仕組みで演算子の優先順位を実現することが可能になる
class Number
func (+) (#expr)
if && == "Expression" typeof #expr
== "Number" typeof #expr[0]
== "Operator" typeof #expr[1]
|| == (*) #expr[1]
== (/) #expr[1]
+ self expr ; (+ 1 (2.* 3)) --> (+ 1 6)
+ self ##expr ; (+ 3 2 - 3) --> (+ 3 2).- 3
1 + 2 * 3 ; 7
3 + 2 - 1 ; 4
;; 課題 ;;
;; 遅延評価式中のthisをどう扱うか #TODO
;; 案1 遅延評価式独自の空間として扱う
;; 案2 宣言時のスコープにリンクする
;; 案3 動的スコープにリンクする
;;
;; 遅延評価の拡張
;;
;; #コア機能 #拡張機能 #重要度 89%
;;
;; 遅延評価をデフォルトにする
;; 仮引数名の前置`#`も省略可能にする
;; 機能性と多様性、柔軟性ために必要
;; ただしデバッグがしづらくなる(代替案検討)
;;
;; 仮引数側の`#`省略時
;; - 式の評価は仮引数が本文中に出現した際に一度だけ行われる
;; - 本文中に出現する仮引数が前置`#`されていた場合は式を返す
;;
;; 仮引数側の`#`明示時
;; - 式の評価は仮引数が本文中に出現する度に行われる
;;
;; `#`省略時
;;
= f fn (a) ; 評価されない
a ; 2(評価される)
#a ; ++i
a ; 2(前回評価値)
a ; 2(前回評価値)
= i 1
f ++i ; 2
;; `#`明示時
;;
= f fn (#a) ; 評価されない
a ; 2(評価される)
#a ; ++i
a ; 3(評価される)
a ; 4(評価される)
= i 1
f ++i ; 4
;;
;; ブロックの解釈
;;
;; #コア機能 #拡張機能 #重要度 100% #影響度 0%
;;
;; インデントの深さを関数名の幅基準にする拡張
;; インデントの数ではなくインデントの位置でブロックを表現する
;;
; (add 1 2)
add 1
2
; (add 1 (+ 2 3) 4)
add 1 + 2 3
4
; (add 1 (+ 2 3 4))
add 1 + 2 3
4
;; 影響 ;;
printDictionary :name "mary"
:age 16
;; 対応案 ;;
printDictionary (:name "mary"
:age 16)
printDictionary :name "mary"
age 16
printDictionary : name "mary"
age 16
;;
;; 静的スコープ
;;
;; #コア機能 #重要度 100% #影響度 --%
;;
;; クロージャーの実現に必要
;;
= v 9
{echo v}() ; 9
{echo _v}() ; 9
{echo this.v}() ; 9
{echo $static.v}() ; 9
{echo this["__static__"].v}() ; 9
{ = v 8
echo this.v
echo __static__.v
}() ; 89
;; 遅延評価式の静的スコープは元スコープ基準(検討中 #遅延評価式のスコープ)
= v 1
func do (#f)
= v 2
f
do {echo v} ; 1
;;
;; 動的スコープ
;;
;; #コア機能 #重要度 100% #影響度 --%
;;
;; 変数宣言式/代入式を実現するために必要
;; - varの独自定義を可能とする
;; classのメソッド宣言式を実現するために必要
;; - func関数からclassのインスタンスへのアクセスを可能にする
;;
;; varの実装
= var fn (#name val) = $local[#name] val
var i 99 ; = i 99
i ; 99
this.i ; 99
this["i"] ; 99
;; 関数宣言式の実装
= func ~~ (#name #param #...)
= $local[#name] (__builtin__["defun"] #name #param #...)
func add () + $0 $1
#this["add"] ; + $0 $1
;; メソッド宣言式の実装
class X
func get () 99
= i X()
i.get() ; 99
;; 備考 -- クラス宣言式の内部実装案
func class (attr ...members)
:__className__ attr.0
:__isa__ {__className__: (?? attr.1 Object)}
:__ivars__ []
for in #m ...members
__ivars__.push (#m this)
return Class(this)
;; #members[0] ; (var v 9)
;; #members[1] ; (func f () self.v)
;; #this["v"] ; 9
;; #this["f"] ; (~~ self.v)
;; assert == this (#this["f"]).__local__
class X
var v 9
func f () self.v
;; 備考 -- Class関数の内部実装
func Class (class)
= that (__UNIMPLEMENTED__ class)
each class.__ivars__
= (#_)["__static__"] that
return that
;; 備考 -- $localの内部実装
; 案1 - 糖衣構文
$local ; this["__local__"]
$typo ; this["__typo__"]
= var["__local__"] this
var i 99
; 案2 - 新たな仕様として[#暗黙のthis渡し]を加える #TODO
;; 暗黙のthis渡し
func f () $$.v
= v 9
(a 1) ; 9
this["v"] ; 9
;; $localプロパティへの応用
func $local $$["__local__"]
= v 9
do {
$local.v ; 9
this["__local__"] ; 9
}
;;
;; selfとthis
;;
;; クラスをコア機能に取り込む場合は以下の区別を行う
;;
;; this: 関数オブジェクトが自身を参照するために使用
;; self: メソッドがクラスのインスタンスを参照するために使用
;;
;; selfは静的スコープを用いて実装することができる
= self ~~ $$["__static__"]
= super ~~ $$["__static__"]["__isa__"]
class X
= v 99
func f ()
this ; f関数への参照
self ; Xインスタンスへの参照
this.__static__ ; Xインスタンスへの参照
__static__ ; Xインスタンスへの参照
$static ; Xインスタンスへの参照(糖衣構文?)
= v 11
v ; 11
_v ; 11? 99?(検討中)
this.v ; 11
self.v ; 99
$static.v ; 99
;;
;; スコープチェーン
;;
;; 変数の捜索はまずスコープ内で行われる
;; 次に引数リスト
;; 次にthisオブジェクト
;; 次に静的スコープ($static)から同じ手順で
;; $static.スコープ内
;; $static.引数リスト
;; $static.thisオブジェクト
;; $static.$static.スコープ内
;; へと捜索を繰り返す
;;
;; クロージャーはこの仕組みで実現される
= v 99
(~~ print v)() ; "99"
;; selfの省略記法もこの仕組みで実現される
class X
= v 99
func f ()
self.v ; 99
v ; 99
;; 静的スコープとの関係
func foo (#f)
= v 0
f
= v 1
foo {echo v} ; 1
;;
;; 式型
;;
;; #コア機能 #重要度 100% #影響度 0%
;;
;; 遅延評価式の内部表現を定める
;;
;; `else`等のキーワードを関数側で識別するための仕組みが必要
;; 現状ではKey型の`else:`を明示的に渡す方法を採っている
;;`else`を`else:`のエイリアスする方法もあるが名前空間の汚染が問題となる
;; 式展開の段階で式をシンボル化またはKey化、文字列化するための汎用的な仕組みが求められる
;; これらの仕組みがあればDSL的に独自の機能を定義・制御することができる
;; これらの仕組みがあれば変数宣言式をユーザ定義可能にすることができる
;;
= v 9
(#v).__name__ ; v
(#w).__name__ ; w
(#+).__name__ ; + or __ADD__(検討中)
(#8).__name__ ; nil or __NUMBER__(実装依存?)
(#{echo _}).__name__ ; nil or __ANONYMOUS_FUNCTION__
(#(+ 1 2)).__name__ ; nil or __ANONYMOUS_FUNCTION__
(#v).__type__ ; Variable
(#w).__type__ ; Undefined
(#8).__type__ ; Number
(#+).__type__ ; Operator
(#echo).__type__ ; Variable
(#{echo _}).__type__ ; Function
(#(+ 1 2)).__type__ ; Expression
(#:k).__name__ ; k
(#:k).__key__ ; k:
(#:k).__type__ ; Key
(#v).__type__ ; Variable
(#v).__some__ ; {:__name__ nil :__type__ Number}
(#w).__some__ ; {:__name__ nil :__type__ nil }
(#9).__some__ ; nil
(#echo).__some__ ; {:__name__ nil :__type__ Function}
func typeof (#t)
if == "Variable" String((#t).__type__)
String t.__some__.__type__
String t.__type__
typeof v ; "Number"
typeof echo ; "Function"
func if (cond #then #t)
? && == "Key" typeof #then
== "then" String #then
t
then
if yes then "yes" ; "yes"
if yes "yes" ; "yes"
if no "yes" ; nil
;;
;; インライン・インデント
;;
;; #拡張機能 #重要度 70% #影響度 50%
;;
;; インデント区切り(タブまたは2文字以上の空白)を、
;; ブロックの区切りと見なす
;;
+ 1 2 3 4 ; + (1 2) (3 4)
* + 1 2 3 + 3 4 5 ; * (+ 1 2 3) (+ 3 4 5)
* - 1 2 ; * (- 1) 2
? eq 1 2 3 4 ; ? (eq 1 2) (3) (4)
? eq 1 2 3 4 ; ? (eq 1 2 3 4)
;; `|`演算子, `\`演算子の用途考察 #TODO
; ブロックの区切り文字としての利用
+ (+ 1 2) (+ 2 3)
↓
+ |+ 1 2 |+ 2 3
+ \+ 1 2 \+ 2 3
echo : add 1 2 : mul 2 3 ;; 75%
echo | add 1 2 | mul 2 3 ;; 75% ;; パイプ処理、ラムダ式との整合性に難がある
echo \ add 1 2 \ mul 2 3 ;; 75% ;; `\`演算子の用途次第(変数・仮引数での利用を検討中 -> 前置記法)
echo /add 1 2 /mul 2 3 ;; 75% ;; `\`とペアで検討。優先順位の多様性に関する
echo . add 1 2 . mul 2 3 ;; 50% ;; #影響: メソッドチェーン、合成関数 #TODO: 両機能の統合
echo. add 1 2.toString ;; 前置と後置、中置で区別が必要
.append '0'
.toInteger . 3 ; "303"
echo $ add 1 2 $ mul 2 3 ;; 25% ;; 影響: [#ラムダ宣言式の追加]
echo , add 1 2 , mul 2 3 ;; 0% ;; カンマ演算子と競合、位置関係が曖昧(第二引数以降の結合規則など)
echo @ add 1 2 @ mul 2 3 ;; 0% ;; 存在感、重みが強すぎる
echo add 1 2 mul 2 3
;; 結合規則の区別
echo | add 1 2 | mul 2 3 ; (echo) (add 1 2) (mul 2 3)
echo \ add 1 2 \ mul 2 3 ; (echo (add 1 2 (mul 2 3)))
echo, add 1 2, mul 2 3 ; (echo (add 1 2 (mul 2 3)))
echo \add 1 2 |mul 2 3 ; (echo (add 1 2) (mul 2 3))
assert\eq if\eq 1 1 |yes |no ||yes
assert.eq if.eq 1 1 |yes |no ||yes ;; 関連 [#カテゴリー式、グループ式]
assert-eq if-eq 1 1 |yes |no ||yes ;; 関連 [#カテゴリー式、グループ式]
;; その他
echo. add 1 2, 3 ; "5"
echo. add 1 2 . 3 ; "33"
echo. add. sub 1 2 . 2 ; "1" ;; echo + (- 1 2) 2
echo. add. sub 2 1 .. 2 ; "12" ;; echo +(- 2 1) 2
; 検証1
echo . add . sub 1 2 .. 2 ; "1" (echo (+ (- 1 2) 2))
echo. add. sub 1 2 . 2 ; "1"
echo\add\sub 1 2 \ 2 ; "1"
echo\add\sub 2 1 \\ 2 ; "12" (echo +(- 1 2) 2)
echo \add \sub 1 2\ 2 ; "1"
echo. add (sub 1 2) 2 ; "1"
; 検証2
echo add\1 2 ; (echo (add 1 2)) ;; 関連: [#カテゴリー式、グループ式]
echo add\1 2 mul\2 3 ; (echo (add 1 2 (mul 2 3)))
echo \add 1 2 \mul 2 3 ; (echo (add 1 2) (mul 2 3))
echo \add 1 2 \ mul 2 3 ; (echo (add 1 2) mul 2 3)
echo \add 1 2 \\mul 2 3 ; (echo (add 1 2) mul 2 3)
echo \add 1 2\ \mul 2 3 ; (echo (add 1 2) (mul 2 3))
echo if\eq 1 1 \ yes no \\ "\n" ; "yes\n"
; `/`と`.`で結合規則を区別
echo \ add 1 2 \ sub 3 ; (echo (add 1 2) (sub 3))
echo . add 1 2 . sub 3 ; (echo (add 1 2 (sub 3)))
; 前置記法で結合規則を明示
echo \ add 1 2 \sub 3 ; (echo (add 1 2 (sub 3))) ;; ややこしい
echo \add 1 2 \sub 3 ; (echo (add 1 2) (sub 3)) ;; ややこしい
echo .add 1 2 .sub 3 ; (echo 1.add(2 3.sub)) ;; 関連: [#代理関数呼び出し]
echo .add 1 2 ..sub 3 ; (echo 1.add(2) (sub 3))
; 前置のほうが明確
echo .add 1 2 ; "3" ;; echo add(1 2) ;; 関連: [#代理関数呼び出し] ;; "s".echo
"a" .add "b" "c" ; "abc" ;; "a".add("b" "c")
;;
;; 演算子束縛
;;
;; #拡張機能 #重要度 50% #影響度 25%
;;
;; 後置された演算子関数呼び出し式の結果を前方の関数呼び出し式へ束縛する
;;
assert! 1 2 ; assert (! 1 2)
assert= 1 1 ; assert (= 1 1)
;; 応用 - 前提仕様[#演算子の結合規則]
print+ 1 2 3 ; (print (+ 1 2) 3)
if= 1 1 "yes" "no"
;;
;; 演算子の前置記法
;;
;; #コア機能 #重要度 75% #影響度 25%
;;
+ -1 2 ; (+ (- 1) 2)
= *p &v ; int *p = &v;
;; ラムダ式の糖衣構文`~`と区別できるようにする(検討中)
= bnot ~ (bit) ~bit
bnot 0 ; -1
~(bnot 0) ; 0
~ (bnot 0) ; fn () (bnot 0)
*(1 2 3) ; 1
**(1 2 3) ; -- 検討中(可変長演算子)
; **(1 2 3) ; 2 案1
; **(1 2 3) ; (2 3) 案2
+(1 2 3) ; (2 3)
*+(1 2 3) ; 2 -- 検討中(演算子の逐次適用)
; `+`演算子の挙動案 #TODO
; assert == +1 2
; assert == +"abc" "bc"
; +"2" ???: ""
; +"2" ???: 2
1 +2 ; (1 (+ 2))
1 + 2 ; (1 (+) 2)
;;
;; 前置呼び出し
;;
;; #コア機能 #拡張機能 #重要度 100% #影響度 0%
;; #関連仕様 [#演算子の前置記法]
;;
+(1 2) ; (+ 1 2)
-1 ; (- 1)
print(1 2) ; (print 1 2)
;; 影響
^(a b) + a b ; (fn (a) b) (+ a b)
;;
;; 前置呼び出し昇格
;;
;; #拡張機能 #重要度 9% #影響度 100%
;; #前提仕様 [#前置呼び出し]
;; #代替仕様 [#式展開の原則]
;;
;; 前置呼び出しされた式をオペレータとして解釈させる
;; - 前置呼び出しされた式はオペレータに昇格する
;; - 続く式はオペランドとして解釈される
;;
~[a b] + a b ; (fn (a b) + a b)
^[a b] - a b ; (fn (a b) - a b)
;; 展開規則
= d ~~ #arguments
d[a b] ; [Array([a b])]
d(a b) ; [Variable(a) Variable(b)]
d{a b} ; [Function(fn () (a b))]
d<a b> ; [Function(fn () (a b))]
;; 辞書型宣言用の糖衣構文はこの仕様により実現が可能となる
:a 1 :b 2 ; (: a 1 (: b 2))
;; 影響
print -1 2 ; print (- 1 2)
print f() 2 ; print (f() 2)
== :key val ; == (: key val)
func f(a) nil ; func (f a nil)
;; 対応案
print -1, 2 ; print -1 2
== key: val ; = key: key ;; 後置/前置で異なる結合規則を取り入れる
;; 参考:[#段落結合]
; [#式展開の原則]
;;
;; 逐次呼び出し
;; オペレーターチェーン
;;
;; #コア機能 #重要度 75% #影響度 0%
;;
fun a echo "a"
fun b echo "b"
a|b ; "ba" -- 案1
a|b ; "ab" -- 案2
a-b ; -- 案3(影響: [#名前解決])
a<>b ; -- 案4(関連: [#部分適用式])
a<b ; "ba"
a>b ; "ab"
a->b ; "ab"
a<-b ; "ba"
;; 戻り値の受け渡しが行われる
func a () + 1 _
func b () + 2 _
a|b 0 ; 3
;; プロパティ呼び出しへの応用も視野に入れる
99.nod.toS ; 99.numberOfDigits().toString()
99.toS.len ; 99.toString().length()
;;
;; 名前解決
;;
;; #拡張機能 #重要度 60% #影響度 100%
;;
;; キャメルケースとスネークケースとチェインケースに相互互換性を持たせる
;;
exte Number func numberOfDigits () Integer (+ 1 Math.log10(self))
99.numberOfDigits ; 2
99.number-of-digits ; 2
99.number_of_digits ; 2
;;
;; 部分適用式
;;
;; オペレータに対する後置記法を関数の部分適用式として解釈する
;; 部分適用やカリー化の糖衣構文を実現する事ができる
;;
; map (fn (a) * 2 a}) [1 2 3]
map{* 2 _} [1 2 3] ; [2 4 6]
map<* 2 _> [1 2 3] ; [2 4 6]
map<* 2> [1 2 3] ; [2 4 6]
map<+ "0"> [1 2 3] ; ["01" "02" "03"]
sort{>} [1 2 3] ; [3 2 1]
filter{< 1} [1 2 3] ; [2 3] ;; 関連: [#部分適用]
reverse|map<* 2>filter{< 1} (1 2 3) ; (6 4) -- 案1(関連: [#前置呼び出し昇格] [#逐次呼び出し])
filter{< 1}map<* 2>|reverse (1 2 3) ; (6 4) -- 案2(関連: [#前置呼び出し昇格] [#逐次呼び出し])
= f sort{>}
f [4 5 6] ; [6 5 4]
f [7 8 9] ; [9 8 7]
= f {add<$0>}
= g (f 9) ; add<9>
g 1 ; 10
;; 応用
;; コードの多様性を実現する用途にも活用できる
[1 2 3].take 2 ; [1 2]
[1 2 3].take{>2} ; [1]
= f (>3)
[1 2 3].take f ; [1 2] ; 曖昧(fは数値なのか関数なのか)
[1 2 3].take{f} ; [1 2] ; 明確
;; このようなセマンティクスの明確化によって
;; オーバーロードの欠点を補うことも可能となる
;; 備考
;; 本仕様は[#前置呼び出し昇格]の仕組みで代用することもできる
func map (f a)
switch _arguments.length
(0) #map
(1) ~~ [aa] map f aa
(2) for<f> a
(_) map f [a ...]
map{* 2} [1 2 3] ; [2 4 6]
= f map{* 2}
f [1 2 3] ; [2 4 6]
= (+) {== 1 len(...) {+ $$0 $0} (__builtin__.+ _0 _1)}
= add {+ ...}
add(9) ; #(+ 9 $0)
add(9) 1 ; 10
;;
;; 部分適用
;;
;; #コア機能 #重要度 59% #影響度 200%
;; #関連仕様 [#遅延評価]
;;
;; 部分適用を基本機能として組み込む
;; 全ての式をカリー化の対象にする
;;
= f ~~ + _ _
= g (f 1) ; {[a] |b| f a b} 1
(g 2) ; 3
(f 1)(2) ; 3
= lt (< 1)
lt 2 ; true
;; 部分適用式との比較
f<1> 2
lt{< 1} 2
;;
;; 代理関数呼び出し
;;
;; #コア機能 #拡張機能 #重要度 90% #影響度 25%
;;
;; 1. 関数呼び出し時
;; 第一オペランドがオペレータと同名のメンバ関数を持つ場合はそちら呼び出す
;; 2. メソッド呼び出し時
;; メンバ関数が存在しない場合は同名のグローバル関数を呼び出す
;; ※ 両探索は再帰的に行われないものとする
;;
len "a" ; "a".len()
1.+ 2 ; (+ 1 2)
;; 問題点
;; プライベートメソッドを誤って呼び出してしまう
;; 対応案
;; アンダースコアで暗黙的な非公開メソッドを明示する
exte String
fn _privateFn () nil
fn publicFn () nil
fn _print () "A"
fn log () % "String: \"%s\"" __raw__
privateFn "" ;; error
publicFn "" ;; ok
print "" ; <String: 0x12345678>
_print "" ; "A"
log "" ; <String: "">
;;
;; プロパティ呼び出し
;;
;; #コア機能 #重要度 60% #影響度 100%
;; #関連仕様 [#遅延評価 #式展開の原則]
;;
;; プロパティを実現するために関数呼び出しの仕組みを変更する案
;;
;; 案1 -- 関数呼び出しをデフォルトにする
"ab".len ; 2
#"ab".len ; func String::len
"ab".len# ; 案2
"ab".len& ; 案3
"ab".&len ; 案4(前置のほうが明確)
"ab"::len ; 案5(静的メンバ採用時注意 -> Int::MAX vs 9::MAX)
;; 案2 -- 後置"."を関数呼び出しのトリガーにする
self.copy.append "a" ; self().copy().append("a")
;; 案3 -- 遅延評価の仕様に例外を設ける
func test (#f)
;; before
f ; func String::len
;; after
f ; 2
test "ab".len ; 2
test #"ab".len ; func String::len
;;
;; 式展開の原則
;;
;; #コア機能 #拡張機能
;; #重要度 75% #影響度 200%
;; #前提仕様 [#遅延評価]
;; #関連仕様 [#プロパティ呼び出し]
;;
;; 遅延評価の仕様を拡張
;; 式の文脈に応じて式の展開と譲渡を分ける
;; - [#プロパティ呼び出し 案1]の実現に必要
;;
;; 1. 式がオペレータとして評価できる場合は展開を行う
;; 2. 式がオペランドとして評価される場合は展開を行わない
;; 3. オペレータが遅延評価式の場合は展開を行う
;; 4. メンバアクセスについては常に展開を行う
;; 5. アンダースコアで始まるシンボルの場合は展開を行う
;;
= say ~~ "hello"
say ; "hello"
#say ; ~~ "hello"
{#_0} say ; ~~ "hello"
{#_0} (say 1) ; "hello"
say.len ; 5
"a".len ; 1
{#_0} "a".len ; 1
{#_0} #"a".len ; func String::len
;; [#前置呼び出し昇格]への影響を考慮する必要がある
^(a) print a ; (fn (a) print a) ; (## fn (a) pritn a)
;; break文の実現
func while (#cond #stmt)
= i 0
= stop 0
= break ~~ :stop 1 :$local["return"] $0
if && cond
!stop
stmt i--
while true
if > 9 $0
print $0
break
;;
;; 引数リスト
;;
;; #重要度 75%
;;
;; ラムダ宣言時の仮引数の明示/省略を可能とする
;; 第一引数を仮引数リストとして解釈するラムダ式(`~ (a) a`)と
;; そうでないラムダ式(`~~ _0`)、その両者の区別をなくす
;; 基本仕様:
;; 引数リストは配列リテラルと同等の記法で表現する
;; 拡張仕様:
;; 引数リストは`|`で囲われたリストの形での表現も可能
;; `{}`内では開始`|`の省略が可能
;; 引数リストは`|`で囲われたリストが用いられた場合、`{}`の省略が可能
;;
= add ~~ [a b] (+ a b)
= sub ~~ (- _0 _1)
= mul ~ (* $0 $1)
= not fn !! _
{[a] print a} 1 ; "1"
{print _} 2 ; "2"
{a| print a} 1 ; "1"
flip(apply) 1 |a| print a ; "1"
;; 影響
{print| 0 1}() ; (0 1)
{print | 0 1}() ; "1"
+= add {last | last }
+= add {first ...rest | + first (...rest) }
add 1 2 3 ; 6
; 可読性の低下
f(g v| g 1 v) ; `g v`は関数呼び出し式に見えてしまう
f(g, v| g 1 v) ; 若干明確
f(|g v| g 1 v) ; より明確(ラムダ式の開始位置が明確になる)
;; 影響
;; コア機能に影響
;; ラムダ宣言関数`fn`, `~~`の内部で引数リスト`[]`の判定が必要になる
;; 配列リテラルとリストの内部表現を区別する必要がある
; before
typeof [1 2] ; List
typeof (1 2) ; List
; after
typeof [1 2] ; Array
typeof (1 2) ; List
;; 対応
;; 前置引数リスト
;; 配列リテラルとの区別が可能になる
;; ただし紛らわしい
;; #重要度 25%
;;
[a b]{+ a b}
(a b){+ a b}
sort (a b) {< a b} ; sort (a b), {< a b}
sort [a b] {< a b} ; sort ([a b] {< a b})
sort (a b){< a b} ; sort ((a b) {< a b})
;;
;; 引数リストの記法に意味を持たせる
;;
;; #関連 [#関数オーバーロード]
;;
+= sum {[a b] "a"}
+= sum {(a b) "b"}
sum [1 2] ; "a"
sum 1 2 ; "b"
;;
;; 遅延評価の拡張
;;
;; 変数宣言時にも遅延評価の仕組みを利用可能にする
;;
#= f (+ 1 2)
#f ; (+ 1 2)
&f ; (+ 1 2)
f ; 3
*f ; 3
=# f (+ 1 2) ; 案2(`=#`演算子側で遅延束縛~~参照バインド~~)
# f (+ 1 2) ; 案3(`#`演算子を定義)
= f #(+ 1 2) ; 案4(前置`#`でラップ)
= f &(+ 1 2) ; 案5
=& f (+ 1 2) ; 案6
;;
;; 連結演算子
;;
1 . [2 3] ; [1 2 3]
. 1 [2 3] ; 要検討 #TODO (.f class{__call__: assert(_ "f")})
; (. class{__call__: assert(_ "" )})
[1] . [2 3] ; [[1] 2 3]
+ [1] [2 3] ; [1 2 3]
{|first ...rest| first.rest}(1 2) ; [1 2]
{|v.w| w}(1 2 3) ; ...(2 3)
{[v.w] w}(1 2 3) ; [2 3]
+= sum {0}
+= sum {[car.cdr] + car (sum cdr)}
sum [1 2 3] ; 6
;;
;; 演算子の結合規則
;;
;; 演算子を優先的に解釈する
;;
print + 1 2 ; print (+ 1 2)
+ 1 + 2 3 ; (+ 1 (+ 2 3))
+ 1 (+) 2 3 ; (+ 1 + 2 3)
;; 二項演算子は第二引数までを処理する
;;
+ 1 2 3 ; (+ 1 2) 3
+ + 1 2 3 ; (+ (+ 1 2) 3)
+ + 1 2 3 4 ; (+ (+ 1 2) 3) 4
if == 1 2 + 1 2 ; (if (== 1 2) (+ 1 2))
if == 1 + 2 3 4 ; (if (== 1 (+ 2 3) 4))
;; 単行演算子は第1引数までを処理する
;;
! 1 ; false
~ 0 ; -1
;; 問題
- 1 2 ; (- 1) (2)
~ [a] echo a ; (~ [a]) (echo a)
;; 代案 --> [#前置呼び出し]
;; 代案 --> [#TODO 優先順位の既定] #重要度 0%
;; 代案 --> [#二項演算優先の原則] --> [#可変長式]
- - 2 1 ; -1
! - 2 2 ; true
;;
;; 演算子の結合規則(拡張)
;;
;; #関連 [#ブロック内包式の結合規則]
;;
;; 二項演算の最終オペランドに続く要素が他のオペレータのオペランドになりえない場合
;; 最終オペランドをオペレータとみなし、続く要素をそのオペレータのオペランドとみなす
;;
== "String" typeof "" ; (== "String" (typeof ""))
;; #TODO
if == "String" typeof "" yes ;; !!!: (typeof "" yes)
if == "String" typeof ""
yes
if == a b yes ; if (== a b) yes ;; 演算子優先
;;
;; 可変長式
;;
;; 二項演算優先の原則に例外を設ける
;;
;; #TODO 整理必要
;;
;; ※ 二項演算優先の原則自体の廃止を検討 #2017-01-08
;; - 演算子のみを特別に扱うのは一貫性に欠けるのではないか
;; - 関数と演算子は等価に扱うべきか
;; - 一貫性と多様性のどちらを重視するべきか
;;
;; 1. 演算子に続く要素が値として評価できる場合は
;; たとえそれが三項目以降の要素であっても
;; 演算子に対応する被演算子と見なすことができる
+ 1 2 3 ; (+ 1 2 3)
+ 1 2 - 3 ; (+ 1 2) (- 3)
print(+ 1 2 3) ; print (+ 1 2 3)
;; 2. 続く要素に演算子が現れた場合はその後に続く要素全てを
;; その演算子の被演算子とみなすことができる
+ 1 + 2 3 4 ; + 1 (+ 2 3 4)
= v + 1 2 3 ; = v (+ 1 2 3)
= v + 1 + 2 3 4 ; = v (+ 1 (+ 2 3 4))
= add ~ (a b) + a b ;; = add (~ (a b) (+ a b))
= add fn (a b) + a b ;; ???: 予約語については要検討
;; 3. オペレータが連続する場合は内側のオペレータを二項演算として処理する
+ + 1 2 3 4 ; + (+ 1 2) 3 4
if != nil obj print obj ; if (!= nil obj) print obj
;; 4. ユーザ定義関数については(1.)の仕様のみが適用される
add add 1 2 3 ; (add (add) 1 2 3)
; ※ ifを文ではなく関数と仮定した場合
if eq 1 1 yes no ; (if eq 1 1 yes no)
if (eq 1 1) yes no ; (if (eq 1 1) yes no)
;; 可変長式は可変長引数で処理する
func add (...) (+ ...)
add 1 2 ; 3
add 1 2 3 ; 6
;; switch文の実装
func switch (val ...cases)
= [i c] [0 size(cases)] ; = [:i 0 :c size(cases)] ; :i 0 :c size(cases)
while [(< i c) ++i]
if == val cases[i][0]
return cases[i][1]
switch argc
1 print "1"
2 print "2"
;; ヨーダ記法との相性
== "abc" + a b c
== (+ a b c) "abc" ; ヨーダ記法未使用時
;; 備考 #2017-01-08
;;
;; 以前、以下のような解釈を検討していた
== "A" upcase "a" ; == "A" (upcase "a")
;;
;; オペランドの結合規則
;;
;; #コア機能 #拡張機能 #重要度 100% #影響度 100%
;;
;; オペランドが複数指定された場合の結合規則
;;
;; カンマ演算子の結合規則
;;
;; #拡張機能 #重要度 75% #影響度 100%
;;
;; カンマの記述箇所によって要素式の結合規則が変化する
;;
;; コロン演算子の結合規則
;;
;; #拡張機能 #重要度 75% #影響度 50%
;; #関連 [#段落結合]
;;
;; コロンが後置された場合(`f a: b c`)
;; 以降の式を、外延する単一の要素式とする(`(f a (b c))`)
;; コロンが前後空白有りで後置された場合(`f a : b c`)
;; 以降の要素式の並びを、外延する要素式の並びとする(`(f a b c)`)
;;
;; 案0 -- 左畳み込みを基準とする
a b c d ; (((a b) c) d) ;; #TODO:部分適用のデフォルト化
a b c, d ; ((a (b c)) d)
;; 案1 -- オペレータとオペランドの関係性を基準とする
a b c d ; (a b c d)
a b c, d ; (a (b c) d) ;; (オペレータ重視)
echo add 1 2 ; echo (add) 1 2)
echo add 1, 2 ; echo (add 1) 2
if eq 1 2, yes no ; if (eq 1 2) yes no
echo, add 1 2 ; echo (add 1 2)
echo:add 1 2 ; echo (add 1 2)
;; 案2 -- 右畳み込みを基準とする
a b c d ; (a (b (c d)))
a b c, d ; (a (b c d)) ;; (オペランド重視)
echo add 1 2 ; echo (add (1 2))
echo add 1, 2 ; echo (add 1 2)
echo, add 1, 2 ; echo (add 1) 2
echo add 1, 2 3 ; echo (add 1 (2 3))
echo add 1, minus 2 ; echo (add 1 (minus 2))
echo eq add 1, 2 ; echo (eq) (add 1 2)
; echo (eq (add 1 2))
echo add 1, 2,, 3 ; echo (add 1 2) 3
echo add 1, 2 : 3 ; echo (add 1 2) 3
if eq 1, 2: print yes ; if (eq 1 2) (print yes)
if eq 1, 2 : yes no ; if (eq 1 2) yes no
if eq 1 2 : yes no ; if (eq 1 2) yes no ;; 関連:[#演算子の結合規則(拡張)]
; 検証
echo add 1, 2,, 3 ; echo (add 1 2) 3
echo add 1, 2 : 3 ; echo (add 1 2) 3
echo (add 1 2) 3 ; echo (add 1 2) 3
if, eq 0 "", yes, no
if eq 3 add 1, 2,,, yes no
if eq 3 add 1, 2 :: yes no
;;
;; アンダースコア命名規則
;;
;; #コア機能 #重要度 75% #影響度 50%
;;
;; アンダースコアで始まる変数は暗黙的にthisのメンバを指すものとする
;;
= add ~~ + _0 _1 ; = add (~~ (+ this["0"] this["1"]))
{echo _} 2 ; 2? this[""]?
class X
= v 1
func f () _v
= x X
x.f ; 1
= (#x.f)._v 2
x.f ; 2
x.v ; 1
;;
;; アンダースコア1文字変数
;;
;; #関連 [#アンダースコア命名規則]
;;
;; `_`出現時の暗黙の関数呼び出しを実現する仕様が必要(関連: [#式展開の原則])
;; 以下の記法の実現を前提とする
;;
[1 2 3].sort {> _ _} ; [3 2 1]
= add ~~ + _ _ ;; `+ _0 _1`と同等処理
add 1 2 ; 3
= isdigit IsDigit {
&& >= _ '0' <= _ '9' ;; `_0 _0`と同等処理
}
class IsDigit
fn init [:_f f:Function] :_f.__static__ self
fn operator() [:_arg arg:Character] _f arg
fn _ [] _arg
class Add
fn init [f:Function] = _f f
fn operator() [...args:Any]
= _args Array(...args)
= _f.__static__ self
_f arg
fn _ [] _args.pop
= add Add {+ _ _}
;;
;; ドルマーク一文字オブジェクト
;;
;; `$`で始まる記法を特別に解釈する
;;
$ ; 第一仮引数
$0 ; 第一仮引数
$.0 ; メンバアクセス
$::v ; 未規定
$this ; 自身の関数
$() ; 関数呼び出し
;;
;; 比較演算子の拡張
;;
;; #拡張機能 #重要度 0% #影響度 100%
;; #代替案 [#代入演算子の変更]
;;
;; 式中の代入演算子`=`を文脈に応じて比較演算子`==`として解釈させる
;;
= a "foo" ;; 案1
=b "bar" ;; 案2
if (= a b) print a ; if (== a b) print a
;; 影響
func lazyView () ?? _view = _view (View new) ; javascript: return _view || (_view = new View)
while = next next.next print next.v
;; 対応案
return =_view (View new)
return : _view (View new)
return :: _view (View new)
return == _view (View new)
;;
;; 演算子の用途変更
;;
;; #コア機能 #拡張機能 #影響度 100%
;; #重要度 70% #2017-01-06
;; #重要度 50% #2016-12-28
;;
;; 文字数の少ない演算子を利用頻度の高い演算子へ優先的に割り当てる
;; - 前置記法の性質上、文字数の広い記号を用いることによる
;; 視認性や可読性の向上はさほど期待できない
;; * 中置記法の場合はオペランド間の区切りを
;; より明確にできるという意味では実に効果的であった
;; - 前置記法の場合は文字揃えを効果的に用いることで、
;; より視認性・可読性の高いコードを書くことができる
;; - 一文字幅の演算子はきわめて尊い存在であり
;; また2文字幅インデントとの相性も良いことから
;; 頻繁に使われる演算に対して優先的に割り当てたい
;; - コア機能として取り込むか、または
;; 演算子オーバーロードでユーザ定義可能にするかは検討中
;; `func (=) #__builtin__.operators["EQ"]`
;; `func (!) #__builtin__.operators["NOT_EQ"]`
;;
;; | `==` | 束縛演算子 -- 案1
;; | `:` | 束縛演算子 -- 案2
;; | `=` | 比較演算子 (EQ)
;; | `!` | 比較演算子 (NOT EQ)
;; | `!=` | 論理演算子 (NOT)-- 案1
;; | `!!` | 論理演算子 (NOT)-- 案2
;; | `~=` | ビット演算子(bitwise NOT)-- 案1
;; | `!~` | ビット演算子(bitwise NOT)-- 案2
;; | `&` | 論理演算子 (AND)
;; | `|` | 論理演算子 (OR)
;; | `&&` | ビット演算子(bitwise AND)-- 案1
;; | `||` | ビット演算子(bitwise OR) -- 案1
;; | `&^` | ビット演算子(bitwise AND)-- 案2
;; | `|^` | ビット演算子(bitwise OR) -- 案2
;; | `&~` | ビット演算子(bitwise AND)-- 案3
;; | `|~` | ビット演算子(bitwise OR) -- 案3
;; | `^^` | 排他的論理和(XOR)
;; | `^` | ラムダ宣言式 -- 未定
;; | `?` | 条件演算子
;; | `??` | 未定 - 案: (?? 0 1) clang: (0 ?: 1) == 1
;; | `?:` | 未定 - 案: (?; 0 1 0) clang: (0 ? 1 : 0) == 1
;;
= 1 2 ; javascript: 1 == 2
! 1 2 ; javascript: 1 != 2
!!true ; javascript: !true ; 案1
!true ; javascript: !true ; 案2
! true 2 ; javascript: true != 2 ; 案2
== s "foo"
if (= s "foo") print s ; "foo"
if & ! s null
| = s "UTF8" ;; [#ブロック内包式の結合規則#ブロック内包式の演算子結合]
= s "SJIS"
print "yes"
; if (s != null &&
; s == "UTF8" ||
; s == "SJIS")
; print("yes")
cond with:bar
(= "String" typeof _) cond with:_
(= "bar" _) print "Bar"
(! "foo" _) print "oof"
(= "Number" typeof _) cond with:_
(& 0xFF00 _) print ^^ _
(| 0x0F0F _) print !! _
;;
;; 代入演算子の変更
;;
;; #拡張機能 #重要度 75% #影響度 100%
;; #関連仕様 [#演算子の用途変更]
;; [#遅延評価]
;; [#遅延評価の拡張]
;;
;; `=`(代入演算子/変数宣言式)を廃止
;; `=`を比較演算子として利用
;; `:`を代入演算子として利用
;; Map型の宣言式と変数宣言式を統合する
;;
:a "foo" ; var a = "foo";
a: "foo"
: a "foo"
:b :a "foo" ; var b = {a: "foo"}; ???
:a 1 :b 2 ; var a = 1; var b = 2;
[:a 1 :b 2] ; {a: 1, b: 2}
{:a 1 :b 2} ; fn () {:a 1 :b 2}
[:a 1 :b 2] ; {this.a = 1; this.b = 2;}.a == 1
:dic {:a 1 :b 2}() ;; #TODO [#束縛演算子の戻り値](案: thisを返す)
dic.a ; 1
:dic {:a 1 :b 2}
dic.a ; 1 ;; #TODO [#静的メンバ] [#遅延関数呼び出し]
{ :a 1 :b 2
:sum fn () + a b
} sum ; 3
< len(":v 9") len("= v 9")
; < ":v 9".len "= v 9".len ; MARK: 可読性低い
;; #TODO
assert = 1 {1}()
assert = 2 {1 2}()
assert = 1 {:v 1 2}().v ;; undefined == 2.v
assert = 1 {:v 1 2 this}().v
assert = {:v 1}() {:v 1 this}()
assert = {:v 1}() {:v 1}().__this__
;; 問題 ;;
;; 一文字変数利用時にコメントとの区別がしずらくなる
;; コメント1
:i ~~ $1 $2
;; コメント2
:j ~~ $1 $2
;; 対応
: i ~~ $1 $2
;; 対応
$i ~~ $1 $2
;; 対応
::i ~~ $1 $2
;;
;; 静的メンバ
;;
;; #重要度 50%
;; #前提仕様 [#代入演算子の変更]
;;
;; 関数オブジェクトへのメンバアクセス時について
;; 関数内の式中から対応する同名のローカル変数をメンバ変数として取得する
;;
{:a 9}.a ; 9
{:a 9}.b ; nil
{|b| :a b}.a ; nil
{|b| :a b}(2).a ; 2
:b 8
:dic {:a b}
dic.a ; 8
:b 7
dic.a ; 8?
;;
;; 遅延関数呼び出し
;;
;; #重要度 50%
;; #前提仕様 [#代入演算子の変更] [#束縛演算子の戻り値]
;;
;; 関数オブジェクトを束縛した変数へのメンバアクセスが行われた際には
;; 関数オブジェクトの呼び出し結果を自身の変数に再束縛した上でメンバアクセスを行う
;;
::dic {:a 9}
typeof dic ; Function(anonymous {:a 9})
dic.a ; 9
typeof dic ; Map({:a 9})
;;
;; ラムダ宣言式の追加
;;
;; #重要度 75%
;; #関連仕様 [#演算子の用途変更] [#引数リスト]
;;
;; `||`をラムダ式に応用する
;; ラムダ式の出現箇所を強調する意図がある
;; 縦方向に広いグリフは目立ちやすいという特性を活かす
;; また引数追加時の対応がしやすくなるという利点がある
;; `~~` --> `~(arg)` ; before
;; `||` --> `|arg|` ; after
;;
= f || echo _ ; 論理OR文を採用した言語との区別が面倒で煩わしい
= g |v| echo v
f "foo" ; foo
g "bar" ; bar
{|v| echo v}
|v| {echo v} ; `|`演算子との共存が難しい。カンマを必須にする必要がある
{v| echo v} ; `|`一つではラムダ式としての認知のし易さに難点あり
[v| echo v] ; `map(v| -v)`は綺麗だが曖昧、`map(|v| -v)`のほうが明確で認知効率が高い(とりわけ仮引数名が長くなる場合)
[v]{echo v} ; 括弧を用いれば、どこからどこまでが仮引数リストの範囲なのかが明確
<v>{echo v} ; `|`と`{}`の組み合わせはフォントによっては読みづらくなる
; `|`がベースライン寄りに描画されることがあるため
; 中央に表示される`<>`であれば安定
; 空白の記述も省略可能で安定した記述となる
; `{}`よりも`<>`のほうが縦に短いためバランスも良い(左向き三角のシルエット `<>{}`)
{<v> echo v}
{<>.echo}
{echo <>}
echo<>
<>.echo
f(<v> echo v)
{+ <>}(1 2) ; 3
[1 2].fold 0 +<>
#v echo v
v # echo v
each(item, index # echo item)
each{#(item, index) echo item}
[].each (item index) #
echo item
$ echo $0 ;; #domain-specific
{|a| $echo a _}(9)(8) ; "98"
{|a| $(b) echo a b}(9)(8) ; "98"
;; 糖衣構文
= p ^print "hello" ;; 案1
= p ~print "hello" ;; 案2
= p #print "hello" ;; 案3
p() ;; "hello"
:p ^print
p "hello" ;; "hello"
;; 省略記法: `|`が後置されていた場合
sort(a b| > a b) ; sort(|a b| > a b)
;; 省略記法: `[]`がオペレータとして解釈可能な場合
__typeof__ [a b] + a b ; Function
__typeof__ [a b] + a b ; Array & Expression
;; 合理性検証
[].map |v| + 1 v
[].map{|v| + 1 v}.sort
[].map(|v| + 1 v).sort
[].map(<v> + 1 v).sort
[].map(|| + 1 _).sort
[].map(~~ + 1 _).sort
[].map<+ 1>.map{<v> + 1 v}
[].map<+ 1>.map <v> + 1 v
[].map<[_ <* 2>]>.map <v w...> + v w
[].each{print _}
[].each{print $0}
[].each{print <>}
[].each<print {}>
[].each <>.print ; 外部スコープを参照してしまっている
[].each print<> ; 外部スコープを参照してしまっている
[].each<>.print
;;
;; 段落結合
;;
;; #拡張機能 #重要度 50% #影響度 75%
;; #用語案 [段落結合 後置結合]
;;
;; 次の段落に出現する式を現在の式に対応する要素式として解釈させる
;;
;; 案1 -- `key:`式がオペレータとして評価可能な場合は結合可能式と見なす
if nil
print "yes"
else:
print "no"
; before
; (if nil (print "yes")) (else: (print "no"))
; after(案1) -- 有力案
; (if nil (print "yes") (else: print "no"))
; after(案2)
; (if nil (print "yes") else: (print "no"))
;; 影響
;;
;; Key型の定義と内部表現をより厳格に定める必要がある #TODO
;; Symbol型、KeyValue型
;; キーワードに対する`:`前置記法と後置記法に異なる意味を持たせる
;;
;; 対応案
;;
;; `:key val` -> (: key val) ;; 従来通りMap型への糖衣構文
;; `key: val` -> ((key:) (val)) ;; 一意のオブジェクト
;; `key: val` -> (key: val) ;; オペレータとして扱う
;;
;; 応用例
;;
;; ベースクラスの指定
;; `class Integer: Number`
;; 型の明示
;; `func join (separator: String items: Array)`
;; 名前付き引数
;; print 1 2 separator: "," ; (print 1 2 (separator: ","))
;;
;; 実行時評価
;;
;; = key :KEY
;; print key: ; ??? :key
;; print :key ; ??? :KEY
;;
;; キー型
;;
;; `:`が前置された場合は単純なキー型として扱う
;; 式は値として評価される
;;
;; = map (:a 1 :b 2)
;; map.0 ; Key(:a)
;; map.3 ; Number(2)
;;
;; セル型
;;
;; `:`が後置された場合はオペレータとして扱う
;; 式はオペランドを内包するリスト型として評価される
;;
;; class Array
;; fn __doesNotUnderstand__ (a b c)
;; if & = a.0 :setObject
;; = b.0 :atIndex
;; Array_insertValueAtIndex(__raw__ b.1 a.1)
;; throw "unrecognized selector"
;;
;; ([] setObject:"a" atIndex:0)
;;
;; 可読性に関する実験
;;
;; alpha: 1 beta: 2 --> alpha: 1, beta: 2
;; alpha:1 beta:2 --> シンタックスハイライトを効かせればカンマ不要
;; :alpha 1 :beta 2 --> `:`が区切り文字の替わりになるためカンマ不要
;; :ary["key"] "val" --> 代入処理としての明確さは高い
;; ary["key"]: "val"
;; :key "val" --> 関数呼び出しと解釈される恐れがあり
;;
;; 末尾要素式に対する後置`:`の解釈
;;
;; 影響:[#セル型]
;;
;; 複要素式の末尾に`:`が記述された場合
;; 以降の階層を一続きのブロックとみなす
;;
;; if = no nil: ;; 出力:"no"
;; print "n"
;; print "o"
;;
;; インデントが二重の場合はセル型として解釈する
;;
;; if true then:
;; yes
;; else:
;; no
;;
;; 末尾コロンの利用には、条件部と処理部の区別を容易にする目的がある
;; コロンが後置された行の次の行では字下げが行われていることが自明であるため
;; 両行が異なる領域に記述された処理であることが直感的に理解できるようになる
;;
;; = vl mc_fn_a()
;; if = vl fn_b(): ;; 制御文であることが直感的に理解できる
;; print fn_c() ;; コロンの後なので、字下げされていることがすぐに分かる
;; ;; 上記のインデントを確認せずとも、コロンの有無だけで字下げを判断することができる
;;
;; `;`の他、` :`や`,`の利用も検討する
;;
;; 案2 -- 段落間の改行が省略された場合に前後の式を結合する
; (if nil (print "yes") (else print "no"))
= else #:else
if nil
print "yes"
else
print "no"
; (if nil (print "yes")) (else print "no"))
if nil
print "yes"
else
print "no"
;; 案2-3
if = no nil:
print "no"
elif = yes true:
print "yes"
;; その他
value:
a: "a"
+ a "b"
print value ; "ab"
; #TODO
; 空行の記述を容認した場合
; 変数初期化式が段落結合の対象になってしまう問題あり
if yes
print "yes"
elsa:
"Elsa"
;;
;; 型の明示
;;
;; 空白を挟まない`要素:型名`記法が用いられていた場合、
;; インタプリタ側では`:型名`の部分を無視する
;;
func makeView (point:Point size:Size):View
(View point size)
;;
;; 型システム
;;
;; [#型の明示]を正式な型システムに取り入れる場合は、
;; 仮引数のインターフェースを厳格に定める必要がある
;; - Key型の仕組みを活用する
;; - または式型の仕組みに取り込む #2017-01-08
;;
;; 代替案 [#ブロック・コメント]
;; 型情報をコメントとして記述する
;; 型情報は静的解析時等に活用する
;;
= func ~ (name #params ...)
= $local[name] (fn #params ...)
#params
# params (func makeView (point:Point size:Size):View nil)
#params[0] ; {:type Point :name point}
#params[1] ; {:type Size :name size }
; 案1
#params.type ; View
#params.name ; nil
; 案2
#params.type ; Array
#params.attr ; {:type Object :some View}
(#(():[:a "1" :b "2"])).attr
; {:type Map :some [:a "1" :b "2"]}
class Sub: Super, Equatable
func equals (a): [type:Bool throws:IllegalArgumentException]
Bool(== self a)
func copy(from: [const, String] to: [type: String])
sweetassert (#from).attr.contains(const)
__builtin__["libc/string.h"].strcpy to.__raw__ from.__raw__
func print (terminator: [default:"\n"])
print value: self
separator: ", "
terminator: terminator
func add(a b): [Int Int String]
String(+ a b)
func add(a b): [a:Int b:Int String]
String(+ a b)
func add(a b) ;(Int Int String)
String(+ a b)
;;
;; 名前付き引数
;;
;; [#型システム]との整合性も意識する
;;
(View point:(2 3) size:(600 450)) ; 案1
(View (2 3):point (600 450):size) ; 案2
;;
;; 糖衣構文(辞書型)
;;
= bob :name "bob" :age 16 ; = bob {name:"bob", age:16}
= tom :name "tom"
:age 32
;;
;; 糖衣構文($)
;;
;; #コア機能 #重要度 50% #影響度 0%
;;
;; `$`で始まる変数をメンバアクセスの糖衣構文にする
;;
$static ;; this["__static__"]
{echo $0} ;; ~~ echo this["__0__"]
{$length}(1 1) ; 2
;;
;; 糖衣構文(_)
;;
;; #多様性 #重要度 40% #影響度 1%
;;
;; `_`で始まる数値を仮引数の糖衣構文にする
;; ただし、可読性が低く、数値として認知されやすいという欠点がある
;; その他、メンバ変数との競合あり
;; [#糖衣構文($)]の応用を視野に入れる
;;
{echo _0} ;; ~~ echo this["__0__"]
;;
;; コメント
;;
; inline comment
;;
;; ブロック・コメント
;;
;; `;`に続く文字が開始括弧で始まる場合、ブロックコメントの開始コメントと見なす
;; `;`に続く文字が閉じ括弧で始まる場合、ブロックコメントの終了コメントと見なす
;;
;; 例
;( block comment ;)
;( block comment ) ;; 検討中(インライン時限定)
;[ block comment ;]
;| inline comment ;|
; ( inline comment ;)
; [ inline comment ;]
;; 応用例(ネスト)
;{
memberof ";{;}"
;[
memberof ";[;]"
;]
memberof ";{;}"
;}
;; 応用例(トグル)
;[
echo "i was here"
;]
; [
echo "i am here"
;]
;(echo
"i was here"
)
(echo
"here i am"
)
;; 応用例(アノテーション、型情報)
;(override) func sound ();String
"nyan"
func strcpy (from:String;(nonnull) to:String;nonnull
):String;(nullable, overloadable) {}
; @(override) func sound () @String "nyan"
; func strcpy (from:String@(nonnull) to:String @nonnull
; ):String @(nullable, overloadable) {}
;; 拡張案
;;
;; `(; <expression>...)`式をコメントとする
;;
(; (print "a") )
(;
(print "a")
(print "b")
)
(;if yes
"y"
"n")
;;
;; ドキュメント・コメント
;;
;;# heading
;;- item-1
;;- item-2
;;## subheading
;;| A B
;;| C D
;;;;;;;;;;;;;;;;;;;;;;;;
;
; # heading
; - item-1
; - item-2
; ## subheading
; | A B
; | C D
;
; ~~~ js ~~~~~~~~~~~~~~~
; var f = (i) => i * 2
; ~~~~~~~~~~~~~~~~~~~~~~
;
;; 変換後
; <h1>split</h1>
; <ul><li>item-1</li>
; <li>item-2</li></ul>
; <table><tr><td>A</td><td>B</td></tr>
; <tr><td>C</td><td>D</td></tr></table>
;;
;; その他
;;
;; 関数をオブジェクトとして渡すための記法
call + 1 2 ; (call (+ 1 2))
call +, 1 2 ; (call + 1 2)
call (+) 1 2 ; 代替案2
call #+ 1 2 ; 代替案3
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; 基本型
;;
"" ; String
1 ; Number
3.1 ; Number
:a ; Key
(1 2) ; List
[1 2] ; Array
[:a 1] ; Map
{_} ; Function
~~ _ ; Function
~ (v) v ; Function
|v| v ; Function
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; 基本構文
;;
+ a b ; 演算子呼び出し
f a ; 関数呼び出し
f(a) ; 前置呼び出し
v.m ; プロパティ呼び出し
a b ; インライン・インデント
k: v ; 複合文
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; 標準ライブラリ
;;
;; operator
func + (a ...b) __builtin__.operator["ADD"] a ...b
func - (a ...b) __builtin__.operator["SUB"] a ...b
func * (a ...b) __builtin__.operator["MUL"] a ...b
func / (a ...b) __builtin__.operator["DIV"] a ...b
func == (a b) __builtin__.operator["EQ"] a b
func = (a b) __builtin__.operator["ASSIGN"] a b
;; if
func if (c #t #e) ? c #t #e
;; while
func while (c #s) if c (do s (this #c #s))
;; do
func do (v ...w) & v ...w
;; cond
func cond (a ...b)
:validate ~~ if (== 1 _0) _1()
:iterate ~~ [ary f]
:next ary
while next then:
break (if (f next.car))
break (if (:next next.cdr))
if = "List" (typeof a) [
iterate b #(if (_[0] nil) (return _[1]))
] if = "Map" (typeof a) [
if = :is a.keys.first
iterate b #(if (= a (_[0] nil)) return _[1])
iterate b #(if (_[0] a) return _[1])
]
(none:)
;; switch
func switch (a ...) (cond (is:a) ...)
func switch (a ...)
if ! (none:) (cond (is:a) ...)
do (filter{= default:}|reverse ...).car.cdr
;; test cond "List"
assert "b" cond
(= 0 1) "a"
(= 1 1) "b"
(true) "default"
;; test cond:with
assert "b" cond with:1
(= 0 _) "a"
(= 1 ta_) "b"
(true) "default"
;; test cond:is
assert "b" cond is:1
(0) "a"
(1) "b"
;; test switch
assert "b" switch 1
(0) "a"
(1) "b"
:2 "c"
:3 "d"
assert "x" switch 9
(0) "a" (1) "b"
(2) "c" (3) "d"
(default:) "x"
assert "x" switch 9 (_) "x"
assert 9 switch 9 (_) _
;; String
class String: _s: []
func operator.ADD (s) _s.copy.add(s)
func String.operator.SUB (s) - _s.int s
func String.operator.`*` (s) * int(_s) s
func String.`/` (s) / _s.float s
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; 予約語
;;
;; 今後の言語拡張を想定し、いくつかの演算子およびキーワードを予約語とする
;;
;; 以下の演算子・記号・識別子をコア言語側の予約語とする
;;
;; | 一般的な演算子 (+ - * / & % etc.)
;; | (? ?? ?: : ~ ~~ ` \ _ $ @ #)
;;
;; 準予約語
;;
;; ライブラリ側での利用を想定し、以下のキーワードを準予約語とする
;;
;; | "_", "$" で始まる全ての識別子
;; | (fn func fun class struct)
;; | (ret return break)
;; | (in it is as eq has)
;; | (then else end)
;; | (not or and)
;; | (self this that)
;; | (may be to do)
;; | (yes no T nil)
;; | (typeof void)
;;
;; | (category extension/exte)
;; | その他、一般的な言語の予約後(interface implements etc.)
;;
;;
;; 想定される予約語/準予約語の利用用途
;;
? "cond"
echo "then"
echo "else"
= f ~~ echo _
f 99 ; "99"
{echo it} 99 ; 99
{echo $} 99 ; 99
do {echo "a"} {echo "b"} ; "ab"
do ((= a 1) (+ a 2)) ; 3
typeof "" ; String
;;
;; fnキーワードは予約後にしない方針
;;
;; 組み込みのラムダ式は`~~`, `~ ()`, `{}`に限定
;; fnキーワードとシンボル名が連続して記述されると読みづらい
;;
; こちらよりも
= tn fn (a b) + a b
call fn (a b) + a b
; こちらのほうが明瞭で読みやすい
= tn ~~ (a b) + a b
call ~~ (a b) + a b
;; MEMO: サンドイッチのような(キーワード オペレーター キーワード オペレーター)記述を意識するとメリハリが付いて読みやすいコードになる
; NG
+ + a b c
if eq a b 1 2
; Good
add + a b c
if == a b 1 2
;;
;; ライブラリ側でfuncとfnの定義を区別することができる
;;
;; 関数宣言(引数明示しない)
func add + _0 _1
;; 関数宣言(引数明示する)
fn add (a b) + a b
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; TODO
;;
;; 重要度低め。要整理統合。
;;
;;
;; チェインケース
;;
;; `-`記号による連結記法をサポートする
;; | シンボル名 | `/[a-zA-Z_]+-\w+/`
;; | 未規定 | `/[a-zA-Z_]+-/`
;; | 未規定 | `/-[a-zA-Z_]+(-\w+)*/`
;; | 未規定 | `/\d+-\w+/`
;;
;; 関連案・代替案
;; - [#名前解決]
;; - [#プリプロセッサ] ; TODO
;; 影響
;; - [#カテゴリー式、グループ式]
;; 関連
;; - [#演算子束縛]
;;
= variable-name "value" ; 可能
3-1 ; 3.operator-(1) ; 不可
3 - 1 ; 3.operator-(1) ; 可能
;; プリプロセッサで実現予定の宣言文
extension String+classMethod() puts "Class Method"
extension String-instanceMethod() puts "Instance Method"
String.classMethod() ; "Class Method"
"".instanceMethod() ; "Instance Method"
;; 名前解決への応用を視野に入れる
;; 影響 - [#前置呼び出し]
enum Align
Left
Right
:align Align-Left
switch align
:-Left "L"
:-Right "R"
-Left "L"
-Right "R"
:Left "Left"
assert! align Left
assert= align -Left
assert= align Left-
;; 束縛記法としての応用
;; 関連: [#演算子束縛] [#カテゴリー式、グループ式]
:eq {= _0 _1}
; before
assert (eq 1 2)
assert eq 1 2
; after
assert-eq 1 2
print-add 1 2 3 ; (print (add 1 2 3))
print-add 1 2 3 ; (print (add 1 2) 3)
;;
;; プリプロセッサ
;;
;; #コア機能 #重要度 100% #影響度 0%
;;
;; 基本構文を拡張するための仕組み
;; 宣言文を独自に定義できるようにする
;; ユーザ定義の記法を事前にパースさせる仕組みが必要
;; 糖衣構文の実現を可能とする
;;
;; 予約語 案: [macro define/def/dyndef expression/expr/static_expression syntax/dynamic_syntax]
;;
expression `/([a-zA-Z_])+-(\w+)/` ($1 $2)
; dynamic_syntax_tree_register_symbol($1 "-" $2)
__dst__.create_symbol_begin
__dst__.create_symbol_append $1
__dst__.create_symbol_append "-"
__dst__.create_symbol_append $2
__dst__.create_symbol_end
(typeof symbol-name) ; "Symbol"
expression `#assert` ()
__dst__.create_function_begin()
__dst__.create_function_add_return("void")
__dst__.create_function_add_parameter("bool")
__dst__.create_function_add_callback{ expr |
__builtin__.assert(expr)
}
__dst__.create_function_end()
#assert(eq 1 2)
= f #assert
f(eq 1 2)
;; コーディング規約の表明
expression `if` ()
if == (=) (typeof __dst__.cdr.car)
__dst__.static_assert "assignment in conditional expression"
if (= encoding UTF8) "y" "n" ; failed: assignment in conditional expression
;; 糖衣構文の定義
expression `{` <expression>* `|` <expression>* `}` ($)
? __dst__.register_expression_exist($)
__dst__.register_expression_begin($)
__dst__.create_lambda_begin()
__dst__.create_lambda_add_parameters $.nonterminal_symbols.0
__dst__.create_lambda_add_body $.nonterminal_symbols.1
__dst__.create_lambda_end()
__dst__.register_expression_end($)
{a b| + a b} 1 2 ; 3
;;
;; 可変長演算子
;;
;; 連続する演算子の多重定義を可能とする
;;
operator `-` (n)
switch n
:1 (-)
:2 (--)
:3 (~~ (#ignore) void)
- 9 ; -9
--- "i was here"
;;
;; 関数オーバーロード
;;
;; 型の種類と引数リストのサイズによるオーバーロード解決
;;
+= max {a | $ max a $0} ;; A
+= max {a b| ? (> a b) a b} ;; B
max(1)(2) ; 2 ;; AB
max(1 2) ; 2 ;; B
+= max { (first ...) ;; C
+= max {a|a} ;; D
max first max(...)
}
max(1 2) ; 2 ;; CDB
max(1 2 3) ; 3 ;; CBB
max(1 2 3 4) ; 4 ;; CCBBB
max(1) ; {max 1 $0} ;; A
+= len { 0 } ;; C
+= len {first ...| + 1 len ... } ;; B
+= len {ary | len ...ary} ;; A
len 0 ; 0 ;; AC
len 0 0 0 ; 3 ;; BBBC
len [0 0 0] ; 3 ;; ABBBC
+= len {[first ...rest] | len first rest} ;; D
+= len {first.rest | len first rest} ;; D'
len [0 0 0] ; 3 ;; D'BBBC
..."abc" ; ('a' . 'b' . 'c') ; (! '\n' tail(..."abc"))
len "abc" ; 3
+= do |v| v
+= do |v.w| & v (do w)
+= f |a| echo "a"
+= f |b| echo "b"
f nil ; "b"
f a:nil ; "a"
f b:nil ; "b"
;;
;; 演算代入演算子の記法
;;
;; 可変長演算子との整合性も視野に入れる
;; `=+`の記法であれば加算処理を`=`に内包させることが可能
;; `+=`であれば代入処理との区別が容易になる
;;
= val 1
+= val 1 ; 2(案1 75%)
=+ val 1 ; 3(案2 25%)
+:val 1 ; 4(束縛演算子`:`利用時)
;;
;; 記号の整理
;;
;; ラムダ系の演算子と、ビット演算系演算子で`~`と`^`の記号を活用している
;; 両記号はどちらか一方のカテゴリでのみ一貫して利用されるべきである
;; 煩雑な記法になりやすい: `~[a] ~~ ^~a &~ _0`
;; 対応案1: `~[a] ~~ ^~a ^& _0`
;; 対応案2: `~[a] ~~ ^^a &^ _0`
;; 対応案3: `^[a] ^^ ~~a &~ _0`
;;
;; ラムダ系演算子の統一
;;
;; `~`と`^`のどちらを使うべきか
;; `~`の存在感を取るか、`^`の違和感を取るか
;; `~(a b) + a b` vs `^(a b) + a b`
;; `~~ + _0 _1` vs `^ + _0 _1`
;; `~print` vs `^print`
;; `^`のほうが控えめな印象を受ける。メインの処理を引き立てる
;; `^`はλ(ラムダ)記号と形が似ている
;; `~`は溶け込みすぎる(適切な空白や`~~`記法の利用が求められる)
;; `~`は環境によって表示方法が異なる。等幅フォントでは中央表示が多数派
;;
;;
;; ビット演算系演算子の統一
;;
;; `~`と`^`のどちらを使うべきか
;; `&~` bitwise AND vs `&^` bitwise AND
;; `|~` bitwise OR vs `|^` bitwise OR
;; `^~` XOR vs `^^` XOR
;; `~~` bitwise NOT vs `~^` bitwise NOT
;; `~`の印象: 「複雑」「混沌」「泥臭さ」「低レイヤー」「バイナリー」
;; `^`の印象: 「特別」「異質」「未来」「クリーンルーム」
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; 用語
;;
;; | 演算子 | オペレータに相当するもの
;; | 被演算子 | オペランドに相当するもの
;; | 関数 | 演算子と等価関係にあるもの。通常はラベル名で表現された関数のことを指す
;; | 演算子関数 | 演算子として定義された関数。通常は記号で表現された関数のことを指す
;; | メソッド | オブジェクトのメンバ関数
;;
;; | 式 | 要素のまとまり
;; | 要素 | 値や変数または要素式
;; | 要素式 | 式の要素となりうる式
;; | 複要素式 | 複数の要素を持った式
;; | 値 | 単項式に相当するもの。数値や文字等のリテラルを含む
;; | 遅延評価式 | 遅延評価が可能な式。`#`装飾された式や仮引数
;;
;; | 式渡し | 遅延評価の仕組みによって式が渡ること/渡すこと
;; | 式の譲渡 | 式渡しと同義
;; | 式の展開 | 式の評価や実行と同義
;;
;; | 字下げ | インデントのこと。タブまたは空白2つ以上で表現される
;; | 段落 | パラグラフのこと。同じ階層に並ぶ複数行のうちの各行のこと
;; | 階層 | 字下げによって変化する式の位置や式の位置関係
;;
;; | 組み込み型 | 標準型・基本型と同義。リスト型や文字列型も含む
;; | 基本構文 | コア機能に組み込まれた基本的な記法。if文もといif関数はこれに含まれない
;;
;; | コア機能 | 言語仕様に相当するもの。本言語が持つ普遍的な機能
;; | 拡張機能 | 処理系固有の機能として実装可能な仕様。コア機能の拡張または改変を伴う機能
;; | 影響度 | 仕様追加によって生じる既存仕様への影響の度合い
;;
;;
;; | javascript: | ECMAScriptによるコードを明示する際に利用
;; | clang: | C言語によるコードを明示する際に利用。GCC拡張が有効なClangコンパイラを想定
;;
;;
(= v (+ 1 2)) ; 式
= ; 関数・演算子
v ; 要素・被演算子
+ ; 関数・演算子
(+ 1 2) ; 要素・要素式・式
1 ; 要素・被演算子・値
+ v 1 ; 式
+ ; 関数・演算子
v ; 要素・被演算子・値・変数
1 ; 要素・被演算子・値
(print "a") ; 式
print ; 関数
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; 実験
;;
;; プロトタイプ ;;
class String
let _lib __builtin__["string.h"]
var _s util.empty
;; 拡張 ;;
class String: public
func replace (target replacement) nil
func substr (p n)
_lib.slice _s p (+ p n)
;_lib.substr p n
;_lib.copy (+ p _s) n _lib.new(n)
class String: private(mcException)
func release () nil
"".release ; >> mcException:(3:0) String.release <<
;; カテゴリー ;;
class String: category(regex)
func replace (target replacement) nil
"\t\n".regex:replace "\\s", " "
[1 2 3].reduce |a b| + a b
reduce(|a b| + a b, [1 2 3])
reduce(|a b| + a b) [1 2 3]
reduce(<a b> + a b, [1 2 3])
echo, reduce(|a b| + a b) [1 2 3]
reduce<|a b| + a b> [1 2 3]
reduce {|a b| + a b} [1 2 3]
reduce [1 2 3] |a b| + a b
reduce=[1 2 3] |a b| + a b
reduce<[1 2 3]> |a b| + a b
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; 備考
;;
;; 配列リテラル`[1 2 3]`の採用を検討中
;; リストリテラル`(1 2 3)`の廃止が可能になる
;; 辞書リテラル`{:key val}`を採用しない方針を検討中
;; 代替記法: `[:key val]`
;; `{}`をラムダ式の糖衣構文として使いたい
;; `{:`で始まる式を辞書リテラルと解釈するための仕様も検討
;; 二項演算優先の規約に例外的な仕様を設ける
;; `+ 1 2 3`は`(+ 1 2 3)`として解釈される
;; 中置記法の実現するための拡張案を検討中
;; C言語スタイルでの記述を可能にする
;; 記法の定義と制御をライブラリ側で行えるようにする
;; インタプリタインタプリタの実現が必要
;; 言語仕様の肥大化に繋がる
;; fn関数はコア機能とせず、ユーザ定義を可能とする
;; = fn ~~ (...) #(~~ ...)
;; return文を実現するための仕様が必要
;; ユーザ定義を可能とする
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; サンプル(マークアップ言語)
;;
;; 本言語で解釈可能となる予定の構文案
;;
members
-------------------------
name トム・ドリル
email tom@gmail_com
-------------------------
name ボブ・グリーン
email bobby@gmail_com
-------------------------
name メアリー・フロイト
email mary@gmail_com
;; {members: [
;; {name: "tom", email: "tom@gmail_com" },
;; {name: "bob", email: "bobby@gmail_com"},
;; {name: "mary", email: "mary@gmail_com" }, ]}
members
name トム・ドリル
email tom@gmail_com
name ボブ・グリーン
email bobby@gmail_com
--------------------
name:
Java
extensions:
[java jsp]
keywords:
import, extends
--------------------
name "C++"
extensions [cpp cxx cp cc]
keywords
constexpr
mutable
static_cast, const_cast
--------------------
name: Rust
extensions: rs, rlib
keywords: trait
impl
pub
;; [ { name: "Java",
;; extensions: ["java", "jsp"],
;; keywords: ["import", "extensions"] },
;; { name: "C++",
;; extensions: ["cpp", "cxx"],
;; keywords: ["constexpr", "mutable", ["static_cast", "const_cast"]] }
;; { name: "Rust",
;; extensions: ["rs", "rlib"],
;; keywords: ["trait", "impl", "pub"] }, ]
-
item-1-1
item-1-2
- item-2-1
item-2-2
------------------
item-3-1
- item-3-1-1
- item-3-1-2
item-3-2 -
item-3-2-1
item-3-2-2
item-3-3
------------------
item-4-1
item-4-2
item-4-2-1
item-4-2-2
animal
dog
Pug
- Frank the Pug
- APO
Boston terrier
Iggy
Maron
Bulldog:
Golden Retriever:
cat
American Shorthair:
Maine Coon:
Siamese
- Kitty
;; {animal:
;; {dog: ["Pug" : ["Frank the Pug", "APO"], "Boston terrier", ["Iggy", "Maron"]"Bulldog", "Golden Retriever"],
;; cat: ["American Shorthair", "Maine Coon", "Siamese"]}}