前置記法を採用したプログラミング言語

;;
;; 概要
;;

前置記法/ポーランド記法を採用したプログラミング言語。

+ 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

if == "hello" str
  print "yes"
  print "no"

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]

func counter ()
  = c 0
  fn () = c (+ c 1)

= f counter
f  ; 1
f  ; 2

func fact n
  if == n 0
     1
     * n
       fact - n 1

fact 3  ; 6
fact 4  ; 24

times 3 print str $  ; "hello0hello1hello2"
times<3 i> print i   ; "012"

len "str"  ; 3
"str".len  ; 3
1.+ 2      ; 3
1.- 2      ; -1
1 + 2      ; 3  (1.+ 2)

;;
;; 設計方針
;;

- インタプリタ
- 型システム無し
- evalあり
- for文if文等の基本機能はライブラリ関数として実装
- コア言語側である程度の組み込み型を用意する
  - Number型、String型、List型、Map型、Key型、Function型
  - 組み込み型のメンバ関数はライブラリ側で実装する
- DSLの実現を可能とする汎用的な言語仕様
  - マックアップ言語への応用を可能とする
  - ライブラリ次第でまったく異なる構文の利用が可能となる

;;
;; 仕様
;;
;; 2016年12月24日 公開
;; 2017年01月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 ;; 糖衣構文

;; 辞書
;;
= dic [:key 99 :may 5]
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
= 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との混在が可能)-- 参考:[#引数リスト]

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; オブジェクト指向
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; メソッド
;;
"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 (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        ; ラムダ式

;; インスタンス化
;;
= v (Number 99)

;; メソッド呼び出し
;;
v.is 2     ; v.is(2)
+ v 2      ; v.+(2)
10.pow 3   ; 1000
v get      ; 9
v.get()    ; 9
v.get      ; func Number::get
v.get nil  ; 9
(9.get)    ; 9

;; 糖衣構文
;;
"".split(",") ; ("".split ",")
"".len()      ; ("".len void)
print("")     ; (print "")

;; オブジェクト
;;
;; あらゆる値はオブジェクトで表現される
;; 各演算子の挙動は被演算子側のオブジェクト実装に依存する
;;
= (+) fn (a b) (a.+ b)
+ 1 2       ; 3
class String
  func (+) (s) (self.copy().append s)
+ "a" "b"   ; "ab"

;; Objectクラス
;; 全てのオブジェクトはObjectクラスに準拠する
;;
class Object
  func (==) (a) __UNIMPLEMENTED__ a
  func (!=) (a) ! self.==(a)
class String
  func (==) (a) ! (__builtin__["string.h"].strcmp
                    self.__raw__
                       a.__raw__)
(!= "a" "b") ; true

;; 中置記法
;;
class Number
  func __call__ (op ...)
    if == (+) op
      + self ...
      __UNIMPLEMENTED__
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)
-
  + 1 2
    3
; = 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 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%
;;
;; ブロックを内包する式の結合規則に例外を設ける
;;
; if (== "String" (typeof String)) "yes"
if == "String" typeof String
  "yes"
; if (== "String" typeof) (String) ("yes")
if == "String" typeof String "yes"

;;
;; ブロックの明示
;; 
;; #コア機能  #拡張機能  #重要度 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 (
  = 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 (i in ...)
    = (#i).__prototype__["#"] (#)
    = (#i).__prototype__["-"] (-)
    i()
  join  separator:"\n"
       terminator:""
            items:ary

; "<h1>Heading</h1>\n<li>list item</li>"
markdown
  # Headding
  - list item

;;
;; 暗黙のブロック
;; 
;; #拡張機能  #重要度 25%  #影響度 10%
;;
;; オペランドを必要とするオペレータが単独で使用された場合、
;; 次の行の式をそのオペレータに対応するオペランドとして解釈する
;; オペランドの探索は空行が出現するまで繰り返される
;;
; + 1 2
+
1
2
; {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"
;; この仕組みで演算子の優先順位を実現することが可能になる
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%
;;
;; 遅延評価をデフォルトにする
;; 仮引数名の前置`#`も省略可能にする
;; 機能性と多様性、柔軟性ために必要
;; ただしデバッグがしづらくなる(代替案検討)
;;
;; `#`省略時
;;  - 式の評価は仮引数が本文中に出現した際に行われる
;;  - 評価は一度だけ行われる
;;  - 本文中に出現する仮引数が前置`#`されていた場合は式を返す
;;
= foo fn (a)   ; 評価されない
        a      ; 2(評価される)
        #a     ; ++i
        a      ; 2(前回評価値)
        a      ; 2(前回評価値)
= i 1
foo ++i  ; 2
;;
;; `#`明示時
;;
= foo fn (#a)  ; 評価されない
        a      ; 2(評価される)
        #a     ; ++i
        a      ; 3(評価される)
        a      ; 4(評価される)
= i 1
foo ++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 fn (#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)
  map 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
(#(+ 1 2)).__name__  ; nil

(#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)

;;
;; 演算子の前置記法
;;
;; #コア機能  #重要度 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  ;; 後置/前置で異なる結合規則を取り入れる
                          ;; 参考:[#段落結合]
; [#式展開の原則]

;;
;; 逐次呼び出し
;;
;; #コア機能  #重要度 50%  #影響度 0%
;;
func a () echo "a"
func b () echo "b"
a|b    ; "ba" -- 案1
a|b    ; "ab" -- 案2
a<>b   ;      -- 案3
a<b    ; "ba"
a>b    ; "ab"
func a () + _0 1
func b () + _0 2
a|b 0  ;  3

;;
;; 部分適用式
;;
;; オペレータに対する後置記法を関数の部分適用式として解釈する
;; 部分適用やカリー化の糖衣構文を実現する事ができる
;;
; 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]
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(関連:[#逐次呼び出し])

;; 備考
;;   本仕様は[#前置呼び出し昇格]の仕組みで代用することも出来る
func map (f a)
  switch _arguments.length
    (0) #map
    (1) ~~ [aa] map f aa
    (2) for<f> a
    (default:) (map f [a ...])
map{* 2} [1 2 3]  ; [2 4 6]
= f map{* 2}
f [1 2 3]         ; [2 4 6]

;;
;; 代理関数呼び出し
;;
;; #コア機能  #拡張機能  #重要度 90%  #影響度 25%
;;
;; 1. 関数呼び出し時
;;    第一オペランドがオペレータと同名のメンバ関数を持つ場合はそちら呼び出す
;; 2. メソッド呼び出し時
;;    メンバ関数が存在しない場合は同名のグローバル関数を呼び出す
;; ※ 両探索は再帰的に行われないものとする
;;
len "a"   ; "a".len()
1.+ 2     ; (+ 1 2)

;;
;; プロパティ呼び出し
;;
;; #コア機能  #重要度 60%  #影響度 100%
;; #関連仕様 [#遅延評価 #式展開の原則]
;;
;; プロパティを実現するために関数呼び出しの仕組みを変更する案
;;
;; 案1 -- 関数呼び出しをデフォルトにする
"ab".len   ; 2
#"ab".len  ; func String::len
"ab".len#  ; 案2
"ab".len&  ; 案3
"ab"::len  ; 案4(静的メンバ採用時注意 -> 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. メンバアクセスについては常に展開を行う
;;
= say ~~ "hello"
say             ; "hello"
#say            ; ~~ "hello"
{#_0} say       ; ~~ "hello"
{#_0} (say 1)   ; "hello"
"a".len         ; 3
{#_0}  "a".len  ; 3
{#_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
  if && cond
        !stop
    stmt i--
while true
  if > 9 $0
    print $0
    break

;;
;; 引数リスト
;;
;;  仮引数の明示/省略を区別するための仕様案
;;  第一引数を仮引数リストとして解釈するラムダ式とそうでないラムダ式の、
;;  その両者の区別をなくすために必要となる
;;  引数リストは配列リテラルで表現する
;;
= add ~~ [a b] (+ a b)
= sub ~~ (- _0 _1)
= mul ~ (* $0 $1)
= not fn !! _
{[a] print a} 1 ; "1"
{print _} 2     ; "2"

;; 影響
;;   コア機能に影響
;;   ラムダ宣言関数`fn`, `~~`の内部で引数リスト`[]`の判定が必要になる
;;   配列リテラルとリストの内部表現を区別する必要がある
; before
typeof [1 2]  ; List
typeof (1 2)  ; List
; after
typeof [1 2]  ; Array
typeof (1 2)  ; List

;;
;; 遅延評価の拡張
;;
;; 変数宣言時にも遅延評価の仕組みを利用可能にする
;;
#= 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

;;
;; 演算子の結合規則
;;

;; 演算子を優先的に解釈する
print + 1 2  ; print (+ 1 2)
  
;; 二項演算子は第二引数までを処理する
+ 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  ; 0
~ 0  ; -1
;; 問題
- 1 2  ; (- 1) (2)
~ [a] echo a  ; (~ [a]) (echo a)
;; 代案 --> [#前置呼び出し]

;;
;; 可変長式
;;
;; #整理必要
;;
;; ※ 二項演算優先の原則自体の廃止を検討中  #2017-01-08
;;  - 演算子のみを特別に扱うのは一貫性に欠けるのではないか
;;  - 関数と演算子は等価に扱うべきか
;;  - 一貫性と多様性のどちらを重視するべきか
;;
;; 二項演算優先の原則に例外を設ける
;;

;; 1. 演算子に続く要素が値として評価できる場合は、
;;    たとえそれが三項目以降の要素であっても、
;;    演算子に対応する被演算子と見なすことができる
+ 1 2 3  ; (+ 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 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))
    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")

;;
;; アンダースコア命名規則
;;
;; #コア機能  #重要度 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

;;
;; 比較演算子の拡張
;;
;; #拡張機能  #重要度 0%  #影響度 100%
;;
;; 式中の代入演算子`=`を文脈に応じて比較演算子`==`として解釈させる
;;
= a "foo"
if (= a nil) print a  ; if (== a nil) print a
;; 影響
func lazyView ()
  return = _view (View new)
while = next next.next  print next.v

;;
;; 演算子の用途変更
;;
;; #コア機能  #拡張機能  #影響度 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)
;; |  ||  | ビット演算子(bitwise OR)
;; |  ^^  | 排他的論理和(XOR)
;; |  ^   | ラムダ宣言式 -- 未定
;; |  ?   | 条件演算子
;; |  ?:  | 未定
;;
= 1 2  ; javascript: 1 == 2
! 1 2  ; javascript: 1 != 2
!!true ; javascript: !true

== 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";
: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}
:map {:a 1 :b 2}()
map.a       ; 1
{ :a 1 :b 2
  :sum fn () + a b
}().sum     ; 3

;;
;; 段落結合
;;
;; #拡張機能  #重要度 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)     ;; オペレータとして扱う
;;     応用例1 -- ベースクラスの指定
;;       `class Integer: Number`
;;     応用例2 -- 型の明示
;;       `func join (separator: String items: Array)`
;;     応用例3 -- 名前付き引数
;;       print 1 2 separator: ","  ; (print 1 2 (separator: ","))
;;

;; 案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"

;;
;; 型の明示
;;
;; 空白を挟まない`要素:型名`記法が用いられていた場合、
;; インタプリタ側では`:型名`の部分を無視する
;;
func makeView (point:Point size:Size):View
  (View point size)

;;
;; 型システム
;;
;; [#型の明示]を正式な型システムに取り入れる場合は、
;; 仮引数のインターフェースを厳格に定める必要がある
;;  - Key型の仕組みを活用する
;;  - または式型の仕組みに取り込む  #2017-01-08
;;
= func fn (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
;;
;; 名前付き引数
;;
;; [#型システム]との整合性も意識する
;;
(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__"]

;;
;; その他
;;
;; 関数をオブジェクトとして渡すための記法
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
a:      ; Key
(1 2)   ; List
[1 2]   ; Array
[:a 1]  ; Map
fn () 0 ; Function
~ () 0  ; Function
~~ 0    ; Function
{0}     ; Function

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; 標準ライブラリ
;;

; if
func if (c t e) ? c #t #e
; while
func while (c s) if c (while #c #s)
;; 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 _) "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"
assert "_" switch 9
             (0) "a"
             (1) "b"
             (default:) "_"

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; 予約語
;;
;; 今後の言語拡張を想定し、いくつかの演算子およびキーワードを予約語とする
;;
;; 以下の演算子・記号・識別子をコア言語側の予約語とする
;;
;;  | 一般的な演算子 (+ - * / & % etc.)
;;  | (? ?: : ~ ~~ ` \ _)
;;
;; 準予約語
;;
;; ライブラリ側での利用を想定し、以下のキーワードを準予約語とする
;;
;;  | "_", "$" で始まる全ての識別子
;;  | (fn func fun class)
;;  | (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)
;;
;; 想定される予約語/準予約語の利用用途
? "cond"
  echo "then"
  echo "else"
= f ~~ echo _
f 99   ; "99"
do {echo "a"} {echo "b"} ; "ab"
do ((= a 1) (+ a 2))     ; 3
typeof ""  ; String

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; 用語
;;
;; | 演算子   | オペレータに相当するもの
;; | 被演算子  | オペランドに相当するもの
;; | 関数    | 演算子と等価関係にあるもの
;; | メソッド  | オブジェクトのメンバ関数
;;
;; | 式     | 要素のまとまり
;; | 要素    | 値や変数または要素式
;; | 要素式   | 式の要素となりうる式
;; | 値     | 単項式に相当するもの。数値や文字等のリテラルを含む
;; | 遅延評価式 | 遅延評価が可能な式。`#`装飾された式や仮引数
;;
;; | 式渡し   | 遅延評価の仕組みによって式が渡ること/渡すこと
;; | 式の譲渡  | 式渡しと同義
;; | 式の展開  | 式の評価や実行と同義
;;
;; | 字下げ   | インデントのこと。タブまたは空白2つ以上で表現される
;; | 段落    | パラグラフのこと。同じ階層に並ぶ複数行のうちの各行のこと
;; | 階層    | 字下げによって変化する式の位置や式の位置関係
;;
;; | 組み込み型 | 標準型・基本型と同義。リスト型や文字列型も含む
;;
(= v (+ 1 2))  ; 式
 =             ; 関数・演算子
   v           ; 要素・被演算子
      +        ; 関数・演算子
     (+ 1 2)   ; 要素・要素式・式
        1      ; 要素・被演算子・値
+ v 1          ; 式
+              ; 関数・演算子
  v            ; 要素・被演算子・値・変数
    1          ; 要素・被演算子・値
(print "a")    ; 式
 print         ; 関数・演算子

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; 備考
;;
;; 配列リテラル`[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"]}}