JRuby/スクリプト解析を読む
をテンプレートにして作成
[
トップ
] [
新規
|
一覧
|
単語検索
|
最終更新
|
ヘルプ
]
開始行:
#contents
*はじめに [#c9f90f26]
[[前回>JRuby/初期化を読む]]、JRubyの初期化(org.jruby.Rub...
*org.jruby.Ruby [#y7e981e6]
**runFromMainメソッド [#ve598d94]
スクリプト解析、実行のエントリポイントはrunFromMainメソッ...
+parseFromMainメソッド:スクリプトの解析
+runNormallyメソッド:解析したスクリプトの実行
++tryCompileメソッド:スクリプトをバイトコードへのコンパ...
++runScriptメソッド:コンパイルしたバイトコードの実行
それでは個々に見ていきましょう。
**parseFromMainメソッド [#yd68ef33]
スクリプトの解析を行っているのはorg.jruby.parser.Parserク...
それでは具体的にRuby19Parserを見てみましょう。Ruby19Parse...
さて、構文解析を行う際に利用されるのはParserSupportクラス...
*解析してみる [#cb96d332]
例によって実際のスクリプトを使って構文解析の流れを追って...
class MonteCarlo
def pi(n)
count = 0
(1..n).each do
x = rand
y = rand
if x * x + y * y <= 1
count += 1
end
end
(count.to_f / n) * 4
end
end
n = 10000 * 10000
pi = MonteCarlo.new.pi(n)
puts "pi = #{pi}"
それではマッチする規則を見ていくことにしましょう。
**primary(kCLASS cpath superclass) [#hdf254ae]
クラス定義はprimary規則のうち、「kCLASS cpath superclass...
:cpath|クラスのパスを表すNode
:superclass|スーパークラスを表すNode
:bodystmt|クラスを定義するNode
***cpath [#of612d85]
cpath規則ではcnameのみのものがマッチするため、ParserSuppo...
**primary(kDEF fname) [#pc891b4a]
メソッド定義はprimary規則のうち、「kDEF fname」がマッチし...
:f_arglist|引数を表すNode
:bodystmt|メソッドを定義するNode
ちなみに、メソッド名もNodeになっていますがこれは定義位置...
***f_args(f_arg opt_f_block_arg) [#hf3432cc]
引数の部分はf_args規則のうち、「f_arg opt_f_block_arg」が...
ところで代入が行われるって、それなんてオプション引数な気...
***f_argおよびf_arg_item [#t0ed2f6e]
f_arg_item規則により個々の引数に対してArgumentNodeが作ら...
なお、引数はローカル変数として現在のスコープに追加され、A...
**arg(lhs '=' arg) ブロック外の場合 [#p39ba9c8]
次は「count = 0」の部分です。arg規則のうち、「lhs '=' arg...
lhsではParserSupport.assignableメソッドが呼び出されます。...
#code(Java){{
/**
* Make a DASgn or LocalAsgn node based on scope logic
*
* @param position
* @param name
* @param value
* @return
*/
public AssignableNode assign(ISourcePosition position, St...
return assign(position, name, value, this, 0);
}
}}
現在のスコープがブロック内なのかブロック外なのかで作られ...
「count = 0」のうち0の部分はarg → primary → literal → num...
**stmts(stmts terms stmt) [#bdae2826]
次は「(1..n).each do」です。でもその前に複数の文をどう接...
**arg(arg tDOT2 arg) [#zeceb63d]
で、「(1..n).each do」です。まず、(1..n)の部分について説...
1つ目のargは先ほどと同様FixNumNodeになります。2つ目のarg...
**primary(method_call brace_block) [#gccd57e2]
「each do」の部分はprimary規則のうち「method_call brace_b...
method_call規則では「primary_value tDOT operation2 opt_pa...
brace_blockの中身はこれから見ますがブロック本体はIterNode...
**arg(lhs '=' arg) ブロック内の場合 [#qc13336f]
ブロックの始めにあるのは「x = rand」です。先ほどの代入と...
#code(Java){{
public class BlockStaticScope extends StaticScope {
protected AssignableNode assign(ISourcePosition posit...
StaticScope topScope, int depth) {
int slot = exists(name);
if (slot >= 0) return new DAsgnNode(position, nam...
return enclosingScope.assign(position, name, valu...
}
}
}}
xはまだ定義されていないので一番下のenclosingScope.assign...
#code(Java){{
public class LocalStaticScope extends StaticScope {
public AssignableNode assign(ISourcePosition position...
StaticScope topScope, int depth) {
int slot = exists(name);
// We can assign if we already have variable of t...
// scope in the chain (which Local scopes always ...
if (slot >= 0) {
return new LocalAsgnNode(position, name, ((de...
} else if (topScope == this) {
slot = addVariable(name);
return new LocalAsgnNode(position, name, slot...
}
// We know this is a block scope because a local ...
// If topScope was itself it would have created a...
return ((BlockStaticScope) topScope).addAssign(po...
}
}
}}
ブロック外にもxはないのでBlockStaticScopeに戻ってxが追加...
次にrandの部分ですがここは注意が必要です。人間は知識があ...
#code(Java){{
public class BlockStaticScope extends StaticScope {
public Node declare(ISourcePosition position, String ...
int slot = exists(name);
if (slot >= 0) return new DVarNode(position, ((de...
return enclosingScope.declare(position, name, dep...
}
}
}}
スコープ内にrandはないのでenclosingScopeに委譲。
#code(Java){{
public class LocalStaticScope extends StaticScope {
public Node declare(ISourcePosition position, String ...
int slot = exists(name);
if (slot >= 0) return new LocalVarNode(position, ...
return new VCallNode(position, name);
}
}
}}
enclosingScopeでも定義されてない → 関数呼び出ししてみる、...
**primary(kIF expr_value then compstmt if_tail kEND) [#b1...
次は「if x * x + y * y <= 1」です。primary規則の「kIF exp...
:expr_value|条件を表すNode
:compstmt|条件が真の場合に実行されるNode
:if_tail|条件が偽の場合に実行されるNode。elsifやelse
条件部の「x * x + y * y <= 1」はarg規則にある「arg tSTAR2...
真の場合の実行文「count += 1」はarg規則の「var_lhs tOP_AS...
**command(operation command_args) [#w115b181]
途中飛ばして「puts "pi = #{pi}"」です。関数呼び出しに括弧...
次に引数の"pi = #{pi}"の部分です。RubyYaccLexer.yylexメソ...
StringTerm.parseStringメソッドでは「#」を見つけると式展開...
**変換結果 [#b9c5940f]
以上でスクリプトの解析(Nodeへの変換)は終了です。変換結...
*おわりに [#m06d2964]
今回はJRubyのうち、スクリプト解析部分を読んでいきました。...
-ローカルスコープ、ブロックスコープのオブジェクトを用意し...
-引数の数、種類により構築するNodeを変える
スクリプト解析はさらっと流してコンパイルまで書こうと思っ...
終了行:
#contents
*はじめに [#c9f90f26]
[[前回>JRuby/初期化を読む]]、JRubyの初期化(org.jruby.Rub...
*org.jruby.Ruby [#y7e981e6]
**runFromMainメソッド [#ve598d94]
スクリプト解析、実行のエントリポイントはrunFromMainメソッ...
+parseFromMainメソッド:スクリプトの解析
+runNormallyメソッド:解析したスクリプトの実行
++tryCompileメソッド:スクリプトをバイトコードへのコンパ...
++runScriptメソッド:コンパイルしたバイトコードの実行
それでは個々に見ていきましょう。
**parseFromMainメソッド [#yd68ef33]
スクリプトの解析を行っているのはorg.jruby.parser.Parserク...
それでは具体的にRuby19Parserを見てみましょう。Ruby19Parse...
さて、構文解析を行う際に利用されるのはParserSupportクラス...
*解析してみる [#cb96d332]
例によって実際のスクリプトを使って構文解析の流れを追って...
class MonteCarlo
def pi(n)
count = 0
(1..n).each do
x = rand
y = rand
if x * x + y * y <= 1
count += 1
end
end
(count.to_f / n) * 4
end
end
n = 10000 * 10000
pi = MonteCarlo.new.pi(n)
puts "pi = #{pi}"
それではマッチする規則を見ていくことにしましょう。
**primary(kCLASS cpath superclass) [#hdf254ae]
クラス定義はprimary規則のうち、「kCLASS cpath superclass...
:cpath|クラスのパスを表すNode
:superclass|スーパークラスを表すNode
:bodystmt|クラスを定義するNode
***cpath [#of612d85]
cpath規則ではcnameのみのものがマッチするため、ParserSuppo...
**primary(kDEF fname) [#pc891b4a]
メソッド定義はprimary規則のうち、「kDEF fname」がマッチし...
:f_arglist|引数を表すNode
:bodystmt|メソッドを定義するNode
ちなみに、メソッド名もNodeになっていますがこれは定義位置...
***f_args(f_arg opt_f_block_arg) [#hf3432cc]
引数の部分はf_args規則のうち、「f_arg opt_f_block_arg」が...
ところで代入が行われるって、それなんてオプション引数な気...
***f_argおよびf_arg_item [#t0ed2f6e]
f_arg_item規則により個々の引数に対してArgumentNodeが作ら...
なお、引数はローカル変数として現在のスコープに追加され、A...
**arg(lhs '=' arg) ブロック外の場合 [#p39ba9c8]
次は「count = 0」の部分です。arg規則のうち、「lhs '=' arg...
lhsではParserSupport.assignableメソッドが呼び出されます。...
#code(Java){{
/**
* Make a DASgn or LocalAsgn node based on scope logic
*
* @param position
* @param name
* @param value
* @return
*/
public AssignableNode assign(ISourcePosition position, St...
return assign(position, name, value, this, 0);
}
}}
現在のスコープがブロック内なのかブロック外なのかで作られ...
「count = 0」のうち0の部分はarg → primary → literal → num...
**stmts(stmts terms stmt) [#bdae2826]
次は「(1..n).each do」です。でもその前に複数の文をどう接...
**arg(arg tDOT2 arg) [#zeceb63d]
で、「(1..n).each do」です。まず、(1..n)の部分について説...
1つ目のargは先ほどと同様FixNumNodeになります。2つ目のarg...
**primary(method_call brace_block) [#gccd57e2]
「each do」の部分はprimary規則のうち「method_call brace_b...
method_call規則では「primary_value tDOT operation2 opt_pa...
brace_blockの中身はこれから見ますがブロック本体はIterNode...
**arg(lhs '=' arg) ブロック内の場合 [#qc13336f]
ブロックの始めにあるのは「x = rand」です。先ほどの代入と...
#code(Java){{
public class BlockStaticScope extends StaticScope {
protected AssignableNode assign(ISourcePosition posit...
StaticScope topScope, int depth) {
int slot = exists(name);
if (slot >= 0) return new DAsgnNode(position, nam...
return enclosingScope.assign(position, name, valu...
}
}
}}
xはまだ定義されていないので一番下のenclosingScope.assign...
#code(Java){{
public class LocalStaticScope extends StaticScope {
public AssignableNode assign(ISourcePosition position...
StaticScope topScope, int depth) {
int slot = exists(name);
// We can assign if we already have variable of t...
// scope in the chain (which Local scopes always ...
if (slot >= 0) {
return new LocalAsgnNode(position, name, ((de...
} else if (topScope == this) {
slot = addVariable(name);
return new LocalAsgnNode(position, name, slot...
}
// We know this is a block scope because a local ...
// If topScope was itself it would have created a...
return ((BlockStaticScope) topScope).addAssign(po...
}
}
}}
ブロック外にもxはないのでBlockStaticScopeに戻ってxが追加...
次にrandの部分ですがここは注意が必要です。人間は知識があ...
#code(Java){{
public class BlockStaticScope extends StaticScope {
public Node declare(ISourcePosition position, String ...
int slot = exists(name);
if (slot >= 0) return new DVarNode(position, ((de...
return enclosingScope.declare(position, name, dep...
}
}
}}
スコープ内にrandはないのでenclosingScopeに委譲。
#code(Java){{
public class LocalStaticScope extends StaticScope {
public Node declare(ISourcePosition position, String ...
int slot = exists(name);
if (slot >= 0) return new LocalVarNode(position, ...
return new VCallNode(position, name);
}
}
}}
enclosingScopeでも定義されてない → 関数呼び出ししてみる、...
**primary(kIF expr_value then compstmt if_tail kEND) [#b1...
次は「if x * x + y * y <= 1」です。primary規則の「kIF exp...
:expr_value|条件を表すNode
:compstmt|条件が真の場合に実行されるNode
:if_tail|条件が偽の場合に実行されるNode。elsifやelse
条件部の「x * x + y * y <= 1」はarg規則にある「arg tSTAR2...
真の場合の実行文「count += 1」はarg規則の「var_lhs tOP_AS...
**command(operation command_args) [#w115b181]
途中飛ばして「puts "pi = #{pi}"」です。関数呼び出しに括弧...
次に引数の"pi = #{pi}"の部分です。RubyYaccLexer.yylexメソ...
StringTerm.parseStringメソッドでは「#」を見つけると式展開...
**変換結果 [#b9c5940f]
以上でスクリプトの解析(Nodeへの変換)は終了です。変換結...
*おわりに [#m06d2964]
今回はJRubyのうち、スクリプト解析部分を読んでいきました。...
-ローカルスコープ、ブロックスコープのオブジェクトを用意し...
-引数の数、種類により構築するNodeを変える
スクリプト解析はさらっと流してコンパイルまで書こうと思っ...
ページ名: