Module: Lox::AST
- Defined in:
- lib/loxby/helpers/ast.rb
Overview
Interface: “‘ruby
Lox::AST.define_ast(
"ASTBaseClass",
{
:ast_type => [
[:field_one_type, :field_one_name],
[:field_two_type, :field_two_name]
],
:other_ast_type => [[:field_type, :field_name]]
}
)
“‘
This call to ‘#define_ast` generates `Lox::AST::ASTBaseClass`, as well as `::AstType` and `::OtherAstType` descending from and scoped uner it. Generated classes follow the Visitor pattern: `::AstType` generates with `#accept(visitor)` which calls `visitor.visit_ast_type(self)`.
Class Method Summary collapse
- .define_ast(base_name, types) ⇒ Object
- .define_class(class_name, klass, base_class: Lox::AST) ⇒ Object
-
.define_type(base_class, base_class_name, subtype_name, fields) ⇒ Object
rubocop:disable Metrics/MethodLength,Metrics/AbcSize.
Class Method Details
.define_ast(base_name, types) ⇒ Object
38 39 40 41 42 43 44 45 46 47 48 49 |
# File 'lib/loxby/helpers/ast.rb', line 38 def define_ast(base_name, types) base_class = Class.new base_class.include Visitable # Define boilerplate visitor methods Visitor.define_types(base_name, types.keys) # Dynamically create subclasses for each AST type types.each do |class_name, fields| define_type(base_class, base_name, class_name, fields) end define_class base_name.to_camel_case, base_class end |
.define_class(class_name, klass, base_class: Lox::AST) ⇒ Object
72 73 74 |
# File 'lib/loxby/helpers/ast.rb', line 72 def define_class(class_name, klass, base_class: Lox::AST) base_class.const_set class_name, klass end |
.define_type(base_class, base_class_name, subtype_name, fields) ⇒ Object
rubocop:disable Metrics/MethodLength,Metrics/AbcSize
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
# File 'lib/loxby/helpers/ast.rb', line 51 def define_type(base_class, base_class_name, subtype_name, fields) # rubocop:disable Metrics/MethodLength,Metrics/AbcSize subtype = Class.new(base_class) parameters = fields.map { _1[1].to_s } subtype.class_eval <<~RUBY, __FILE__, __LINE__ + 1 include Visitable # Visitor pattern #{parameters.empty? ? '' : 'attr_reader '}#{parameters.map { ":#{_1}" }.join(', ')} def initialize(#{parameters.map { "#{_1}:" }.join(', ')}) #{parameters.map { "@#{_1}" }.join(', ')}#{parameters.empty? ? '' : ' = '}#{parameters.join ', '} end # This function was dynamically generated for visitor pattern. # Expects visitors to define `#visit_#{subtype_name}_#{base_class_name}`. def accept(visitor) visitor.visit_#{subtype_name}_#{base_class_name}(self) end RUBY define_class(subtype_name.to_camel_case, subtype, base_class:) end |