Grammar < BasicObject, Common::Patterns::ShorthandMethods {

var rule_table: ::Ruby::Hash.new

# Force evaluation of the rule tree in a way that
# doesn't get stuck in an infinite recursion.
construct_all_rules: {
  # Consider all rules with "root" in the name
  rules.memes.each |name, meme| {
    meme.name.to_s.include?("root") && (
      meme.result_for(rules).inner.construct
    )
  }

  seen_keys = []
  loop {
    new_keys = rule_table.keys - seen_keys
    new_keys.empty? && break
    new_keys.each |key| {
      rule_table[key].inner.construct
      seen_keys.push(key)
    }
  }
}

[decorators]

const token: Decorator {
  apply: |meme| {
    orig_meme = meme.dup
    meme.body = &{ orig_meme.result.token(:"t_"meme.name"") }
  }
  [transforms]
  cache: true
}

const rule: Decorator {
  apply: |meme| {
    name = meme.name
    # TODO: use some kind of Decorator#wrap mechanism instead
    meme.target.declare_meme(name, [:memoize]) {
      outer_self = self
      rule = Capture::Patterns::RuleCall {
        name: name
        inner: meme.result_for(outer_self)
      }
      rule_table[name] = rule
      rule
    }
  }
  [transforms]
  expose: false # Exposing the original meme would overwrite the wrapped one
}

[rules]
rule root: String::Patterns::AnyCharacter.new.*

}