Fomentを読む(6)
前回はこちら。月一でやろうかなと言っていたけど、先月はちょっと忙しくて休載した。しかしまあ「長期的には成し遂げたいけど、短期的には優先度が高くない課題」に対する手法としては、月に一日だけやるというのはわりと良さそうな感じがしてきた。
前回はsynrules.cppの提供する2つの関数、CompileSyntaxRulesとExpandSyntaxRulesについて、どの補助関数が呼ばれているかを調べたのだった。次は何をしようかなぁ。とりあえずこれらの関数の引数と返り値が知りたいな。
ExpandSyntaxRules
synrules.cppを見る。ExpandSyntaxRulesはExpandTemplateの結果を返す。ExpandTemplateはMakePairかListToVectorの結果を返すので、Schemeレベルの値を返すっぽい。
引数の方はどうだろうか。ぜんぶFObjectだから分かんないんだよな...。綺麗なコードだと言ったけど、Cなのに事実上型がないような感じでつらみが出てきた。
FObject ExpandSyntaxRules(FObject se, FObject sr, FObject expr)
ともあれsrはFAssert(SyntaxRulesP(sr));
とあるので、foment.hppにあるSyntaxRulesRecordTypeによると、レコード型SyntaxRulesRecordTypeっぽい。
レコード型について
時間が空いたので再度まとめておくが、RecordTypeはMakeRecordTypeCから作られるもので、
R.SyntaxRulesRecordType = MakeRecordTypeC("syntax-rules",
sizeof(SyntaxRulesFieldsC) / sizeof(char *), SyntaxRulesFieldsC);
MakeRecordによってFXxxXxxのようなインスタンスを作成できる。
FSyntaxRules * sr = (FSyntaxRules *) MakeRecord(R.SyntaxRulesRecordType);
ややこしいので、このシリーズではレコード型はFSyntaxRulesみたいな名前で統一しようかな。
ExpandSyntaxRulesのシグネチャ
ここまでで分かっているExpandSyntaxRulesのシグネチャは以下。
ExpandSyntaxRules(se, FSyntaxRules sr, expr) -> PairとかVectorとか
exprはSchemeの式なのだろう。seはMatchPatternの第一引数で、MatchReferenceの第二引数である。MatchReferenceはsynpass.cppにあった。seはResolveIdentifierの第一引数。ResolveIdentifierには以下のアサーションがあるので、FSyntacticEnvだと分かった。
FAssert(SyntacticEnvP(se));
FSyntacticEnv
FSyntacticEnvはたぶん、syntactic closure関係の何かだと思う。syntactic closureについては僕も説明できるほど理解していない(理解してたらfomentの実装とか読んでない)ので、知りたい人はググるか、ポインタとしてはこちらの記事などを。
このシリーズでもいずれ説明することになる、はず。
CompileSyntaxRulesのシグネチャ
CompileSyntaxRulesの方は以下のようなシグネチャだった。
- CompileSyntaxRules(FObject se, FObject obj) -> FObject
synpass.cppでの使用箇所を見るとseはFSyntacticEnv、objはSchemeの式(expr)っぽい。また返り値はMakeSyntaxRulesなのでFSyntaxRules。ということでこうなる。
- CompileSyntaxRules(FSyntacticEnv se, expr) -> FSyntaxRules
CompileSyntaxRulesの使い方
synpass.cppのSPassSpecialSyntaxという関数に使用箇所がある。
- SPassSpecialSyntax(FObject enc, FSyntacticEnv se, ss, expr)
ここではquote, lambda, if, set!, let, let*などの組み込みの構文と、syntax-rulesによるユーザ定義構文を処理しているようだ。(syntax-rules xxx)
のようなS式だったらそれをFSyntaxRulesにコンパイルするということかな。
else if (ss == DoSyntax)
{
// (do ((<variable> <init> [<step>]) ...) (<test> <expression> ...) <command> ...)
return(SPassDo(enc, se, expr));
}
else if (ss == SyntaxRulesSyntax)
{
// (syntax-rules (<literal> ...) <syntax rule> ...)
// (syntax-rules <ellipse> (<literal> ...) <syntax rule> ...)
return(CompileSyntaxRules(MakeSyntacticEnv(se), expr));
}
ExpandSyntaxRulesの使い方
上記の関数SPassSpecialSyntaxは、同じsynrules.cppのSPassExpressionから呼ばれている。ここを見るとExpandSyntaxRulesの方の呼び出しもあった。(foo 1 2 3)
みたいな式があって、fooがsytnax-rulesで定義された構文だったら、これをExpandSyntaxRulesで展開するということのようだ。
val = EnvironmentGet(AsReference(op)->Binding, AsReference(op)->Identifier);
}
if (SpecialSyntaxP(val))
return(SPassSpecialSyntax(enc, se, val, expr));
if (SyntaxRulesP(val))
return(SPassExpression(enc, se, ExpandSyntaxRules(se, val, Rest(expr))));
まとめ
今回は前にやった内容を思い出しつつ、CompileSyntaxRulesとExpandSyntaxRulesのシグネチャを調べた。コールグラフとともに再掲しておく。
- CompileSyntaxRules(FSyntacticEnv se, expr) -> FSyntaxRules
- CopyLiterals
- LiteralFind
- CompileRule
- CompilePatternVariables
- PatternVariableFind, LiteralFind
- AssignVariableIndexes
- CompilePattern
- PatternVariableFind, LiteralFind
- CountPatternsAfterRepeat
- RepeatPatternVariables
- PatternVariableFind
- CompileTemplate
- PatternVariableFind
- AddVarToTemplateRepeat
- ListFind
- ExpandSyntaxRules(FSyntacticEnv se, FSyntaxRules sr, expr) -> expr
- MatchPattern
- InitRepeatVariables
- GatherRepeatVariables
- ExpandTemplate
- CheckRepeatVariables
- SetRepeatVariables
- ExpandTemplateRepeat -> ExpandTemplateを呼ぶことがある(相互再帰)