rubex 0.0.1 → 0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (135) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +4 -0
  3. data/.travis.yml +14 -0
  4. data/CONTRIBUTING.md +101 -0
  5. data/HISTORY.md +3 -0
  6. data/README.md +112 -297
  7. data/REFERENCE.md +753 -0
  8. data/Rakefile +4 -1
  9. data/TUTORIAL.md +234 -0
  10. data/bin/rubex +1 -1
  11. data/docs/_config.yml +1 -0
  12. data/docs/index.html +1 -0
  13. data/examples/c_struct_interface/c_struct_interface.rb +6 -0
  14. data/examples/c_struct_interface/c_struct_interface.rubex +47 -0
  15. data/examples/linked_list/linked_list.rubex +39 -0
  16. data/examples/linked_list/rb_linked_list.rb +8 -0
  17. data/examples/rcsv wrapper/rcsv/README.md +1 -0
  18. data/examples/rcsv wrapper/rcsv/Rakefile +7 -0
  19. data/examples/rcsv wrapper/rcsv/ext/rcsv/extconf.rb +3 -0
  20. data/examples/rcsv wrapper/rcsv/ext/rcsv/rcsv.c +302 -0
  21. data/examples/rcsv wrapper/rcsv/ext/rcsv/rcsv.rubex +124 -0
  22. data/examples/rcsv wrapper/rcsv/lib/rcsv.rb +8 -0
  23. data/examples/rcsv wrapper/rcsv/lib/rcsv.so +0 -0
  24. data/examples/rcsv wrapper/rcsv/lib/rcsv/version.rb +1 -0
  25. data/examples/rcsv wrapper/rcsv/rcsv.gemspec +27 -0
  26. data/examples/rcsv wrapper/rcsv/spec/rcsv.csv +5 -0
  27. data/examples/rcsv wrapper/rcsv/spec/rcsv_spec.rb +17 -0
  28. data/examples/rcsv wrapper/rcsv/spec/spec_helper.rb +6 -0
  29. data/{spec/fixtures/basic_ruby_method/Makefile → examples/rcsv wrapper/rcsv/tmp/x86_64-linux/rcsv/2.3.3/Makefile } +20 -20
  30. data/examples/rcsv wrapper/rcsv/tmp/x86_64-linux/rcsv/2.3.3/rcsv.o +0 -0
  31. data/examples/rcsv wrapper/rcsv/tmp/x86_64-linux/rcsv/2.3.3/rcsv.so +0 -0
  32. data/examples/rcsv wrapper/rcsv/tmp/x86_64-linux/stage/lib/rcsv.so +0 -0
  33. data/lib/rubex.rb +6 -50
  34. data/lib/rubex/ast.rb +1 -3
  35. data/lib/rubex/ast/expression.rb +1257 -8
  36. data/lib/rubex/ast/node.rb +226 -28
  37. data/lib/rubex/ast/statement.rb +1162 -35
  38. data/lib/rubex/ast/top_statement.rb +815 -0
  39. data/lib/rubex/code_writer.rb +103 -26
  40. data/lib/rubex/compiler.rb +72 -0
  41. data/lib/rubex/compiler_config.rb +19 -0
  42. data/lib/rubex/constants.rb +145 -8
  43. data/lib/rubex/data_type.rb +667 -4
  44. data/lib/rubex/error.rb +15 -0
  45. data/lib/rubex/helpers.rb +154 -0
  46. data/lib/rubex/lexer.rex +186 -22
  47. data/lib/rubex/lexer.rex.rb +261 -35
  48. data/lib/rubex/parser.racc +876 -28
  49. data/lib/rubex/parser.racc.rb +2845 -90
  50. data/lib/rubex/rake_task.rb +34 -0
  51. data/lib/rubex/symbol_table/entry.rb +17 -3
  52. data/lib/rubex/symbol_table/scope.rb +298 -25
  53. data/lib/rubex/version.rb +1 -1
  54. data/rubex.gemspec +11 -3
  55. data/spec/basic_ruby_method_spec.rb +15 -21
  56. data/spec/binding_ptr_args_spec.rb +33 -0
  57. data/spec/bitwise_operators_spec.rb +40 -0
  58. data/spec/blocks_spec.rb +35 -0
  59. data/spec/c_bindings_spec.rb +36 -0
  60. data/spec/c_constants_spec.rb +33 -0
  61. data/spec/c_function_ptrs_spec.rb +38 -0
  62. data/spec/c_functions_spec.rb +35 -0
  63. data/spec/c_struct_interface_spec.rb +38 -0
  64. data/spec/call_by_reference_spec.rb +33 -0
  65. data/spec/class_methods_spec.rb +33 -0
  66. data/spec/class_spec.rb +40 -0
  67. data/spec/comments_spec.rb +33 -0
  68. data/spec/default_args_spec.rb +37 -0
  69. data/spec/error_handling_spec.rb +42 -0
  70. data/spec/examples_spec.rb +52 -0
  71. data/spec/expressions_spec.rb +33 -0
  72. data/spec/fixtures/basic_ruby_method/basic_ruby_method.rubex +2 -0
  73. data/spec/fixtures/binding_ptr_args/binding_ptr_args.rubex +30 -0
  74. data/spec/fixtures/bitwise_operators/bitwise_operators.rubex +40 -0
  75. data/spec/fixtures/blocks/blocks.rubex +11 -0
  76. data/spec/fixtures/c_bindings/c_bindings.rubex +58 -0
  77. data/spec/fixtures/c_constants/c_constants.rubex +7 -0
  78. data/spec/fixtures/c_function_ptrs/c_function_ptrs.rubex +52 -0
  79. data/spec/fixtures/c_functions/c_functions.rubex +25 -0
  80. data/spec/fixtures/c_struct_interface/c_struct_interface.rubex +34 -0
  81. data/spec/fixtures/call_by_reference/call_by_reference.rubex +30 -0
  82. data/spec/fixtures/class/class.rubex +20 -0
  83. data/spec/fixtures/class_methods/class_methods.rubex +12 -0
  84. data/spec/fixtures/comments/comments.rubex +9 -0
  85. data/spec/fixtures/default_args/default_args.rubex +11 -0
  86. data/spec/fixtures/error_handling/error_handling.rubex +54 -0
  87. data/spec/fixtures/examples/array_to_hash.rubex +14 -0
  88. data/spec/fixtures/examples/rcsv.csv +5 -0
  89. data/spec/fixtures/examples/rcsv.rubex +329 -0
  90. data/spec/fixtures/expressions/expressions.rubex +10 -0
  91. data/spec/fixtures/if_else/if_else.rubex +77 -0
  92. data/spec/fixtures/implicit_lib_include/implicit_lib_include.rubex +15 -0
  93. data/spec/fixtures/init_ruby_objects_with_literal_syntax/init_ruby_objects_with_literal_syntax.rubex +17 -0
  94. data/spec/fixtures/loops/loops.rubex +33 -0
  95. data/spec/fixtures/recursion/recursion.rubex +9 -0
  96. data/spec/fixtures/ruby_constant_method_calls/ruby_constant_method_calls.rubex +17 -0
  97. data/spec/fixtures/ruby_operators/ruby_operators.rubex +29 -0
  98. data/spec/fixtures/ruby_raise/ruby_raise.rubex +13 -0
  99. data/spec/fixtures/ruby_strings/ruby_strings.rubex +19 -0
  100. data/spec/fixtures/ruby_strings/string_blank_bm.rb +37 -0
  101. data/spec/fixtures/ruby_symbols/ruby_symbols.rubex +12 -0
  102. data/spec/fixtures/ruby_types/ruby_types.rubex +15 -0
  103. data/spec/fixtures/statement_expression/statement_expression.rubex +23 -0
  104. data/spec/fixtures/static_array/static_array.rubex +20 -0
  105. data/spec/fixtures/string_literals/string_literals.rubex +15 -0
  106. data/spec/fixtures/struct/struct.rubex +82 -0
  107. data/spec/fixtures/typecasting/typecasting.rubex +23 -0
  108. data/spec/fixtures/var_declarations/var_declarations.rubex +39 -0
  109. data/spec/if_else_spec.rb +39 -0
  110. data/spec/implicit_lib_include_spec.rb +33 -0
  111. data/spec/init_ruby_objects_with_literal_syntax_spec.rb +39 -0
  112. data/spec/loops_spec.rb +34 -0
  113. data/spec/recursion_spec.rb +35 -0
  114. data/spec/ruby_constant_method_calls_spec.rb +35 -0
  115. data/spec/ruby_operators_spec.rb +40 -0
  116. data/spec/ruby_raise_spec.rb +35 -0
  117. data/spec/ruby_strings_spec.rb +33 -0
  118. data/spec/ruby_symbols_spec.rb +37 -0
  119. data/spec/ruby_types_spec.rb +35 -0
  120. data/spec/spec_helper.rb +54 -1
  121. data/spec/statement_expression_spec.rb +34 -0
  122. data/spec/static_array_spec.rb +33 -0
  123. data/spec/string_literals_spec.rb +34 -0
  124. data/spec/struct_spec.rb +36 -0
  125. data/spec/typecasting_spec.rb +38 -0
  126. data/spec/var_declarions_spec.rb +35 -0
  127. metadata +255 -29
  128. data/lib/rubex/ast/argument_list.rb +0 -20
  129. data/lib/rubex/ast/c_base_type.rb +0 -11
  130. data/lib/rubex/ast/ruby_method_def.rb +0 -84
  131. data/spec/fixtures/basic_ruby_method/basic.rb +0 -3
  132. data/spec/fixtures/basic_ruby_method/basic_ruby_method.c +0 -16
  133. data/spec/fixtures/basic_ruby_method/basic_ruby_method.o +0 -0
  134. data/spec/fixtures/basic_ruby_method/basic_ruby_method.so +0 -0
  135. data/spec/fixtures/basic_ruby_method/extconf.rb +0 -3
@@ -0,0 +1,753 @@
1
+ # Rubex (RUBy EXtension Language)
2
+
3
+ Rubex is a language designed to keep you happy even when writing C extension.
4
+
5
+ # Table of Contents
6
+ <!-- MarkdownTOC autolink="true" bracket="round" depth="3"-->
7
+
8
+ - [Comments](#comments)
9
+ - [C data types](#c-data-types)
10
+ - [Primitive data types](#primitive-data-types)
11
+ - [C struct, union and enum](#c-struct-union-and-enum)
12
+ - [Forward declarations](#forward-declarations)
13
+ - [Pointers](#pointers)
14
+ - [Ruby Objects](#ruby-objects)
15
+ - [Literals](#literals)
16
+ - [Integer](#integer)
17
+ - [Float](#float)
18
+ - [Character](#character)
19
+ - [String](#string)
20
+ - [Ruby Literals](#ruby-literals)
21
+ - [Ruby Symbol](#ruby-symbol)
22
+ - [Ruby Array](#ruby-array)
23
+ - [Ruby Hash](#ruby-hash)
24
+ - [C Functions and Ruby Methods](#c-functions-and-ruby-methods)
25
+ - [Ruby Constants](#ruby-constants)
26
+ - [The print statement](#the-print-statement)
27
+ - [Loops](#loops)
28
+ - [The while loop](#the-while-loop)
29
+ - [The for loop](#the-for-loop)
30
+ - [Conditionals](#conditionals)
31
+ - [Important Note](#important-note)
32
+ - [Interfacing C libraries with lib](#interfacing-c-libraries-with-lib)
33
+ - [Basic Usage](#basic-usage)
34
+ - [Supported declarations](#supported-declarations)
35
+ - [Functions](#functions)
36
+ - [Variables](#variables)
37
+ - [Macros](#macros)
38
+ - [Types](#types)
39
+ - [Typedefs](#typedefs)
40
+ - [Linking Libraries](#linking-libraries)
41
+ - [Ready-to-use C functions](#ready-to-use-c-functions)
42
+ - [Filename: "rubex/ruby"](#filename-rubexruby)
43
+ - [Filename: "rubex/ruby/encoding"](#filename-rubexrubyencoding)
44
+ - [Filename: "rubex/stdlib"](#filename-rubexstdlib)
45
+ - [Exception Handling](#exception-handling)
46
+ - ['Attach' Classes](#attach-classes)
47
+ - [The attach keyword](#the-attach-keyword)
48
+ - [The data$ variable](#the-data-variable)
49
+ - [Special C functions in attach classes](#special-c-functions-in-attach-classes)
50
+ - [deallocate](#deallocate)
51
+ - [allocate](#allocate)
52
+ - [memcount](#memcount)
53
+ - [get_struct](#getstruct)
54
+ - [gc_mark](#gcmark)
55
+ - [Typecast](#typecast)
56
+ - [Alias](#alias)
57
+ - [Conversions between Ruby and C data](#conversions-between-ruby-and-c-data)
58
+ - [C callbacks](#c-callbacks)
59
+ - [Inline C](#inline-c)
60
+ - [Handling Strings](#handling-strings)
61
+ - [Differences from C](#differences-from-c)
62
+ - [Differences from Ruby](#differences-from-ruby)
63
+ - [Limitations](#limitations)
64
+
65
+ <!-- /MarkdownTOC -->
66
+
67
+ # Comments
68
+
69
+ Similar to Ruby, comments start with `#`.
70
+
71
+ Example:
72
+ ```
73
+ # This is a comment.
74
+ def funky(int j) # ...so is this.
75
+ return j
76
+ end
77
+ ```
78
+
79
+ # C data types
80
+
81
+ ## Primitive data types
82
+
83
+ Following are the Rubex keywords for data types and their corresponding C types and description.
84
+
85
+ |rubex keyword | C type | Description |
86
+ |:--- |:--- |:--- |
87
+ |char |char |Character |
88
+ |i8 |int8_t |8 bit integer |
89
+ |i16 |int16_t |16 bit integer |
90
+ |i32 |int32_t |32 bit integer |
91
+ |i64 |int64_t |64 bit integer |
92
+ |u8 |uint8_t |8 bit unsigned integer |
93
+ |u16 |uint16_t |16 bit unsigned integer |
94
+ |u32 |uint32_t |32 bit unsigned integer |
95
+ |u64 |uint64_t |64 bit unsigned integer |
96
+ |int |int | Integer >= 16 bits. |
97
+ |unsigned int |unsigned int | Unsigned integer >= 16 bits. |
98
+ |long int |long int | Integer >= 32 bits.|
99
+ |unsigned long int |unsigned long int|Unsigned Integer >= 32 bits. |
100
+ |long long int |long long int |Integer >= 64 bits.|
101
+ |unsigned long long int|unsigned long long int|Unsigned Integer >= 64 bits.|
102
+ |f32/float |float |32 bit floating point |
103
+ |f64/double |double |64 bit floating point |
104
+ |long f64/long double |long double |Long double >= 96 bits. |
105
+ |object |VALUE |Ruby object |
106
+
107
+ ## C struct, union and enum
108
+
109
+ C structs can defined using the `struct` keyword. For example:
110
+ ``` ruby
111
+ struct node
112
+ int a
113
+ end
114
+
115
+ def foo
116
+ node a
117
+ a.a = 3
118
+
119
+ return a.a
120
+ end
121
+ ```
122
+
123
+ Structs can either be at the global, class or method scope. Their accessibility will differ according to the scope they are defined in. Take note that once you define a `struct node`, the only way to define a variable of type `struct node` is just use `node` for the variable definition, not `struct node`. So `node a` will work but `struct node a` will not work.
124
+
125
+ In case you declare a pointer to a struct, the elements of the struct should still be accessed with `.` since the `->` operator is not supported in Rubex.
126
+ Example:
127
+ ``` ruby
128
+ def foo
129
+ struct bar
130
+ int a
131
+ end
132
+
133
+ bar *n
134
+ n.a = 3
135
+
136
+ return n.a
137
+ end
138
+ ```
139
+
140
+ ### Forward declarations
141
+
142
+ In case your struct has a member of a type whose definition has to be after your struct, you can use a forward declaration with the `fwd` keyword.
143
+ ``` ruby
144
+ fwd struct other_node
145
+ struct node
146
+ i32 a, b
147
+ other_node *hello
148
+ end
149
+
150
+ struct other_node
151
+ i64 a, b
152
+ end
153
+ ```
154
+
155
+ ## Pointers
156
+
157
+ You can define pointers and pass them to functions just like you do in C. Pointers can be specified using the `*` operator and addresses of variables can be accessed using the `&` (address-of) operator.
158
+
159
+ Keep in mind that Rubex does not support the `*` operator for dereferencing a pointer. You will need to use the `[]` operator and access the value of pointer with `[0]` (since accessing the value of a pointer is analogous to accessing the value of an array in C).
160
+
161
+ For example:
162
+ ``` ruby
163
+ class CPointersDemo
164
+ def foo
165
+ int *i
166
+ int *j
167
+
168
+ i[0] = 5
169
+ j = i
170
+
171
+ return j[0]
172
+ end
173
+ end
174
+ ```
175
+
176
+ # Ruby Objects
177
+
178
+ Any variable of type `object` is a Ruby object. You must take care to not manually free objects as it will inevitably lead to memory leaks. Let the GC take care of them.
179
+
180
+ Variables that are assigned values without actually specifying the data type are also assumed to be objects.
181
+
182
+ For example:
183
+ ``` ruby
184
+ def ruby_obj_demo
185
+ object a = "string!"
186
+ b = "string!"
187
+
188
+ return a == b
189
+ end
190
+ ```
191
+
192
+ Above function will return `true`.
193
+
194
+ # Literals
195
+
196
+ Literals in Rubex can either be represented as C data or Ruby objects depending on the type of the variable that they are assigned to. Therefore, something like `a = 1` will cause `a` to be a Ruby object with an `Integer` value `1` and something like `int a = 1` will cause `a` to be of C type `int`.
197
+
198
+ ## Integer
199
+
200
+ Integers are supported. Assigning an integer to a C type has the same effect as the assignment would in C code.
201
+ ``` ruby
202
+ def foo
203
+ float a = 3
204
+ int b = -2
205
+ char c = 34
206
+ end
207
+ ```
208
+
209
+ ## Float
210
+
211
+ Similar to integers.
212
+ ``` ruby
213
+ def foo
214
+ float i = 4.5
215
+ double j = -32.66
216
+ int c = 6.9
217
+ end
218
+ ```
219
+
220
+ ## Character
221
+
222
+ Characters can be specified with a single quote. If assigning to a Ruby object, `char` will be implicitly converted to a Ruby `String`.
223
+ ``` ruby
224
+ def foo
225
+ char c = 'a'
226
+
227
+ return c
228
+ end
229
+ ```
230
+
231
+ ## String
232
+
233
+ Strings are specified with double quotes. Note that Ruby-like single quoted strings are _not_ supported in Rubex. String literals are C strings (`char*` arrays) by default but if you assign them to a Ruby object they are implicitly converted into Ruby strings.
234
+
235
+ For example:
236
+ ``` ruby
237
+ def foo
238
+ s = "hello world!"
239
+ char *cs = "hello world!"
240
+
241
+ return cs
242
+ end
243
+ ```
244
+ The `char*` can be implicitly converted to Ruby object. Read the [Handling Strings](#handling-strings) section to know more about string inter-conversion.
245
+
246
+ ## Ruby Literals
247
+
248
+ Apart from `String`, Rubex also supports creating basic Ruby objects like `Array`, `Hash` and `Symbol` from literals using the same familiar Ruby syntax.
249
+
250
+ ### Ruby Symbol
251
+
252
+ Symbols are specified with `:` before the identifier.
253
+ ``` ruby
254
+ def foo
255
+ a = :hello
256
+ return a
257
+ end
258
+ ```
259
+
260
+ ### Ruby Array
261
+
262
+ Can be specified using `[]`. All members of the Array should be implicitly convertible to Ruby objects (like primitive C types or object). Putting instances of `struct` will lead to errors.
263
+ ``` ruby
264
+ def foo
265
+ a = [1,2,3,"hello", "world", :symbol]
266
+ return a
267
+ end
268
+ ```
269
+
270
+ ### Ruby Hash
271
+
272
+ Hashes can be specified with `{}`.
273
+
274
+ Example:
275
+ ``` ruby
276
+ def foo
277
+ a = {
278
+ :hello => "world",
279
+ 3 => 4,
280
+ "foo" => :bar
281
+ }
282
+
283
+ return a
284
+ end
285
+ ```
286
+
287
+ # C Functions and Ruby Methods
288
+
289
+ Apart from Ruby class methods and instance methods, Rubex allows you to define 'C functions' that are only accessible inside classes from within Rubex. These functions cannot be accessed from an external Ruby script.
290
+
291
+ C functions are defined used the `cfunc` keyword. You also need to specify the return type of the function along with its definition. For example:
292
+ ``` ruby
293
+ class CFunctionTest
294
+ def foo(int n)
295
+ return bar(n)
296
+ end
297
+
298
+ cfunc int bar(int n)
299
+ return n + 5
300
+ end
301
+ end
302
+ ```
303
+
304
+ C functions are 'lexically scoped' and are available inside both Ruby instance and class methods of the class and its hierarchy.
305
+
306
+ # Ruby Constants
307
+
308
+ Ruby constants can be specified using identifiers that start with capital letters. Since many C libraries contain functions or macros that start with capital letters, the Rubex compiler will first search for such identifiers, and if it does not find any, will assume that the identifier is a Ruby constant.
309
+ ``` ruby
310
+ def foo
311
+ a = String.new("foo bar")
312
+ return a
313
+ end
314
+ ```
315
+
316
+ # The print statement
317
+
318
+ The `print` statement makes it easy to print something to the console using C's `printf` function underneath. If it is passed a Ruby object instead of a C data type, the `#inspect` method will be called on the object and the resultant string will be printed. `print` can accept multiple comma-separated arguments and will concatenate them into a single string.
319
+ ``` ruby
320
+ def foo(a, b)
321
+ int i = 5
322
+
323
+ print "Obj a is : ", a, ".", " b is: ", b, "... and i is: ", i
324
+ end
325
+ ```
326
+
327
+ # Loops
328
+
329
+ Loops in Rubex are directly translated to C loops, thus giving massive gains in speed by just porting Ruby loops to Rubex. Rubex supports two kinds of loops: `while` loops and `for` loops.
330
+
331
+ ## The while loop
332
+
333
+ The `while` loop in Rubex looks exactly like that in Ruby. Keep in mind that using C types for the conditional will save you the additional burden of a Ruby method call (which is takes non-trivial time for a long running loop).
334
+ ``` ruby
335
+ def while_loop
336
+ int i = 0, j
337
+
338
+ while i < 100 do
339
+ j += 1
340
+ i += 1
341
+ end
342
+
343
+ return j
344
+ end
345
+ ```
346
+
347
+ ## The for loop
348
+
349
+ For loops look slightly different in Rubex than they do in Ruby. This has mainly been done to accommodate for the fact that Ruby for loops normally work with Ranges, but since that would make the code slow, Rubex `for` loops are directly translated into C `for` loops and thus follow a slightly different syntax. For example:
350
+ ``` ruby
351
+ def for_loop_demo
352
+ int i, j = 0
353
+
354
+ for 0 <= i < 100 do
355
+ j += 1
356
+ end
357
+
358
+ return j
359
+ end
360
+ ```
361
+ Above code will initialize `i` to `0` and iterate through it until it does not satisfy the second conditional. The inequalities must belong to the set `{<|<=}` OR `{>|>=}`.
362
+
363
+ # Conditionals
364
+
365
+ Similar to Ruby, conditionals in Rubex can be written as follows:
366
+ ``` ruby
367
+ def foo(a)
368
+ int i = 3
369
+
370
+ return true if a == i
371
+ return false
372
+ end
373
+ ```
374
+
375
+ In the above case, since `a` is a Ruby object and `i` is an `int`, `i` will be implicitly converted into a Ruby `Integer` and the comparison with the `==` operator will take place as though the two variables are Ruby objects (using `.send(:==)`).
376
+
377
+ ## Important Note
378
+
379
+ If the expression in an `if` statements consists only of C variables, the values `0` and `NULL` (null pointer) are treated as _falsey_ and everything else is _truthy_ (exactly like C).
380
+
381
+ However, in case you intermingle Ruby and C types, Rubex will use the convention used in Ruby, i.e. `nil` (NilClass) and `false` (FalseClass) are _falsey_ whereas everything else (including zero, i.e. a Ruby `Integer` with value `0`) is _truthy_.
382
+
383
+ `0` and `NULL` will NOT be treated as _falsey_ if the expression type evaluates to a Ruby object.
384
+
385
+ # Interfacing C libraries with lib
386
+
387
+ The `lib` directive is used for interfacing external C libraries with Rubex.
388
+
389
+ ## Basic Usage
390
+
391
+ Say you want to interface the `cos` and `sin` functions from the `math.h` C header file.
392
+
393
+ It is best demonstrated by this example:
394
+ ``` ruby
395
+ lib "<math.h>"
396
+ double sin(double)
397
+ double cos(double)
398
+ end
399
+
400
+ class CMath
401
+ def f_sin(double n)
402
+ return sin(n)
403
+ end
404
+
405
+ def f_cos(double n)
406
+ return cos(n)
407
+ end
408
+ end
409
+ ```
410
+
411
+ The string arugument (`"<math.h>"`) supplied to `lib` is the C header file that you want to interface your code with. You first need to tell Rubex that you will be using the functions `sin` and `cos` in your program, and that they accept a `double`as an argument and also return a `double`.
412
+
413
+ These can then be directly called from the Rubex program like any other function. Keep in mind that any method/function name in your Rubex program cannot have the same names as the external C functions since they are not namespaced. This will probably be fixed in a later version.
414
+
415
+ ## Supported declarations
416
+
417
+ Following statements can be used inside the `lib` directive for telling rubex about functions/variables to be used from an external C library:
418
+
419
+ ### Functions
420
+
421
+ Specify the return type and arguments of the functions that you will be using in your program:
422
+ ``` ruby
423
+ lib "<math.h>"
424
+ double cos(double)
425
+ end
426
+ ```
427
+
428
+ ### Variables
429
+
430
+ You can specify to the Rubex compiler that you will be using constants or error values defined in C header files by specifying the name and type of the variable just like a normal variable declaration. For example:
431
+
432
+ ``` ruby
433
+ lib "<ruby.h>"
434
+ int HAVE_RUBY_DEFINES_H
435
+ end
436
+
437
+ def have_ruby_h
438
+ return HAVE_RUBY_DEFINES_H
439
+ end
440
+ ```
441
+
442
+ ### Macros
443
+
444
+ Macros that work like functions, i.e. accept values and can be said to have 'return values' can be declared like any other C function:
445
+ ``` ruby
446
+ lib "<ruby.h>"
447
+ object INT2FIX(int)
448
+ end
449
+ ```
450
+
451
+ ### Types
452
+
453
+ If the C library uses structs or unions, you need to specify the exact name of the type and its members that you will be using so that Rubex knows what to expect from the type that you will be using. If you will not be using a certain member of the struct, there is no need to specify it. If the struct is just an argument to a function or no members are being accessed, just leave the definition empty.
454
+ ``` ruby
455
+ lib "<math.h>"
456
+ struct exception
457
+ int type
458
+ char *name
459
+ end
460
+ end
461
+ ```
462
+
463
+ ### Typedefs
464
+
465
+ ## Linking Libraries
466
+
467
+ Frequently it is necessary to link external C binaries with the compiler in order to effectively compile the C file. This is normally done by passing `-l` flags to the compiler.
468
+
469
+ Rubex allows you to do this directly inside the compiler using the `link:` option supplied to the `lib` directive. This is best demonstrated with the following example:
470
+ ``` ruby
471
+ lib "csv.h", link: "csv"
472
+ # some functions ...
473
+ end
474
+
475
+ def foo
476
+ # some code ...
477
+ end
478
+ ```
479
+
480
+ The above code will add `-lcsv` option the compiler during the compilation phase.
481
+
482
+ ## Ready-to-use C functions
483
+
484
+ In order to simplify interfacing with the standard library and to call some specific functions from the Ruby C API (if you must), Rubex provides a whole bunch of ready-to-use C functions from various header files that are available by default in most systems.
485
+
486
+ For example:
487
+ ``` ruby
488
+ lib "rubex/ruby"; end
489
+
490
+ def foo(a)
491
+ return true if TYPE(a) == T_INT
492
+ return false
493
+ end
494
+ ```
495
+
496
+ Above code will use the `TYPE()` macro from the `ruby.h` header file and check if the type is `Integer`, which is denoted by the `T_INT` macro, which is another macro from `ruby.h`. Many such libraries and their enclosing functions come as default with Rubex. Here is a complete list and the also the library names that you need to pass in order to make said functions visible to your program:
497
+
498
+ ### Filename: "rubex/ruby"
499
+
500
+ Functions:
501
+
502
+ |Name and prototype| Description|
503
+ |:--- |:--- |
504
+ |`void* xmalloc(void*)` | |
505
+ |`void xfree(void*)` | |
506
+ |`int TYPE(object)`||
507
+ |`object rb_str_new(char* string, long lenghth)`||
508
+ |`object rb_ary_includes(object array, object item)`||
509
+
510
+ Variables:
511
+
512
+ |Type|Name|Description|
513
+ |:---|:---|:--- |
514
+ |`int`|`T_ARRAY`||
515
+ |`int`|`T_NIL`||
516
+ |`int`|`T_TRUE`||
517
+ |`int`|`T_FALSE`||
518
+ |`int`|`T_FLOAT`||
519
+ |`int`|`T_FIXNUM`||
520
+ |`int`|`T_BIGNUM`||
521
+ |`int`|`T_REGEXP`||
522
+ |`int`|`T_STRING`||
523
+
524
+ ### Filename: "rubex/ruby/encoding"
525
+
526
+ Functions:
527
+
528
+ |Name and prototype| Description|
529
+ |:--- |:--- |
530
+ |`int rb_enc_find_index(char* encoding)`||
531
+ |`object rb_enc_associate_index(object string, int encoding)`||
532
+
533
+ ### Filename: "rubex/stdlib"
534
+
535
+ Functions:
536
+
537
+ |Name and prototype|Description|
538
+ |:--- |:--- |
539
+ | `int atoi(char *string)`||
540
+ | `long atol(char *string)`||
541
+ | `long long atoll(char *string)`||
542
+ | `double atof(char *string)`||
543
+
544
+ # Exception Handling
545
+
546
+ Exception handling in Rubex can be done exactly like that in Ruby. No more dealing with `rb_protect()` or [complex tutorials](https://silverhammermba.github.io/emberb/c/#exceptions) on error handling in C extensions.
547
+
548
+ Just simply use `begin-rescue-else-ensure` blocks the way you would in Ruby. You can also make variable declarations inside these blocks and any value you define inside can be used outside too, just like in Ruby.
549
+
550
+ Example:
551
+ ``` ruby
552
+ def foo(int n)
553
+ begin
554
+ raise ArgumentError if n == 1
555
+ raise SyntaxError if n == 2
556
+ rescue ArgumentError
557
+ n += 1
558
+ rescue SyntaxError
559
+ n += 2
560
+ else
561
+ n += 5
562
+ ensure
563
+ n += 10
564
+ end
565
+
566
+ return n
567
+ end
568
+ ```
569
+
570
+ # 'Attach' Classes
571
+
572
+ Rubex introduces a special syntax that allows you to directly interface Ruby with C structs using some special language constructs, called 'attach' classes. These are normal Ruby classes and can be instantiated and used just like any other Ruby class, but with one caveat - they are permanently attached to a C struct and implicitly interface this struct with the Ruby VM.
573
+
574
+ Let me demonstrate with an example:
575
+ ``` ruby
576
+ # file: structs.rubex
577
+ lib "rubex/ruby"; end
578
+
579
+ struct mp3info
580
+ int id
581
+ char* title
582
+ end
583
+
584
+ class Music attach mp3info
585
+ def initialize(id, title)
586
+ mp3info* mp3 = data$.mp3info
587
+
588
+ mp3.id = id
589
+ mp3.title = title
590
+ end
591
+
592
+ def id
593
+ return data$.id
594
+ end
595
+
596
+ def title
597
+ return data$.title
598
+ end
599
+
600
+ cfunc void deallocate
601
+ xfree(data$.mp3info)
602
+ end
603
+ end
604
+ ```
605
+ This program can be used in a Ruby script like this:
606
+ ``` ruby
607
+ require 'structs.so'
608
+
609
+ id = 1
610
+ title = "CAFO"
611
+ m = Music.new id, title
612
+ puts m.id, m.title
613
+ ```
614
+
615
+ The above example has some notable Rubex constructs:
616
+
617
+ ## The attach keyword
618
+
619
+ The 'attach' keyword is a special keyword that is used for associating a particular struct with a Ruby class. Once this keyword is used, the Rubex compiler will take care of allocation, deallocation and fetching of the struct, i.e. it will add calls to various functions essential for interfacing the struct with Ruby VM and the Garbage Collector. It will also create the `ruby_data_type_t` struct that [holds all the information](https://ruby-doc.org/core-2.3.0/doc/extension_rdoc.html#label-C+struct+to+Ruby+object)for interfacing structs with the Ruby VM, for example pointers to the marking and freeing functions.
620
+
621
+ In the above case, `attach` creates tells the class `Music` that it will be associated with a C struct of type `mp3info`.
622
+
623
+ ## The data$ variable
624
+
625
+ The `data$` variable is a special variable keyword that is available _only_ inside attach classes. The `data$` variable allows access to the `mp3info` struct. In order to do this, it makes available a **pointer** to the struct that is of the same name as the struct (i.e. `mp3info` for `struct mp3info` or `foo` for `struct foo`). This pointer to the struct can then be used for reading or writing elements in the struct.
626
+
627
+ Read the 'Internals' section in [CONTRIBUTING](CONTRIBUTING.md) if you want to know more about the `data$` variable.
628
+
629
+ ## Special C functions in attach classes
630
+
631
+ In most cases, the default configuration of the attach classes will suffice and you will not need to write any of the functions listed below by yourself (Rubex will write those functions in C for you), but if in some special cases where customization by the user is necessary, it can be done using some special functions that are translated directly into the relevant functions that need to interface with the Ruby VM for successfully interfacing a struct.
632
+
633
+ ### deallocate
634
+
635
+ This is the only function that you must write by yourself, since a lot of GC deallocation depends upon specific data inside the struct and it is best if specified by the user.
636
+
637
+ Once you are done using an instance of your newly created attach class, Ruby's GC will want to clean up the memory used by it so that it can be used by other objects. In order to not have any memory leaks later, it is important to tell the GC that the memory that was used up by the `mp3info` struct needs to be freed. This freeing up of memory should be done inside the `deallocate` function.
638
+
639
+ The `xfree` function, which is the standard memory freeing function provided by the Ruby interpreter is used for this purpose.
640
+
641
+ ### allocate
642
+
643
+ ### memcount
644
+
645
+ ### get_struct
646
+
647
+ ### gc_mark
648
+
649
+ # Typecast
650
+
651
+ You can use a C typecast using `<>`. For example:
652
+ ``` ruby
653
+ def foo
654
+ float a = 4.5
655
+ int b = <int>a
656
+
657
+ return b
658
+ end
659
+ ```
660
+
661
+ Do not attempt typecasting between C and Ruby types. It will lead to problems. Let Rubex do that for you.
662
+
663
+ # Alias
664
+
665
+ The `alias` keyword can be used for aliasing data types. It is akin to `typedef` in C. Once the alias is declared, you can use it in your program just like any other data type.
666
+
667
+ ``` ruby
668
+ def foo
669
+ struct node
670
+ int a, b
671
+ end
672
+
673
+ alias node_69 = node
674
+
675
+ node_69 n
676
+ n.a = 4
677
+
678
+ return n.a
679
+ end
680
+ ```
681
+
682
+ # Conversions between Ruby and C data
683
+
684
+ Rubex will implicitly convert most primitive C types like `char`, `int` and `float` to their equivalent Ruby types and vice versa. However, types conversions for user defined types like structs and unions are not supported.
685
+
686
+ # C callbacks
687
+
688
+ Frequently, C libraries use C function pointers to pass functions to other functions as callbacks. Rubex supports this behaviour too.
689
+
690
+ A C function pointer for a function that returns an `int` and accepts two `int`s as arguments can be declared as:
691
+ ```
692
+ int (*foo)(int, int)
693
+ ```
694
+
695
+ You can also alias function pointers with `alias`:
696
+ ```
697
+ alias foo = int (*)(int, int)
698
+ ```
699
+
700
+ A sample program using C function pointers is demonstrated below:
701
+ ``` ruby
702
+ cfunc int foo1(int a)
703
+ return a + 1
704
+ end
705
+
706
+ cfunc int baz1(int a, int b)
707
+ return a + b + 1
708
+ end
709
+
710
+ cfunc int bar(int (*func1)(int), int (*func2)(int, int), int a, int b)
711
+ return func1(a) + func2(a, b)
712
+ end
713
+
714
+ def foo
715
+ alias goswim = int (*ernub)(int, int)
716
+ int (*func_ptr1)(int)
717
+ goswim func_ptr2
718
+ int a = 1
719
+ int b = 1
720
+
721
+ func_ptr1 = foo1
722
+ func_ptr2 = baz1
723
+
724
+ return bar(func_ptr1, func_ptr2, a, b)
725
+ end
726
+ ```
727
+
728
+ # Inline C
729
+
730
+ # Handling Strings
731
+
732
+ For purposes of optimization and compatibility with C, Rubex makes certain assumptions about strings. When you assign a Ruby object to a `char*`, Rubex will automatically pass a pointer to the C string contained inside the object to the `char*`, thereby increasing the efficiency of operations on the string. The resulting string is a regular `\0` delimited C string.
733
+
734
+ It should be noted that strings MUST use the double quotation syntax (`""`) and not single quotes in all cases. Single quote is reserved for use by C `char` data. For example, to assign a literal value to a C char, you can write `char a = 'b'`, to assign a literal C string to a `char*` array, use `char* a = "hello"`.
735
+
736
+ # Differences from C
737
+
738
+ * Rubex does not have dereferencing operator (`*`). Instead use `[0]` to access values pointed to by pointers.
739
+ * There is no `->` operator for accessing struct elements from a pointer to a struct. Use the `.` operator directly.
740
+
741
+ # Differences from Ruby
742
+
743
+ * The `return` statement must be specified to return a value. Unlike Ruby, Rubex does not return the last expression in a method.
744
+ * Specify arguments for method definitions inside round brackets.
745
+ * As of now, there is very limited support for metaprogramming.
746
+ * Blocks are not supported yet, though this will change by v0.2.
747
+
748
+ # Limitations
749
+
750
+ Most of the below limitations are temporary and will be taken care of in future versions:
751
+
752
+ * The `require` statement is currently not supported.
753
+ * Multi-file Rubex programs are not yet possible.