2007年 10月 21日

Io で ERB みたいなの

EIo := Object clone do (
	string := ""
	compiledString := ""

	setString := method(string,
		self string = string asMutable
		self compiledString = self compileString(self string)
		self
	)

	doInObject := method(obj,
		# 汚さないように clone
		obj clone do (
			h := method(v,
				v asString asMutable replaceSeq("&", "&") ¥
				                     replaceSeq("<", "&lt;") ¥
				                     replaceSeq(">", "&gt;")
			)
		) doString(self compiledString)
	)

	compileString := method(string,
		ret := "_eio_string := ¥"¥" asMutable¥n" asMutable
		n   := 0
		p   := 0
		while (n = string findSeq("<%", p),
			s   := string slice(p, n) replaceSeq("¥"", "¥¥¥"")
			n = n + 2
			c   := string findSeq("%>", n)
			mes := string slice(n, c)
			ret appendSeq("_eio_string appendSeq(¥"#{s}¥")¥n" interpolate)
			if (mes beginsWithSeq("="),
				if (mes beginsWithSeq("=="),
					ret appendSeq("_eio_string appendSeq(#{mes slice(2)})¥n" interpolate)
				,
					ret appendSeq("_eio_string appendSeq(h(#{mes slice(1)}))¥n" interpolate)
				)
			,
				ret appendSeq("#{mes}¥n" interpolate)
			)


			p = c + 2
		)
		s   := string slice(p) replaceSeq("¥"", "¥¥¥"")
		ret appendSeq("_eio_string appendSeq(¥"#{s}¥")¥n_eio_string" interpolate)
		ret
	)
)

# data := File openForReading("test.eio") contents
data := """
<p><%=hoge%></p>
<ol>
<% list("aaa", "bbbb", "ccccc", "ddddddd") foreach(i, v, %>
	<li><%=i+1%>. <%=v%></li>
<% ) %>
</ol>
"""

eio := EIo clone setString(data)
# eio compiledString print

context := Object clone do (
	hoge := "hogeog&e<>"
)
eio doInObject(context) print

出力

<p>hogeog&amp;e&lt;&gt;</p>
<ol>

        <li>1. aaa</li>

        <li>2. bbbb</li>

        <li>3. ccccc</li>

        <li>4. ddddddd</li>

</ol>

ヒアドキュメント書けた。トリプルクオートだった。ので修正

Io の解釈

Message fromString(code) code print

すると、Io がその文字列をどうやって解釈しているかわかる。

Message fromString("<p class='hoge'>aaaaa</p>") code print
#=> <(p class =' hoge '> aaaaa </ p) >

ol や p とかっていう呼びだしを method_missing みたいのでキャッチできれば E4X もユーザレベルで実装できそう。だけど method_missing 相当のことをどうやってやるのかわからない。

Io における演算子拡張

Io は演算子の Map を内部に持っていて、パース時にそれを参照する。

例えば =~ は定義されていないので

Message fromString("\"abc\" =~ \"a.\"") code print
#=> "abc" =~ "a."

となり、これだと =~ というメッセージを定義しても、後ろの文字列 (Sequence) は =~ メッセージの引数とは解釈されない。"abc" =~ と "a." は別の文になるわけです。

しかしながらこれは拡張することができて

OperatorTable addOperator("=~", 7)
Message fromString("\"abc\" =~ \"a.\"") code print
#=> "abc" =~("a.")

ということができる。7 は演算子の優先順で、OperatorTable print すれば登録済みの演算子とその優先順位がわかる。

Operators
  0   ' ( ) . ? @ @@
  1   **
  2   ++ --
  3   % * /
  4   + -
  5   << >>
  6   < <= > >=
  7   != ==
  8   &
  9   ^
  10  |
  11  && and
  12  or ||
  13  ..
  14  %= &= *= += -= -> /= <- <-> <<= >>= ^= |=
  15  return
  16  ,

Assign Operators
  ::= newSlot
  :=  setSlot
  =   updateSlot

To add a new operator: OperatorTable addOperator("+", 4) and implement the + message.
To add a new assign operator: OperatorTable addAssignOperator("=", "updateSlot") and implement the updateSlot message.

ところで若干のハマりどころなのは、

Object =~ := method(s,
	call message print
)
OperatorTable addOperator("=~", 7)

"abc" =~ "a."

とやっても、"abc" =~ "a." をパースする時点では addOperator はまだ評価されていないので、演算子にはならない。doString とかでこのあとにパースされるようにしないといけない。実際つかうとするとファイルをわけて doFile みたいになると思う。

Io かっけー

Io における method と block の違い

一番大きいのは doc に書いてあるとおりスコープの違い (というか、ローカルオブジェクト (=変数オブジェクト) がどこからクローンされるか) だけれど、それだけじゃなくて、call が必要かどうかもあるみたいだ。

a := Object clone do (
	aBlock  := block("called block")
	aMethod := method("called method")
)

a aBlock print
#=>
# # test.io:3
# method(
#     "called block"
# )
a aBlock call print  #=> called block
a aMethod print      #=> called method
a getSlot("aMethod") print
#=>
# # test.io:4
# method(
#     "called method"
# )

block の場合は自動的に呼ばれない。

Io × Vim

対応言語いっぱいの Vim でも io は色付けしてくれない。はてグに書くときは ruby としてシンタクスハイライト (意味的にどうよ)

ちなみに Io の do は Ruby でいうところの instance_eval で、レシーバをローカルオブジェクトにしてメッセージを評価する Object のメソッド

構文っぽくなる do, if, while とかはメソッド名のあとにスペース入れるようにしてる。

手編みのマフラー

手編みのマフラーというのは、愛情の大きさと継続性をあわせると考えうる限り最強のアイテムなので、安易に使用してはいけない。(別に恋愛に限らず親子愛であれ姉弟愛であれ)

ださ☆きも

はてなをダサキモということにしておくと、その程度でつかうのをやめるような人を効率的にフィルタリングできるので悪いとはいえない。

Io ObjcBridge

Io は ObjcBridge が最初からついてきててなかなかおもしろそう……と思いきやうまく動かなかった。

ObjcBridge autoLookupClassNamesOn
ObjcBridge debugOn

AppDelegate := Object clone do (
	applicationDidFinishLaunching: := method(aNotification,
		"launched" print
	)
)

app := NSApplication sharedApplication
app setDelegate:(AppDelegate clone)
app run
Io -> Objc (id)sharedApplication()
Io -> Objc (void)setDelegate:(id)
[Objc2Io respondsToSelector:"applicationWillBecomeActive:"] = 0
[Objc2Io respondsToSelector:"applicationWillResignActive:"] = 0
[Objc2Io respondsToSelector:"applicationWillFinishLaunching:"] = 0
[Objc2Io respondsToSelector:"applicationDidUpdate:"] = 0
[Objc2Io respondsToSelector:"applicationDidUnhide:"] = 0
[Objc2Io respondsToSelector:"applicationWillUnhide:"] = 0
[Objc2Io respondsToSelector:"applicationWillUpdate:"] = 0
[Objc2Io respondsToSelector:"applicationWillTerminate:"] = 0
[Objc2Io respondsToSelector:"applicationDidChangeScreenParameters:"] = 0
[Objc2Io respondsToSelector:"applicationDidBecomeActive:"] = 0
[Objc2Io respondsToSelector:"applicationDidResignActive:"] = 0
[Objc2Io respondsToSelector:"applicationDidFinishLaunching:"] = 1
[Objc2Io respondsToSelector:"applicationWillHide:"] = 0
[Objc2Io respondsToSelector:"applicationDidHide:"] = 0
[Objc2Io respondsToSelector:"validRequestorForSendType:returnType:"] = 0
Io -> Objc (void)run()
[Objc2Io respondsToSelector:"application:runTest:duration:"] = 0
[Objc2Io respondsToSelector:"application:openFiles:"] = 0
[Objc2Io respondsToSelector:"application:openFile:"] = 0
Objc -> Io (void)applicationDidFinishLaunching:(id)

Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_PROTECTION_FAILURE at address: 0x00000000
0x00000000 in ?? ()

debugOn だとブリッジのメッセージのやりとりがみれる。delegate 呼ぶときにおちてる。深く追ってない (追えない)

みてのとおり obj-c との名前の変換はない。

squareBrackets が未定義なのはこれのためってのもありそう? (実際 ObjcBridge では squareBrackets が定義されてる。けどいまいち使いかたがわからない)

.vim/syntax/io.vim

http://lab.lowreal.net/trac/browser/config/.vim/syntax/io.vim

で、ですね、書いたあと気付いたのですが、Io-2007-10-10/projects/SyntaxHighlighters/Vim にあったんですよ。どうしよう

Suddenly the Dungeon collapses!! - You die...

screen がおちた。はじめてだ。