Class: RubyLess::RubyLessProcessor

Inherits:
SexpProcessor
  • Object
show all
Defined in:
lib/ruby_less/processor.rb

Constant Summary collapse

INFIX_OPERATOR =
['<=>', '==', '<', '>', '<=', '>=', '-', '+', '*', '/', '%']
PREFIX_OPERATOR =
['-@']

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(helper) ⇒ RubyLessProcessor

Returns a new instance of RubyLessProcessor.



28
29
30
31
32
33
34
35
# File 'lib/ruby_less/processor.rb', line 28

def initialize(helper)
  super()
  @helper = helper
  @indent = "  "
  self.auto_shift_type = true
  self.strict = true
  self.expected = TypedString
end

Instance Attribute Details

#rubyObject (readonly)

Returns the value of attribute ruby.



7
8
9
# File 'lib/ruby_less/processor.rb', line 7

def ruby
  @ruby
end

Class Method Details

.translate(receiver, string) ⇒ Object



12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# File 'lib/ruby_less/processor.rb', line 12

def self.translate(receiver, string)
  if sexp = RubyParser.new.parse(string)
    res = self.new(receiver).process(sexp)
    if res.klass.kind_of?(Hash)
      res.opts[:class] = Hash
    end
    res
  elsif string.size == 0
    ''
  else
    raise RubyLess::SyntaxError.new("Syntax error")
  end
rescue Racc::ParseError => err
  raise RubyLess::SyntaxError.new(err.message)
end

Instance Method Details

#process(exp) ⇒ Object



37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/ruby_less/processor.rb', line 37

def process(exp)
  super
rescue UnknownNodeError => err
  if err.message =~ /Unknown node-type :(.*?) /
    raise RubyLess::SyntaxError.new("'#{$1}' not available in RubyLess.")
  else
    raise RubyLess::SyntaxError.new(err.message)
  end
  # return nil if exp.nil?
  # method = exp.shift
  # send("process_#{method}", exp)
end

#process_and(exp) ⇒ Object



71
72
73
# File 'lib/ruby_less/processor.rb', line 71

def process_and(exp)
  t "(#{process(exp.shift)} and #{process(exp.shift)})", Boolean
end

#process_arglist(exp) ⇒ Object



125
126
127
128
129
130
131
# File 'lib/ruby_less/processor.rb', line 125

def process_arglist(exp)
  code = t("")
  until exp.empty? do
    code.append_argument(process(exp.shift))
  end
  code
end

#process_array(exp) ⇒ Object



133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
# File 'lib/ruby_less/processor.rb', line 133

def process_array(exp)
  literal = true
  list    = []
  classes = []
  while !exp.empty?
    res = process(exp.shift)
    content_class ||= res.opts[:class]
    unless res.opts[:class] <= content_class
      classes = list.map { content_class.name } + [res.opts[:class].name]
      raise RubyLess::Error.new("Mixed Array not supported ([#{classes * ','}]).")
    end
    list << res
  end

  res.opts[:class] = [content_class] # Array
  res.opts[:elem] = content_class
  t "[#{list * ','}]", res.opts.merge(:literal => nil)
end

#process_call(exp) ⇒ Object



113
114
115
116
117
118
119
# File 'lib/ruby_less/processor.rb', line 113

def process_call(exp)
  unless receiver = process(exp.shift)
    receiver = @helper.kind_of?(TypedString) ? @helper : nil
  end

  method_call(receiver, exp)
end

#process_const(exp) ⇒ Object



50
51
52
53
54
55
56
57
# File 'lib/ruby_less/processor.rb', line 50

def process_const(exp)
  const_name = exp.pop.to_s
  if opts = @helper.respond_to?(:safe_const_type) ? @helper.safe_const_type(const_name) : nil
    t opts[:method], opts
  else
    raise RubyLess::Error.new("Unknown constant '#{const_name}'.")
  end
end

#process_dot2(exp) ⇒ Object



179
180
181
182
183
# File 'lib/ruby_less/processor.rb', line 179

def process_dot2(exp)
  a = process(exp.shift)
  b = process(exp.shift)
  t "(#{a}..#{b})", Range
end

#process_dstr(exp) ⇒ Object



175
176
177
# File 'lib/ruby_less/processor.rb', line 175

def process_dstr(exp)
  t "\"#{parse_dstr(exp)}\"", String
end

#process_evstr(exp) ⇒ Object



185
186
187
# File 'lib/ruby_less/processor.rb', line 185

def process_evstr(exp)
  exp.empty? ? t('', String) : process(exp.shift)
end

#process_false(*args) ⇒ Object



63
64
65
# File 'lib/ruby_less/processor.rb', line 63

def process_false(*args)
  t 'false', {:class => Boolean, :literal => false}
end

#process_fcall(exp) ⇒ Object



121
122
123
# File 'lib/ruby_less/processor.rb', line 121

def process_fcall(exp)
  method_call(@helper.kind_of?(TypedString) ? @helper : nil, exp)
end

#process_hash(exp) ⇒ Object



189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
# File 'lib/ruby_less/processor.rb', line 189

def process_hash(exp)
  result = t "", String
  until exp.empty?
    key = exp.shift
    if [:lit, :str].include?(key.first)
      key = key[1]

      rhs = exp.shift
      type = rhs.first
      rhs = process rhs
      #rhs = "(#{rhs})" unless [:lit, :str].include? type # TODO: verify better!
      result.set_hash(key, rhs)
    else
      # ERROR: invalid key
      raise RubyLess::SyntaxError.new("Invalid key type for hash (should be a literal value, was #{key.first.inspect})")
    end
  end
  result.rebuild_hash
  result
end

#process_if(exp) ⇒ Object



88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/ruby_less/processor.rb', line 88

def process_if(exp)
  cond      = process(exp.shift)
  true_res  = process(exp.shift)
  false_res = process(exp.shift)

  if true_res && false_res
    if true_res.klass != false_res.klass
      if true_res.klass == NilClass
        # Change true_res to false_res class (could_be_nil? is true)
        true_res.opts[:class] = false_res.klass
      elsif false_res.klass == NilClass
        # Change false_res to true_res class (could_be_nil? is true)
        false_res.opts[:class] = true_res.klass
      else
        raise RubyLess::SyntaxError.new("Error in conditional expression: '#{true_res}' and '#{false_res}' do not return results of same type (#{true_res.klass} != #{false_res.klass}).")
      end
    end
  end
  raise RubyLess::SyntaxError.new("Error in conditional expression.") unless true_res || false_res
  opts = {}
  opts[:nil] = true_res.nil? || true_res.could_be_nil? || false_res.nil? || false_res.could_be_nil?
  opts[:class] = true_res ? true_res.klass : false_res.klass
  t "(#{cond} ? #{true_res || 'nil'} : #{false_res || 'nil'})", opts
end

#process_ivar(exp) ⇒ Object



210
211
212
# File 'lib/ruby_less/processor.rb', line 210

def process_ivar(exp)
  method_call(nil, exp)
end

#process_lit(exp) ⇒ Object



165
166
167
168
# File 'lib/ruby_less/processor.rb', line 165

def process_lit(exp)
  lit = exp.shift
  t lit.inspect, get_lit_class(lit)
end

#process_nil(*args) ⇒ Object



67
68
69
# File 'lib/ruby_less/processor.rb', line 67

def process_nil(*args)
  t 'nil', {:class => NilClass, :literal => nil, :nil => true}
end

#process_not(exp) ⇒ Object



84
85
86
# File 'lib/ruby_less/processor.rb', line 84

def process_not(exp)
  t "not #{process(exp.shift)}", Boolean
end

#process_or(exp) ⇒ Object



75
76
77
78
79
80
81
82
# File 'lib/ruby_less/processor.rb', line 75

def process_or(exp)
  left, right = process(exp.shift), process(exp.shift)
  if left.klass == right.klass
    t "(#{left} or #{right})", :class => right.klass, :nil => right.could_be_nil?
  else
    t "(#{left} or #{right})", Boolean
  end
end

#process_str(exp) ⇒ Object



170
171
172
173
# File 'lib/ruby_less/processor.rb', line 170

def process_str(exp)
  lit = exp.shift
  t lit.inspect, :class => String, :literal => lit
end

#process_true(*args) ⇒ Object



59
60
61
# File 'lib/ruby_less/processor.rb', line 59

def process_true(*args)
  t 'true', {:class => Boolean, :literal => true}
end

#process_vcall(exp) ⇒ Object

Is this used ?



153
154
155
156
157
158
159
160
161
162
163
# File 'lib/ruby_less/processor.rb', line 153

def process_vcall(exp)
  var_name = exp.shift
  unless opts = get_method(nil, [var_name])
    raise RubyLess::Error.new("Unknown variable or method '#{var_name}'.")
  end
  method = opts[:method]
  if args = opts[:prepend_args]
    method = "#{method}(#{args.raw})"
  end
  t method, opts
end