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,22 @@
|
|
1
|
+
require_relative 'helper'
|
2
|
+
module Rubex
|
3
|
+
module AST
|
4
|
+
module Statement
|
5
|
+
class IfBlock < Base
|
6
|
+
class Elsif < Base
|
7
|
+
attr_reader :expr, :statements, :if_tail
|
8
|
+
include Rubex::AST::Statement::IfBlock::Helper
|
9
|
+
|
10
|
+
def initialize(expr, statements, if_tail, location)
|
11
|
+
super(location)
|
12
|
+
@expr = expr
|
13
|
+
@statements = statements
|
14
|
+
@if_tail = if_tail
|
15
|
+
end
|
16
|
+
|
17
|
+
def generate_code(code, local_scope); end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Rubex
|
2
|
+
module AST
|
3
|
+
module Statement
|
4
|
+
class IfBlock < Base
|
5
|
+
module Helper
|
6
|
+
def analyse_statement(local_scope)
|
7
|
+
@statements.each do |stat|
|
8
|
+
stat.analyse_statement local_scope
|
9
|
+
end
|
10
|
+
|
11
|
+
@if_tail&.analyse_statement(local_scope)
|
12
|
+
end
|
13
|
+
|
14
|
+
def generate_code_for_statement(stat, code, local_scope, node)
|
15
|
+
if stat != 'else'
|
16
|
+
condition = node.expr.c_code(local_scope)
|
17
|
+
expr_condition = node.expr.type.object? ? "RTEST(#{condition})" : condition
|
18
|
+
code << "#{stat} (#{expr_condition}) "
|
19
|
+
else
|
20
|
+
code << stat.to_s
|
21
|
+
end
|
22
|
+
|
23
|
+
code.block do
|
24
|
+
node.statements.each do |stat|
|
25
|
+
stat.generate_code code, local_scope
|
26
|
+
code.nl
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
if stat != 'else'
|
31
|
+
node.if_tail&.generate_code(code, local_scope)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Rubex
|
2
|
+
module AST
|
3
|
+
module Statement
|
4
|
+
class Print < Base
|
5
|
+
def initialize(expressions, location)
|
6
|
+
super(location)
|
7
|
+
@expressions = expressions
|
8
|
+
end
|
9
|
+
|
10
|
+
def analyse_statement(local_scope)
|
11
|
+
@expressions.each do |expr|
|
12
|
+
expr.analyse_types local_scope
|
13
|
+
expr.allocate_temps local_scope
|
14
|
+
expr.release_temps local_scope
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def generate_code(code, local_scope)
|
19
|
+
super
|
20
|
+
@expressions.each do |expr|
|
21
|
+
expr.generate_evaluation_code code, local_scope
|
22
|
+
|
23
|
+
str = 'printf('
|
24
|
+
str << "\"#{expr.type.p_formatter}\""
|
25
|
+
str << ", #{inspected_expr(expr, local_scope)}"
|
26
|
+
str << ');'
|
27
|
+
code << str
|
28
|
+
code.nl
|
29
|
+
|
30
|
+
expr.generate_disposal_code code
|
31
|
+
end
|
32
|
+
|
33
|
+
code.nl
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def inspected_expr(expr, local_scope)
|
39
|
+
obj = expr.c_code(local_scope)
|
40
|
+
if expr.type.object?
|
41
|
+
"RSTRING_PTR(rb_funcall(#{obj}, rb_intern(\"inspect\"), 0, NULL))"
|
42
|
+
else
|
43
|
+
obj
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module Rubex
|
2
|
+
module AST
|
3
|
+
module Statement
|
4
|
+
class Raise < Base
|
5
|
+
def initialize(args)
|
6
|
+
@args = args
|
7
|
+
end
|
8
|
+
|
9
|
+
def analyse_statement(local_scope)
|
10
|
+
@args.analyse_types local_scope
|
11
|
+
@args.allocate_temps local_scope
|
12
|
+
@args.release_temps local_scope
|
13
|
+
unless @args.empty? || @args[0].is_a?(AST::Expression::Name) ||
|
14
|
+
@args[0].is_a?(AST::Expression::Literal::StringLit)
|
15
|
+
raise Rubex::TypeMismatchError, "Wrong argument list #{@args.inspect} for raise."
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def generate_code(code, local_scope)
|
20
|
+
@args.generate_evaluation_code code, local_scope
|
21
|
+
str = ''
|
22
|
+
str << 'rb_raise('
|
23
|
+
|
24
|
+
if @args[0].is_a?(AST::Expression::Name)
|
25
|
+
str << @args[0].c_code(local_scope) + ','
|
26
|
+
args = @args[1..-1]
|
27
|
+
else
|
28
|
+
str << Rubex::DEFAULT_CLASS_MAPPINGS['RuntimeError'] + ','
|
29
|
+
args = @args
|
30
|
+
end
|
31
|
+
|
32
|
+
unless args.empty?
|
33
|
+
str << "\"#{prepare_format_string(args)}\" ,"
|
34
|
+
str << args.map { |arg| (inspected_expr(arg, local_scope)).to_s }.join(',')
|
35
|
+
else
|
36
|
+
str << '""'
|
37
|
+
end
|
38
|
+
str << ');'
|
39
|
+
code << str
|
40
|
+
code.nl
|
41
|
+
@args.generate_disposal_code code
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def prepare_format_string(args)
|
47
|
+
format_string = ''
|
48
|
+
args.each do |expr|
|
49
|
+
format_string << expr.type.p_formatter
|
50
|
+
end
|
51
|
+
|
52
|
+
format_string
|
53
|
+
end
|
54
|
+
|
55
|
+
def inspected_expr(expr, local_scope)
|
56
|
+
obj = expr.c_code(local_scope)
|
57
|
+
if expr.type.object?
|
58
|
+
"RSTRING_PTR(rb_funcall(#{obj}, rb_intern(\"inspect\"), 0, NULL))"
|
59
|
+
else
|
60
|
+
obj
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Rubex
|
2
|
+
module AST
|
3
|
+
module Statement
|
4
|
+
class Return < Base
|
5
|
+
def initialize(expression, location)
|
6
|
+
super(location)
|
7
|
+
@expression = expression
|
8
|
+
end
|
9
|
+
|
10
|
+
def analyse_statement(local_scope)
|
11
|
+
unless @expression
|
12
|
+
if local_scope.type.ruby_method?
|
13
|
+
@expression = Rubex::AST::Expression::Literal::Nil.new 'Qnil'
|
14
|
+
elsif local_scope.type.c_function?
|
15
|
+
@expression = Rubex::AST::Expression::Empty.new
|
16
|
+
end # FIXME: print a warning for type mismatch if none of above
|
17
|
+
end
|
18
|
+
|
19
|
+
@expression.analyse_types local_scope
|
20
|
+
@expression.allocate_temps local_scope
|
21
|
+
@expression.release_temps local_scope
|
22
|
+
t = @expression.type
|
23
|
+
|
24
|
+
@type =
|
25
|
+
if t.c_function? || t.alias_type?
|
26
|
+
t.type
|
27
|
+
else
|
28
|
+
t
|
29
|
+
end
|
30
|
+
@expression = @expression.to_ruby_object if local_scope.type.type.object?
|
31
|
+
|
32
|
+
# TODO: Raise error if type as inferred from the
|
33
|
+
# is not compatible with the return statement type.
|
34
|
+
end
|
35
|
+
|
36
|
+
def generate_code(code, local_scope)
|
37
|
+
super
|
38
|
+
@expression.generate_evaluation_code code, local_scope
|
39
|
+
code << "return #{@expression.c_code(local_scope)};"
|
40
|
+
code.nl
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Rubex
|
2
|
+
module AST
|
3
|
+
module Statement
|
4
|
+
class VarDecl < Base
|
5
|
+
attr_reader :type, :value
|
6
|
+
|
7
|
+
def initialize(type, name, value, location)
|
8
|
+
super(location)
|
9
|
+
@name = name
|
10
|
+
@value = value
|
11
|
+
@type = type
|
12
|
+
end
|
13
|
+
|
14
|
+
def analyse_statement(local_scope, extern: false)
|
15
|
+
# TODO: Have type checks for knowing if correct literal assignment
|
16
|
+
# is taking place. For example, a char should not be assigned a float.
|
17
|
+
@type = Helpers.determine_dtype @type, ''
|
18
|
+
c_name = extern ? @name : Rubex::VAR_PREFIX + @name
|
19
|
+
if @value
|
20
|
+
@value.analyse_for_target_type(@type, local_scope)
|
21
|
+
@value.allocate_temps local_scope
|
22
|
+
@value = Helpers.to_lhs_type(self, @value)
|
23
|
+
@value.release_temps local_scope
|
24
|
+
end
|
25
|
+
|
26
|
+
local_scope.declare_var name: @name, c_name: c_name, type: @type,
|
27
|
+
value: @value, extern: extern
|
28
|
+
end
|
29
|
+
|
30
|
+
def rescan_declarations(scope)
|
31
|
+
if @type.is_a? String
|
32
|
+
@type = Rubex::CUSTOM_TYPES[@type]
|
33
|
+
scope[@name].type = @type
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def generate_code(code, local_scope)
|
38
|
+
if @value
|
39
|
+
@value.generate_evaluation_code code, local_scope
|
40
|
+
lhs = local_scope.find(@name).c_name
|
41
|
+
code << "#{lhs} = #{@value.c_code(local_scope)};"
|
42
|
+
code.nl
|
43
|
+
@value.generate_disposal_code code
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Rubex
|
2
|
+
module AST
|
3
|
+
module Statement
|
4
|
+
class While < Base
|
5
|
+
def initialize(expr, statements, location)
|
6
|
+
super(location)
|
7
|
+
@expr = expr
|
8
|
+
@statements = statements
|
9
|
+
end
|
10
|
+
|
11
|
+
def analyse_statement(local_scope)
|
12
|
+
@expr.analyse_types local_scope
|
13
|
+
@expr.release_temps local_scope
|
14
|
+
@statements.each do |stat|
|
15
|
+
stat.analyse_statement local_scope
|
16
|
+
end
|
17
|
+
@expr.release_temps local_scope
|
18
|
+
end
|
19
|
+
|
20
|
+
def generate_code(code, local_scope)
|
21
|
+
@expr.generate_evaluation_code code, local_scope
|
22
|
+
stmt = "while (#{@expr.c_code(local_scope)})"
|
23
|
+
code << stmt
|
24
|
+
code.block do
|
25
|
+
@statements.each do |stat|
|
26
|
+
stat.generate_code code, local_scope
|
27
|
+
end
|
28
|
+
end
|
29
|
+
@expr.generate_disposal_code code
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Rubex
|
2
|
+
module AST
|
3
|
+
module Statement
|
4
|
+
class Yield < Base
|
5
|
+
def initialize(args)
|
6
|
+
@args = args
|
7
|
+
end
|
8
|
+
|
9
|
+
def analyse_statement(local_scope)
|
10
|
+
@args = @args.map do |arg|
|
11
|
+
arg.analyse_types local_scope
|
12
|
+
arg.allocate_temps local_scope
|
13
|
+
arg.to_ruby_object
|
14
|
+
end
|
15
|
+
@args.each do |arg|
|
16
|
+
arg.release_temps local_scope
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def generate_code(code, local_scope)
|
21
|
+
@args.each do |a|
|
22
|
+
a.generate_evaluation_code code, local_scope
|
23
|
+
end
|
24
|
+
|
25
|
+
if !@args.empty?
|
26
|
+
code << "rb_yield_values(#{@args.size}, "
|
27
|
+
code << (@args.map { |a| a.c_code(local_scope) }.join(',')).to_s
|
28
|
+
code << ');'
|
29
|
+
else
|
30
|
+
code << 'rb_yield(Qnil);'
|
31
|
+
end
|
32
|
+
code.nl
|
33
|
+
|
34
|
+
@args.each do |a|
|
35
|
+
a.generate_disposal_code code
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -1,815 +1 @@
|
|
1
|
-
|
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, @comp_opts, @declarations, @location = lib, comp_opts,
|
9
|
-
declarations, location
|
10
|
-
end
|
11
|
-
|
12
|
-
def analyse_statement local_scope
|
13
|
-
unless @declarations
|
14
|
-
@declarations = []
|
15
|
-
load_predecided_declarations
|
16
|
-
end
|
17
|
-
@declarations.each do |stat|
|
18
|
-
stat.analyse_statement local_scope, extern: true
|
19
|
-
end
|
20
|
-
local_scope.include_files.push @lib
|
21
|
-
update_compiler_config
|
22
|
-
end
|
23
|
-
|
24
|
-
def generate_code code
|
25
|
-
|
26
|
-
end
|
27
|
-
|
28
|
-
private
|
29
|
-
def update_compiler_config
|
30
|
-
@comp_opts.each do |h|
|
31
|
-
if h[:link]
|
32
|
-
Rubex::Compiler::CONFIG.add_link h[:link]
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
def load_predecided_declarations
|
38
|
-
if @lib == 'rubex/ruby'
|
39
|
-
load_ruby_functions_and_types
|
40
|
-
@lib = '<ruby.h>'
|
41
|
-
elsif @lib == 'rubex/ruby/encoding'
|
42
|
-
load_ruby_encoding_functions_and_type
|
43
|
-
@lib = '<ruby/encoding.h>'
|
44
|
-
elsif @lib == 'rubex/stdlib'
|
45
|
-
load_stdlib_functions_and_types
|
46
|
-
@lib = '<stdlib.h>'
|
47
|
-
else
|
48
|
-
raise Rubex::LibraryNotFoundError, "Cannot find #{@lib}."
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
def load_ruby_functions_and_types
|
53
|
-
@declarations << xmalloc
|
54
|
-
@declarations << xfree
|
55
|
-
@declarations << type_get
|
56
|
-
@declarations.concat type_identifiers
|
57
|
-
@declarations << rb_str_new
|
58
|
-
@declarations << rb_ary_includes
|
59
|
-
end
|
60
|
-
|
61
|
-
def load_ruby_encoding_functions_and_type
|
62
|
-
@declarations << rb_enc_associate_index
|
63
|
-
@declarations << rb_enc_find_index
|
64
|
-
end
|
65
|
-
|
66
|
-
def load_stdlib_functions_and_types
|
67
|
-
@declarations.concat atox_functions
|
68
|
-
end
|
69
|
-
|
70
|
-
def rb_ary_includes
|
71
|
-
cfunc_decl('object', '', 'rb_ary_includes',
|
72
|
-
arg_list([arg('object', '','ary'), arg('object', '','item')]))
|
73
|
-
end
|
74
|
-
|
75
|
-
def atox_functions
|
76
|
-
[
|
77
|
-
['int', 'atoi'], ['long', 'atol'], ['long long', 'atoll'],
|
78
|
-
['double', 'atof']
|
79
|
-
].map do |type, ident|
|
80
|
-
cfunc_decl(type, '', ident, arg_list([arg('char', '*', 'str')]))
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
def rb_enc_find_index
|
85
|
-
cfunc_decl('int', '', 'rb_enc_find_index',
|
86
|
-
arg_list([arg('char', '*', 'enc')]))
|
87
|
-
end
|
88
|
-
|
89
|
-
def rb_enc_associate_index
|
90
|
-
args = arg_list([arg('object', '', 'string'), arg('int', '', 'enc')])
|
91
|
-
cfunc_decl('object', '', 'rb_enc_associate_index', args)
|
92
|
-
end
|
93
|
-
|
94
|
-
def rb_str_new
|
95
|
-
args = arg_list([arg('char', '*', 'str'), arg('long', '', 'length')])
|
96
|
-
cfunc_decl('object', '', 'rb_str_new', args)
|
97
|
-
end
|
98
|
-
|
99
|
-
def type_get
|
100
|
-
cfunc_decl('int', '', 'TYPE', arg_list([arg('object', '', 'dummy')]))
|
101
|
-
end
|
102
|
-
|
103
|
-
def type_identifiers
|
104
|
-
stmts = [
|
105
|
-
'T_ARRAY', 'T_NIL', 'T_TRUE', 'T_FALSE', 'T_FLOAT', 'T_FIXNUM',
|
106
|
-
'T_BIGNUM', 'T_REGEXP', 'T_STRING'
|
107
|
-
].map do |ident|
|
108
|
-
Statement::VarDecl.new('int', ident, nil, @location)
|
109
|
-
end
|
110
|
-
|
111
|
-
stmts
|
112
|
-
end
|
113
|
-
|
114
|
-
def xmalloc
|
115
|
-
args = Statement::ArgumentList.new([
|
116
|
-
Expression::ArgDeclaration.new({
|
117
|
-
dtype: 'size_t', variables: [{ident: 'dummy'}] })
|
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 # class CBindings
|
142
|
-
|
143
|
-
class MethodDef
|
144
|
-
include Rubex::Helpers::Writers
|
145
|
-
# Ruby name of the method.
|
146
|
-
attr_reader :name
|
147
|
-
# Method arguments. Accessor because arguments need to be modified in
|
148
|
-
# case of auxillary C functions of attach classes.
|
149
|
-
attr_accessor :arg_list
|
150
|
-
# The statments/expressions contained within the method.
|
151
|
-
attr_reader :statements
|
152
|
-
# Symbol Table entry.
|
153
|
-
attr_reader :entry
|
154
|
-
# Instance of Scope::Local for this method.
|
155
|
-
attr_reader :scope
|
156
|
-
# Variable name that identifies 'self'
|
157
|
-
attr_reader :self_name
|
158
|
-
|
159
|
-
def initialize name, arg_list, statements
|
160
|
-
@name, @arg_list, @statements = name, arg_list, statements
|
161
|
-
@self_name = Rubex::ARG_PREFIX + "self"
|
162
|
-
end
|
163
|
-
|
164
|
-
def analyse_statement outer_scope
|
165
|
-
@entry = outer_scope.find @name
|
166
|
-
@scope = @entry.type.scope
|
167
|
-
@scope.type = @entry.type
|
168
|
-
@scope.self_name = @self_name
|
169
|
-
@arg_list = @entry.type.arg_list
|
170
|
-
@statements.each do |stat|
|
171
|
-
stat.analyse_statement @scope
|
172
|
-
end
|
173
|
-
end
|
174
|
-
|
175
|
-
# Option c_function - When set to true, certain code that is not required
|
176
|
-
# for Ruby methods will be generated too.
|
177
|
-
def generate_code code, c_function: false
|
178
|
-
code.block do
|
179
|
-
generate_function_definition code, c_function: c_function
|
180
|
-
end
|
181
|
-
end
|
182
|
-
|
183
|
-
def rescan_declarations scope
|
184
|
-
@statements.each do |stat|
|
185
|
-
stat.respond_to?(:rescan_declarations) and
|
186
|
-
stat.rescan_declarations(@scope)
|
187
|
-
end
|
188
|
-
end
|
189
|
-
|
190
|
-
private
|
191
|
-
def generate_function_definition code, c_function:
|
192
|
-
declare_types code, @scope
|
193
|
-
declare_args code unless c_function
|
194
|
-
declare_vars code, @scope
|
195
|
-
declare_carrays code, @scope
|
196
|
-
declare_ruby_objects code, @scope
|
197
|
-
declare_temps code, @scope
|
198
|
-
generate_arg_checking code unless c_function
|
199
|
-
init_args code unless c_function
|
200
|
-
declare_carrays_using_init_var_value code
|
201
|
-
generate_statements code
|
202
|
-
end
|
203
|
-
|
204
|
-
def declare_args code
|
205
|
-
@scope.arg_entries.each do |arg|
|
206
|
-
code.declare_variable type: arg.type.to_s, c_name: arg.c_name
|
207
|
-
end
|
208
|
-
end
|
209
|
-
|
210
|
-
def generate_statements code
|
211
|
-
@statements.each do |stat|
|
212
|
-
stat.generate_code code, @scope
|
213
|
-
end
|
214
|
-
end
|
215
|
-
|
216
|
-
def init_args code
|
217
|
-
@scope.arg_entries.each_with_index do |arg, i|
|
218
|
-
code << arg.c_name + '=' + arg.type.from_ruby_object("argv[#{i}]") + ';'
|
219
|
-
code.nl
|
220
|
-
end
|
221
|
-
end
|
222
|
-
|
223
|
-
def declare_carrays_using_init_var_value code
|
224
|
-
@scope.carray_entries.select { |s|
|
225
|
-
!s.type.dimension.is_a?(Rubex::AST::Expression::Literal::Base)
|
226
|
-
}. each do |arr|
|
227
|
-
type = arr.type.type.to_s
|
228
|
-
c_name = arr.c_name
|
229
|
-
dimension = arr.type.dimension.c_code(@scope)
|
230
|
-
value = arr.value.map { |a| a.c_code(@scope) } if arr.value
|
231
|
-
code.declare_carray(type: type, c_name: c_name, dimension: dimension,
|
232
|
-
value: value)
|
233
|
-
end
|
234
|
-
end
|
235
|
-
|
236
|
-
def generate_arg_checking code
|
237
|
-
code << 'if (argc < ' + @scope.arg_entries.size.to_s + ")"
|
238
|
-
code.block do
|
239
|
-
code << %Q{rb_raise(rb_eArgError, "Need #{@scope.arg_entries.size} args, not %d", argc);\n}
|
240
|
-
end
|
241
|
-
end
|
242
|
-
end
|
243
|
-
|
244
|
-
class RubyMethodDef < MethodDef
|
245
|
-
attr_reader :singleton
|
246
|
-
|
247
|
-
def initialize name, arg_list, statements, singleton: false
|
248
|
-
super(name, arg_list, statements)
|
249
|
-
@singleton = singleton
|
250
|
-
end
|
251
|
-
|
252
|
-
def analyse_statement local_scope
|
253
|
-
super
|
254
|
-
@entry.singleton = @singleton
|
255
|
-
end
|
256
|
-
|
257
|
-
def generate_code code
|
258
|
-
code.write_ruby_method_header(type: @entry.type.type.to_s,
|
259
|
-
c_name: @entry.c_name)
|
260
|
-
super
|
261
|
-
end
|
262
|
-
|
263
|
-
def == other
|
264
|
-
self.class == other.class && @name == other.name &&
|
265
|
-
@c_name == other.c_name && @arg_list == other.arg_list &&
|
266
|
-
@statements == other.statements && @entry == other.entry &&
|
267
|
-
@type == other.type
|
268
|
-
end
|
269
|
-
end # class RubyMethodDef
|
270
|
-
|
271
|
-
class CFunctionDef < MethodDef
|
272
|
-
attr_reader :type, :return_ptr_level
|
273
|
-
|
274
|
-
def initialize type, return_ptr_level, name, arg_list, statements
|
275
|
-
super(name, arg_list, statements)
|
276
|
-
@type = type
|
277
|
-
@return_ptr_level = return_ptr_level
|
278
|
-
end
|
279
|
-
|
280
|
-
def analyse_statement outer_scope, extern: false
|
281
|
-
super(outer_scope)
|
282
|
-
end
|
283
|
-
|
284
|
-
def generate_code code
|
285
|
-
code.write_c_method_header(type: @entry.type.type.to_s,
|
286
|
-
c_name: @entry.c_name, args: Helpers.create_arg_arrays(@arg_list))
|
287
|
-
super code, c_function: true
|
288
|
-
end
|
289
|
-
end # class CFunctionDef
|
290
|
-
|
291
|
-
class Klass
|
292
|
-
include Rubex::Helpers::Writers
|
293
|
-
# Stores the scope of the class. Rubex::SymbolTable::Scope::Klass.
|
294
|
-
attr_reader :scope
|
295
|
-
|
296
|
-
attr_reader :name
|
297
|
-
|
298
|
-
attr_reader :ancestor
|
299
|
-
|
300
|
-
attr_reader :statements
|
301
|
-
|
302
|
-
attr_reader :entry
|
303
|
-
|
304
|
-
# Name of the class. Ancestor can be Scope::Klass or String object
|
305
|
-
# depending on whether invoker is another higher level scope or
|
306
|
-
# the parser. Statements are the statements inside the class.
|
307
|
-
def initialize name, ancestor, statements
|
308
|
-
@name, @ancestor, @statements = name, ancestor, statements
|
309
|
-
@ancestor = 'Object' if @ancestor.nil?
|
310
|
-
end
|
311
|
-
|
312
|
-
def analyse_statement local_scope, attach_klass: false
|
313
|
-
@entry = local_scope.find(@name)
|
314
|
-
@scope = @entry.type.scope
|
315
|
-
@ancestor = @entry.type.ancestor
|
316
|
-
add_statement_symbols_to_symbol_table
|
317
|
-
if !attach_klass
|
318
|
-
@statements.each do |stat|
|
319
|
-
stat.analyse_statement @scope
|
320
|
-
end
|
321
|
-
end
|
322
|
-
end
|
323
|
-
|
324
|
-
def rescan_declarations local_scope
|
325
|
-
@statements.each do |stat|
|
326
|
-
stat&.rescan_declarations(@scope)
|
327
|
-
end
|
328
|
-
end
|
329
|
-
|
330
|
-
def generate_code code
|
331
|
-
@scope.begin_block_callbacks.each do |cb|
|
332
|
-
cb.generate_code code
|
333
|
-
end
|
334
|
-
|
335
|
-
@statements.each do |stat|
|
336
|
-
stat.generate_code code
|
337
|
-
end
|
338
|
-
end
|
339
|
-
|
340
|
-
protected
|
341
|
-
|
342
|
-
def add_statement_symbols_to_symbol_table
|
343
|
-
@statements.each do |stmt|
|
344
|
-
if ruby_method_or_c_function?(stmt)
|
345
|
-
f_name, f_scope = prepare_name_and_scope_of_functions(stmt)
|
346
|
-
if !auxillary_c_function_for_attached_klass?(f_name)
|
347
|
-
stmt.arg_list.analyse_statement(f_scope)
|
348
|
-
if stmt.is_a? Rubex::AST::TopStatement::RubyMethodDef
|
349
|
-
add_ruby_method_to_scope f_name, f_scope, stmt.arg_list
|
350
|
-
elsif stmt.is_a? Rubex::AST::TopStatement::CFunctionDef
|
351
|
-
return_type = Helpers.determine_dtype(stmt.type, stmt.return_ptr_level)
|
352
|
-
add_c_function_to_scope f_name, f_scope, stmt.arg_list, return_type
|
353
|
-
end
|
354
|
-
end
|
355
|
-
end
|
356
|
-
end
|
357
|
-
end
|
358
|
-
|
359
|
-
def auxillary_c_function_for_attached_klass? f_name
|
360
|
-
self.is_a?(AttachedKlass) and [
|
361
|
-
Rubex::ALLOC_FUNC_NAME, Rubex::DEALLOC_FUNC_NAME,
|
362
|
-
Rubex::MEMCOUNT_FUNC_NAME, Rubex::GET_STRUCT_FUNC_NAME
|
363
|
-
].include?(f_name)
|
364
|
-
end
|
365
|
-
|
366
|
-
def add_c_function_to_scope f_name, f_scope, arg_list, return_type
|
367
|
-
c_name = c_func_c_name(f_name)
|
368
|
-
arg_list.each do |arg|
|
369
|
-
if arg.entry.value
|
370
|
-
e = arg.entry
|
371
|
-
e.value = Rubex::Helpers.to_lhs_type(e, e.value)
|
372
|
-
end
|
373
|
-
end
|
374
|
-
@scope.add_c_method(
|
375
|
-
name: f_name,
|
376
|
-
c_name: c_name,
|
377
|
-
extern: false,
|
378
|
-
return_type: return_type,
|
379
|
-
arg_list: arg_list,
|
380
|
-
scope: f_scope
|
381
|
-
)
|
382
|
-
end
|
383
|
-
|
384
|
-
def add_ruby_method_to_scope f_name, f_scope, arg_list
|
385
|
-
c_name = Rubex::RUBY_FUNC_PREFIX + @name + "_" +
|
386
|
-
f_name.gsub("?", "_qmark").gsub("!", "_bang")
|
387
|
-
@scope.add_ruby_method(
|
388
|
-
name: f_name,
|
389
|
-
c_name: c_name,
|
390
|
-
scope: f_scope,
|
391
|
-
arg_list: arg_list
|
392
|
-
)
|
393
|
-
end
|
394
|
-
|
395
|
-
def prepare_name_and_scope_of_functions stmt
|
396
|
-
f_name = stmt.name
|
397
|
-
f_scope = Rubex::SymbolTable::Scope::Local.new f_name, @scope
|
398
|
-
[f_name, f_scope]
|
399
|
-
end
|
400
|
-
|
401
|
-
def ruby_method_or_c_function? stmt
|
402
|
-
stmt.is_a?(Rubex::AST::TopStatement::RubyMethodDef) ||
|
403
|
-
stmt.is_a?(Rubex::AST::TopStatement::CFunctionDef)
|
404
|
-
end
|
405
|
-
|
406
|
-
def c_func_c_name name
|
407
|
-
Rubex::C_FUNC_PREFIX + @name + "_" + name
|
408
|
-
end
|
409
|
-
end # class Klass
|
410
|
-
|
411
|
-
class AttachedKlass < Klass
|
412
|
-
|
413
|
-
attr_reader :attached_type
|
414
|
-
|
415
|
-
ALLOC_FUNC_NAME = Rubex::ALLOC_FUNC_NAME
|
416
|
-
DEALLOC_FUNC_NAME = Rubex::DEALLOC_FUNC_NAME
|
417
|
-
MEMCOUNT_FUNC_NAME = Rubex::MEMCOUNT_FUNC_NAME
|
418
|
-
GET_STRUCT_FUNC_NAME = Rubex::GET_STRUCT_FUNC_NAME
|
419
|
-
|
420
|
-
def initialize name, attached_type, ancestor, statements, location
|
421
|
-
@attached_type = attached_type
|
422
|
-
@location = location
|
423
|
-
super(name, ancestor, statements)
|
424
|
-
end
|
425
|
-
|
426
|
-
def analyse_statement outer_scope
|
427
|
-
super(outer_scope, attach_klass: true)
|
428
|
-
prepare_data_holding_struct
|
429
|
-
prepare_rb_data_type_t_struct
|
430
|
-
detach_and_modify_auxillary_c_functions_from_statements
|
431
|
-
add_auxillary_functions_to_klass_scope
|
432
|
-
prepare_auxillary_c_functions
|
433
|
-
@statements[1..-1].each do |stmt| # 0th stmt is the data struct
|
434
|
-
if ruby_method_or_c_func?(stmt)
|
435
|
-
rewrite_method_with_data_fetching stmt
|
436
|
-
end
|
437
|
-
stmt.analyse_statement @scope
|
438
|
-
end
|
439
|
-
analyse_auxillary_c_functions
|
440
|
-
end
|
441
|
-
|
442
|
-
def generate_code code
|
443
|
-
write_auxillary_c_functions code
|
444
|
-
write_data_type_t_struct code
|
445
|
-
write_get_struct_c_function code
|
446
|
-
write_alloc_c_function code
|
447
|
-
super
|
448
|
-
end
|
449
|
-
|
450
|
-
private
|
451
|
-
|
452
|
-
# Since auxillary functions are detached from the klass statements,
|
453
|
-
# analyse their arg_list separately and add function names to the
|
454
|
-
# class scope so that their statements can be analysed properly later.
|
455
|
-
def add_auxillary_functions_to_klass_scope
|
456
|
-
@auxillary_c_functions.each_value do |func|
|
457
|
-
f_name, f_scope = prepare_name_and_scope_of_functions func
|
458
|
-
func.arg_list.analyse_statement(f_scope)
|
459
|
-
return_type = Helpers.determine_dtype(func.type, func.return_ptr_level)
|
460
|
-
add_c_function_to_scope f_name, f_scope, func.arg_list, return_type
|
461
|
-
end
|
462
|
-
end
|
463
|
-
|
464
|
-
def analyse_auxillary_c_functions
|
465
|
-
@auxillary_c_functions.each_value do |func|
|
466
|
-
func.analyse_statement(@scope)
|
467
|
-
end
|
468
|
-
end
|
469
|
-
|
470
|
-
# Detach the user-supplied auxlically C functions from the class and
|
471
|
-
# store them in Hash @auxillary_c_functions. Make modifications to
|
472
|
-
# them if necessary and also set an ivar that indicates if an
|
473
|
-
# auxillary function is user-supplied or not.
|
474
|
-
def detach_and_modify_auxillary_c_functions_from_statements
|
475
|
-
@auxillary_c_functions = {}
|
476
|
-
|
477
|
-
indexes = []
|
478
|
-
@statements.each_with_index do |stmt, idx|
|
479
|
-
if stmt.is_a?(CFunctionDef)
|
480
|
-
if stmt.name == ALLOC_FUNC_NAME
|
481
|
-
@auxillary_c_functions[ALLOC_FUNC_NAME] = stmt
|
482
|
-
@user_defined_alloc = true
|
483
|
-
indexes << idx
|
484
|
-
elsif stmt.name == DEALLOC_FUNC_NAME
|
485
|
-
@auxillary_c_functions[DEALLOC_FUNC_NAME] = stmt
|
486
|
-
@user_defined_dealloc = true
|
487
|
-
modify_dealloc_func stmt
|
488
|
-
indexes << idx
|
489
|
-
elsif stmt.name == MEMCOUNT_FUNC_NAME
|
490
|
-
@auxillary_c_functions[MEMCOUNT_FUNC_NAME] = stmt
|
491
|
-
@user_defined_memcount = true
|
492
|
-
indexes << idx
|
493
|
-
elsif stmt.name == GET_STRUCT_FUNC_NAME
|
494
|
-
@auxillary_c_functions[GET_STRUCT_FUNC_NAME] = stmt
|
495
|
-
@user_defined_get_struct = true
|
496
|
-
indexes << idx
|
497
|
-
end
|
498
|
-
end
|
499
|
-
end
|
500
|
-
|
501
|
-
indexes.each do |idx|
|
502
|
-
@statements.delete_at idx
|
503
|
-
end
|
504
|
-
end
|
505
|
-
|
506
|
-
def write_auxillary_c_functions code
|
507
|
-
write_dealloc_c_function code
|
508
|
-
write_memcount_c_function code
|
509
|
-
end
|
510
|
-
|
511
|
-
# Actually write the alloc function into C code.
|
512
|
-
def write_alloc_c_function code
|
513
|
-
if user_defined_alloc?
|
514
|
-
@auxillary_c_functions[ALLOC_FUNC_NAME].generate_code code
|
515
|
-
else
|
516
|
-
code.write_c_method_header(
|
517
|
-
type: @alloc_c_func.type.type.to_s,
|
518
|
-
c_name: @alloc_c_func.c_name,
|
519
|
-
args: Helpers.create_arg_arrays(@alloc_c_func.type.arg_list))
|
520
|
-
code.block do
|
521
|
-
lines = ""
|
522
|
-
lines << "#{@data_struct.entry.c_name} *data;\n\n"
|
523
|
-
|
524
|
-
lines << "data = (#{@data_struct.entry.c_name}*)xmalloc("
|
525
|
-
lines << "sizeof(#{@data_struct.entry.c_name}));\n"
|
526
|
-
|
527
|
-
lines << member_struct_allocations
|
528
|
-
|
529
|
-
lines << "return TypedData_Wrap_Struct("
|
530
|
-
lines << "#{@alloc_c_func.type.arg_list[0].entry.c_name},"
|
531
|
-
lines << "&#{@data_type_t}, data);\n"
|
532
|
-
|
533
|
-
code << lines
|
534
|
-
end
|
535
|
-
end
|
536
|
-
end
|
537
|
-
|
538
|
-
#TODO: modify for supporting inheritance
|
539
|
-
def member_struct_allocations
|
540
|
-
c_name = @scope.find(@attached_type).c_name
|
541
|
-
"data->#{Rubex::POINTER_PREFIX + @attached_type} = (#{c_name}*)xmalloc(sizeof(#{c_name}));\n"
|
542
|
-
end
|
543
|
-
|
544
|
-
# Actually write the dealloc function into C code.
|
545
|
-
def write_dealloc_c_function code
|
546
|
-
if user_defined_dealloc?
|
547
|
-
@auxillary_c_functions[DEALLOC_FUNC_NAME].generate_code code
|
548
|
-
else
|
549
|
-
# TODO: define dealloc if user hasnt supplied.
|
550
|
-
end
|
551
|
-
end
|
552
|
-
|
553
|
-
# Actually write the memcount function into C code.
|
554
|
-
def write_memcount_c_function code
|
555
|
-
if user_defined_memcount?
|
556
|
-
@auxillary_c_functions[MEMCOUNT_FUNC_NAME].generate_code code
|
557
|
-
else
|
558
|
-
code.write_c_method_header(
|
559
|
-
type: @memcount_c_func.type.type.to_s,
|
560
|
-
c_name: @memcount_c_func.c_name,
|
561
|
-
args: Helpers.create_arg_arrays(@memcount_c_func.type.arg_list))
|
562
|
-
code.block do
|
563
|
-
code << "return sizeof(#{@memcount_c_func.type.arg_list[0].entry.c_name})"
|
564
|
-
code.colon
|
565
|
-
code.nl
|
566
|
-
end
|
567
|
-
end
|
568
|
-
end
|
569
|
-
|
570
|
-
# Actually write the get_struct function into C code.
|
571
|
-
def write_get_struct_c_function code
|
572
|
-
if user_defined_get_struct?
|
573
|
-
@auxillary_c_functions[GET_STRUCT_FUNC_NAME].generate_code code
|
574
|
-
else
|
575
|
-
code.write_c_method_header(
|
576
|
-
type: @get_struct_c_func.type.type.to_s,
|
577
|
-
c_name: @get_struct_c_func.c_name,
|
578
|
-
args: Helpers.create_arg_arrays(@get_struct_c_func.type.arg_list))
|
579
|
-
code.block do
|
580
|
-
lines = ""
|
581
|
-
lines << "#{@data_struct.entry.c_name} *data;\n\n"
|
582
|
-
lines << "TypedData_Get_Struct("
|
583
|
-
lines << "#{@get_struct_c_func.type.arg_list[0].entry.c_name}, "
|
584
|
-
lines << "#{@data_struct.entry.c_name}, &#{@data_type_t}, data);\n"
|
585
|
-
lines << "return data;\n"
|
586
|
-
|
587
|
-
code << lines
|
588
|
-
end
|
589
|
-
end
|
590
|
-
end
|
591
|
-
|
592
|
-
def write_data_type_t_struct code
|
593
|
-
decl = ""
|
594
|
-
decl << "static const rb_data_type_t #{@data_type_t} = {\n"
|
595
|
-
decl << " \"#{@name}\",\n"
|
596
|
-
decl << " {0, #{@dealloc_c_func.c_name}, #{@memcount_c_func.c_name},\n"
|
597
|
-
decl << " 0}, 0, 0, RUBY_TYPED_FREE_IMMEDIATELY\n"
|
598
|
-
decl << "};\n"
|
599
|
-
|
600
|
-
code << decl
|
601
|
-
code.new_line
|
602
|
-
end
|
603
|
-
|
604
|
-
# Prepare the data holding struct 'data' that will hold a pointer to the
|
605
|
-
# struct that is attached to this class.
|
606
|
-
def prepare_data_holding_struct
|
607
|
-
struct_name = @name + "_data_struct"
|
608
|
-
declarations = declarations_for_data_struct
|
609
|
-
@data_struct = Statement::CStructOrUnionDef.new(
|
610
|
-
:struct, struct_name, declarations, @location)
|
611
|
-
@data_struct.analyse_statement(@scope)
|
612
|
-
@statements.unshift @data_struct
|
613
|
-
end
|
614
|
-
|
615
|
-
# TODO: support inherited attached structs.
|
616
|
-
def declarations_for_data_struct
|
617
|
-
stmts = []
|
618
|
-
stmts << Statement::CPtrDecl.new(@attached_type, @attached_type, nil,
|
619
|
-
"*", @location)
|
620
|
-
|
621
|
-
stmts
|
622
|
-
end
|
623
|
-
|
624
|
-
def prepare_rb_data_type_t_struct
|
625
|
-
@data_type_t = Rubex::ATTACH_CLASS_PREFIX + "_" + @name + "_data_type_t"
|
626
|
-
end
|
627
|
-
|
628
|
-
# Prepare auxillary function in case they have not been supplied by user
|
629
|
-
# and create ivars for their Symbol Table entries for easy accesss later.
|
630
|
-
def prepare_auxillary_c_functions
|
631
|
-
prepare_alloc_c_function
|
632
|
-
prepare_memcount_c_function
|
633
|
-
prepare_deallocation_c_function
|
634
|
-
prepare_get_struct_c_function
|
635
|
-
end
|
636
|
-
|
637
|
-
def ruby_method_or_c_func? stmt
|
638
|
-
stmt.is_a?(RubyMethodDef) || stmt.is_a?(CFunctionDef)
|
639
|
-
end
|
640
|
-
|
641
|
-
# Rewrite method `stmt` so that the `data` variable becomes available
|
642
|
-
# inside the scope of the method.
|
643
|
-
def rewrite_method_with_data_fetching stmt
|
644
|
-
data_stmt = Statement::CPtrDecl.new(@data_struct.name, 'data',
|
645
|
-
get_struct_func_call(stmt), "*", @location)
|
646
|
-
stmt.statements.unshift data_stmt
|
647
|
-
end
|
648
|
-
|
649
|
-
def get_struct_func_call stmt
|
650
|
-
Expression::CommandCall.new(nil, @get_struct_c_func.name,
|
651
|
-
Statement::ArgumentList.new([]))
|
652
|
-
end
|
653
|
-
|
654
|
-
# Create an alloc function if it is not supplied by user.
|
655
|
-
def prepare_alloc_c_function
|
656
|
-
if user_defined_alloc?
|
657
|
-
@alloc_c_func = @scope.find(ALLOC_FUNC_NAME)
|
658
|
-
else
|
659
|
-
c_name = c_func_c_name(ALLOC_FUNC_NAME)
|
660
|
-
scope = Rubex::SymbolTable::Scope::Local.new(ALLOC_FUNC_NAME, @scope)
|
661
|
-
arg_list = Statement::ArgumentList.new([
|
662
|
-
Expression::ArgDeclaration.new({
|
663
|
-
dtype: 'object',
|
664
|
-
variables: [
|
665
|
-
{
|
666
|
-
ident: 'self'
|
667
|
-
}
|
668
|
-
]
|
669
|
-
})
|
670
|
-
])
|
671
|
-
arg_list.analyse_statement(scope)
|
672
|
-
@alloc_c_func = @scope.add_c_method(
|
673
|
-
name: ALLOC_FUNC_NAME,
|
674
|
-
c_name: c_name,
|
675
|
-
arg_list: arg_list,
|
676
|
-
return_type: DataType::RubyObject.new,
|
677
|
-
scope: scope)
|
678
|
-
end
|
679
|
-
end
|
680
|
-
|
681
|
-
# Create a memcount function if it is not supplied by user.
|
682
|
-
def prepare_memcount_c_function
|
683
|
-
if user_defined_memcount?
|
684
|
-
@memcount_c_func = @scope.find(MEMCOUNT_FUNC_NAME)
|
685
|
-
else
|
686
|
-
c_name = c_func_c_name(MEMCOUNT_FUNC_NAME)
|
687
|
-
scope = Rubex::SymbolTable::Scope::Local.new(MEMCOUNT_FUNC_NAME, @scope)
|
688
|
-
arg_list = Statement::ArgumentList.new([
|
689
|
-
Expression::ArgDeclaration.new({
|
690
|
-
dtype: "void",
|
691
|
-
variables: [
|
692
|
-
{
|
693
|
-
ptr_level: "*",
|
694
|
-
ident: "raw_data"
|
695
|
-
}
|
696
|
-
]
|
697
|
-
})
|
698
|
-
])
|
699
|
-
arg_list.analyse_statement(scope)
|
700
|
-
@memcount_c_func = @scope.add_c_method(
|
701
|
-
name: MEMCOUNT_FUNC_NAME,
|
702
|
-
c_name: c_name,
|
703
|
-
arg_list: arg_list,
|
704
|
-
return_type: DataType::Size_t.new,
|
705
|
-
scope: scope)
|
706
|
-
end
|
707
|
-
end
|
708
|
-
|
709
|
-
# Create a deallocate function if it is not supplied by user.
|
710
|
-
def prepare_deallocation_c_function
|
711
|
-
if user_defined_dealloc?
|
712
|
-
@dealloc_c_func = @scope.find(DEALLOC_FUNC_NAME)
|
713
|
-
else
|
714
|
-
c_name = c_func_c_name(DEALLOC_FUNC_NAME)
|
715
|
-
scope = Rubex::SymbolTable::Scope::Local.new(DEALLOC_FUNC_NAME, @scope)
|
716
|
-
arg_list = Statement::ArgumentList.new([
|
717
|
-
Expression::ArgDeclaration.new({
|
718
|
-
dtype: "void",
|
719
|
-
variables: [
|
720
|
-
{
|
721
|
-
ptr_level: "*",
|
722
|
-
ident: "raw_data"
|
723
|
-
}
|
724
|
-
]
|
725
|
-
})
|
726
|
-
])
|
727
|
-
arg_list.analyse_statement(scope)
|
728
|
-
@dealloc_c_func = @scope.add_c_method(
|
729
|
-
name: DEALLOC_FUNC_NAME,
|
730
|
-
c_name: c_name,
|
731
|
-
return_type: DataType::Void.new,
|
732
|
-
scope: scope,
|
733
|
-
arg_list: arg_list)
|
734
|
-
end
|
735
|
-
end
|
736
|
-
|
737
|
-
# Create a get_struct function if it is not supplied by user.
|
738
|
-
def prepare_get_struct_c_function
|
739
|
-
if user_defined_get_struct?
|
740
|
-
@get_struct_c_func = @scope.find(GET_STRUCT_FUNC_NAME)
|
741
|
-
else
|
742
|
-
c_name = c_func_c_name(GET_STRUCT_FUNC_NAME)
|
743
|
-
scope = Rubex::SymbolTable::Scope::Local.new(
|
744
|
-
GET_STRUCT_FUNC_NAME, @scope)
|
745
|
-
arg_list = Statement::ArgumentList.new([
|
746
|
-
Expression::ArgDeclaration.new({
|
747
|
-
dtype: "object",
|
748
|
-
variables: [
|
749
|
-
{
|
750
|
-
ident: "obj"
|
751
|
-
}
|
752
|
-
]
|
753
|
-
})
|
754
|
-
])
|
755
|
-
arg_list.analyse_statement(scope)
|
756
|
-
return_type = DataType::CPtr.new(
|
757
|
-
DataType::CStructOrUnion.new(
|
758
|
-
:struct, @data_struct.name, @data_struct.entry.c_name, nil)
|
759
|
-
)
|
760
|
-
@get_struct_c_func = @scope.add_c_method(
|
761
|
-
name: GET_STRUCT_FUNC_NAME,
|
762
|
-
c_name: c_name,
|
763
|
-
return_type: return_type,
|
764
|
-
arg_list: arg_list,
|
765
|
-
scope: scope
|
766
|
-
)
|
767
|
-
end
|
768
|
-
end
|
769
|
-
|
770
|
-
# Modify the dealloc function by adding an argument of type void* so
|
771
|
-
# that it is compatible with what Ruby expects. This is done so that
|
772
|
-
# the user is not burdened with additional knowledge of knowing the
|
773
|
-
# the correct argument for deallocate.
|
774
|
-
def modify_dealloc_func func
|
775
|
-
func.arg_list = Statement::ArgumentList.new([
|
776
|
-
Expression::ArgDeclaration.new({
|
777
|
-
dtype: "void",
|
778
|
-
variables: [
|
779
|
-
{
|
780
|
-
ptr_level: "*",
|
781
|
-
ident: "raw_data"
|
782
|
-
}
|
783
|
-
]
|
784
|
-
})
|
785
|
-
])
|
786
|
-
value = Expression::Name.new('raw_data')
|
787
|
-
value.typecast = Expression::Typecast.new(@data_struct.name, "*")
|
788
|
-
data_var = Statement::CPtrDecl.new(@data_struct.name, 'data', value,
|
789
|
-
"*", @location)
|
790
|
-
xfree = Expression::CommandCall.new(nil, 'xfree',
|
791
|
-
[Expression::Name.new('data')])
|
792
|
-
data_xfree = Statement::Expression.new xfree, @location
|
793
|
-
func.statements.unshift data_var
|
794
|
-
func.statements.push data_xfree
|
795
|
-
end
|
796
|
-
|
797
|
-
def user_defined_dealloc?
|
798
|
-
@user_defined_dealloc
|
799
|
-
end
|
800
|
-
|
801
|
-
def user_defined_alloc?
|
802
|
-
@user_defined_alloc
|
803
|
-
end
|
804
|
-
|
805
|
-
def user_defined_memcount?
|
806
|
-
@user_defined_memcount
|
807
|
-
end
|
808
|
-
|
809
|
-
def user_defined_get_struct?
|
810
|
-
@user_defined_get_struct
|
811
|
-
end
|
812
|
-
end # class AttachedKlass
|
813
|
-
end # module TopStatement
|
814
|
-
end # module AST
|
815
|
-
end # module Rubex
|
1
|
+
Dir['./lib/rubex/ast/top_statement/**/*.rb'].sort.each { |f| require f }
|