rubex 0.1 → 0.1.1
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.
- checksums.yaml +5 -5
- data/.gitignore +3 -2
- data/.travis.yml +9 -1
- data/CONTRIBUTING.md +2 -2
- data/README.md +4 -1
- data/Rakefile +2 -2
- data/bin/rubex +4 -5
- data/lib/rubex.rb +4 -4
- data/lib/rubex/ast.rb +4 -1
- data/lib/rubex/ast/expression.rb +22 -1191
- data/lib/rubex/ast/expression/actual_arg_list.rb +40 -0
- data/lib/rubex/ast/expression/analysed_element_ref.rb +26 -0
- data/lib/rubex/ast/expression/analysed_element_ref/c_var_element_ref.rb +30 -0
- data/lib/rubex/ast/expression/analysed_element_ref/ruby_object_element_ref.rb +42 -0
- data/lib/rubex/ast/expression/arg_declaration.rb +43 -0
- data/lib/rubex/ast/expression/binary.rb +57 -0
- data/lib/rubex/ast/expression/binary/binary_boolean.rb +23 -0
- data/lib/rubex/ast/expression/binary/binary_boolean_special_op.rb +20 -0
- data/lib/rubex/ast/expression/binary/empty_classes.rb +62 -0
- data/lib/rubex/ast/expression/block_given.rb +15 -0
- data/lib/rubex/ast/expression/coerce_object.rb +15 -0
- data/lib/rubex/ast/expression/command_call.rb +74 -0
- data/lib/rubex/ast/expression/command_call/struct_or_union_member_call.rb +38 -0
- data/lib/rubex/ast/expression/element_ref.rb +64 -0
- data/lib/rubex/ast/expression/empty.rb +13 -0
- data/lib/rubex/ast/expression/from_ruby_object.rb +20 -0
- data/lib/rubex/ast/expression/func_ptr_arg_declaration.rb +21 -0
- data/lib/rubex/ast/expression/func_ptr_internal_arg_declaration.rb +13 -0
- data/lib/rubex/ast/expression/literal.rb +30 -0
- data/lib/rubex/ast/expression/literal/array_lit.rb +51 -0
- data/lib/rubex/ast/expression/literal/c_null.rb +15 -0
- data/lib/rubex/ast/expression/literal/char.rb +36 -0
- data/lib/rubex/ast/expression/literal/double.rb +14 -0
- data/lib/rubex/ast/expression/literal/false.rb +33 -0
- data/lib/rubex/ast/expression/literal/hash_lit.rb +45 -0
- data/lib/rubex/ast/expression/literal/int.rb +14 -0
- data/lib/rubex/ast/expression/literal/nil.rb +14 -0
- data/lib/rubex/ast/expression/literal/ruby_symbol.rb +22 -0
- data/lib/rubex/ast/expression/literal/string_lit.rb +45 -0
- data/lib/rubex/ast/expression/literal/true.rb +29 -0
- data/lib/rubex/ast/expression/method_call.rb +52 -0
- data/lib/rubex/ast/expression/method_call/c_function_call.rb +40 -0
- data/lib/rubex/ast/expression/method_call/ruby_method_call.rb +83 -0
- data/lib/rubex/ast/expression/name.rb +127 -0
- data/lib/rubex/ast/expression/ruby_constant.rb +25 -0
- data/lib/rubex/ast/expression/ruby_object_element_ref/ruby_array_element_ref.rb +20 -0
- data/lib/rubex/ast/expression/ruby_object_element_ref/ruby_hash_element_ref.rb +22 -0
- data/lib/rubex/ast/expression/self.rb +15 -0
- data/lib/rubex/ast/expression/size_of.rb +22 -0
- data/lib/rubex/ast/expression/struct_or_union_member_call/element_ref_member_call.rb +23 -0
- data/lib/rubex/ast/expression/to_ruby_object.rb +21 -0
- data/lib/rubex/ast/expression/typecast.rb +20 -0
- data/lib/rubex/ast/expression/typecast_to.rb +10 -0
- data/lib/rubex/ast/expression/unary.rb +37 -0
- data/lib/rubex/ast/expression/unary_base.rb +24 -0
- data/lib/rubex/ast/expression/unary_base/ampersand.rb +16 -0
- data/lib/rubex/ast/expression/unary_base/unary_bit_not.rb +18 -0
- data/lib/rubex/ast/expression/unary_base/unary_not.rb +18 -0
- data/lib/rubex/ast/expression/unary_base/unary_sub.rb +18 -0
- data/lib/rubex/ast/node.rb +111 -111
- data/lib/rubex/ast/statement.rb +9 -1160
- data/lib/rubex/ast/statement/alias.rb +43 -0
- data/lib/rubex/ast/statement/argument_list.rb +59 -0
- data/lib/rubex/ast/statement/assign.rb +35 -0
- data/lib/rubex/ast/statement/begin_block.rb +14 -0
- data/lib/rubex/ast/statement/begin_block/begin.rb +202 -0
- data/lib/rubex/ast/statement/begin_block/else.rb +21 -0
- data/lib/rubex/ast/statement/begin_block/ensure.rb +21 -0
- data/lib/rubex/ast/statement/begin_block/rescue.rb +34 -0
- data/lib/rubex/ast/statement/break.rb +18 -0
- data/lib/rubex/ast/statement/c_array_decl.rb +49 -0
- data/lib/rubex/ast/statement/c_base_type.rb +26 -0
- data/lib/rubex/ast/statement/c_function_decl.rb +30 -0
- data/lib/rubex/ast/statement/c_ptr_decl.rb +52 -0
- data/lib/rubex/ast/statement/c_ptr_decl/c_ptr_func_decl.rb +25 -0
- data/lib/rubex/ast/statement/c_struct_or_union_def.rb +49 -0
- data/lib/rubex/ast/statement/expression.rb +26 -0
- data/lib/rubex/ast/statement/for.rb +73 -0
- data/lib/rubex/ast/statement/forward_decl.rb +31 -0
- data/lib/rubex/ast/statement/if_block.rb +64 -0
- data/lib/rubex/ast/statement/if_block/else.rb +30 -0
- data/lib/rubex/ast/statement/if_block/elsif.rb +22 -0
- data/lib/rubex/ast/statement/if_block/helper.rb +38 -0
- data/lib/rubex/ast/statement/print.rb +49 -0
- data/lib/rubex/ast/statement/raise.rb +66 -0
- data/lib/rubex/ast/statement/return.rb +45 -0
- data/lib/rubex/ast/statement/var_decl.rb +49 -0
- data/lib/rubex/ast/statement/while.rb +34 -0
- data/lib/rubex/ast/statement/yield.rb +41 -0
- data/lib/rubex/ast/top_statement.rb +1 -815
- data/lib/rubex/ast/top_statement/c_bindings.rb +145 -0
- data/lib/rubex/ast/top_statement/klass.rb +125 -0
- data/lib/rubex/ast/top_statement/klass/attached_klass.rb +417 -0
- data/lib/rubex/ast/top_statement/method_def.rb +110 -0
- data/lib/rubex/ast/top_statement/method_def/c_function_def.rb +26 -0
- data/lib/rubex/ast/top_statement/method_def/ruby_method_def.rb +33 -0
- data/lib/rubex/cli.rb +26 -0
- data/lib/rubex/code_writer.rb +1 -1
- data/lib/rubex/compiler.rb +49 -28
- data/lib/rubex/compiler_config.rb +4 -2
- data/lib/rubex/constants.rb +71 -71
- data/lib/rubex/data_type.rb +9 -675
- data/lib/rubex/data_type/c_array.rb +33 -0
- data/lib/rubex/data_type/c_function.rb +23 -0
- data/lib/rubex/data_type/c_ptr.rb +71 -0
- data/lib/rubex/data_type/c_str.rb +23 -0
- data/lib/rubex/data_type/c_struct_or_union.rb +23 -0
- data/lib/rubex/data_type/char.rb +30 -0
- data/lib/rubex/data_type/f_32.rb +38 -0
- data/lib/rubex/data_type/f_64.rb +38 -0
- data/lib/rubex/data_type/int.rb +32 -0
- data/lib/rubex/data_type/int/c_boolean.rb +13 -0
- data/lib/rubex/data_type/int_16.rb +32 -0
- data/lib/rubex/data_type/int_32.rb +32 -0
- data/lib/rubex/data_type/int_64.rb +36 -0
- data/lib/rubex/data_type/int_8.rb +33 -0
- data/lib/rubex/data_type/l_int.rb +38 -0
- data/lib/rubex/data_type/l_l_int.rb +26 -0
- data/lib/rubex/data_type/ruby_method.rb +22 -0
- data/lib/rubex/data_type/ruby_object.rb +19 -0
- data/lib/rubex/data_type/ruby_object/boolean.rb +11 -0
- data/lib/rubex/data_type/ruby_object/boolean/false_type.rb +5 -0
- data/lib/rubex/data_type/ruby_object/boolean/true_type.rb +5 -0
- data/lib/rubex/data_type/ruby_object/nil_type.rb +9 -0
- data/lib/rubex/data_type/ruby_object/ruby_array.rb +10 -0
- data/lib/rubex/data_type/ruby_object/ruby_constant.rb +18 -0
- data/lib/rubex/data_type/ruby_object/ruby_constant/ruby_class.rb +18 -0
- data/lib/rubex/data_type/ruby_object/ruby_hash.rb +9 -0
- data/lib/rubex/data_type/ruby_object/ruby_string.rb +10 -0
- data/lib/rubex/data_type/ruby_object/ruby_symbol.rb +10 -0
- data/lib/rubex/data_type/type_def.rb +34 -0
- data/lib/rubex/data_type/u_char.rb +27 -0
- data/lib/rubex/data_type/u_int.rb +32 -0
- data/lib/rubex/data_type/u_int_16.rb +22 -0
- data/lib/rubex/data_type/u_int_32.rb +22 -0
- data/lib/rubex/data_type/u_int_64.rb +26 -0
- data/lib/rubex/data_type/u_int_8.rb +22 -0
- data/lib/rubex/data_type/u_l_int.rb +36 -0
- data/lib/rubex/data_type/u_l_int/size_t.rb +10 -0
- data/lib/rubex/data_type/u_l_l_int.rb +26 -0
- data/lib/rubex/data_type/void.rb +15 -0
- data/lib/rubex/data_type_helpers/float_helpers.rb +8 -0
- data/lib/rubex/data_type_helpers/helpers.rb +48 -0
- data/lib/rubex/data_type_helpers/int_helpers.rb +10 -0
- data/lib/rubex/data_type_helpers/u_int_helpers.rb +11 -0
- data/lib/rubex/helpers.rb +35 -118
- data/lib/rubex/helpers/node_type_methods.rb +9 -0
- data/lib/rubex/helpers/writers.rb +79 -0
- data/lib/rubex/parser.racc +83 -34
- data/lib/rubex/parser.racc.rb +233 -184
- data/lib/rubex/version.rb +2 -2
- data/rubex.gemspec +2 -0
- data/spec/basic_ruby_method_spec.rb +1 -1
- data/spec/binding_ptr_args_spec.rb +2 -2
- data/spec/bitwise_operators_spec.rb +1 -1
- data/spec/blocks_spec.rb +2 -2
- data/spec/c_bindings_spec.rb +1 -1
- data/spec/c_constants_spec.rb +1 -1
- data/spec/c_function_ptrs_spec.rb +1 -1
- data/spec/c_functions_spec.rb +2 -2
- data/spec/c_struct_interface_spec.rb +1 -1
- data/spec/call_by_reference_spec.rb +2 -2
- data/spec/class_methods_spec.rb +2 -2
- data/spec/class_spec.rb +4 -4
- data/spec/cli_spec.rb +43 -0
- data/spec/comments_spec.rb +2 -2
- data/spec/default_args_spec.rb +21 -23
- data/spec/error_handling_spec.rb +1 -1
- data/spec/examples_spec.rb +4 -4
- data/spec/expressions_spec.rb +1 -1
- data/spec/fixtures/cli/cli.rubex +3 -0
- data/spec/fixtures/examples/array_to_hash.rubex +1 -1
- data/spec/fixtures/examples/rcsv.rubex +10 -6
- data/spec/fixtures/loops/loops.rubex +1 -1
- data/spec/fixtures/ruby_strings/string_blank_bm.rb +7 -5
- data/spec/fixtures/struct/struct.rubex +7 -2
- data/spec/fixtures/temp_allocation/temp_allocation.rubex +8 -0
- data/spec/if_else_spec.rb +3 -7
- data/spec/implicit_lib_include_spec.rb +1 -1
- data/spec/init_ruby_objects_with_literal_syntax_spec.rb +1 -1
- data/spec/loops_spec.rb +1 -1
- data/spec/recursion_spec.rb +18 -21
- data/spec/ruby_constant_method_calls_spec.rb +4 -4
- data/spec/ruby_operators_spec.rb +1 -1
- data/spec/ruby_raise_spec.rb +1 -1
- data/spec/ruby_strings_spec.rb +3 -3
- data/spec/ruby_symbols_spec.rb +1 -1
- data/spec/ruby_types_spec.rb +2 -2
- data/spec/spec_helper.rb +42 -10
- data/spec/statement_expression_spec.rb +3 -3
- data/spec/static_array_spec.rb +3 -3
- data/spec/string_literals_spec.rb +2 -2
- data/spec/struct_spec.rb +4 -4
- data/spec/temp_allocation_spec.rb +35 -0
- data/spec/typecasting_spec.rb +2 -2
- data/spec/var_declarions_spec.rb +2 -2
- metadata +168 -3
@@ -0,0 +1,145 @@
|
|
1
|
+
module Rubex
|
2
|
+
module AST
|
3
|
+
module TopStatement
|
4
|
+
class CBindings
|
5
|
+
attr_reader :lib, :declarations, :location
|
6
|
+
|
7
|
+
def initialize(lib, comp_opts, declarations, location)
|
8
|
+
@lib = lib
|
9
|
+
@comp_opts = comp_opts
|
10
|
+
@declarations = declarations
|
11
|
+
@location = location
|
12
|
+
end
|
13
|
+
|
14
|
+
def analyse_statement(local_scope)
|
15
|
+
unless @declarations
|
16
|
+
@declarations = []
|
17
|
+
load_predecided_declarations
|
18
|
+
end
|
19
|
+
@declarations.each do |stat|
|
20
|
+
stat.analyse_statement local_scope, extern: true
|
21
|
+
end
|
22
|
+
local_scope.include_files.push @lib
|
23
|
+
update_compiler_config
|
24
|
+
end
|
25
|
+
|
26
|
+
def generate_code(code); end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def update_compiler_config
|
31
|
+
@comp_opts.each do |h|
|
32
|
+
Rubex::Compiler::CONFIG.add_link h[:link] if h[:link]
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def load_predecided_declarations
|
37
|
+
if @lib == 'rubex/ruby'
|
38
|
+
load_ruby_functions_and_types
|
39
|
+
@lib = '<ruby.h>'
|
40
|
+
elsif @lib == 'rubex/ruby/encoding'
|
41
|
+
load_ruby_encoding_functions_and_type
|
42
|
+
@lib = '<ruby/encoding.h>'
|
43
|
+
elsif @lib == 'rubex/stdlib'
|
44
|
+
load_stdlib_functions_and_types
|
45
|
+
@lib = '<stdlib.h>'
|
46
|
+
else
|
47
|
+
raise Rubex::LibraryNotFoundError, "Cannot find #{@lib}."
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def load_ruby_functions_and_types
|
52
|
+
@declarations << xmalloc
|
53
|
+
@declarations << xfree
|
54
|
+
@declarations << type_get
|
55
|
+
@declarations.concat type_identifiers
|
56
|
+
@declarations << rb_str_new
|
57
|
+
@declarations << rb_ary_includes
|
58
|
+
end
|
59
|
+
|
60
|
+
def load_ruby_encoding_functions_and_type
|
61
|
+
@declarations << rb_enc_associate_index
|
62
|
+
@declarations << rb_enc_find_index
|
63
|
+
end
|
64
|
+
|
65
|
+
def load_stdlib_functions_and_types
|
66
|
+
@declarations.concat atox_functions
|
67
|
+
end
|
68
|
+
|
69
|
+
def rb_ary_includes
|
70
|
+
cfunc_decl('object', '', 'rb_ary_includes',
|
71
|
+
arg_list([arg('object', '', 'ary'), arg('object', '', 'item')]))
|
72
|
+
end
|
73
|
+
|
74
|
+
def atox_functions
|
75
|
+
[
|
76
|
+
%w[int atoi], %w[long atol], ['long long', 'atoll'],
|
77
|
+
%w[double atof]
|
78
|
+
].map do |type, ident|
|
79
|
+
cfunc_decl(type, '', ident, arg_list([arg('char', '*', 'str')]))
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def rb_enc_find_index
|
84
|
+
cfunc_decl('int', '', 'rb_enc_find_index',
|
85
|
+
arg_list([arg('char', '*', 'enc')]))
|
86
|
+
end
|
87
|
+
|
88
|
+
def rb_enc_associate_index
|
89
|
+
args = arg_list([arg('object', '', 'string'), arg('int', '', 'enc')])
|
90
|
+
cfunc_decl('object', '', 'rb_enc_associate_index', args)
|
91
|
+
end
|
92
|
+
|
93
|
+
def rb_str_new
|
94
|
+
args = arg_list([arg('char', '*', 'str'), arg('long', '', 'length')])
|
95
|
+
cfunc_decl('object', '', 'rb_str_new', args)
|
96
|
+
end
|
97
|
+
|
98
|
+
def type_get
|
99
|
+
cfunc_decl('int', '', 'TYPE', arg_list([arg('object', '', 'dummy')]))
|
100
|
+
end
|
101
|
+
|
102
|
+
def type_identifiers
|
103
|
+
stmts = %w[
|
104
|
+
T_ARRAY T_NIL T_TRUE T_FALSE T_FLOAT T_FIXNUM
|
105
|
+
T_BIGNUM T_REGEXP T_STRING
|
106
|
+
].map do |ident|
|
107
|
+
Statement::VarDecl.new('int', ident, nil, @location)
|
108
|
+
end
|
109
|
+
|
110
|
+
stmts
|
111
|
+
end
|
112
|
+
|
113
|
+
def xmalloc
|
114
|
+
args = Statement::ArgumentList.new([
|
115
|
+
Expression::ArgDeclaration.new(
|
116
|
+
dtype: 'size_t', variables: [{ ident: 'dummy' }]
|
117
|
+
)
|
118
|
+
])
|
119
|
+
Statement::CFunctionDecl.new('void', '*', 'xmalloc', args)
|
120
|
+
end
|
121
|
+
|
122
|
+
def xfree
|
123
|
+
cfunc_decl 'void', '', 'xfree', arg_list([arg('void', '*', 'dummy')])
|
124
|
+
end
|
125
|
+
|
126
|
+
private
|
127
|
+
|
128
|
+
def arg(type, ptr_level, ident)
|
129
|
+
Expression::ArgDeclaration.new(
|
130
|
+
dtype: type, variables: [{ ident: ident, ptr_level: ptr_level }]
|
131
|
+
)
|
132
|
+
end
|
133
|
+
|
134
|
+
def cfunc_decl(return_type, return_ptr_level, ident, args)
|
135
|
+
Statement::CFunctionDecl.new(return_type, return_ptr_level, ident, args)
|
136
|
+
end
|
137
|
+
|
138
|
+
def arg_list(args)
|
139
|
+
Statement::ArgumentList.new args
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
@@ -0,0 +1,125 @@
|
|
1
|
+
module Rubex
|
2
|
+
module AST
|
3
|
+
module TopStatement
|
4
|
+
class Klass
|
5
|
+
include Rubex::Helpers::Writers
|
6
|
+
# Stores the scope of the class. Rubex::SymbolTable::Scope::Klass.
|
7
|
+
attr_reader :scope
|
8
|
+
|
9
|
+
attr_reader :name
|
10
|
+
|
11
|
+
attr_reader :ancestor
|
12
|
+
|
13
|
+
attr_reader :statements
|
14
|
+
|
15
|
+
attr_reader :entry
|
16
|
+
|
17
|
+
# Name of the class. Ancestor can be Scope::Klass or String object
|
18
|
+
# depending on whether invoker is another higher level scope or
|
19
|
+
# the parser. Statements are the statements inside the class.
|
20
|
+
def initialize(name, ancestor, statements)
|
21
|
+
@name = name
|
22
|
+
@ancestor = ancestor
|
23
|
+
@statements = statements
|
24
|
+
@ancestor = 'Object' if @ancestor.nil?
|
25
|
+
end
|
26
|
+
|
27
|
+
def analyse_statement(local_scope, attach_klass: false)
|
28
|
+
@entry = local_scope.find(@name)
|
29
|
+
@scope = @entry.type.scope
|
30
|
+
@ancestor = @entry.type.ancestor
|
31
|
+
add_statement_symbols_to_symbol_table
|
32
|
+
unless attach_klass
|
33
|
+
@statements.each do |stat|
|
34
|
+
stat.analyse_statement @scope
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def rescan_declarations(_local_scope)
|
40
|
+
@statements.each do |stat|
|
41
|
+
stat&.rescan_declarations(@scope)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def generate_code(code)
|
46
|
+
@scope.begin_block_callbacks.each do |cb|
|
47
|
+
cb.generate_code code
|
48
|
+
end
|
49
|
+
|
50
|
+
@statements.each do |stat|
|
51
|
+
stat.generate_code code
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
protected
|
56
|
+
|
57
|
+
def add_statement_symbols_to_symbol_table
|
58
|
+
@statements.each do |stmt|
|
59
|
+
next unless ruby_method_or_c_function?(stmt)
|
60
|
+
f_name, f_scope = prepare_name_and_scope_of_functions(stmt)
|
61
|
+
next if auxillary_c_function_for_attached_klass?(f_name)
|
62
|
+
stmt.arg_list.analyse_statement(f_scope)
|
63
|
+
if stmt.is_a? Rubex::AST::TopStatement::RubyMethodDef
|
64
|
+
add_ruby_method_to_scope f_name, f_scope, stmt.arg_list
|
65
|
+
elsif stmt.is_a? Rubex::AST::TopStatement::CFunctionDef
|
66
|
+
return_type = Helpers.determine_dtype(stmt.type, stmt.return_ptr_level)
|
67
|
+
add_c_function_to_scope f_name, f_scope, stmt.arg_list, return_type
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def auxillary_c_function_for_attached_klass?(f_name)
|
73
|
+
is_a?(AttachedKlass) && [
|
74
|
+
Rubex::ALLOC_FUNC_NAME, Rubex::DEALLOC_FUNC_NAME,
|
75
|
+
Rubex::MEMCOUNT_FUNC_NAME, Rubex::GET_STRUCT_FUNC_NAME
|
76
|
+
].include?(f_name)
|
77
|
+
end
|
78
|
+
|
79
|
+
def add_c_function_to_scope(f_name, f_scope, arg_list, return_type)
|
80
|
+
c_name = c_func_c_name(f_name)
|
81
|
+
arg_list.each do |arg|
|
82
|
+
if arg.entry&.value
|
83
|
+
e = arg.entry
|
84
|
+
e.value = Rubex::Helpers.to_lhs_type(e, e.value)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
@scope.add_c_method(
|
88
|
+
name: f_name,
|
89
|
+
c_name: c_name,
|
90
|
+
extern: false,
|
91
|
+
return_type: return_type,
|
92
|
+
arg_list: arg_list,
|
93
|
+
scope: f_scope
|
94
|
+
)
|
95
|
+
end
|
96
|
+
|
97
|
+
def add_ruby_method_to_scope(f_name, f_scope, arg_list)
|
98
|
+
c_name = Rubex::RUBY_FUNC_PREFIX + @name + '_' +
|
99
|
+
f_name.gsub('?', '_qmark').gsub('!', '_bang')
|
100
|
+
@scope.add_ruby_method(
|
101
|
+
name: f_name,
|
102
|
+
c_name: c_name,
|
103
|
+
scope: f_scope,
|
104
|
+
arg_list: arg_list
|
105
|
+
)
|
106
|
+
end
|
107
|
+
|
108
|
+
def prepare_name_and_scope_of_functions(stmt)
|
109
|
+
f_name = stmt.name
|
110
|
+
f_scope = Rubex::SymbolTable::Scope::Local.new f_name, @scope
|
111
|
+
[f_name, f_scope]
|
112
|
+
end
|
113
|
+
|
114
|
+
def ruby_method_or_c_function?(stmt)
|
115
|
+
stmt.is_a?(Rubex::AST::TopStatement::RubyMethodDef) ||
|
116
|
+
stmt.is_a?(Rubex::AST::TopStatement::CFunctionDef)
|
117
|
+
end
|
118
|
+
|
119
|
+
def c_func_c_name(name)
|
120
|
+
Rubex::C_FUNC_PREFIX + @name + '_' + name
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
@@ -0,0 +1,417 @@
|
|
1
|
+
module Rubex
|
2
|
+
module AST
|
3
|
+
module TopStatement
|
4
|
+
class AttachedKlass < Klass
|
5
|
+
attr_reader :attached_type
|
6
|
+
|
7
|
+
ALLOC_FUNC_NAME = Rubex::ALLOC_FUNC_NAME
|
8
|
+
DEALLOC_FUNC_NAME = Rubex::DEALLOC_FUNC_NAME
|
9
|
+
MEMCOUNT_FUNC_NAME = Rubex::MEMCOUNT_FUNC_NAME
|
10
|
+
GET_STRUCT_FUNC_NAME = Rubex::GET_STRUCT_FUNC_NAME
|
11
|
+
|
12
|
+
def initialize(name, attached_type, ancestor, statements, location)
|
13
|
+
@attached_type = attached_type
|
14
|
+
@location = location
|
15
|
+
super(name, ancestor, statements)
|
16
|
+
end
|
17
|
+
|
18
|
+
def analyse_statement(outer_scope)
|
19
|
+
super(outer_scope, attach_klass: true)
|
20
|
+
prepare_data_holding_struct
|
21
|
+
prepare_rb_data_type_t_struct
|
22
|
+
detach_and_modify_auxillary_c_functions_from_statements
|
23
|
+
add_auxillary_functions_to_klass_scope
|
24
|
+
prepare_auxillary_c_functions
|
25
|
+
@statements[1..-1].each do |stmt| # 0th stmt is the data struct
|
26
|
+
if ruby_method_or_c_func?(stmt)
|
27
|
+
rewrite_method_with_data_fetching stmt
|
28
|
+
end
|
29
|
+
stmt.analyse_statement @scope
|
30
|
+
end
|
31
|
+
analyse_auxillary_c_functions
|
32
|
+
end
|
33
|
+
|
34
|
+
def generate_code(code)
|
35
|
+
write_auxillary_c_functions code
|
36
|
+
write_data_type_t_struct code
|
37
|
+
write_get_struct_c_function code
|
38
|
+
write_alloc_c_function code
|
39
|
+
super
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
# Since auxillary functions are detached from the klass statements,
|
45
|
+
# analyse their arg_list separately and add function names to the
|
46
|
+
# class scope so that their statements can be analysed properly later.
|
47
|
+
def add_auxillary_functions_to_klass_scope
|
48
|
+
@auxillary_c_functions.each_value do |func|
|
49
|
+
f_name, f_scope = prepare_name_and_scope_of_functions func
|
50
|
+
func.arg_list.analyse_statement(f_scope)
|
51
|
+
return_type = Helpers.determine_dtype(func.type, func.return_ptr_level)
|
52
|
+
add_c_function_to_scope f_name, f_scope, func.arg_list, return_type
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def analyse_auxillary_c_functions
|
57
|
+
@auxillary_c_functions.each_value do |func|
|
58
|
+
func.analyse_statement(@scope)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# Detach the user-supplied auxlically C functions from the class and
|
63
|
+
# store them in Hash @auxillary_c_functions. Make modifications to
|
64
|
+
# them if necessary and also set an ivar that indicates if an
|
65
|
+
# auxillary function is user-supplied or not.
|
66
|
+
def detach_and_modify_auxillary_c_functions_from_statements
|
67
|
+
@auxillary_c_functions = {}
|
68
|
+
|
69
|
+
indexes = []
|
70
|
+
@statements.each_with_index do |stmt, idx|
|
71
|
+
if stmt.is_a?(CFunctionDef)
|
72
|
+
if stmt.name == ALLOC_FUNC_NAME
|
73
|
+
@auxillary_c_functions[ALLOC_FUNC_NAME] = stmt
|
74
|
+
@user_defined_alloc = true
|
75
|
+
indexes << idx
|
76
|
+
elsif stmt.name == DEALLOC_FUNC_NAME
|
77
|
+
@auxillary_c_functions[DEALLOC_FUNC_NAME] = stmt
|
78
|
+
@user_defined_dealloc = true
|
79
|
+
modify_dealloc_func stmt
|
80
|
+
indexes << idx
|
81
|
+
elsif stmt.name == MEMCOUNT_FUNC_NAME
|
82
|
+
@auxillary_c_functions[MEMCOUNT_FUNC_NAME] = stmt
|
83
|
+
@user_defined_memcount = true
|
84
|
+
indexes << idx
|
85
|
+
elsif stmt.name == GET_STRUCT_FUNC_NAME
|
86
|
+
@auxillary_c_functions[GET_STRUCT_FUNC_NAME] = stmt
|
87
|
+
@user_defined_get_struct = true
|
88
|
+
indexes << idx
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
indexes.each do |idx|
|
94
|
+
@statements.delete_at idx
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def write_auxillary_c_functions(code)
|
99
|
+
write_dealloc_c_function code
|
100
|
+
write_memcount_c_function code
|
101
|
+
end
|
102
|
+
|
103
|
+
# Actually write the alloc function into C code.
|
104
|
+
def write_alloc_c_function(code)
|
105
|
+
if user_defined_alloc?
|
106
|
+
@auxillary_c_functions[ALLOC_FUNC_NAME].generate_code code
|
107
|
+
else
|
108
|
+
code.write_c_method_header(
|
109
|
+
type: @alloc_c_func.type.type.to_s,
|
110
|
+
c_name: @alloc_c_func.c_name,
|
111
|
+
args: Helpers.create_arg_arrays(@alloc_c_func.type.arg_list)
|
112
|
+
)
|
113
|
+
code.block do
|
114
|
+
lines = ''
|
115
|
+
lines << "#{@data_struct.entry.c_name} *data;\n\n"
|
116
|
+
|
117
|
+
lines << "data = (#{@data_struct.entry.c_name}*)xmalloc("
|
118
|
+
lines << "sizeof(#{@data_struct.entry.c_name}));\n"
|
119
|
+
|
120
|
+
lines << member_struct_allocations
|
121
|
+
|
122
|
+
lines << 'return TypedData_Wrap_Struct('
|
123
|
+
lines << "#{@alloc_c_func.type.arg_list[0].entry.c_name},"
|
124
|
+
lines << "&#{@data_type_t}, data);\n"
|
125
|
+
|
126
|
+
code << lines
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
# TODO: modify for supporting inheritance
|
132
|
+
def member_struct_allocations
|
133
|
+
c_name = @scope.find(@attached_type).c_name
|
134
|
+
"data->#{Rubex::POINTER_PREFIX + @attached_type} = (#{c_name}*)xmalloc(sizeof(#{c_name}));\n"
|
135
|
+
end
|
136
|
+
|
137
|
+
# Actually write the dealloc function into C code.
|
138
|
+
def write_dealloc_c_function(code)
|
139
|
+
if user_defined_dealloc?
|
140
|
+
@auxillary_c_functions[DEALLOC_FUNC_NAME].generate_code code
|
141
|
+
else
|
142
|
+
# TODO: define dealloc if user hasnt supplied.
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
# Actually write the memcount function into C code.
|
147
|
+
def write_memcount_c_function(code)
|
148
|
+
if user_defined_memcount?
|
149
|
+
@auxillary_c_functions[MEMCOUNT_FUNC_NAME].generate_code code
|
150
|
+
else
|
151
|
+
code.write_c_method_header(
|
152
|
+
type: @memcount_c_func.type.type.to_s,
|
153
|
+
c_name: @memcount_c_func.c_name,
|
154
|
+
args: Helpers.create_arg_arrays(@memcount_c_func.type.arg_list)
|
155
|
+
)
|
156
|
+
code.block do
|
157
|
+
code << "return sizeof(#{@memcount_c_func.type.arg_list[0].entry.c_name})"
|
158
|
+
code.colon
|
159
|
+
code.nl
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
# Actually write the get_struct function into C code.
|
165
|
+
def write_get_struct_c_function(code)
|
166
|
+
if user_defined_get_struct?
|
167
|
+
@auxillary_c_functions[GET_STRUCT_FUNC_NAME].generate_code code
|
168
|
+
else
|
169
|
+
code.write_c_method_header(
|
170
|
+
type: @get_struct_c_func.type.type.to_s,
|
171
|
+
c_name: @get_struct_c_func.c_name,
|
172
|
+
args: Helpers.create_arg_arrays(@get_struct_c_func.type.arg_list)
|
173
|
+
)
|
174
|
+
code.block do
|
175
|
+
lines = ''
|
176
|
+
lines << "#{@data_struct.entry.c_name} *data;\n\n"
|
177
|
+
lines << 'TypedData_Get_Struct('
|
178
|
+
lines << "#{@get_struct_c_func.type.arg_list[0].entry.c_name}, "
|
179
|
+
lines << "#{@data_struct.entry.c_name}, &#{@data_type_t}, data);\n"
|
180
|
+
lines << "return data;\n"
|
181
|
+
|
182
|
+
code << lines
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
def write_data_type_t_struct(code)
|
188
|
+
decl = ''
|
189
|
+
decl << "static const rb_data_type_t #{@data_type_t} = {\n"
|
190
|
+
decl << " \"#{@name}\",\n"
|
191
|
+
decl << " {0, #{@dealloc_c_func.c_name}, #{@memcount_c_func.c_name},\n"
|
192
|
+
decl << " 0}, 0, 0, RUBY_TYPED_FREE_IMMEDIATELY\n"
|
193
|
+
decl << "};\n"
|
194
|
+
|
195
|
+
code << decl
|
196
|
+
code.new_line
|
197
|
+
end
|
198
|
+
|
199
|
+
# Prepare the data holding struct 'data' that will hold a pointer to the
|
200
|
+
# struct that is attached to this class.
|
201
|
+
def prepare_data_holding_struct
|
202
|
+
struct_name = @name + '_data_struct'
|
203
|
+
declarations = declarations_for_data_struct
|
204
|
+
@data_struct = Statement::CStructOrUnionDef.new(
|
205
|
+
:struct, struct_name, declarations, @location
|
206
|
+
)
|
207
|
+
@data_struct.analyse_statement(@scope)
|
208
|
+
@statements.unshift @data_struct
|
209
|
+
end
|
210
|
+
|
211
|
+
# TODO: support inherited attached structs.
|
212
|
+
def declarations_for_data_struct
|
213
|
+
stmts = []
|
214
|
+
stmts << Statement::CPtrDecl.new(@attached_type, @attached_type, nil,
|
215
|
+
'*', @location)
|
216
|
+
|
217
|
+
stmts
|
218
|
+
end
|
219
|
+
|
220
|
+
def prepare_rb_data_type_t_struct
|
221
|
+
@data_type_t = Rubex::ATTACH_CLASS_PREFIX + '_' + @name + '_data_type_t'
|
222
|
+
end
|
223
|
+
|
224
|
+
# Prepare auxillary function in case they have not been supplied by user
|
225
|
+
# and create ivars for their Symbol Table entries for easy accesss later.
|
226
|
+
def prepare_auxillary_c_functions
|
227
|
+
prepare_alloc_c_function
|
228
|
+
prepare_memcount_c_function
|
229
|
+
prepare_deallocation_c_function
|
230
|
+
prepare_get_struct_c_function
|
231
|
+
end
|
232
|
+
|
233
|
+
def ruby_method_or_c_func?(stmt)
|
234
|
+
stmt.is_a?(RubyMethodDef) || stmt.is_a?(CFunctionDef)
|
235
|
+
end
|
236
|
+
|
237
|
+
# Rewrite method `stmt` so that the `data` variable becomes available
|
238
|
+
# inside the scope of the method.
|
239
|
+
def rewrite_method_with_data_fetching(stmt)
|
240
|
+
data_stmt = Statement::CPtrDecl.new(@data_struct.name, 'data',
|
241
|
+
get_struct_func_call(stmt), '*', @location)
|
242
|
+
stmt.statements.unshift data_stmt
|
243
|
+
end
|
244
|
+
|
245
|
+
def get_struct_func_call(_stmt)
|
246
|
+
Expression::CommandCall.new(nil, @get_struct_c_func.name,
|
247
|
+
Expression::ActualArgList.new([]))
|
248
|
+
end
|
249
|
+
|
250
|
+
# Create an alloc function if it is not supplied by user.
|
251
|
+
def prepare_alloc_c_function
|
252
|
+
if user_defined_alloc?
|
253
|
+
@alloc_c_func = @scope.find(ALLOC_FUNC_NAME)
|
254
|
+
else
|
255
|
+
c_name = c_func_c_name(ALLOC_FUNC_NAME)
|
256
|
+
scope = Rubex::SymbolTable::Scope::Local.new(ALLOC_FUNC_NAME, @scope)
|
257
|
+
arg_list = Statement::ArgumentList.new([
|
258
|
+
Expression::ArgDeclaration.new(
|
259
|
+
dtype: 'object',
|
260
|
+
variables: [
|
261
|
+
{
|
262
|
+
ident: 'self'
|
263
|
+
}
|
264
|
+
]
|
265
|
+
)
|
266
|
+
])
|
267
|
+
arg_list.analyse_statement(scope)
|
268
|
+
@alloc_c_func = @scope.add_c_method(
|
269
|
+
name: ALLOC_FUNC_NAME,
|
270
|
+
c_name: c_name,
|
271
|
+
arg_list: arg_list,
|
272
|
+
return_type: DataType::RubyObject.new,
|
273
|
+
scope: scope
|
274
|
+
)
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
# Create a memcount function if it is not supplied by user.
|
279
|
+
def prepare_memcount_c_function
|
280
|
+
if user_defined_memcount?
|
281
|
+
@memcount_c_func = @scope.find(MEMCOUNT_FUNC_NAME)
|
282
|
+
else
|
283
|
+
c_name = c_func_c_name(MEMCOUNT_FUNC_NAME)
|
284
|
+
scope = Rubex::SymbolTable::Scope::Local.new(MEMCOUNT_FUNC_NAME, @scope)
|
285
|
+
arg_list = Statement::ArgumentList.new([
|
286
|
+
Expression::ArgDeclaration.new(
|
287
|
+
dtype: 'void',
|
288
|
+
variables: [
|
289
|
+
{
|
290
|
+
ptr_level: '*',
|
291
|
+
ident: 'raw_data'
|
292
|
+
}
|
293
|
+
]
|
294
|
+
)
|
295
|
+
])
|
296
|
+
arg_list.analyse_statement(scope)
|
297
|
+
@memcount_c_func = @scope.add_c_method(
|
298
|
+
name: MEMCOUNT_FUNC_NAME,
|
299
|
+
c_name: c_name,
|
300
|
+
arg_list: arg_list,
|
301
|
+
return_type: DataType::Size_t.new,
|
302
|
+
scope: scope
|
303
|
+
)
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
307
|
+
# Create a deallocate function if it is not supplied by user.
|
308
|
+
def prepare_deallocation_c_function
|
309
|
+
if user_defined_dealloc?
|
310
|
+
@dealloc_c_func = @scope.find(DEALLOC_FUNC_NAME)
|
311
|
+
else
|
312
|
+
c_name = c_func_c_name(DEALLOC_FUNC_NAME)
|
313
|
+
scope = Rubex::SymbolTable::Scope::Local.new(DEALLOC_FUNC_NAME, @scope)
|
314
|
+
arg_list = Statement::ArgumentList.new([
|
315
|
+
Expression::ArgDeclaration.new(
|
316
|
+
dtype: 'void',
|
317
|
+
variables: [
|
318
|
+
{
|
319
|
+
ptr_level: '*',
|
320
|
+
ident: 'raw_data'
|
321
|
+
}
|
322
|
+
]
|
323
|
+
)
|
324
|
+
])
|
325
|
+
arg_list.analyse_statement(scope)
|
326
|
+
@dealloc_c_func = @scope.add_c_method(
|
327
|
+
name: DEALLOC_FUNC_NAME,
|
328
|
+
c_name: c_name,
|
329
|
+
return_type: DataType::Void.new,
|
330
|
+
scope: scope,
|
331
|
+
arg_list: arg_list
|
332
|
+
)
|
333
|
+
end
|
334
|
+
end
|
335
|
+
|
336
|
+
# Create a get_struct function if it is not supplied by user.
|
337
|
+
def prepare_get_struct_c_function
|
338
|
+
if user_defined_get_struct?
|
339
|
+
@get_struct_c_func = @scope.find(GET_STRUCT_FUNC_NAME)
|
340
|
+
else
|
341
|
+
c_name = c_func_c_name(GET_STRUCT_FUNC_NAME)
|
342
|
+
scope = Rubex::SymbolTable::Scope::Local.new(
|
343
|
+
GET_STRUCT_FUNC_NAME, @scope
|
344
|
+
)
|
345
|
+
arg_list = Statement::ArgumentList.new([
|
346
|
+
Expression::ArgDeclaration.new(
|
347
|
+
dtype: 'object',
|
348
|
+
variables: [
|
349
|
+
{
|
350
|
+
ident: 'obj'
|
351
|
+
}
|
352
|
+
]
|
353
|
+
)
|
354
|
+
])
|
355
|
+
arg_list.analyse_statement(scope)
|
356
|
+
return_type = DataType::CPtr.new(
|
357
|
+
DataType::CStructOrUnion.new(
|
358
|
+
:struct, @data_struct.name, @data_struct.entry.c_name, nil
|
359
|
+
)
|
360
|
+
)
|
361
|
+
@get_struct_c_func = @scope.add_c_method(
|
362
|
+
name: GET_STRUCT_FUNC_NAME,
|
363
|
+
c_name: c_name,
|
364
|
+
return_type: return_type,
|
365
|
+
arg_list: arg_list,
|
366
|
+
scope: scope
|
367
|
+
)
|
368
|
+
end
|
369
|
+
end
|
370
|
+
|
371
|
+
# Modify the dealloc function by adding an argument of type void* so
|
372
|
+
# that it is compatible with what Ruby expects. This is done so that
|
373
|
+
# the user is not burdened with additional knowledge of knowing the
|
374
|
+
# the correct argument for deallocate.
|
375
|
+
def modify_dealloc_func(func)
|
376
|
+
func.arg_list = Statement::ArgumentList.new([
|
377
|
+
Expression::ArgDeclaration.new(
|
378
|
+
dtype: 'void',
|
379
|
+
variables: [
|
380
|
+
{
|
381
|
+
ptr_level: '*',
|
382
|
+
ident: 'raw_data'
|
383
|
+
}
|
384
|
+
]
|
385
|
+
)
|
386
|
+
])
|
387
|
+
value = Expression::Name.new('raw_data')
|
388
|
+
value.typecast = Expression::Typecast.new(@data_struct.name, '*')
|
389
|
+
data_var = Statement::CPtrDecl.new(@data_struct.name, 'data', value,
|
390
|
+
'*', @location)
|
391
|
+
xfree = Expression::CommandCall.new(nil, 'xfree',
|
392
|
+
Expression::ActualArgList.new(
|
393
|
+
[Expression::Name.new('data')]))
|
394
|
+
data_xfree = Statement::Expression.new xfree, @location
|
395
|
+
func.statements.unshift data_var
|
396
|
+
func.statements.push data_xfree
|
397
|
+
end
|
398
|
+
|
399
|
+
def user_defined_dealloc?
|
400
|
+
@user_defined_dealloc
|
401
|
+
end
|
402
|
+
|
403
|
+
def user_defined_alloc?
|
404
|
+
@user_defined_alloc
|
405
|
+
end
|
406
|
+
|
407
|
+
def user_defined_memcount?
|
408
|
+
@user_defined_memcount
|
409
|
+
end
|
410
|
+
|
411
|
+
def user_defined_get_struct?
|
412
|
+
@user_defined_get_struct
|
413
|
+
end
|
414
|
+
end
|
415
|
+
end
|
416
|
+
end
|
417
|
+
end
|