import lexer_example
@with_lexer(foo_lexer)
grammar foo_grammar {
    name <- Name(@identifier)
    @main_rule main_rule <- list+(or(
        | Def("def" name imports vars expr)
        | expr
    ))
    imports <- pick("(" list*(derived_ref) ")")
    var <- Var(name "=" expr)
    vars <- pick("{" list*(var) "}")
    expr <- or(atom | plus)
    atom <- or(lit | ref)
    lit <- Lit(@number)
    ref <- Ref(name)
    derived_ref <- DerivedRef(name)
    plus <- pick("(" Plus(expr "+" expr) ")")

}

@abstract class FooNode : Node {
}

class Def : FooNode {
    @parse_field name : Name
    @parse_field imports : ASTList[DerivedRef]
    @parse_field vars : ASTList[Var]
    @parse_field expr : Expr
}

@abstract class Expr : FooNode {
}

@abstract class Atom : Expr {
}

class Lit : Atom implements TokenNode {
}

class Ref : Atom {
    @parse_field name : Name

    @export fun resolve (): FooNode =
    node.node_env().get_first(node.name.symbol)

    @export fun dummy (): Array[FooNode] =
    node.referenced_env().get(node.name.symbol)

    fun referenced_env (): LexicalEnv = null
}

class MiddleRef : Ref {

    fun referenced_env (): LexicalEnv = null
}

class DerivedRef : MiddleRef {

    fun referenced_env (): LexicalEnv =
    node.unit().root.node_env().get_first(node.name.symbol).children_env()
}

class Plus : Expr {
    @parse_field lhs : Expr
    @parse_field rhs : Expr
}

class Name : FooNode implements TokenNode {
}

class Var : FooNode {
    @parse_field name : Name
    @parse_field expr : Expr
}
