Search code examples
pattern-matchingabstract-syntax-treerascal

Pattern matching AST nodes in Rascal


I have the following AST definition:

data Exp =
    app(Exp fun, Exp body)
    | var(str name)
    | nat(int nat)
    | func(list[str] formal, Exp body)
    | cond(Exp cond, Exp then, list[tuple[Exp,Exp]] elifs, Exp otherwise)
    | let(list[str] vars, list[Exp] exps, Exp body)
    | seq(Exp lhs, Exp rhs)
    | mul(Exp lhs, Exp rhs)
    | div(Exp lhs, Exp rhs)
    | md(Exp lhs, Exp rhs)
    | add(Exp lhs, Exp rhs)
    | sub(Exp lhs, Exp rhs)
    | eq(Exp lhs, Exp rhs)
    | gt(Exp lhs, Exp rhs)
    | lt(Exp lhs, Exp rhs)
    | geq(Exp lhs, Exp rhs)
    | leq(Exp lhs, Exp rhs)
    ;

and I am trying to match a node of the tree in a switch statement such that I have access to each child. The things I've tried are:

private str synthesise_f(Core::AST::Exp exp) {
    switch (exp) {
        case \Exp(_, _): {
            println("EXP_,_!");
        }
    }
}

and

private str synthesise_f(Core::AST::Exp exp) {
    switch (exp) {
        case /Exp(_, _): {
            println("EXP_,_!");
        }
    }
}

and

private str synthesise_f(Core::AST::Exp exp) {
    switch (exp) {
        case "Exp"(_, _): {
            println("EXP_,_!");
        }
    }
}

and private str synthesise_f(Core::AST::Exp exp) { case \adt(,): { println("EXP_!"); } }

The last one does work...but doesn't give me access to the children of the node. If I print out the exp that is being used in the switch statement I get:

seq(var("x"),var("y"))

(Comments and locations removed)

I'm wondering how I can match these nodes and then have access to their children.

Thanks!


Solution

  • Well, I have found a solution. What I've done is created a base case node (in this case a \str()) node, then I match on any other generic type. So, this should catch either the base case and if not that means it must be some other type of Exp that I can then process. Code:

    private str synthesise_f(Core::AST::Exp exp) {
        switch (exp) {
            case \var(_): {
                doSomethingWithStr();
            }
            case &T _(Exp e0): {
                doSomethingWith1Exp();
            }
            case &T _(Exp e0, Exp e1): {
                doSomethingWith2Exps();
            }
        }
        return ret;
    }