rubber-generate 0.0.6 → 0.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README.textile CHANGED
@@ -1,6 +1,6 @@
1
1
  h1. Rubber Generate
2
2
 
3
- h2. v0.0.5
3
+ h2. v0.0.7
4
4
 
5
5
  Template language for generating Ruby bindings for C libraries
6
6
  by Geoff Youngs <g@intersect-uk.co.uk>
@@ -18,6 +18,17 @@ it is planned to remove this dependency unless they genuinely require Ruby/GTK.
18
18
  Other features include custom named type-maps, pre/post code inclusion within
19
19
  functions and some rudimentary understanding of C code.
20
20
 
21
+ h3. Changes
22
+
23
+ * 0.0.7 - 7th May 2010
24
+ - Add support for array constants (including autmatic type detection) - e.g array <ConstantName> = [ "Text", NULL, 3 ]
25
+ - Add syntax_error function to parser which reports slightly more helpful syntax error messages for a .cr file
26
+ - Add tracking of code location so that C compiler throws errors which refer to the original line in the .cr file
27
+ - Add support for GSList{type} or GList{type} conversion to arrays as return values for functions
28
+
29
+ * 0.0.6 - 6th May 2010
30
+ - Flags class allows wrapping a bit field with slightly more information. Plus automatic conversion to/from ruby and support for integer values.
31
+
21
32
  h3. Dependencies
22
33
 
23
34
  * Ruby 1.8.6
@@ -0,0 +1,59 @@
1
+ module Rubber
2
+
3
+ class C_Array
4
+ define_members :name, :values, :parent
5
+ def code(io)
6
+ end
7
+ def declare(io)
8
+ #io.puts "static VALUE #{cname};"
9
+ end
10
+ include RegisterChildren
11
+ def default_cname
12
+ #"enum"+name
13
+ end
14
+ def doc_rd(io)
15
+ depth = (fullname.gsub(/[^:]/,'').size >> 1)
16
+ io.puts "=#{'=' * depth} #{fullname}"
17
+ end
18
+ def get_root(); is_root? ? self : parent.get_root; end; def is_root?()
19
+ not parent.respond_to?(:fullname)
20
+ end
21
+ def fullname()
22
+ if parent and parent.respond_to?(:fullname)
23
+ "#{parent.fullname}::#{name}"
24
+ else
25
+ name
26
+ end
27
+ end
28
+ def get_root(); is_root? ? self : parent.get_root; end;
29
+ def is_root?()
30
+ not parent.respond_to?(:fullname)
31
+ end
32
+ def register(io, already_defined=false)
33
+ if parent
34
+ args = "#{@values.size}"
35
+ @values.each_with_index do |hash, index|
36
+ args << ", "
37
+ case hash.keys[0]
38
+ when :int
39
+ args << "INT2NUM(#{hash.values[0]})"
40
+ when :bool
41
+ args << "((#{hash.values[0]}) ? Qtrue : Qfalse)"
42
+ when :float
43
+ args << "FLOAT2NUM(#{hash.values[0]})"
44
+ when :string
45
+ args << "rb_str_new2(#{hash.values[0]})"
46
+ when :nil
47
+ args << "Qnil"
48
+ else
49
+ raise "Unknown key type for static array - #{hash.keys[0]}"
50
+ end
51
+ end
52
+ io.puts " rb_define_const(#{parent.cname}, #{name.inspect}, rb_ary_new3(#{args}));"
53
+ else
54
+ raise "No parent for string constant #{name}"
55
+ end
56
+ end
57
+ end
58
+
59
+ end # Rubber
@@ -2,6 +2,7 @@ module Rubber
2
2
 
3
3
  class C_Function
4
4
  define_members(:name, :args, :text, :parent, {:autofree=>[]}, {:returntype=>'VALUE'}, :doc=>'')
5
+ attr_accessor :source_line, :source_file
5
6
  attr_reader :multi, :block, :rest, :singleton
6
7
  def check()
7
8
  return if @checked
@@ -136,7 +137,9 @@ class C_Function
136
137
  end
137
138
  }
138
139
  end
140
+
139
141
  io.puts ""
142
+ io.puts "#line #{source_line} #{source_file.inspect}" if source_line
140
143
  setupvars = io.string
141
144
  io = oio
142
145
 
@@ -153,7 +156,7 @@ class C_Function
153
156
  to_type = (!(to_type.nil? or to_type.empty?) && to_type || (arg && arg.ctype || guess(cast)))
154
157
  io.write(Rubber.explicit_cast(cast, from_type, to_type))
155
158
  elsif txt = sc.scan(CAST)
156
- warn("<TYPE:VALUE> is deprecated - please use <{FROM_TYPE>TO_TYPE:VALUE}> instead.")
159
+ warn("<TYPE:VALUE> is deprecated - please use <{FROM_TYPE>TO_TYPE:VALUE}> instead.")
157
160
  name, cast = sc[1], sc[2]
158
161
  arg = @arghash[name]
159
162
  io.write(Rubber::explicit_cast(name, arg && arg.ctype || guess(name), cast))
@@ -187,8 +190,8 @@ class C_Function
187
190
  retval << (mini_scanner.get_byte)
188
191
  end
189
192
  end
190
- unless Rubber::native_type?(returntype)
191
- io << Rubber::explicit_cast(retval, returntype, 'VALUE')
193
+ unless Rubber.native_type?(returntype)
194
+ io << Rubber.explicit_cast(retval, returntype, 'VALUE')
192
195
  else
193
196
  io << retval
194
197
  end
@@ -18,9 +18,14 @@ def generate_c_source(scanner, io)
18
18
  io.puts "typedef int rubber_bool;"
19
19
  io.puts "#define bool rubber_bool"
20
20
  io.puts "\n/* Prototypes */"
21
- io.puts '#include "rbglib.h"' if scanner.options.glib?
21
+ if scanner.options.glib?
22
+ io.puts <<-EOGLIB
23
+ #include "rbglib.h"
24
+
25
+ EOGLIB
26
+
22
27
 
23
- if scanner.options.glib? and scanner.options.gtk?
28
+ if scanner.options.gtk?
24
29
  io.write <<-EOI
25
30
  #include "rbgtk.h"
26
31
 
@@ -40,6 +45,7 @@ RUBY_GTK2_VAR VALUE mGdk;
40
45
  #define RBGTK_INITIALIZE(obj,gtkobj)\
41
46
  (rbgtk_initialize_gtkobject(obj, GTK_OBJECT(gtkobj)))
42
47
  EOI
48
+ end
43
49
  end
44
50
 
45
51
 
@@ -69,6 +75,7 @@ end
69
75
  module_function :generate_c_source
70
76
 
71
77
  module RegisterChildren
78
+ attr_accessor :source_line, :source_file
72
79
  attr_reader :child_names
73
80
  def register_children(io)
74
81
  @child_names = {}
@@ -112,6 +119,7 @@ require 'rubber/codegen/function'
112
119
  require 'rubber/codegen/string'
113
120
  require 'rubber/codegen/integer'
114
121
  require 'rubber/codegen/float'
122
+ require 'rubber/codegen/array'
115
123
 
116
124
  # Special
117
125
  require 'rubber/codegen/struct'
@@ -33,7 +33,9 @@ def initialize(file)
33
33
  @options.glib= true
34
34
  @options.gtk= true
35
35
  @options.gnu= false
36
+ @current_file = file
36
37
  end
38
+ attr_reader :current_file
37
39
  def scan_args()
38
40
  args = []
39
41
  return args unless @str.peep(1) == '('
@@ -76,7 +78,7 @@ def scan(fp)
76
78
  end
77
79
  def _scan(fp)
78
80
  @lines = IO.readlines(@file)
79
- @str = StringScanner.new(@lines.join)
81
+ @str = StringScanner.new(@string = @lines.join)
80
82
  tokens = []
81
83
  @state = ScanState.new(0,0,false,0)
82
84
  @stack = [C_RootModule.new]
@@ -129,7 +131,7 @@ def _scan(fp)
129
131
  when 'glib','gtk','gnu'
130
132
  @options[@str[1]] = (@str[2] == 'yes')
131
133
  else
132
- raise "Unknown option #{@str[1]}"
134
+ syntax_error "Unknown option #{@str[1]}"
133
135
  end
134
136
  elsif @str.skip(/%lib\s+(.+)\n/) # Skip single-line comment
135
137
  @libs ||= []
@@ -152,7 +154,7 @@ def _scan(fp)
152
154
  if stack.last.respond_to?(flag)
153
155
  stack.last.__send__(flag, true)
154
156
  else
155
- raise "%flags directive cannot be used here (#{stack.last.class} doesn't respond to #{flag})"
157
+ syntax_error "%flags directive cannot be used here (#{stack.last.class} doesn't respond to #{flag})"
156
158
  end
157
159
  elsif state.in_class > 0 and state.in_func == false and @str.skip(/%feature\s+([a-z0-9_A-Z]+)/)
158
160
  flag = ("feature_"+@str[1]).intern
@@ -165,7 +167,7 @@ def _scan(fp)
165
167
  if stack.last.respond_to?(flag)
166
168
  stack.last.__send__(flag, *args)
167
169
  else
168
- raise "%feature '#{@str[1]}' directive cannot be used here (#{stack.last.class} doesn't support it)"
170
+ syntax_error "%feature '#{@str[1]}' directive cannot be used here (#{stack.last.class} doesn't support it)"
169
171
  end
170
172
  elsif @str.skip(/%/) # Skip single-line comment
171
173
  @str.skip_until(/\n/)
@@ -286,7 +288,7 @@ def _scan(fp)
286
288
  when "gboxed"
287
289
  @classes[name] = C_GBoxed.new(name, gtype, [], [], [])
288
290
  else
289
- raise "#{name} is not a GObject or GInterface..."
291
+ syntax_error "#{name} is not a GObject or GInterface..."
290
292
  end
291
293
  @classes[name].gparent_class = gparent_class
292
294
  @classes[name].parent = stack.last
@@ -324,7 +326,7 @@ def _scan(fp)
324
326
  STDERR.puts "Remaining code: #{@str.rest}"
325
327
  STDERR.puts "Defined Classes: #{@classes.keys.join(', ')}"
326
328
  p stack
327
- raise "Invalid stack entry #{last.class}"
329
+ syntax_error "Invalid stack entry #{last.class}"
328
330
  end
329
331
  elsif @str.skip(/alias\s+:([A-Za-z0-9_]*[\[\]]{0,2}[?!=]?)\s+:([A-Za-z0-9_]*[\[\]]{0,2}[?!=]?)/) # Alias
330
332
  @class.add_alias(@str[1], @str[2]) if @class.respond_to?(:add_alias)
@@ -332,7 +334,7 @@ def _scan(fp)
332
334
  where = @str[1]
333
335
  str = @str.scan_until(/\bend/)#[0,-4]
334
336
  unless str
335
- raise "Invalid #{where}_func definition: #{@str.peek(200).inspect}"
337
+ syntax_error "Invalid #{where}_func definition"
336
338
  end
337
339
  str = str[0..-4].strip
338
340
  except = only = nil
@@ -361,6 +363,30 @@ def _scan(fp)
361
363
  @str.skip(/\s+/)
362
364
  if @str.scan(/([a-zA-Z_* ]+):/)
363
365
  returntype = @str[1]
366
+ elsif @str.skip(/(GS?List){([^}]+)}:/)
367
+ container = @str[1]
368
+ ct = @str[2]
369
+ cn = ct.gsub(/\s+/,'').gsub(/[*]/,'__p')
370
+ rule = container+'{'+ct+'}'
371
+ returntype = rule
372
+
373
+ #syntax_error "Auto converting (#{rule}) GSList of #{ct} is not yet supported"
374
+ # sane
375
+ unless $custom_maps[rule] && $custom_maps[rule]['VALUE']
376
+ function = "rubber_#{container}_of_#{cn}_to_array"
377
+ @raw = @raw.to_s + <<-EOADD
378
+ inline VALUE #{function}(#{container} *list) {
379
+ #{container} *p; volatile VALUE ary;
380
+ ary = rb_ary_new();
381
+ for(p = list ; p ; p = p->next) {
382
+ rb_ary_push(ary, #{Rubber.explicit_cast('(('+ct+') p->data )', ct, 'VALUE')});
383
+ }
384
+ return ary;
385
+ }
386
+ EOADD
387
+ $custom_maps[rule] ||={}
388
+ $custom_maps[rule]['VALUE'] = function+"(%%)"
389
+ end
364
390
  else
365
391
  returntype = 'VALUE'
366
392
  end
@@ -380,6 +406,8 @@ def _scan(fp)
380
406
  stack.last.functions.push(func)
381
407
  puts "def "+ func.fullname
382
408
  stack.push(func)
409
+ func.source_line = current_line
410
+ func.source_file = current_file
383
411
  state.in_func = true
384
412
 
385
413
  elsif state.in_func == false and @str.skip(/(string|integer|float|double|int)(?= )/x) # C String as module wrapper
@@ -404,16 +432,61 @@ def _scan(fp)
404
432
  klass = C_Float
405
433
  end
406
434
  stack.last.classes.push(klass.new(name, string, stack.last)) if klass
407
-
435
+ elsif state.in_func == false && @str.skip(/(array)(?= )/x)
436
+ type = @str[1]
437
+ @str.skip(/\s+/)
438
+ name = @str.scan(/[A-Z][a-z_0-9A-Z]*/)
439
+ @str.skip(/\s*=\s*/)
440
+ values = []
441
+ if @str.skip(/\[/)
442
+ @str.skip(/\s+/)
443
+ until @str.skip(/\s*\]/)
444
+ if @str.skip(/(".*?[^\\]")/)
445
+ values << { :string => @str[1] } # unescape escaped chars?
446
+ elsif @str.skip(/(\d[.]\d+)/)
447
+ values << { :float => @str[1] }
448
+ elsif @str.skip(/(\d+)/)
449
+ values << { :int => @str[1] }
450
+ elsif @str.skip(/NULL/)
451
+ values << { :nil => true }
452
+ elsif @str.skip(/(TRUE|FALSE)/)
453
+ values << { :bool => @str[1] == 'TRUE' }
454
+ elsif @str.skip(/([A-Za-z0-9_]+)/)
455
+ values << { :int => @str[1] } # Assume a constant
456
+ else
457
+ syntax_error "Unrecognised array value"
458
+ end
459
+ @str.skip(/\s*,\s*/)
460
+ end
461
+ stack.last.classes.push(C_Array.new(name, values, stack.last))
462
+ p [ :create_array, values ]
463
+ else
464
+ syntax_error "Arrays should be in the form: [value1, value2, ... valueN]"
465
+ end
408
466
  elsif txt = @str.get_byte # Spare chars
409
467
  if state.in_func
410
468
  func.text += txt
411
469
  else
412
- puts '"' << txt << '"'
470
+ syntax_error "Invalid character #{txt}"
413
471
  end
414
472
  end
415
473
  end
416
474
  end
475
+ def current_line
476
+ count = 0
477
+ @string[0..@str.pos].each_byte { |b| count += 1 if b == 10 }
478
+ count
479
+ end
480
+ def syntax_error(message)
481
+ STDERR.puts "Syntax Error: #{message} at line #{current_line}\n"
482
+ if @str.rest.size > 255
483
+ STDERR.puts @str.rest[0..255]+"..."
484
+ else
485
+ STDERR.puts @str.rest
486
+ end
487
+ exit 1
488
+ end
489
+
417
490
  end
418
491
 
419
492
  end # m Rubber
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 0
8
- - 6
9
- version: 0.0.6
8
+ - 7
9
+ version: 0.0.7
10
10
  platform: ruby
11
11
  authors:
12
12
  - Geoff Youngs
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-05-05 00:00:00 +01:00
17
+ date: 2010-05-07 00:00:00 +01:00
18
18
  default_executable:
19
19
  dependencies: []
20
20
 
@@ -29,6 +29,7 @@ extra_rdoc_files:
29
29
  files:
30
30
  - bin/rubber-generate
31
31
  - lib/rubber/autord.rb
32
+ - lib/rubber/codegen/array.rb
32
33
  - lib/rubber/codegen/class.rb
33
34
  - lib/rubber/codegen/enum.rb
34
35
  - lib/rubber/codegen/flags.rb