Class: RADProcessor

Inherits:
RubyToAnsiC
  • Object
show all
Defined in:
lib/rad/rad_processor.rb

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.translate(file, klass, method) ⇒ Object

REFACTOR: rename to self.process



20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/rad/rad_processor.rb', line 20

def self.translate file, klass, method
  sexp = RubyParser.new.process File.read(file), file
  sexp = s(:block, sexp) unless sexp.sexp_type == :block

  # this sucks... but it finds the class and method within the tree
  # it doesn't currently deal with class methods or anything special
  # AT ALL.

  k_sexp = sexp.find_nodes(:class).find { |k|
    k[1] == klass
  }

  body = k_sexp.scope
  body = body.block if body.block # RubyParser bug?

  m = body.find_nodes(:defn).find { |m|
    m[1] == method
  } rescue nil

  @translator = nil # HACK

  self.translator.process m if m
end

.translatorObject



44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/rad/rad_processor.rb', line 44

def self.translator
  unless @translator then
    @translator = CompositeSexpProcessor.new
    @translator << RADRewriter.new
    @translator << RADTypeChecker.new
    # HACK: more harm than good @translator << CRewriter.new
    @translator << self.new

    @translator.on_error_in(:defn) do |processor, exp, err|
      result = processor.expected.new
      case result
      when Array then
        result << :error
      end
      msg = "// ERROR: #{err.class}: #{err}"
      msg += " in #{exp.inspect}" unless exp.nil? or $TESTING
      msg += " from #{caller.join(', ')}" unless $TESTING
      result << msg
      result
    end

  end
  @translator
end

Instance Method Details

#process_iasgn(exp) ⇒ Object



69
70
71
72
73
# File 'lib/rad/rad_processor.rb', line 69

def process_iasgn(exp)
  name = exp.shift
  val = process exp.shift
  "__#{name.to_s.sub(/^@/, '')} = #{val}"
end

#process_iter(exp) ⇒ Object

Raises:

  • (UnsupportedNodeError)


80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
# File 'lib/rad/rad_processor.rb', line 80

def process_iter(exp)
  # the array identifer may be in one of two locations
  # when using the instance variable (ivar) style it is located at exp[0][1][1]
  if exp[0][1][1]
    enum = exp[0][1][1]
    enum = "__#{enum.to_s.sub(/^@/, '')}" if enum.to_s =~ /^@/
  # for local variables it is located at exp[0][1][2]  
  elsif exp[0][1][2]
    enum = exp[0][1][2]
  end
  
  out = []
  # Only support enums in C-land # not sure if this comment if valid anymore
  raise UnsupportedNodeError if exp[0][1].nil? # HACK ugly
  @env.scope do
    
    call = process exp.shift
    var  = process(exp.shift).intern # semi-HACK-y 
    body = process exp.shift
    
    # array types from varible_processing>post_process_arrays and arduino_sketch>array
    $array_types.each do |k,v|
          @array_type = v if k == enum.to_s.sub(/^__/,"")
    end
    
    index_helper = $array_index_helpers.shift
    index = "index_#{index_helper}" # solves redeclaration issue

    body += ";" unless body =~ /[;}]\Z/
    body.gsub!(/\n\n+/, "\n")

    out << "unsigned int #{index};" # shouldn't need more than int
    out << "for (#{index} = 0; #{index} < (int) (sizeof(#{enum}) / sizeof(#{enum}[0])); #{index}++) {"   
    out << "#{@array_type} #{var} = #{enum}[#{index}];"
    out << body
    out << "}"
  end

  return out.join("\n")
end

#process_ivar(exp) ⇒ Object



75
76
77
78
# File 'lib/rad/rad_processor.rb', line 75

def process_ivar(exp)
  name = exp.shift
  "__#{name.to_s.sub(/^@/, '')}"
end

#process_lasgn(exp) ⇒ Object



121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
# File 'lib/rad/rad_processor.rb', line 121

def process_lasgn(exp)
  out = ""
  var = exp.shift
  value = exp.shift # HACK FUCK || s(:array) # HACK?
  args = value

  exp_type = exp.sexp_type
  @env.add var.to_sym, exp_type
  var_type = self.class.c_type exp_type

  if exp_type.list? then
    assert_type args, :array

    raise "array must be of one type" unless args.sexp_type == Type.homo

    # HACK: until we figure out properly what to do w/ zarray
    # before we know what its type is, we will default to long.
    array_type = args.sexp_types.empty? ? 'void *' : self.class.c_type(args.sexp_types.first)
    # we can fix array here..
    args.shift # :arglist
    out << "#{var} = (#{array_type}) malloc(sizeof(#{array_type}) * #{args.length});\n"
    args.each_with_index do |o,i|
      out << "#{var}[#{i}] = #{process o};\n"
    end
  else
    out << "#{var}"
    out << " = #{process args}" if args
  end

  out.sub!(/;\n\Z/, '')

  return out
end

#process_str(exp) ⇒ Object



155
156
157
158
159
160
161
162
# File 'lib/rad/rad_processor.rb', line 155

def process_str(exp)
  s = exp.shift.gsub(/\n/, '\\n')
  if s.size == 1
    return "\'#{s}\'"
  else
    return "\"#{s}\""
  end
end