Class: Expressir::Express::Visitor

Inherits:
Object
  • Object
show all
Defined in:
lib/expressir/express/visitor.rb

Defined Under Namespace

Classes: Ctx, SimpleCtx

Instance Method Summary collapse

Constructor Details

#initialize(source, include_source: nil) ⇒ Visitor

Returns a new instance of Visitor.

Parameters:

  • Rice-wrapped (::ExpressParser::TokenVector)

    std::vector<TokenProxy>

  • include_source (Boolean) (defaults to: nil)

    attach original source code to model elements



84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/expressir/express/visitor.rb', line 84

def initialize(source, include_source: nil)
  @source = source
  @include_source = include_source

  @attached_remark_tokens = Set.new

  @visit_methods = Hash[
    private_methods.grep(/^visit_/).map do |name|
      rulename = name.to_s.sub(/^visit_/, "").gsub(/_([a-z])/) { $1.upcase }
      [rulename.to_sym, name.to_sym]
    end
  ]
end

Instance Method Details

#get_source(ctx) ⇒ Object



147
148
149
150
# File 'lib/expressir/express/visitor.rb', line 147

def get_source(ctx)
  a, b = get_source_pos ctx
  @source[a..b - 1].strip
end

#get_source_pos(ctx) ⇒ Object



125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
# File 'lib/expressir/express/visitor.rb', line 125

def get_source_pos(ctx)
  nil
  ranges = case ctx
           when Ctx
             ctx.source_pos and return ctx.source_pos # cache
             ctx.values.map { |item| get_source_pos(item) }
           when SimpleCtx
             return nil unless ctx.data.respond_to? :offset

             [[ctx.data.offset, ctx.data.offset + ctx.data.length]]
           when Array
             ctx.map { |item| get_source_pos(item) }
           else
             raise "unknown type in Ctx tree: #{ctx}"
           end
  source_pos = ranges.compact.reduce do |item, acc|
    [[item[0], acc[0]].min, [item[1], acc[1]].max]
  end
  Ctx === ctx and ctx.source_pos = source_pos
  source_pos
end

#to_ctx(ast, name = :unnamed) ⇒ Object



98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
# File 'lib/expressir/express/visitor.rb', line 98

def to_ctx(ast, name = :unnamed)
  case ast
  when Hash
    nodes = Hash[
      ast.map do |k, v|
        if k =~ /^listOf_(.*)$/
          itemkey = $1.to_sym
          ary = Array === v ? v : [v]
          [itemkey, to_ctx(ary.select { |v| v[itemkey] }.map { |v| v.slice(itemkey) })]
        else
          [k, to_ctx(v, k)]
        end
      end
    ]
    Ctx.new nodes, name
  when Array
    ast.map do |v|
      v.length == 1 or raise "element of array invalid (#{v.keys})"
      to_ctx(v.values[0], v.keys[0])
    end
  when nil
    nil
  else
    SimpleCtx.new ast, name
  end
end

#visit(ctx) ⇒ Object



158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
# File 'lib/expressir/express/visitor.rb', line 158

def visit(ctx)
  if Array === ctx
    return ctx.map { |el| visit el }
  end

  node = ctx
  if @visit_methods[ctx.name]
    node = send(@visit_methods[ctx.name], ctx)
    if @include_source && node.respond_to?(:source)
      node.source = get_source ctx
    end
  end

  attach_remarks(ctx, node)
  node
end

#visit_ast(ast, name) ⇒ Object



152
153
154
155
156
# File 'lib/expressir/express/visitor.rb', line 152

def visit_ast(ast, name)
  ctx = to_ctx(ast, name)

  visit ctx
end