SDF3 generated checks prints debug messages on correct AST
I turned the Java-Front SDF2 into SDF3 to get the generated checks that will validate a Java AST. This is useful for the Green Marl compiler as I’m using concrete syntax and with the wrong thing spliced into the concrete syntax you get incorect ASTs that fail to pretty-print.
But consider the following piece of SDF:
context-free syntax ClassMemberDec = FieldDec ClassMemberDec = MethodDec ClassMemberDec = ClassDec ClassMemberDec = InterfaceDec ClassMemberDec.Semicolon = ";"
This generates the following checks:
strategies check-example = check-ClassMemberDec check-ClassMemberDec : t1__ -> <id> where not(is-ClassMemberDec-with-constructor) where <(check-FieldDec <+ error-FieldDec)> t1__ check-ClassMemberDec : t1__ -> <id> where not(is-ClassMemberDec-with-constructor) where <(check-MethodDec <+ error-MethodDec)> t1__ check-ClassMemberDec : t1__ -> <id> where not(is-ClassMemberDec-with-constructor) where <(check-ClassDec <+ error-ClassDec)> t1__ check-ClassMemberDec : t1__ -> <id> where not(is-ClassMemberDec-with-constructor) where <(check-InterfaceDec <+ error-InterfaceDec)> t1__ check-ClassMemberDec : Semicolon() -> <id> is-ClassMemberDec-with-constructor = ?Semicolon() is-ClassMemberDec-with-constructor = fail check-ClassMemberDec : amb([h|hs]) -> <check-ClassMemberDec> h error-ClassMemberDec = debug(!"Unexpected constructor. Expected constructor from sort ClassMemberDec instead. ")
Now whenever my AST has a
MethodDec
, theFieldDec
rule will already trigger, giving me console output like the following, even though the AST is valid and the pretty printer succeeds:Submitted by Jeff Smits on 23 June 2015 at 22:15Unexpected constructor. Expected constructor from sort FieldDec instead. MethodDec( [...] )
Issue Log
What I’m currently doing by hand to fix this is use a combined generic strategy like so: (
is-*
from thesrc-gen/pp
files)check-ClassMemberDec : t1__ -> <id> where not(is-ClassMemberDec-with-constructor) where <( is-FieldDec < check-FieldDec + is-MethodDec < check-MethodDec + is-ClassDec < check-ClassDec + is-InterfaceDec < check-InterfaceDec + error-ClassMemberDec)> t1__
EDIT: Changed the pattern to something less error-prone
By the way: Wouldn’t the following transformation scheme be simpler?
context-free syntax ClassMemberDec = FieldDec ClassMemberDec = MethodDec ClassMemberDec = ClassDec ClassMemberDec = InterfaceDec ClassMemberDec.Semicolon = ";"
⇓
check-ClassMemberDec = ( check-FieldDec + check-MethodDec + check-ClassDec + check-InterfaceDec + Semicolon() ) <+ error-ClassMemberDec
If a constructor has subterms, you can use:
... + Semicolon(try(check-SubTerm1), try(check-SubTerm2)) ...
Oh wait, I guess that would require you to know all the uses of this sort, and generate the strategy in one file.
I guess it would make more sense to just say:check-ClassMemberDec = check-ClassMemberDec-helper <+ error-ClassMemberDec check-ClassMemberDec-helper = check-FieldDec check-ClassMemberDec-helper = check-MethodDec check-ClassMemberDec-helper = check-ClassDec check-ClassMemberDec-helper = check-InterfaceDec check-ClassMemberDec-helper = Semicolon(check-SubTerm1, check-SubTerm2) // fictional subterms for the sake of generality ^
At this point I’m thinking it may be nicer to have more general tree-walking strategies generated from the syntax, like:
walk-ClassMemberDec(no-match) = walk-ClassMemberDec'(no-match) <+ no-match(|"ClassMemberDec") walk-ClassMemberDec'(no-match) = walk-FieldDec(no-match) walk-ClassMemberDec'(no-match) = walk-MethodDec(no-match) walk-ClassMemberDec'(no-match) = walk-ClassDec(no-match) walk-ClassMemberDec'(no-match) = walk-InterfaceDec(no-match) walk-ClassMemberDec'(no-match) = Semicolon(walk-SubTerm1(no-match), walk-SubTerm2(no-match)) // fictional subterms for the sake of generality ^ check-error(|sort) = debug(!$[Expected sort [sort] but got: ]) check-ClassMemberDec = walk-ClassMemberDec(check-error) is-ClassMemberDec = walk-ClassMemberDec(fail)
Log in to post comments