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 { |name|
      rulename = name.to_s.sub(/^visit_/,"").gsub(/_([a-z])/) { $1.upcase }
      [rulename.to_sym,name.to_sym]
    }
  ]
end

Instance Method Details

#get_source(ctx) ⇒ Object



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

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
# File 'lib/expressir/express/visitor.rb', line 125

def get_source_pos(ctx)
  ranges = 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 { |item,acc|
    [ [item[0],acc[0]].min, [item[1],acc[1]].max ]
  }
  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 { |k,v|
        if k.match(/^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
      }
    ]
    Ctx.new nodes,name
  when Array
    ast.map { |v|
      v.length == 1 or raise "element of array invalid (#{v.keys})"
      to_ctx(v.values[0],v.keys[0])
    }
  when nil
    nil
  else
    SimpleCtx.new ast,name
  end
end

#visit(ctx) ⇒ Object



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

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



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

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

  visit ctx
end