Module: Rubber

Defined in:
lib/rubber/types.rb,
lib/rubber/autord.rb,
lib/rubber/tokens.rb,
lib/rubber/codegen.rb,
lib/rubber/scanner.rb,
lib/rubber/version.rb,
lib/rubber/mkextconf.rb,
lib/rubber/codegen/enum.rb,
lib/rubber/codegen/array.rb,
lib/rubber/codegen/class.rb,
lib/rubber/codegen/flags.rb,
lib/rubber/codegen/float.rb,
lib/rubber/codegen/genum.rb,
lib/rubber/codegen/param.rb,
lib/rubber/codegen/gboxed.rb,
lib/rubber/codegen/gflags.rb,
lib/rubber/codegen/module.rb,
lib/rubber/codegen/string.rb,
lib/rubber/codegen/struct.rb,
lib/rubber/codegen/gobject.rb,
lib/rubber/codegen/integer.rb,
lib/rubber/codegen/function.rb,
lib/rubber/codegen/gcrefpool.rb,
lib/rubber/codegen/ginterface.rb

Defined Under Namespace

Modules: RegisterChildren Classes: CRScanner, C_Array, C_Class, C_Enum, C_Flags, C_Float, C_Function, C_GBoxed, C_GCRefPool, C_GEnum, C_GFlags, C_GInterface, C_GObject, C_Integer, C_Module, C_Param, C_RootModule, C_String, C_Struct, Options, ScanState, TokenStringScanner, Tokenizer

Constant Summary collapse

CMAP =

Map most GLib types to normal C style ones

{
  'ruby'=>'VALUE',
  'gboolean'=>'bool',
  'gint'=>'int',
  'glong'=>'long',
  'guint'=>'uint',
  'guint64'=>'uint64',
  'gchar'=>'char',
  'gfloat'=>'double', # Ruby only uses doubles?
  'float'=>'double', # Ruby only uses doubles?
  'gdouble'=>'double'
}
RUBY_CLASS_MAP =
auto_class_map()
RUBY_NATIVE_TYPES =
%w|T_NIL T_OBJECT T_CLASS T_MODULE T_FLOAT T_STRING T_REGEXP T_ARRAY T_FIXNUM T_HASH T_STRUCT T_BIGNUM T_FILE T_TRUE T_FALSE T_DATA T_SYMBOL|
RUBY_NATIVE_NAMES =
%w|Nil Object Class Module Float String Regexp Array Fixnum Hash Struct Bignum File True False Data Symbol|
VERSION =
[0,0,22]

Class Method Summary collapse

Class Method Details

.auto_class_mapObject


20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/rubber/types.rb', line 20

def auto_class_map()
hsh = {}
%w[rb_cObject
rb_cArray
rb_cBignum
rb_cClass
rb_cDir
rb_cData
rb_cFalseClass
rb_cFile
rb_cFixnum
rb_cFloat
rb_cHash
rb_cInteger
rb_cIO
rb_cModule
rb_cNilClass
rb_cNumeric
rb_cProc
rb_cRange
rb_cRegexp
rb_cString
rb_cSymbol
rb_cThread
rb_cTime
rb_cTrueClass
rb_cStruct
rb_eException
rb_eStandardError
rb_eSystemExit
rb_eInterrupt
rb_eSignal
rb_eFatal
rb_eArgError
rb_eEOFError
rb_eIndexError
rb_eRangeError
rb_eIOError
rb_eRuntimeError
rb_eSecurityError
rb_eSystemCallError
rb_eTypeError
rb_eZeroDivError
rb_eNotImpError
rb_eNoMemError
rb_eNoMethodError
rb_eFloatDomainError
rb_eScriptError
rb_eNameError
rb_eSyntaxError
rb_eLoadError].each { |n|
  hsh[$1]= n.strip if n =~ /rb_[ce]([A-Za-z]+)/
}
hsh
end

.count_arr_access(str, name) ⇒ Object


95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/rubber/types.rb', line 95

def self.count_arr_access(str,name)
  if name.include?(?[)
    sc = StringIO.new(name)
    brac, lev = 0, 0
    until sc.eof?
      c = sc.getc
      if lev == 0 and c == ?[
        brac += 1
      end
      case c
      when ?[
        lev += 1
      when ?]
        lev -= 1
      end 
    end
    brac
  else
    0
  end
end

.equivalent_type(ctype, name = nil) ⇒ Object


117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# File 'lib/rubber/types.rb', line 117

def self.equivalent_type(ctype,name=nil)
    ctype.gsub!(/ /,'')
    ctype.strip!
    ctype.gsub!(/(const|static)/,'')
    if name
      brackets = count_arr_access(ctype,name)
      until brackets == 0
        ctype = ctype[0..-2] if ctype[-1] == ?*
        brackets -= 1
      end
    end
    return 'VALUE' if RUBY_NATIVE_TYPES.include?(ctype)
    ctype= $equivalents[ctype] if $equivalents.has_key?(ctype)
    return 'VALUE' if RUBY_NATIVE_TYPES.include?(ctype)
    ctype= CMAP[ctype] if CMAP.has_key?(ctype)
    ctype
end

.explicit_cast(name, ctype, rule) ⇒ Object


135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
# File 'lib/rubber/types.rb', line 135

def self.explicit_cast(name, ctype, rule)
    ctype = equivalent_type(ctype, name)
    rule = equivalent_type(rule)
    #puts "#{name}:#{ctype}->#{rule}"
    return name if ctype == rule
    if $custom_maps.has_key?(ctype)
      if $custom_maps[ctype].has_key?(rule)
        return $custom_maps[ctype][rule].gsub(/%%/,"#{name}")
      end
    end
    case ctype
    when 'VALUE'
      case rule
        when 'char*', 'string'
          "( NIL_P(#{name}) ? NULL : StringValuePtr(#{name}) )"
        when 'bool'
          "RTEST(#{name})"
        when 'int'
          "NUM2INT(#{name})"
        when 'uint'
          "NUM2UINT(#{name})"
		when 'uint64'
		  "rb_num2ull(#{name})"
        when 'long'
          "NUM2LONG(#{name})"
        when 'double'
          "NUM2DBL(#{name})"
        when 'gobject', 'GObject*'
          "RVAL2GOBJ(#{name})"
        else
        raise "Unable to convert #{ctype} to #{rule}"
      #"#{ctype.gsub(/[* ]/,'_').upcase}_TO_#{rule.upcase}(#{name})"
      end
    when 'bool'
      case rule
        when 'char*', 'string'
          "#{name} ? #{"true".inspect} : #{"false".inspect}"
        when 'VALUE', 'ruby'
          " ((#{name}) ? Qtrue : Qfalse)"
        else
        raise "Unable to convert #{ctype} to #{rule}"
      #"#{ctype.gsub(/[* ]/,'_').upcase}_TO_#{rule.upcase}(#{name})"
      end
    when 'uint'
      case rule
        when 'VALUE', 'ruby'
          " UINT2NUM(#{name})"
        else
        raise "Unable to convert #{ctype} to #{rule}"
      end
    when 'uint64'
      case rule
        when 'VALUE', 'ruby'
          " rb_ull2inum(#{name})"
        else
          raise "Unable to convert #{ctype} to #{rule}"
	    end
    when 'char*', 'string'
      case rule
        when 'VALUE', 'ruby'
          " rb_str_new2(#{name})"
        else
        raise "Unable to convert #{ctype} to #{rule}"
      end
    when 'GObject*', 'gobject'
      case rule
        when 'VALUE', 'ruby'
          " GOBJ2RVAL(#{name})"
        else
        raise "Unable to convert #{ctype} to #{rule}"
      end
    when 'int'
      case rule
        when 'VALUE', 'ruby'
          " INT2NUM(#{name})"
        else
        raise "Unable to convert #{ctype} to #{rule}"
      end
    when 'long'
      case rule
        when 'VALUE', 'ruby'
          " LONG2NUM(#{name})"
        else
        raise "Unable to convert #{ctype} to #{rule}"
      end
    when 'double'
      case rule
        when 'VALUE', 'ruby'
          " rb_float_new(#{name})"
        else
        raise "Unable to convert #{ctype} to #{rule}"
      end
    else
      raise "Unable to convert #{ctype} to #{rule}"
      #"#{ctype.gsub(/[* ]/,'_').upcase}_TO_#{rule.upcase}(#{name})"
    end
end

.find_class(classname) ⇒ Object


79
80
81
82
83
84
85
# File 'lib/rubber/types.rb', line 79

def self.find_class(classname)
  return nil if classname.nil?
  return RUBY_CLASS_MAP[classname] if RUBY_CLASS_MAP.has_key?(classname)
  # Should this be rb_c or just c?
  # c{NAME} works better... I think...
  return 'c'+classname
end

.generate_c_source(scanner, io) ⇒ Object


3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/rubber/codegen.rb', line 3

def generate_c_source(scanner, io)
  mod = scanner.stack.first # Pseudo root module for file
  if scanner.options.gnu
  	io.puts "#define _GNU_SOURCE 1"
  end
  io.puts <<-EOX
  /* Includes */
  #include <ruby.h>
  #include <stdlib.h>
  #include <stdio.h>
  #include <string.h>
  #if defined GCC
    #define OPTIONAL_ATTR __attribute__((unused))
  #else
    #define OPTIONAL_ATTR
  #endif
EOX
  if scanner.incs
    scanner.incs.each { |i| io.puts "#include #{i.inspect}"}
  end
  io.puts "\n/* Setup types */"
  io.puts "/* Try not to clash with other definitions of bool... */"
  io.puts "typedef int rubber_bool;"
  io.puts "#define bool rubber_bool"
  io.puts "\n/* Prototypes */"
if scanner.options.glib?
  io.puts <<-EOGLIB
#include "rbglib.h"

EOGLIB

  
if scanner.options.gtk?
  io.write <<-EOI
#include "rbgtk.h"

#if defined(G_PLATFORM_WIN32) && !defined(RUBY_GTK2_STATIC_COMPILATION)
#  ifdef RUBY_GTK2_COMPILATION
#    define RUBY_GTK2_VAR __declspec(dllexport)
#  else
#    define RUBY_GTK2_VAR extern __declspec(dllimport)
#  endif
#else
#  define RUBY_GTK2_VAR extern
#endif

RUBY_GTK2_VAR VALUE mGtk;
RUBY_GTK2_VAR VALUE mGdk;

#define RBGTK_INITIALIZE(obj,gtkobj)\
 (rbgtk_initialize_gtkobject(obj, GTK_OBJECT(gtkobj)))
EOI
end
end


  mod.classes.each { |c|
    c.declare(io)
  }
  if scanner.raw
    io.puts("\n/* Inline C code */")
    io.write(scanner.raw)
  end
  io.puts "\n/* Code */"
  mod.classes.each { |c|
    c.code(io)
  }
  io.puts "/* Init */"
  io.puts "void"
  io.puts "Init_#{scanner.ext}(void)"
  io.puts "{"
  io.puts scanner.pre_init_code if scanner.pre_init_code
    mod.classes.each { |c|
      c.register(io)
    }
  io.puts scanner.post_init_code if scanner.post_init_code
  io.puts "}"
  
end

.generate_extconf(scanner, io) ⇒ Object


3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
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
120
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
154
155
156
157
# File 'lib/rubber/mkextconf.rb', line 3

def generate_extconf(scanner, io)
	io.write <<-EOMK
require 'mkmf'
use_gems = false
begin
  require 'mkmf-gnome2'
rescue LoadError
  use_gems = true
end

if use_gems or Object.const_defined?('Gem')
  require 'rubygems'
  gem 'glib2'
  require 'mkmf-gnome2'
  %w[rbglib.h rbgtk.h rbpango.h rbatk.h].each do |header|
  	Gem.find_files(header).each do |f|
		$CFLAGS += " '-I\#{File.dirname(f)}'"
	end
  end
end
EOMK

io.write <<-EOMK
# Look for headers in {gem_root}/ext/{package}
if use_gems
  %w[
EOMK
  io << " glib2" if scanner.options.glib
  io << " gdk_pixbuf2 atk gtk2" if scanner.options.gtk
  io.write <<-EOX
].each do |package|
    require package
    if Gem.loaded_specs[package]
      $CFLAGS += " -I" + Gem.loaded_specs[package].full_gem_path + "/ext/" + package
    else
      if fn = $".find { |n| n.sub(/[.](so|rb)$/,'') == package }
        dr = $:.find { |d| File.exist?(File.join(d, fn)) }
        pt = File.join(dr,fn) if dr && fn
      else
        pt = "??"
      end
      STDERR.puts "require '" + package + "' loaded '"+pt+"' instead of the gem - trying to continue, but build may fail"
    end
  end
end
EOX

io.write <<-EOY
if RbConfig::CONFIG.has_key?('rubyhdrdir')
  $CFLAGS += " -I" + RbConfig::CONFIG['rubyhdrdir']+'/ruby'
end

$CFLAGS += " -I."
have_func("rb_errinfo")
EOY

    if scanner.inc_dirs
      io.puts "$CFLAGS += "+scanner.inc_dirs.reject { |i| i =~ /:/ }.collect { |i| " '-I#{i}'" }.join().inspect
      scanner.inc_dirs.select { |i| i =~ /gem:/ }.each do |gem_info|
        name,extra = gem_info.split(/:/)[1].split(%r'/', 2)
        extra = "/#{extra}" unless extra.nil? or extra.empty?
        io.puts %Q<gem '#{name}'; $CFLAGS += "  '-I" + Gem.loaded_specs['#{name}'].full_gem_path + "#{extra}'">
      end
    end
    if scanner.lib_dirs
      io.puts "$LDFLAGS += "+scanner.lib_dirs.collect { |i| " '-L#{i}'"}.join().inspect
    end
    if scanner.defs
      io.puts "$CFLAGS += "+scanner.defs.collect { |i| " '-D#{i}'"}.join().inspect
    end
    scanner.pkgs.each { |pkg| io.puts "PKGConfig.have_package(#{pkg.inspect}) or exit(-1)" } if scanner.pkgs
    
    if scanner.incs
      scanner.incs.each { |i|
        io.puts %Q<
unless have_header(#{i.inspect})
  paths = Gem.find_files(#{i.inspect})
  paths.each do |path|
    $CFLAGS += " '-I\#{File.dirname(path)}'"
  end
  have_header(#{i.inspect}) or exit -1
end
>
      }
    end
    if scanner.libs
      scanner.libs.each { |i| io.puts "have_library(#{i.inspect}) or exit(-1)\n$LIBS += \" -l#{i}\""}
    end
    io.write <<-EOB

STDOUT.print("checking for new allocation framework... ") # for ruby-1.7
if Object.respond_to? :allocate
  STDOUT.print "yes\n"
  $defs << "-DHAVE_OBJECT_ALLOCATE"
else
  STDOUT.print "no\n"
end

top = File.expand_path(File.dirname(__FILE__) + '/..') # XXX
$CFLAGS += " " + ['glib/src'].map{|d|
  "-I" + File.join(top, d)
}.join(" ")

have_func("rb_define_alloc_func") # for ruby-1.8

#set_output_lib('libruby-#{scanner.ext}.a')
if /cygwin|mingw/ =~ RUBY_PLATFORM
  top = "../.."
  [
    ["glib/src", "ruby-glib2"],
  ].each{|d,l|
    $LDFLAGS << sprintf(" -L%s/%s", top, d)
    $libs << sprintf(" -l%s", l)
  }
end
begin
  srcdir = File.expand_path(File.dirname($0))

  begin

    obj_ext = "."+$OBJEXT

    $libs = $libs.split(/\s/).uniq.join(' ')
    $source_files = Dir.glob(sprintf("%s/*.c", srcdir)).map{|fname|
      fname[0, srcdir.length+1] = ''
      fname
    }
    $objs = $source_files.collect do |item|
      item.gsub(/\.c$/, obj_ext)
    end

    #
    # create Makefile
    #
    $defs << "-DRUBY_#{scanner.ext.upcase}_COMPILATION"
    # $CFLAGS << $defs.join(' ')
    create_makefile(#{scanner.ext.inspect}, srcdir)
    raise Interrupt if not FileTest.exist? "Makefile"

    File.open("Makefile", "a") do |mfile|
      $source_files.each do |e|
        mfile.print sprintf("%s: %s\n", e.gsub(/\.c$/, obj_ext), e)
      end
    end
  ensure
    #Dir.chdir ".."
  end

  #create_top_makefile()
rescue Interrupt
  print "  [error] " + $!.to_s + "\n"
end

    EOB
end

.generate_rd(scanner, io) ⇒ Object


2
3
4
5
6
7
8
9
# File 'lib/rubber/autord.rb', line 2

def self.generate_rd(scanner, io)
  if scanner.doc
    io.write(scanner.doc + "\n\n")
  end
  scanner.stack.first.classes.each { |c|
    c.doc_rd(io)
  }
end

.native_type?(name) ⇒ Boolean

Returns:

  • (Boolean)

90
91
92
93
# File 'lib/rubber/types.rb', line 90

def self.native_type?(name)
  return true if name.nil? or RUBY_NATIVE_TYPES.include?(equivalent_type(name))
  false
end