import lexer_example
@with_lexer(foo_lexer)
grammar foo_grammar {
    @main_rule main_rule <- list+(scope)
    scope <- Scope(name "{" list*(or(scope | ref)) "}")
    ref <- Ref(name)
    identifier <- Identifier(@identifier)
    name <- or(DottedName(name "." identifier) | identifier)

}

@abstract class FooNode : Node {
}

@abstract class Name : FooNode {

    @abstract fun referenced_name (): Symbol

    @abstract fun referenced_scope (): LexicalEnv

    @abstract fun referenced_parent_scope (): LexicalEnv
}

class DottedName : Name {
    @parse_field prefix : Name
    @parse_field suffix : Identifier

    fun referenced_name (): Symbol = node.suffix.referenced_name()

    fun referenced_parent_scope (): LexicalEnv = node.prefix.referenced_scope()

    fun referenced_scope (): LexicalEnv =
    node.suffix.resolve_scope(node.referenced_parent_scope())
}

class Identifier : Name implements TokenNode {

    fun referenced_name (): Symbol = node.symbol

    fun resolve_scope (from_env : LexicalEnv): LexicalEnv = {
        val env = from_env.do(
            (e) => e, default_val=node.referenced_parent_scope()
        );

        env.get(node.symbol)?(0).children_env()
    }

    fun referenced_parent_scope (): LexicalEnv = node.unit().root.children_env()

    fun referenced_scope (): LexicalEnv = node.resolve_scope(_)
}

class Ref : FooNode {
    @parse_field name : Name

    @export fun resolve (): FooNode = node.name.referenced_scope().env_node
}

class Scope : FooNode {
    @parse_field name : Name
    @parse_field content : ASTList[FooNode]
}
