rubex 0.0.1 → 0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +4 -0
- data/.travis.yml +14 -0
- data/CONTRIBUTING.md +101 -0
- data/HISTORY.md +3 -0
- data/README.md +112 -297
- data/REFERENCE.md +753 -0
- data/Rakefile +4 -1
- data/TUTORIAL.md +234 -0
- data/bin/rubex +1 -1
- data/docs/_config.yml +1 -0
- data/docs/index.html +1 -0
- data/examples/c_struct_interface/c_struct_interface.rb +6 -0
- data/examples/c_struct_interface/c_struct_interface.rubex +47 -0
- data/examples/linked_list/linked_list.rubex +39 -0
- data/examples/linked_list/rb_linked_list.rb +8 -0
- data/examples/rcsv wrapper/rcsv/README.md +1 -0
- data/examples/rcsv wrapper/rcsv/Rakefile +7 -0
- data/examples/rcsv wrapper/rcsv/ext/rcsv/extconf.rb +3 -0
- data/examples/rcsv wrapper/rcsv/ext/rcsv/rcsv.c +302 -0
- data/examples/rcsv wrapper/rcsv/ext/rcsv/rcsv.rubex +124 -0
- data/examples/rcsv wrapper/rcsv/lib/rcsv.rb +8 -0
- data/examples/rcsv wrapper/rcsv/lib/rcsv.so +0 -0
- data/examples/rcsv wrapper/rcsv/lib/rcsv/version.rb +1 -0
- data/examples/rcsv wrapper/rcsv/rcsv.gemspec +27 -0
- data/examples/rcsv wrapper/rcsv/spec/rcsv.csv +5 -0
- data/examples/rcsv wrapper/rcsv/spec/rcsv_spec.rb +17 -0
- data/examples/rcsv wrapper/rcsv/spec/spec_helper.rb +6 -0
- data/{spec/fixtures/basic_ruby_method/Makefile → examples/rcsv wrapper/rcsv/tmp/x86_64-linux/rcsv/2.3.3/Makefile } +20 -20
- data/examples/rcsv wrapper/rcsv/tmp/x86_64-linux/rcsv/2.3.3/rcsv.o +0 -0
- data/examples/rcsv wrapper/rcsv/tmp/x86_64-linux/rcsv/2.3.3/rcsv.so +0 -0
- data/examples/rcsv wrapper/rcsv/tmp/x86_64-linux/stage/lib/rcsv.so +0 -0
- data/lib/rubex.rb +6 -50
- data/lib/rubex/ast.rb +1 -3
- data/lib/rubex/ast/expression.rb +1257 -8
- data/lib/rubex/ast/node.rb +226 -28
- data/lib/rubex/ast/statement.rb +1162 -35
- data/lib/rubex/ast/top_statement.rb +815 -0
- data/lib/rubex/code_writer.rb +103 -26
- data/lib/rubex/compiler.rb +72 -0
- data/lib/rubex/compiler_config.rb +19 -0
- data/lib/rubex/constants.rb +145 -8
- data/lib/rubex/data_type.rb +667 -4
- data/lib/rubex/error.rb +15 -0
- data/lib/rubex/helpers.rb +154 -0
- data/lib/rubex/lexer.rex +186 -22
- data/lib/rubex/lexer.rex.rb +261 -35
- data/lib/rubex/parser.racc +876 -28
- data/lib/rubex/parser.racc.rb +2845 -90
- data/lib/rubex/rake_task.rb +34 -0
- data/lib/rubex/symbol_table/entry.rb +17 -3
- data/lib/rubex/symbol_table/scope.rb +298 -25
- data/lib/rubex/version.rb +1 -1
- data/rubex.gemspec +11 -3
- data/spec/basic_ruby_method_spec.rb +15 -21
- data/spec/binding_ptr_args_spec.rb +33 -0
- data/spec/bitwise_operators_spec.rb +40 -0
- data/spec/blocks_spec.rb +35 -0
- data/spec/c_bindings_spec.rb +36 -0
- data/spec/c_constants_spec.rb +33 -0
- data/spec/c_function_ptrs_spec.rb +38 -0
- data/spec/c_functions_spec.rb +35 -0
- data/spec/c_struct_interface_spec.rb +38 -0
- data/spec/call_by_reference_spec.rb +33 -0
- data/spec/class_methods_spec.rb +33 -0
- data/spec/class_spec.rb +40 -0
- data/spec/comments_spec.rb +33 -0
- data/spec/default_args_spec.rb +37 -0
- data/spec/error_handling_spec.rb +42 -0
- data/spec/examples_spec.rb +52 -0
- data/spec/expressions_spec.rb +33 -0
- data/spec/fixtures/basic_ruby_method/basic_ruby_method.rubex +2 -0
- data/spec/fixtures/binding_ptr_args/binding_ptr_args.rubex +30 -0
- data/spec/fixtures/bitwise_operators/bitwise_operators.rubex +40 -0
- data/spec/fixtures/blocks/blocks.rubex +11 -0
- data/spec/fixtures/c_bindings/c_bindings.rubex +58 -0
- data/spec/fixtures/c_constants/c_constants.rubex +7 -0
- data/spec/fixtures/c_function_ptrs/c_function_ptrs.rubex +52 -0
- data/spec/fixtures/c_functions/c_functions.rubex +25 -0
- data/spec/fixtures/c_struct_interface/c_struct_interface.rubex +34 -0
- data/spec/fixtures/call_by_reference/call_by_reference.rubex +30 -0
- data/spec/fixtures/class/class.rubex +20 -0
- data/spec/fixtures/class_methods/class_methods.rubex +12 -0
- data/spec/fixtures/comments/comments.rubex +9 -0
- data/spec/fixtures/default_args/default_args.rubex +11 -0
- data/spec/fixtures/error_handling/error_handling.rubex +54 -0
- data/spec/fixtures/examples/array_to_hash.rubex +14 -0
- data/spec/fixtures/examples/rcsv.csv +5 -0
- data/spec/fixtures/examples/rcsv.rubex +329 -0
- data/spec/fixtures/expressions/expressions.rubex +10 -0
- data/spec/fixtures/if_else/if_else.rubex +77 -0
- data/spec/fixtures/implicit_lib_include/implicit_lib_include.rubex +15 -0
- data/spec/fixtures/init_ruby_objects_with_literal_syntax/init_ruby_objects_with_literal_syntax.rubex +17 -0
- data/spec/fixtures/loops/loops.rubex +33 -0
- data/spec/fixtures/recursion/recursion.rubex +9 -0
- data/spec/fixtures/ruby_constant_method_calls/ruby_constant_method_calls.rubex +17 -0
- data/spec/fixtures/ruby_operators/ruby_operators.rubex +29 -0
- data/spec/fixtures/ruby_raise/ruby_raise.rubex +13 -0
- data/spec/fixtures/ruby_strings/ruby_strings.rubex +19 -0
- data/spec/fixtures/ruby_strings/string_blank_bm.rb +37 -0
- data/spec/fixtures/ruby_symbols/ruby_symbols.rubex +12 -0
- data/spec/fixtures/ruby_types/ruby_types.rubex +15 -0
- data/spec/fixtures/statement_expression/statement_expression.rubex +23 -0
- data/spec/fixtures/static_array/static_array.rubex +20 -0
- data/spec/fixtures/string_literals/string_literals.rubex +15 -0
- data/spec/fixtures/struct/struct.rubex +82 -0
- data/spec/fixtures/typecasting/typecasting.rubex +23 -0
- data/spec/fixtures/var_declarations/var_declarations.rubex +39 -0
- data/spec/if_else_spec.rb +39 -0
- data/spec/implicit_lib_include_spec.rb +33 -0
- data/spec/init_ruby_objects_with_literal_syntax_spec.rb +39 -0
- data/spec/loops_spec.rb +34 -0
- data/spec/recursion_spec.rb +35 -0
- data/spec/ruby_constant_method_calls_spec.rb +35 -0
- data/spec/ruby_operators_spec.rb +40 -0
- data/spec/ruby_raise_spec.rb +35 -0
- data/spec/ruby_strings_spec.rb +33 -0
- data/spec/ruby_symbols_spec.rb +37 -0
- data/spec/ruby_types_spec.rb +35 -0
- data/spec/spec_helper.rb +54 -1
- data/spec/statement_expression_spec.rb +34 -0
- data/spec/static_array_spec.rb +33 -0
- data/spec/string_literals_spec.rb +34 -0
- data/spec/struct_spec.rb +36 -0
- data/spec/typecasting_spec.rb +38 -0
- data/spec/var_declarions_spec.rb +35 -0
- metadata +255 -29
- data/lib/rubex/ast/argument_list.rb +0 -20
- data/lib/rubex/ast/c_base_type.rb +0 -11
- data/lib/rubex/ast/ruby_method_def.rb +0 -84
- data/spec/fixtures/basic_ruby_method/basic.rb +0 -3
- data/spec/fixtures/basic_ruby_method/basic_ruby_method.c +0 -16
- data/spec/fixtures/basic_ruby_method/basic_ruby_method.o +0 -0
- data/spec/fixtures/basic_ruby_method/basic_ruby_method.so +0 -0
- data/spec/fixtures/basic_ruby_method/extconf.rb +0 -3
data/Rakefile
CHANGED
data/TUTORIAL.md
ADDED
@@ -0,0 +1,234 @@
|
|
1
|
+
# Rubex tutorial
|
2
|
+
|
3
|
+
Here's a quick tutorial of Rubex to get you up and started. Once you're through, take a moment to convert one of your C extensions to Rubex and see the difference in speed of development and simplicity.
|
4
|
+
|
5
|
+
<!-- MarkdownTOC autolink="true" bracket="round" -->
|
6
|
+
|
7
|
+
- [Basics of Rubex](#basics-of-rubex)
|
8
|
+
- [Rubex Hello World](#rubex-hello-world)
|
9
|
+
- [String#blank?](#stringblank)
|
10
|
+
- [Calling C Functions](#calling-c-functions)
|
11
|
+
- [C Functions](#c-functions)
|
12
|
+
- ['Attach' Classes](#attach-classes)
|
13
|
+
- [Error Handling](#error-handling)
|
14
|
+
- [Using Rubex Inside A Gem](#using-rubex-inside-a-gem)
|
15
|
+
- [Examples](#examples)
|
16
|
+
- [Interfacing C structs](#interfacing-c-structs)
|
17
|
+
- [Fully Functional Ruby Gem](#fully-functional-ruby-gem)
|
18
|
+
|
19
|
+
<!-- /MarkdownTOC -->
|
20
|
+
|
21
|
+
# Basics of Rubex
|
22
|
+
|
23
|
+
The Rubex syntax is very close to that of Ruby. In most use cases you can simply add a static types to variables and you're good to go. Rubex files have an extension `.rubex`.
|
24
|
+
|
25
|
+
Before starting, make sure you've installed Rubex with `gem install rubex`.
|
26
|
+
|
27
|
+
## Rubex Hello World
|
28
|
+
|
29
|
+
In a Rubex file titled `hello_word.rubex` paste the following code:
|
30
|
+
``` ruby
|
31
|
+
def hello_world
|
32
|
+
print "Hello world!"
|
33
|
+
end
|
34
|
+
```
|
35
|
+
|
36
|
+
Now the use the `rubex` binary to compile the above program:
|
37
|
+
```
|
38
|
+
rubex hello_world.rubex
|
39
|
+
```
|
40
|
+
|
41
|
+
This will generate a folder called `hello_world` that will contain the files `extconf.rb` and `hello_world.c`. Now run the following:
|
42
|
+
```
|
43
|
+
cd hello_world
|
44
|
+
ruby extconf.rb
|
45
|
+
make
|
46
|
+
```
|
47
|
+
|
48
|
+
This will generate a shared object file called `hello_world.so` that can be used in any normal Ruby script like so:
|
49
|
+
``` ruby
|
50
|
+
require_relative 'hello_world.so'
|
51
|
+
|
52
|
+
hello_world
|
53
|
+
```
|
54
|
+
|
55
|
+
## String#blank?
|
56
|
+
|
57
|
+
Sam Saffron's famous [`fast_blank`](https://github.com/SamSaffron/fast_blank) gem is something that most Rubyists probably use a lot of times in their daily life. It is also a classic example of porting a Ruby gem to a C extension for reasons of speed.
|
58
|
+
|
59
|
+
Here's the Rubex version of fast_blank:
|
60
|
+
``` ruby
|
61
|
+
class String
|
62
|
+
def blank?(string)
|
63
|
+
char *s = string
|
64
|
+
int i = 0
|
65
|
+
|
66
|
+
while i < string.size do
|
67
|
+
return false if s[i] != ' '
|
68
|
+
end
|
69
|
+
|
70
|
+
return true
|
71
|
+
end
|
72
|
+
end
|
73
|
+
```
|
74
|
+
|
75
|
+
As you can see above, Rubex can implicitly convert between Ruby objects and C data types (like a Ruby `String` into a `char*` C array).
|
76
|
+
|
77
|
+
# Calling C Functions
|
78
|
+
|
79
|
+
One of the primary uses of Rubex is making it easy for interfacing with C libraries. This can be done by using the `lib` keyword at the top of a Rubex file.
|
80
|
+
|
81
|
+
So say for example, you want to interface some functions from the `math.h` C header file. In order to do this, you first list out the prototypes of the functions that you want to interface inside `lib`, and then you can use these functions in your program.
|
82
|
+
``` ruby
|
83
|
+
lib "<math.h>"
|
84
|
+
double cos(double)
|
85
|
+
double sin(double)
|
86
|
+
end
|
87
|
+
|
88
|
+
class CMath
|
89
|
+
def f_sin(num)
|
90
|
+
return sin(num)
|
91
|
+
end
|
92
|
+
|
93
|
+
def f_cos(num)
|
94
|
+
return cos(num)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
```
|
98
|
+
|
99
|
+
These functions can be used in a similar manner to our hello_world program above. Keep in mind that you cannot (yet) have function names in your Rubex program that have the same name as that of the external C functions. This will cause name clashes and malfunction.
|
100
|
+
|
101
|
+
Read what you can do more with `lib` in the [REFERENCE](REFERENCE.md).
|
102
|
+
|
103
|
+
# C Functions
|
104
|
+
|
105
|
+
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.
|
106
|
+
|
107
|
+
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:
|
108
|
+
``` ruby
|
109
|
+
class CFunctionTest
|
110
|
+
def foo(int n)
|
111
|
+
return bar(n)
|
112
|
+
end
|
113
|
+
|
114
|
+
# bar is a C function.
|
115
|
+
cfunc int bar(int n)
|
116
|
+
return n + 5
|
117
|
+
end
|
118
|
+
end
|
119
|
+
```
|
120
|
+
|
121
|
+
# 'Attach' Classes
|
122
|
+
|
123
|
+
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.
|
124
|
+
|
125
|
+
Let me demonstrate with an example:
|
126
|
+
``` ruby
|
127
|
+
# file: structs.rubex
|
128
|
+
lib "rubex/ruby"; end
|
129
|
+
|
130
|
+
struct mp3info
|
131
|
+
int id
|
132
|
+
char* title
|
133
|
+
end
|
134
|
+
|
135
|
+
class Music attach mp3info
|
136
|
+
def initialize(id, title)
|
137
|
+
mp3info* mp3 = data$.mp3info
|
138
|
+
|
139
|
+
mp3.id = id
|
140
|
+
mp3.title = title
|
141
|
+
end
|
142
|
+
|
143
|
+
def id
|
144
|
+
return data$.mp3info.id
|
145
|
+
end
|
146
|
+
|
147
|
+
def title
|
148
|
+
return data$.mp3info.title
|
149
|
+
end
|
150
|
+
|
151
|
+
cfunc void deallocate
|
152
|
+
xfree(data$.mp3info)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
```
|
156
|
+
This program can be used in a Ruby script like this:
|
157
|
+
``` ruby
|
158
|
+
require 'structs.so'
|
159
|
+
|
160
|
+
id = 1
|
161
|
+
title = "CAFO"
|
162
|
+
m = Music.new id, title
|
163
|
+
puts m.id, m.title
|
164
|
+
```
|
165
|
+
|
166
|
+
The above example has some notable Rubex constructs:
|
167
|
+
|
168
|
+
### The attach keyword
|
169
|
+
|
170
|
+
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 (more about this in the [REFERENCE](REFERENCE.md)). The user only needs to concern themselves with using and allocating the data inside the struct.
|
171
|
+
|
172
|
+
In the above case, `attach` creates tells the class `Music` that it will be associated with a C struct of type `mp3info`.
|
173
|
+
|
174
|
+
### The data$ variable
|
175
|
+
|
176
|
+
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.
|
177
|
+
|
178
|
+
### The deallocate C function
|
179
|
+
|
180
|
+
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.
|
181
|
+
|
182
|
+
The `xfree` function, which is the standard memory freeing function provided by the Ruby interpreter is used for this purpose.
|
183
|
+
|
184
|
+
# Error Handling
|
185
|
+
|
186
|
+
Rubex greatly simplifies error handling for C extensions. It now gives you the full power of a Ruby `begin-rescue-else-ensure` block. You can also define variables inside these blocks!
|
187
|
+
|
188
|
+
Here's an example:
|
189
|
+
``` ruby
|
190
|
+
def error_example(int n)
|
191
|
+
begin
|
192
|
+
raise ArgumentError if n == 1
|
193
|
+
raise SyntaxError if n == 2
|
194
|
+
rescue ArgumentError
|
195
|
+
n += 10
|
196
|
+
rescue SyntaxError
|
197
|
+
n += 20
|
198
|
+
ensure
|
199
|
+
n += 5
|
200
|
+
end
|
201
|
+
|
202
|
+
return n
|
203
|
+
end
|
204
|
+
```
|
205
|
+
|
206
|
+
# Using Rubex Inside A Gem
|
207
|
+
|
208
|
+
Rubex ships with pre-built rake tasks that can be for compiling a Rubex file. In order to use these, simply drop in the following code into your `Rakefile`:
|
209
|
+
``` ruby
|
210
|
+
require 'rubex/rake_task'
|
211
|
+
|
212
|
+
Rubex::RakeTask.new('hello_world')
|
213
|
+
```
|
214
|
+
|
215
|
+
Above rake task assumes that you use the standard Ruby gem structure:
|
216
|
+
```
|
217
|
+
|-- ext
|
218
|
+
| `-- hello_world
|
219
|
+
| `-- hello_world.rubex
|
220
|
+
|-- lib
|
221
|
+
`-- Rakefile
|
222
|
+
```
|
223
|
+
|
224
|
+
Calling `rake compile` will generate `hello_world.c` and `extconf.rb` in your `ext` folder and place `hello_world.so` in your `lib/` folder which you directly use with a simple `require`.
|
225
|
+
|
226
|
+
# Examples
|
227
|
+
|
228
|
+
## Interfacing C structs
|
229
|
+
|
230
|
+
[This example](https://github.com/v0dro/rubex/tree/master/examples/c_struct_interface) is a program that interfaces with a C struct and creates reader and writer methods for C struct elements through a Ruby interface.
|
231
|
+
|
232
|
+
## Fully Functional Ruby Gem
|
233
|
+
|
234
|
+
See the [rcsv example](https://github.com/v0dro/rubex/tree/master/examples/rcsv%20wrapper/rcsv) for a fully functional rubygem that wraps around the [libcsv](https://sourceforge.net/projects/libcsv/) C library for parsing CSV files.
|
data/bin/rubex
CHANGED
data/docs/_config.yml
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
theme: jekyll-theme-dinky
|
data/docs/index.html
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
<h1>Docs go here!</h1>
|
@@ -0,0 +1,47 @@
|
|
1
|
+
lib "rubex/ruby"; end
|
2
|
+
|
3
|
+
struct mp3info
|
4
|
+
char *artist, *title
|
5
|
+
int id
|
6
|
+
end
|
7
|
+
|
8
|
+
# The class that will be 'attached' to the struct and will make it possible to
|
9
|
+
# initialize instances of the struct. There will be a variable called `data`
|
10
|
+
# which will be made available to the user which will be of type
|
11
|
+
# 'struct __rubex_data_Music'. This variable will be available throughout the class.
|
12
|
+
#
|
13
|
+
# The allocate function will be defined implicitly, and calls to `TypeData_*`
|
14
|
+
# macros will also be implicit.
|
15
|
+
#
|
16
|
+
# The data variable is analogous to the 'params' variable in Sinatra routes.
|
17
|
+
class Music attach mp3info
|
18
|
+
def initialize(artist, title, id)
|
19
|
+
mp3info* mp3 = data$.mp3info
|
20
|
+
int a_size = artist.size
|
21
|
+
int t_size = title.size
|
22
|
+
|
23
|
+
mp3.artist = artist # implicit conversion of Ruby String to char*
|
24
|
+
mp3.title = title # implicit conversion of Ruby String to char*
|
25
|
+
mp3.id = id # implicit typecast to int
|
26
|
+
end
|
27
|
+
|
28
|
+
# The deallocate function will be used by TypeData_* macros as a function
|
29
|
+
# for freeing memory once this class has been GC'd. It will be a compulsory
|
30
|
+
# method for such 'attach' classes and will not be callable through Ruby
|
31
|
+
# scripts.
|
32
|
+
cfunc void deallocate
|
33
|
+
xfree(data$.mp3info)
|
34
|
+
end
|
35
|
+
|
36
|
+
def artist
|
37
|
+
return data$.mp3info.artist # typecast to ruby string
|
38
|
+
end
|
39
|
+
|
40
|
+
def title
|
41
|
+
return data$.mp3info.title # typecast to ruby string
|
42
|
+
end
|
43
|
+
|
44
|
+
def id
|
45
|
+
return data$.mp3info.id
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
struct node
|
2
|
+
int data
|
3
|
+
object next
|
4
|
+
end
|
5
|
+
|
6
|
+
class LLNode attach node
|
7
|
+
def initialize(int d)
|
8
|
+
node n = data.node
|
9
|
+
|
10
|
+
n.data = d
|
11
|
+
n.next = nil
|
12
|
+
endturn
|
13
|
+
|
14
|
+
def add_node d
|
15
|
+
node n = data.node
|
16
|
+
|
17
|
+
new_node = LLNode.new(d)
|
18
|
+
n.next = new_node
|
19
|
+
end
|
20
|
+
|
21
|
+
def print_list
|
22
|
+
node n = data.node
|
23
|
+
|
24
|
+
temp = self
|
25
|
+
print "The linked list is: \n"
|
26
|
+
while next_node do
|
27
|
+
print temp.get_data
|
28
|
+
temp = n.next_node
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def get_data
|
33
|
+
return data.node.data
|
34
|
+
end
|
35
|
+
|
36
|
+
def next_node
|
37
|
+
return data.node.next
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
Rubex wrapper over libcsv.
|
@@ -0,0 +1,302 @@
|
|
1
|
+
/* C extension for rcsv.
|
2
|
+
This file in generated by Rubex::Compiler. Do not change!
|
3
|
+
File generation time: 2017-08-28 23:47:06 +0530.*/
|
4
|
+
|
5
|
+
#include <ruby.h>
|
6
|
+
#include <stdint.h>
|
7
|
+
#include <stdbool.h>
|
8
|
+
#include <ruby.h>
|
9
|
+
#include <ruby/encoding.h>
|
10
|
+
#include <stdlib.h>
|
11
|
+
#include "csv.h"
|
12
|
+
|
13
|
+
#define __rubex_INT2BOOL(arg) (arg ? Qtrue : Qfalse)
|
14
|
+
|
15
|
+
|
16
|
+
|
17
|
+
typedef struct rcsv_metadata
|
18
|
+
{
|
19
|
+
int __rubex_v_skip_current_row;
|
20
|
+
size_t __rubex_v_current_col;
|
21
|
+
size_t __rubex_v_current_row;
|
22
|
+
VALUE __rubex_v_last_entry;
|
23
|
+
VALUE __rubex_v_result;
|
24
|
+
} __rubex_t_Object_rcsv_metadata;
|
25
|
+
|
26
|
+
|
27
|
+
|
28
|
+
VALUE rb_cObject;
|
29
|
+
VALUE rb_eStandardError;
|
30
|
+
VALUE __rubex_rb_cls_RcsvParseError;
|
31
|
+
VALUE __rubex_rb_cls_Rcsv;
|
32
|
+
static VALUE global_begin_block_Rcsv_parse_1__rubex_arg_dummy;
|
33
|
+
static VALUE global_begin_block_Rcsv_parse_1__rubex_v_csvstr;
|
34
|
+
static VALUE global_begin_block_Rcsv_parse_1__rubex_v_csvio;
|
35
|
+
static char* global_begin_block_Rcsv_parse_1__rubex_ptr_csv_string;
|
36
|
+
static int global_begin_block_Rcsv_parse_1__rubex_v_csv_string_len;
|
37
|
+
static struct csv_parser global_begin_block_Rcsv_parse_1__rubex_v_cp;
|
38
|
+
static __rubex_t_Object_rcsv_metadata global_begin_block_Rcsv_parse_1__rubex_v_meta;
|
39
|
+
static int global_begin_block_Rcsv_parse_1__rubex_v_error;
|
40
|
+
static VALUE __rubex_rb_f_Rcsv_parse (int argc,VALUE* argv,VALUE __rubex_arg_self);
|
41
|
+
static void __rubex_c_f_Rcsv_end_of_field_callback (void* __rubex_arg_field,size_t __rubex_arg_field_size,void* __rubex_arg_data,VALUE __rubex_arg_self);
|
42
|
+
static void __rubex_c_f_Rcsv_end_of_line_callback (int __rubex_arg_last_char,void* __rubex_arg_data,VALUE __rubex_arg_self);
|
43
|
+
static VALUE __rubex_c_f_Rcsv_ENCODED_STR_NEW (char* __rubex_arg_string,int __rubex_arg_length,VALUE __rubex_arg_self);
|
44
|
+
static void __rubex_c_f_Rcsv_setup_rcsv_metadata_defaults (__rubex_t_Object_rcsv_metadata* __rubex_arg_p_meta,VALUE __rubex_arg_self);
|
45
|
+
static VALUE __rubex_c_f_begin_block_Rcsv_parse_1 (VALUE global_begin_block_Rcsv_parse_1__rubex_arg_dummy);
|
46
|
+
|
47
|
+
VALUE __rubex_char2rubystr(char ch);
|
48
|
+
VALUE __rubex_char2rubystr(char ch)
|
49
|
+
{
|
50
|
+
char s[2];
|
51
|
+
s[0] = ch;
|
52
|
+
s[1] = '\0';
|
53
|
+
return rb_str_new2(s);
|
54
|
+
}
|
55
|
+
|
56
|
+
|
57
|
+
static VALUE __rubex_c_f_begin_block_Rcsv_parse_1 (VALUE global_begin_block_Rcsv_parse_1__rubex_arg_dummy)
|
58
|
+
{
|
59
|
+
VALUE __rubex_v_ensure_container;
|
60
|
+
VALUE __rubex_temp_1;
|
61
|
+
while (Qtrue)
|
62
|
+
{
|
63
|
+
|
64
|
+
/* Rubex file location: ext/rcsv/rcsv.rubex:93 */
|
65
|
+
global_begin_block_Rcsv_parse_1__rubex_v_csvstr = rb_funcall(global_begin_block_Rcsv_parse_1__rubex_v_csvio, rb_intern("read"), 0, NULL);
|
66
|
+
if (RTEST(( __rubex_INT2BOOL(RTEST(rb_funcall(global_begin_block_Rcsv_parse_1__rubex_v_csvstr, rb_intern("nil?"), 0, NULL)) || RTEST(( rb_funcall(rb_funcall(global_begin_block_Rcsv_parse_1__rubex_v_csvstr, rb_intern("size"), 0, NULL), rb_intern("==") , 1, INT2NUM(0)) ))) )))
|
67
|
+
{
|
68
|
+
|
69
|
+
/* Rubex file location: ext/rcsv/rcsv.rubex:95 */
|
70
|
+
break;
|
71
|
+
|
72
|
+
}
|
73
|
+
|
74
|
+
global_begin_block_Rcsv_parse_1__rubex_ptr_csv_string = StringValueCStr(global_begin_block_Rcsv_parse_1__rubex_v_csvstr);
|
75
|
+
|
76
|
+
/* Rubex file location: ext/rcsv/rcsv.rubex:98 */
|
77
|
+
global_begin_block_Rcsv_parse_1__rubex_v_csv_string_len = NUM2INT(rb_funcall(global_begin_block_Rcsv_parse_1__rubex_v_csvstr, rb_intern("size"), 0, NULL));
|
78
|
+
if (( global_begin_block_Rcsv_parse_1__rubex_v_csv_string_len != csv_parse(&global_begin_block_Rcsv_parse_1__rubex_v_cp,global_begin_block_Rcsv_parse_1__rubex_ptr_csv_string,global_begin_block_Rcsv_parse_1__rubex_v_csv_string_len,&__rubex_c_f_Rcsv_end_of_field_callback,&__rubex_c_f_Rcsv_end_of_line_callback,&global_begin_block_Rcsv_parse_1__rubex_v_meta) ))
|
79
|
+
{
|
80
|
+
global_begin_block_Rcsv_parse_1__rubex_v_error = csv_error(&global_begin_block_Rcsv_parse_1__rubex_v_cp);
|
81
|
+
|
82
|
+
if (( global_begin_block_Rcsv_parse_1__rubex_v_error == CSV_EPARSE ))
|
83
|
+
{
|
84
|
+
__rubex_temp_1 = rb_str_new2("Error when parsing malformed data.");
|
85
|
+
rb_raise(__rubex_rb_cls_RcsvParseError,"%s" ,RSTRING_PTR(rb_funcall(__rubex_temp_1, rb_intern("inspect"), 0, NULL)));
|
86
|
+
__rubex_temp_1 = 0;
|
87
|
+
|
88
|
+
}
|
89
|
+
|
90
|
+
else if (( global_begin_block_Rcsv_parse_1__rubex_v_error == CSV_ENOMEM ))
|
91
|
+
{
|
92
|
+
__rubex_temp_1 = rb_str_new2("No memory.");
|
93
|
+
rb_raise(__rubex_rb_cls_RcsvParseError,"%s" ,RSTRING_PTR(rb_funcall(__rubex_temp_1, rb_intern("inspect"), 0, NULL)));
|
94
|
+
__rubex_temp_1 = 0;
|
95
|
+
|
96
|
+
}
|
97
|
+
|
98
|
+
else if (( global_begin_block_Rcsv_parse_1__rubex_v_error == CSV_ETOOBIG ))
|
99
|
+
{
|
100
|
+
__rubex_temp_1 = rb_str_new2("Field data data is too large.");
|
101
|
+
rb_raise(__rubex_rb_cls_RcsvParseError,"%s" ,RSTRING_PTR(rb_funcall(__rubex_temp_1, rb_intern("inspect"), 0, NULL)));
|
102
|
+
__rubex_temp_1 = 0;
|
103
|
+
|
104
|
+
}
|
105
|
+
|
106
|
+
else if (( global_begin_block_Rcsv_parse_1__rubex_v_error == CSV_EINVALID ))
|
107
|
+
{
|
108
|
+
rb_raise(__rubex_rb_cls_RcsvParseError,"");
|
109
|
+
|
110
|
+
}
|
111
|
+
|
112
|
+
else
|
113
|
+
{
|
114
|
+
__rubex_temp_1 = rb_str_new2("Something went wrong.");
|
115
|
+
rb_raise(__rubex_rb_cls_RcsvParseError,"%s" ,RSTRING_PTR(rb_funcall(__rubex_temp_1, rb_intern("inspect"), 0, NULL)));
|
116
|
+
__rubex_temp_1 = 0;
|
117
|
+
|
118
|
+
}
|
119
|
+
|
120
|
+
|
121
|
+
}
|
122
|
+
|
123
|
+
}
|
124
|
+
|
125
|
+
|
126
|
+
/* Rubex file location: ext/rcsv/rcsv.rubex:117 */
|
127
|
+
csv_fini(&global_begin_block_Rcsv_parse_1__rubex_v_cp,&__rubex_c_f_Rcsv_end_of_field_callback,&__rubex_c_f_Rcsv_end_of_line_callback,&global_begin_block_Rcsv_parse_1__rubex_v_meta);
|
128
|
+
}
|
129
|
+
|
130
|
+
static void __rubex_c_f_Rcsv_end_of_field_callback (void* __rubex_arg_field,size_t __rubex_arg_field_size,void* __rubex_arg_data,VALUE __rubex_arg_self)
|
131
|
+
{
|
132
|
+
char* __rubex_ptr_field_str;
|
133
|
+
__rubex_t_Object_rcsv_metadata* __rubex_ptr_meta_p;
|
134
|
+
__rubex_t_Object_rcsv_metadata __rubex_v_meta;
|
135
|
+
char __rubex_v_row_conversion;
|
136
|
+
VALUE __rubex_v_parsed_field;
|
137
|
+
__rubex_ptr_field_str = (char*)__rubex_arg_field;
|
138
|
+
__rubex_ptr_meta_p = (__rubex_t_Object_rcsv_metadata*)__rubex_arg_data;
|
139
|
+
__rubex_v_meta = __rubex_ptr_meta_p[0];
|
140
|
+
__rubex_v_row_conversion = 0;
|
141
|
+
|
142
|
+
/* Rubex file location: ext/rcsv/rcsv.rubex:48 */
|
143
|
+
__rubex_v_parsed_field = __rubex_c_f_Rcsv_ENCODED_STR_NEW(__rubex_ptr_field_str,__rubex_arg_field_size,__rubex_arg_self);
|
144
|
+
|
145
|
+
/* Rubex file location: ext/rcsv/rcsv.rubex:50 */
|
146
|
+
rb_funcall(__rubex_ptr_meta_p[0].__rubex_v_last_entry, rb_intern("push"), 1 ,__rubex_v_parsed_field);
|
147
|
+
|
148
|
+
/* Rubex file location: ext/rcsv/rcsv.rubex:51 */
|
149
|
+
__rubex_ptr_meta_p[0].__rubex_v_current_col = ( __rubex_ptr_meta_p[0].__rubex_v_current_col + 1 );
|
150
|
+
|
151
|
+
/* Rubex file location: ext/rcsv/rcsv.rubex:52 */
|
152
|
+
return ;
|
153
|
+
}
|
154
|
+
|
155
|
+
static void __rubex_c_f_Rcsv_end_of_line_callback (int __rubex_arg_last_char,void* __rubex_arg_data,VALUE __rubex_arg_self)
|
156
|
+
{
|
157
|
+
__rubex_t_Object_rcsv_metadata* __rubex_ptr_meta;
|
158
|
+
VALUE __rubex_temp_1;
|
159
|
+
__rubex_ptr_meta = (__rubex_t_Object_rcsv_metadata*)__rubex_arg_data;
|
160
|
+
|
161
|
+
/* Rubex file location: ext/rcsv/rcsv.rubex:58 */
|
162
|
+
rb_funcall(__rubex_ptr_meta->__rubex_v_result, rb_intern("push"), 1 ,__rubex_ptr_meta->__rubex_v_last_entry);
|
163
|
+
if (( __rubex_arg_last_char != -1 ))
|
164
|
+
{
|
165
|
+
|
166
|
+
/* Rubex file location: ext/rcsv/rcsv.rubex:59 */
|
167
|
+
__rubex_temp_1 = rb_ary_new2(0);
|
168
|
+
__rubex_ptr_meta->__rubex_v_last_entry = __rubex_temp_1;
|
169
|
+
__rubex_temp_1 = 0;
|
170
|
+
|
171
|
+
}
|
172
|
+
|
173
|
+
|
174
|
+
/* Rubex file location: ext/rcsv/rcsv.rubex:60 */
|
175
|
+
__rubex_ptr_meta->__rubex_v_current_col = 0;
|
176
|
+
|
177
|
+
/* Rubex file location: ext/rcsv/rcsv.rubex:61 */
|
178
|
+
__rubex_ptr_meta->__rubex_v_current_row = ( __rubex_ptr_meta->__rubex_v_current_row + 1 );
|
179
|
+
}
|
180
|
+
|
181
|
+
static VALUE __rubex_c_f_Rcsv_ENCODED_STR_NEW (char* __rubex_arg_string,int __rubex_arg_length,VALUE __rubex_arg_self)
|
182
|
+
{
|
183
|
+
|
184
|
+
/* Rubex file location: ext/rcsv/rcsv.rubex:65 */
|
185
|
+
return rb_str_new(__rubex_arg_string,__rubex_arg_length);
|
186
|
+
}
|
187
|
+
|
188
|
+
static void __rubex_c_f_Rcsv_setup_rcsv_metadata_defaults (__rubex_t_Object_rcsv_metadata* __rubex_arg_p_meta,VALUE __rubex_arg_self)
|
189
|
+
{
|
190
|
+
VALUE __rubex_temp_1;
|
191
|
+
|
192
|
+
/* Rubex file location: ext/rcsv/rcsv.rubex:69 */
|
193
|
+
__rubex_arg_p_meta->__rubex_v_skip_current_row = 0;
|
194
|
+
|
195
|
+
/* Rubex file location: ext/rcsv/rcsv.rubex:70 */
|
196
|
+
__rubex_arg_p_meta->__rubex_v_current_col = 0;
|
197
|
+
|
198
|
+
/* Rubex file location: ext/rcsv/rcsv.rubex:71 */
|
199
|
+
__rubex_arg_p_meta->__rubex_v_current_row = 0;
|
200
|
+
|
201
|
+
/* Rubex file location: ext/rcsv/rcsv.rubex:72 */
|
202
|
+
__rubex_temp_1 = rb_ary_new2(0);
|
203
|
+
__rubex_arg_p_meta->__rubex_v_result = __rubex_temp_1;
|
204
|
+
__rubex_temp_1 = 0;
|
205
|
+
}
|
206
|
+
|
207
|
+
static VALUE __rubex_rb_f_Rcsv_parse (int argc,VALUE* argv,VALUE __rubex_arg_self)
|
208
|
+
{
|
209
|
+
VALUE __rubex_arg_file_name;
|
210
|
+
VALUE __rubex_arg_opts;
|
211
|
+
VALUE __rubex_v_options;
|
212
|
+
VALUE __rubex_v_option;
|
213
|
+
unsigned char __rubex_v_csv_options;
|
214
|
+
int __rubex_v_begin_block_1_state;
|
215
|
+
VALUE __rubex_v_begin_block_1_exec;
|
216
|
+
int __rubex_v_begin_block_1_unhandled_error;
|
217
|
+
VALUE __rubex_v_ensure_container;
|
218
|
+
VALUE __rubex_temp_1;
|
219
|
+
if (argc < 2)
|
220
|
+
{
|
221
|
+
rb_raise(rb_eArgError, "Need 2 args, not %d", argc);
|
222
|
+
}
|
223
|
+
|
224
|
+
__rubex_arg_file_name=argv[0];
|
225
|
+
__rubex_arg_opts=argv[1];
|
226
|
+
|
227
|
+
/* Rubex file location: ext/rcsv/rcsv.rubex:79 */
|
228
|
+
__rubex_temp_1 = rb_ary_new2(0);
|
229
|
+
__rubex_v_ensure_container = __rubex_temp_1;
|
230
|
+
__rubex_temp_1 = 0;
|
231
|
+
__rubex_temp_1 = 0;
|
232
|
+
__rubex_v_csv_options = ( CSV_STRICT_FINI | CSV_APPEND_NULL );
|
233
|
+
|
234
|
+
/* Rubex file location: ext/rcsv/rcsv.rubex:83 */
|
235
|
+
__rubex_c_f_Rcsv_setup_rcsv_metadata_defaults(&global_begin_block_Rcsv_parse_1__rubex_v_meta,__rubex_arg_self);
|
236
|
+
|
237
|
+
/* Rubex file location: ext/rcsv/rcsv.rubex:84 */
|
238
|
+
global_begin_block_Rcsv_parse_1__rubex_v_csvio = rb_funcall(rb_const_get(CLASS_OF(__rubex_arg_self), rb_intern("StringIO")), rb_intern("new"), 1 ,__rubex_arg_file_name);
|
239
|
+
if (( csv_init(&global_begin_block_Rcsv_parse_1__rubex_v_cp,__rubex_v_csv_options) == -1 ))
|
240
|
+
{
|
241
|
+
__rubex_temp_1 = rb_str_new2("Failed to initialize libcsv.");
|
242
|
+
rb_raise(__rubex_rb_cls_RcsvParseError,"%s" ,RSTRING_PTR(rb_funcall(__rubex_temp_1, rb_intern("inspect"), 0, NULL)));
|
243
|
+
__rubex_temp_1 = 0;
|
244
|
+
|
245
|
+
}
|
246
|
+
|
247
|
+
|
248
|
+
/* Rubex file location: ext/rcsv/rcsv.rubex:89 */
|
249
|
+
__rubex_temp_1 = rb_ary_new2(0);
|
250
|
+
global_begin_block_Rcsv_parse_1__rubex_v_meta.__rubex_v_last_entry = __rubex_temp_1;
|
251
|
+
__rubex_temp_1 = 0;
|
252
|
+
|
253
|
+
/* begin-rescue-else-ensure-end block begins: */
|
254
|
+
|
255
|
+
/* Rubex file location: ext/rcsv/rcsv.rubex:120 */
|
256
|
+
__rubex_v_begin_block_1_state = 0;
|
257
|
+
rb_protect(__rubex_c_f_begin_block_Rcsv_parse_1, Qnil, &__rubex_v_begin_block_1_state);
|
258
|
+
__rubex_v_begin_block_1_exec = rb_errinfo();
|
259
|
+
__rubex_v_begin_block_1_unhandled_error = 0;
|
260
|
+
if (0) {}
|
261
|
+
else
|
262
|
+
{
|
263
|
+
/* If exception not among those captured in raise */
|
264
|
+
if (__rubex_v_begin_block_1_state)
|
265
|
+
{
|
266
|
+
__rubex_v_begin_block_1_unhandled_error = 1;
|
267
|
+
}
|
268
|
+
|
269
|
+
}
|
270
|
+
|
271
|
+
if (&global_begin_block_Rcsv_parse_1__rubex_v_cp)
|
272
|
+
{
|
273
|
+
|
274
|
+
/* Rubex file location: ext/rcsv/rcsv.rubex:119 */
|
275
|
+
csv_free(&global_begin_block_Rcsv_parse_1__rubex_v_cp);
|
276
|
+
|
277
|
+
}
|
278
|
+
|
279
|
+
if (__rubex_v_begin_block_1_unhandled_error)
|
280
|
+
{
|
281
|
+
rb_jump_tag(__rubex_v_begin_block_1_state);
|
282
|
+
}
|
283
|
+
|
284
|
+
rb_set_errinfo(Qnil);
|
285
|
+
|
286
|
+
/* Rubex file location: ext/rcsv/rcsv.rubex:122 */
|
287
|
+
return global_begin_block_Rcsv_parse_1__rubex_v_meta.__rubex_v_result;
|
288
|
+
}
|
289
|
+
|
290
|
+
|
291
|
+
void Init_rcsv ();
|
292
|
+
void Init_rcsv ()
|
293
|
+
{
|
294
|
+
VALUE __rubex_rb_cls_RcsvParseError;
|
295
|
+
VALUE __rubex_rb_cls_Rcsv;
|
296
|
+
|
297
|
+
__rubex_rb_cls_RcsvParseError = rb_define_class("RcsvParseError", rb_eStandardError);
|
298
|
+
__rubex_rb_cls_Rcsv = rb_define_class("Rcsv", rb_cObject);
|
299
|
+
|
300
|
+
rb_define_singleton_method(__rubex_rb_cls_Rcsv ,"parse", __rubex_rb_f_Rcsv_parse, -1);
|
301
|
+
}
|
302
|
+
|