文法定義と型チェックをいっぺんにできないか?

次のプログラミング言語のパーサをつくってみよう.

class Foo {
   int get () {
       test().get()
       this.set()
   }
   int test() {
   }
}

普通,構文解析にパーサジェネレータを使うが,文法を定義する支援はしてくれても,意味解析はしてくれない.せめて型があっているかどうかくらいチェックしてほしいものだ...と考えたら次のような定義をかんがえついた.

文法定義は次のようにする

文法定義
   ?Prologの式*  opt
   ^Prologの式*  opt

パーサは,文法定義にマッチする文章をみつけ,しかもそれが「?Prologの式」 を充足させたら,「^Prologの式」 をデータベースに登録する.

ただし,

  • 文法定義内で使われた変数は自由変数として参照可能
  • ^TypeName は TypeNameクラスの新しいオブジェクトを作る
  • ?TypeName は TypeNameクラスのオブジェクトを探索してあてはめる.(普通のPrologでいうと大文字ではじまる変数)
ClassDecl  ::= 'class' Name MethodDecl  
     ^DeclBy(^Class , ClassDecl)
     ^OwnedBy( MethodDecl , ^Class).
     ^NameOf (^Class, Name)

MethodDecl ::= Type Name Args Block
      ?OwnedBy (MethodDecl, ?Class)
      ^DeclBy(^Method, MethodDecl)
      ^OwnedBy(^Method, ?Class)
      ^BlockOf(^Method, Block)
      ^NameOf (^Method, Name)
      ^TypeOf (^Method, Type)

// Expr は Expr の要素.つまり Block内で要素Exprをみつけるたびに 
// OwnedBy(Expr, Block) をデータベースに追加する
Block ::= '{' Expr '}'
     ^OwnedBy( Expr , Block).

Expr ::= This | LocalVarDecl | MethodInvocation

LocalVarDecl ::= Type Name 
       ?OwnedBy(LocalVarDecl, ?Block),
       ^DeclBy(^LocalVar, LocalVarDecl), 
       ^TypeOf(^LocalVar, Type),
       ^NameOf(^LocalVar, Name).
       ^InScope(^LocalVar, ?Block).
       
This ::= 'this'
     ?OwnedBy(This, ?Class) 
     ^TypeOf (This, ?Class)

// ※ これはただのPrologの式
OwnedBy(?Expr, ?Class) :-
     OwnedBy(?Expr, ?Block)
     OwnedBy(?Block, ?Method)
     OwnedBy(?Method, ?Class).

LocalVarRef  ::= Name
     ?OwnedBy(LocalVarRef, ?Block)
     ?InScope(?LocalVar, ?Block) 
     ?NameOf (?LocalVar , Name)
     ?TypeOf (?LocalVar, ?T).
     ^TypeOf (LocalVarRef, ?T).

MethodInvocation ::= Name '(' Arg ')'
    ?OwnedBy(MethodInvocation, ?Class), 
    ?OwnedBy(?Method, ?Class).
    ?NameOf (?Method, ?Name),
    ?TypeOf (?Method, ?T)
    ^TypeOf  (MethodInvocation, ?T)

MethodInvocation ::= Expr . Name '(' Arg[] ')'
    ?TypeOf(Expr, ?T), 
    ?OwnedBy(?Method, ?T). 
    ?NameOf (?Method, ?Name),
    ?TypeOf (?Method, ?RT),
    ^TypeOf (MethodInvocation, ?RT)