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, the FieldDec rule will already trigger, giving me console output like the following, even though the AST is valid and the pretty printer succeeds:

Unexpected constructor. Expected constructor from sort FieldDec instead. MethodDec(   [...]   )
Submitted by Jeff Smits on 23 June 2015 at 22:15

On 25 June 2015 at 23:40 Jeff Smits commented:

What I’m currently doing by hand to fix this is use a combined generic strategy like so: (is-* from the src-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


On 25 June 2015 at 23:53 Jeff Smits commented:

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))
  ...

On 26 June 2015 at 00:18 Jeff Smits commented:

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