rubex 0.0.1 → 0.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.
Files changed (135) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +4 -0
  3. data/.travis.yml +14 -0
  4. data/CONTRIBUTING.md +101 -0
  5. data/HISTORY.md +3 -0
  6. data/README.md +112 -297
  7. data/REFERENCE.md +753 -0
  8. data/Rakefile +4 -1
  9. data/TUTORIAL.md +234 -0
  10. data/bin/rubex +1 -1
  11. data/docs/_config.yml +1 -0
  12. data/docs/index.html +1 -0
  13. data/examples/c_struct_interface/c_struct_interface.rb +6 -0
  14. data/examples/c_struct_interface/c_struct_interface.rubex +47 -0
  15. data/examples/linked_list/linked_list.rubex +39 -0
  16. data/examples/linked_list/rb_linked_list.rb +8 -0
  17. data/examples/rcsv wrapper/rcsv/README.md +1 -0
  18. data/examples/rcsv wrapper/rcsv/Rakefile +7 -0
  19. data/examples/rcsv wrapper/rcsv/ext/rcsv/extconf.rb +3 -0
  20. data/examples/rcsv wrapper/rcsv/ext/rcsv/rcsv.c +302 -0
  21. data/examples/rcsv wrapper/rcsv/ext/rcsv/rcsv.rubex +124 -0
  22. data/examples/rcsv wrapper/rcsv/lib/rcsv.rb +8 -0
  23. data/examples/rcsv wrapper/rcsv/lib/rcsv.so +0 -0
  24. data/examples/rcsv wrapper/rcsv/lib/rcsv/version.rb +1 -0
  25. data/examples/rcsv wrapper/rcsv/rcsv.gemspec +27 -0
  26. data/examples/rcsv wrapper/rcsv/spec/rcsv.csv +5 -0
  27. data/examples/rcsv wrapper/rcsv/spec/rcsv_spec.rb +17 -0
  28. data/examples/rcsv wrapper/rcsv/spec/spec_helper.rb +6 -0
  29. data/{spec/fixtures/basic_ruby_method/Makefile → examples/rcsv wrapper/rcsv/tmp/x86_64-linux/rcsv/2.3.3/Makefile } +20 -20
  30. data/examples/rcsv wrapper/rcsv/tmp/x86_64-linux/rcsv/2.3.3/rcsv.o +0 -0
  31. data/examples/rcsv wrapper/rcsv/tmp/x86_64-linux/rcsv/2.3.3/rcsv.so +0 -0
  32. data/examples/rcsv wrapper/rcsv/tmp/x86_64-linux/stage/lib/rcsv.so +0 -0
  33. data/lib/rubex.rb +6 -50
  34. data/lib/rubex/ast.rb +1 -3
  35. data/lib/rubex/ast/expression.rb +1257 -8
  36. data/lib/rubex/ast/node.rb +226 -28
  37. data/lib/rubex/ast/statement.rb +1162 -35
  38. data/lib/rubex/ast/top_statement.rb +815 -0
  39. data/lib/rubex/code_writer.rb +103 -26
  40. data/lib/rubex/compiler.rb +72 -0
  41. data/lib/rubex/compiler_config.rb +19 -0
  42. data/lib/rubex/constants.rb +145 -8
  43. data/lib/rubex/data_type.rb +667 -4
  44. data/lib/rubex/error.rb +15 -0
  45. data/lib/rubex/helpers.rb +154 -0
  46. data/lib/rubex/lexer.rex +186 -22
  47. data/lib/rubex/lexer.rex.rb +261 -35
  48. data/lib/rubex/parser.racc +876 -28
  49. data/lib/rubex/parser.racc.rb +2845 -90
  50. data/lib/rubex/rake_task.rb +34 -0
  51. data/lib/rubex/symbol_table/entry.rb +17 -3
  52. data/lib/rubex/symbol_table/scope.rb +298 -25
  53. data/lib/rubex/version.rb +1 -1
  54. data/rubex.gemspec +11 -3
  55. data/spec/basic_ruby_method_spec.rb +15 -21
  56. data/spec/binding_ptr_args_spec.rb +33 -0
  57. data/spec/bitwise_operators_spec.rb +40 -0
  58. data/spec/blocks_spec.rb +35 -0
  59. data/spec/c_bindings_spec.rb +36 -0
  60. data/spec/c_constants_spec.rb +33 -0
  61. data/spec/c_function_ptrs_spec.rb +38 -0
  62. data/spec/c_functions_spec.rb +35 -0
  63. data/spec/c_struct_interface_spec.rb +38 -0
  64. data/spec/call_by_reference_spec.rb +33 -0
  65. data/spec/class_methods_spec.rb +33 -0
  66. data/spec/class_spec.rb +40 -0
  67. data/spec/comments_spec.rb +33 -0
  68. data/spec/default_args_spec.rb +37 -0
  69. data/spec/error_handling_spec.rb +42 -0
  70. data/spec/examples_spec.rb +52 -0
  71. data/spec/expressions_spec.rb +33 -0
  72. data/spec/fixtures/basic_ruby_method/basic_ruby_method.rubex +2 -0
  73. data/spec/fixtures/binding_ptr_args/binding_ptr_args.rubex +30 -0
  74. data/spec/fixtures/bitwise_operators/bitwise_operators.rubex +40 -0
  75. data/spec/fixtures/blocks/blocks.rubex +11 -0
  76. data/spec/fixtures/c_bindings/c_bindings.rubex +58 -0
  77. data/spec/fixtures/c_constants/c_constants.rubex +7 -0
  78. data/spec/fixtures/c_function_ptrs/c_function_ptrs.rubex +52 -0
  79. data/spec/fixtures/c_functions/c_functions.rubex +25 -0
  80. data/spec/fixtures/c_struct_interface/c_struct_interface.rubex +34 -0
  81. data/spec/fixtures/call_by_reference/call_by_reference.rubex +30 -0
  82. data/spec/fixtures/class/class.rubex +20 -0
  83. data/spec/fixtures/class_methods/class_methods.rubex +12 -0
  84. data/spec/fixtures/comments/comments.rubex +9 -0
  85. data/spec/fixtures/default_args/default_args.rubex +11 -0
  86. data/spec/fixtures/error_handling/error_handling.rubex +54 -0
  87. data/spec/fixtures/examples/array_to_hash.rubex +14 -0
  88. data/spec/fixtures/examples/rcsv.csv +5 -0
  89. data/spec/fixtures/examples/rcsv.rubex +329 -0
  90. data/spec/fixtures/expressions/expressions.rubex +10 -0
  91. data/spec/fixtures/if_else/if_else.rubex +77 -0
  92. data/spec/fixtures/implicit_lib_include/implicit_lib_include.rubex +15 -0
  93. data/spec/fixtures/init_ruby_objects_with_literal_syntax/init_ruby_objects_with_literal_syntax.rubex +17 -0
  94. data/spec/fixtures/loops/loops.rubex +33 -0
  95. data/spec/fixtures/recursion/recursion.rubex +9 -0
  96. data/spec/fixtures/ruby_constant_method_calls/ruby_constant_method_calls.rubex +17 -0
  97. data/spec/fixtures/ruby_operators/ruby_operators.rubex +29 -0
  98. data/spec/fixtures/ruby_raise/ruby_raise.rubex +13 -0
  99. data/spec/fixtures/ruby_strings/ruby_strings.rubex +19 -0
  100. data/spec/fixtures/ruby_strings/string_blank_bm.rb +37 -0
  101. data/spec/fixtures/ruby_symbols/ruby_symbols.rubex +12 -0
  102. data/spec/fixtures/ruby_types/ruby_types.rubex +15 -0
  103. data/spec/fixtures/statement_expression/statement_expression.rubex +23 -0
  104. data/spec/fixtures/static_array/static_array.rubex +20 -0
  105. data/spec/fixtures/string_literals/string_literals.rubex +15 -0
  106. data/spec/fixtures/struct/struct.rubex +82 -0
  107. data/spec/fixtures/typecasting/typecasting.rubex +23 -0
  108. data/spec/fixtures/var_declarations/var_declarations.rubex +39 -0
  109. data/spec/if_else_spec.rb +39 -0
  110. data/spec/implicit_lib_include_spec.rb +33 -0
  111. data/spec/init_ruby_objects_with_literal_syntax_spec.rb +39 -0
  112. data/spec/loops_spec.rb +34 -0
  113. data/spec/recursion_spec.rb +35 -0
  114. data/spec/ruby_constant_method_calls_spec.rb +35 -0
  115. data/spec/ruby_operators_spec.rb +40 -0
  116. data/spec/ruby_raise_spec.rb +35 -0
  117. data/spec/ruby_strings_spec.rb +33 -0
  118. data/spec/ruby_symbols_spec.rb +37 -0
  119. data/spec/ruby_types_spec.rb +35 -0
  120. data/spec/spec_helper.rb +54 -1
  121. data/spec/statement_expression_spec.rb +34 -0
  122. data/spec/static_array_spec.rb +33 -0
  123. data/spec/string_literals_spec.rb +34 -0
  124. data/spec/struct_spec.rb +36 -0
  125. data/spec/typecasting_spec.rb +38 -0
  126. data/spec/var_declarions_spec.rb +35 -0
  127. metadata +255 -29
  128. data/lib/rubex/ast/argument_list.rb +0 -20
  129. data/lib/rubex/ast/c_base_type.rb +0 -11
  130. data/lib/rubex/ast/ruby_method_def.rb +0 -84
  131. data/spec/fixtures/basic_ruby_method/basic.rb +0 -3
  132. data/spec/fixtures/basic_ruby_method/basic_ruby_method.c +0 -16
  133. data/spec/fixtures/basic_ruby_method/basic_ruby_method.o +0 -0
  134. data/spec/fixtures/basic_ruby_method/basic_ruby_method.so +0 -0
  135. data/spec/fixtures/basic_ruby_method/extconf.rb +0 -3
@@ -4,64 +4,141 @@ module Rubex
4
4
 
5
5
  def initialize target_name
6
6
  @code = "/* C extension for #{target_name}.\n"\
7
- "This file in generated by Rubex. Do not change!\n"\
8
- "*/\n"
7
+ "This file in generated by Rubex::Compiler. Do not change!\n"\
8
+ "File generation time: #{Time.now}."\
9
+ "*/\n\n"
9
10
  @indent = 0
10
11
  end
11
12
 
12
- def write_func_declaration return_type, c_name, args=""
13
- write_func_prototype return_type, c_name, args
13
+ # type - Return type of the method.
14
+ # c_name - C Name.
15
+ # args - Array of Arrays containing data type and variable name.
16
+ def write_func_declaration type:, c_name:, args: [], static: true
17
+ write_func_prototype type, c_name, args, static: static
14
18
  @code << ";"
15
19
  new_line
16
20
  end
17
21
 
18
- def write_func_definition_header return_type, c_name, args=""
19
- write_func_prototype return_type, c_name, args
20
- @code << "\n"
21
- @code << "{\n"
22
+ def colon
23
+ @code << ";"
24
+ new_line
25
+ end
26
+
27
+ def c_macro macro
28
+ @code << "#define #{macro}"
29
+ new_line
30
+ end
31
+
32
+ def write_c_method_header type: , c_name: , args: [], static: true
33
+ write_func_prototype type, c_name, args, static: static
34
+ end
35
+
36
+ def write_ruby_method_header type: , c_name:
37
+ args = [["int", "argc"], ["VALUE*", "argv"],
38
+ ["VALUE", "#{Rubex::ARG_PREFIX + "self"}"]]
39
+ write_func_prototype type, c_name, args
40
+ end
41
+
42
+ def write_location location
43
+ new_line
44
+ self << "/* Rubex file location: #{location} */"
45
+ new_line
46
+ end
47
+
48
+ def declare_variable type:, c_name:
49
+ @code << " "*@indent + "#{type} #{c_name};"
50
+ new_line
51
+ end
52
+
53
+ def declare_func_ptr var:
54
+ type = var.type
55
+ func = type.base_type
56
+ @code << " "*@indent
57
+ @code << "#{func.type.to_s} (#{type.ptr_level}#{func.c_name}) "
58
+ @code << "(" + func.arg_list.map { |e| e.type.to_s }.join(',') + ")"
59
+ @code << ";"
60
+ nl
22
61
  end
23
62
 
24
- def declare_variable var
25
- @code << "#{var.type.to_s} #{var.c_name};\n"
63
+ def declare_carray type:, c_name:, dimension:, value: nil
64
+ stmt = "#{type} #{c_name}[#{dimension}]"
65
+ stmt << " = {" + value.join(',') + "}" if value
66
+ stmt << ";"
67
+ self << stmt
68
+ nl
26
69
  end
27
-
28
- def << s
29
- @code << s
70
+
71
+ def init_variable lhs: , rhs:
72
+ stat = " "*@indent + "#{lhs} = #{rhs};"
73
+ @code << stat
74
+ new_line
75
+ end
76
+
77
+ def << str
78
+ str.each_line do |s|
79
+ @code << " "*@indent
80
+ @code << s
81
+ end
30
82
  end
31
83
 
32
84
  def new_line
33
85
  @code << "\n"
34
86
  end
87
+ alias :nl :new_line
35
88
 
36
89
  def indent
37
- @indent += 1
90
+ @indent += 2
38
91
  end
39
92
 
40
93
  def dedent
41
94
  raise "Cannot dedent, already 0." if @indent == 0
42
- @indent -= 1
95
+ @indent -= 2
43
96
  end
44
97
 
45
- def define_instance_method_under scope, name, c_name
46
- @code << "rb_define_method(" + scope.c_name + " ,\"" + name + "\", " +
47
- c_name + ", -1);\n"
98
+ def write_instance_method klass: , method_name: , method_c_name:
99
+ @code << " "*@indent + "rb_define_method(" + klass + " ,\"" +
100
+ method_name + "\", " + method_c_name + ", -1);"
101
+ new_line
102
+ end
103
+
104
+ def write_singleton_method klass:, method_name:, method_c_name:
105
+ @code << " "*@indent + "rb_define_singleton_method(" + klass + " ,\"" +
106
+ method_name + "\", " + method_c_name + ", -1);"
107
+ new_line
48
108
  end
49
109
 
50
110
  def to_s
51
111
  @code
52
112
  end
53
113
 
114
+ def lbrace
115
+ @code << (" "*@indent + "{")
116
+ end
117
+
118
+ def rbrace
119
+ @code << (" "*@indent + "}")
120
+ end
121
+
122
+ def block str="", &block
123
+ new_line
124
+ lbrace
125
+ indent
126
+ new_line
127
+ block.call
128
+ dedent
129
+ rbrace
130
+ @code << str
131
+ new_line
132
+ new_line
133
+ end
134
+
54
135
  private
55
136
 
56
- def write_func_prototype return_type, c_name, args
57
- @code << "#{return_type} #{c_name} "
137
+ def write_func_prototype return_type, c_name, args, static: true
138
+ @code << "#{static ? "static " : ""}#{return_type} #{c_name} "
58
139
  @code << "("
59
- if args.empty?
60
- @code << "int argc, VALUE* argv, VALUE #{Rubex::ARG_PREFIX}self"
61
- else
62
- @code << args
63
- end
64
- @code << ")"
140
+ @code << args.map { |type_arg| type_arg.join(" ") }.join(",")
141
+ @code << ")"
65
142
  end
66
143
  end
67
144
  end
@@ -0,0 +1,72 @@
1
+ module Rubex
2
+ class Compiler
3
+ CONFIG = Rubex::CompilerConfig.new
4
+
5
+ class << self
6
+ def compile path, test: false, directory: nil
7
+ tree = ast path, test: test
8
+ target_name = extract_target_name path
9
+ code = generate_code tree, target_name
10
+ ext = extconf target_name, directory: directory
11
+ CONFIG.flush
12
+
13
+ return [tree, code, ext] if test
14
+ write_files target_name, code, ext, directory: directory
15
+ end
16
+
17
+ def ast path, test: false
18
+ if test
19
+ parser = Rubex::Parser.new
20
+ parser.parse(path)
21
+ parser.do_parse
22
+ else
23
+ begin
24
+ parser = Rubex::Parser.new
25
+ parser.parse(path)
26
+ parser.do_parse
27
+ rescue Racc::ParseError => e
28
+ error_msg = "\nPARSE ERROR:\n"
29
+ error_msg << "Line: #{parser.string.split("\n")[parser.lineno-1]}\n"
30
+ error_msg << "Location: #{parser.location}\n"
31
+ error_msg << "Error:\n#{e}"
32
+ STDERR.puts error_msg
33
+ end
34
+ end
35
+ end
36
+
37
+ def extconf target_name, directory: nil
38
+ path = directory ? directory : "#{Dir.pwd}/#{target_name}"
39
+ extconf = ""
40
+ extconf << "require 'mkmf'\n"
41
+ extconf << "$libs += \" #{CONFIG.link_flags}\"\n"
42
+ extconf << "create_makefile('#{path}/#{target_name}')\n"
43
+ extconf
44
+ end
45
+
46
+ def generate_code tree, target_name
47
+ code = Rubex::CodeWriter.new target_name
48
+ raise "Must be a Rubex::AST::Node, not #{tree.class}" unless
49
+ tree.is_a? Rubex::AST::Node
50
+ tree.process_statements target_name, code
51
+ code
52
+ end
53
+
54
+ def extract_target_name path
55
+ File.basename(path).split('.')[0]
56
+ end
57
+
58
+ def write_files target_name, code, ext, directory: nil
59
+ path = directory ? directory : "#{Dir.pwd}/#{target_name}"
60
+ Dir.mkdir(path) unless directory
61
+
62
+ code_file = File.new "#{path}/#{target_name}.c", "w+"
63
+ code_file.puts code.to_s
64
+ code_file.close
65
+
66
+ extconf_file = File.new "#{path}/extconf.rb", "w+"
67
+ extconf_file.puts ext
68
+ extconf_file.close
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,19 @@
1
+ module Rubex
2
+ class CompilerConfig
3
+ def initialize
4
+ @links = []
5
+ end
6
+
7
+ def add_link link_str
8
+ @links << link_str
9
+ end
10
+
11
+ def link_flags
12
+ @links.map { |l| l.dup.prepend('-l') }.join(' ')
13
+ end
14
+
15
+ def flush
16
+ @links = []
17
+ end
18
+ end
19
+ end
@@ -1,17 +1,154 @@
1
1
  module Rubex
2
2
  RUBEX_PREFIX = "__rubex_"
3
-
4
- FUNC_PREFIX = RUBEX_PREFIX + "f_"
3
+ GLOBAL_PREFIX = "global_"
4
+
5
+ TEMP_PREFIX = RUBEX_PREFIX + "temp_"
6
+ RUBY_FUNC_PREFIX = RUBEX_PREFIX + "rb_f_"
7
+ C_FUNC_PREFIX = RUBEX_PREFIX + "c_f_"
5
8
  VAR_PREFIX = RUBEX_PREFIX + "v_"
6
- CLASS_PREFIX = RUBEX_PREFIX + "c_"
9
+ RUBY_CLASS_PREFIX = RUBEX_PREFIX + "rb_cls_"
10
+ ATTACH_CLASS_PREFIX = RUBEX_PREFIX + "attach_rb_cls"
7
11
  ARG_PREFIX = RUBEX_PREFIX + "arg_"
12
+ ARRAY_PREFIX = RUBEX_PREFIX + "arr_"
13
+ POINTER_PREFIX = RUBEX_PREFIX + "ptr_"
14
+ TYPE_PREFIX = RUBEX_PREFIX + "t_"
15
+
16
+ ACTUAL_ARGS_SUFFIX = "_actual_args"
8
17
 
9
18
  TYPE_MAPPINGS = {
10
- 'i32' => Rubex::DataType::CInt32,
11
- 'object' => Rubex::DataType::RubyObject
19
+ 'char' => Rubex::DataType::Char,
20
+ 'bool' => Rubex::DataType::CBoolean,
21
+ 'unsigned char' => Rubex::DataType::UChar,
22
+ 'i8' => Rubex::DataType::Int8,
23
+ 'i16' => Rubex::DataType::Int16,
24
+ 'i32' => Rubex::DataType::Int32,
25
+ 'i64' => Rubex::DataType::Int64,
26
+ 'u8' => Rubex::DataType::UInt8,
27
+ 'u16' => Rubex::DataType::UInt16,
28
+ 'u32' => Rubex::DataType::UInt32,
29
+ 'u64' => Rubex::DataType::UInt64,
30
+ 'int' => Rubex::DataType::Int,
31
+ 'unsigned int' => Rubex::DataType::UInt,
32
+ 'long int' => Rubex::DataType::LInt,
33
+ 'long' => Rubex::DataType::LInt,
34
+ 'unsigned long int' => Rubex::DataType::ULInt,
35
+ 'long long int' => Rubex::DataType::LLInt,
36
+ 'long long' => Rubex::DataType::LLInt,
37
+ 'unsigned long long int' => Rubex::DataType::ULLInt,
38
+ 'f32' => Rubex::DataType::F32,
39
+ 'float' => Rubex::DataType::F32,
40
+ 'f64' => Rubex::DataType::F64,
41
+ 'double' => Rubex::DataType::F64,
42
+ 'object' => Rubex::DataType::RubyObject,
43
+ 'void' => Rubex::DataType::Void,
44
+ 'size_t' => Rubex::DataType::Size_t,
45
+ 'str' => Rubex::DataType::RubyString,
46
+ 'arr' => Rubex::DataType::RubyArray,
47
+ 'hsh' => Rubex::DataType::RubyHash
48
+ }
49
+
50
+ CUSTOM_TYPES = {}
51
+
52
+ DEFAULT_CLASS_MAPPINGS = {
53
+ "Kernel" => "rb_mKernel",
54
+ "Comparable" => "rb_mComparable",
55
+ "Enumerable" => "rb_mEnumerable",
56
+ "Errno" => "rb_mErrno",
57
+ "FileTest" => "rb_mFileTest",
58
+ "GC" => "rb_mGC",
59
+ "Math" => "rb_mMath",
60
+ "Process" => "rb_mProcess",
61
+ "WaitReadable" => "rb_mWaitReadable",
62
+ "WaitWritable" => "rb_mWaitWritable",
63
+ "BasicObject" => "rb_cBasicObject",
64
+ "Object" => "rb_cObject",
65
+ "Array" => "rb_cArray",
66
+ "Bignum" => "rb_cBignum",
67
+ "Binding" => "rb_cBinding",
68
+ "Class" => "rb_cClass",
69
+ "Cont" => "rb_cCont",
70
+ "Dir" => "rb_cDir",
71
+ "Data" => "rb_cData",
72
+ "FalseClass" => "rb_cFalseClass",
73
+ "Encoding" => "rb_cEncoding",
74
+ "Enumerator" => "rb_cEnumerator",
75
+ "File" => "rb_cFile",
76
+ "Fixnum" => "rb_cFixnum",
77
+ "Float" => "rb_cFloat",
78
+ "Hash" => "rb_cHash",
79
+ "Integer" => "rb_cInteger",
80
+ "IO" => "rb_cIO",
81
+ "Match" => "rb_cMatch",
82
+ "Method" => "rb_cMethod",
83
+ "Module" => "rb_cModule",
84
+ "NameErrorMesg" => "rb_cNameErrorMesg",
85
+ "NilClass" => "rb_cNilClass",
86
+ "Numeric" => "rb_cNumeric",
87
+ "Proc" => "rb_cProc",
88
+ "Random" => "rb_cRandom",
89
+ "Range" => "rb_cRange",
90
+ "Rational" => "rb_cRational",
91
+ "Complex" => "rb_cComplex",
92
+ "Regexp" => "rb_cRegexp",
93
+ "Stat" => "rb_cStat",
94
+ "String" => "rb_cString",
95
+ "Struct" => "rb_cStruct",
96
+ "Symbol" => "rb_cSymbol",
97
+ "Thread" => "rb_cThread",
98
+ "Time" => "rb_cTime",
99
+ "TrueClass" => "rb_cTrueClass",
100
+ "UnboundMethod" => "rb_cUnboundMethod",
101
+ "Exception" => "rb_eException",
102
+ "StandardError" => "rb_eStandardError",
103
+ "SystemExit" => "rb_eSystemExit",
104
+ "Interrupt" => "rb_eInterrupt",
105
+ "Signal" => "rb_eSignal",
106
+ "Fatal" => "rb_eFatal",
107
+ "ArgumentError" => "rb_eArgError",
108
+ "EOFError" => "rb_eEOFError",
109
+ "IndexError" => "rb_eIndexError",
110
+ "StopIteration" => "rb_eStopIteration",
111
+ "KeyError" => "rb_eKeyError",
112
+ "RangeError" => "rb_eRangeError",
113
+ "IOError" => "rb_eIOError",
114
+ "RuntimeError" => "rb_eRuntimeError",
115
+ "SecurityError" => "rb_eSecurityError",
116
+ "SystemCallError" => "rb_eSystemCallError",
117
+ "ThreadError" => "rb_eThreadError",
118
+ "TypeError" => "rb_eTypeError",
119
+ "ZeroDivError" => "rb_eZeroDivError",
120
+ "NotImpError" => "rb_eNotImpError",
121
+ "NoMemError" => "rb_eNoMemError",
122
+ "NoMethodError" => "rb_eNoMethodError",
123
+ "FloatDomainError" => "rb_eFloatDomainError",
124
+ "LocalJumpError" => "rb_eLocalJumpError",
125
+ "SysStackError" => "rb_eSysStackError",
126
+ "RegexpError" => "rb_eRegexpError",
127
+ "EncodingError" => "rb_eEncodingError",
128
+ "EncCompatError" => "rb_eEncCompatError",
129
+ "ScriptError" => "rb_eScriptError",
130
+ "NameError" => "rb_eNameError",
131
+ "SyntaxError" => "rb_eSyntaxError",
132
+ "LoadError" => "rb_eLoadError",
133
+ "MathDomainError" => "rb_eMathDomainError",
134
+ "STDIN" => "rb_stdin",
135
+ "STDOUT" => "rb_stdout",
136
+ "STDERR" => "rb_stderr",
12
137
  }
13
138
 
14
- CLASS_MAPPINGS = {
15
- 'Object' => 'rb_cObject'
139
+ C_MACRO_INT2BOOL = Rubex::RUBEX_PREFIX + "INT2BOOL"
140
+ C_FUNC_CHAR2RUBYSTR = Rubex::RUBEX_PREFIX + "char2rubystr"
141
+
142
+ ALLOC_FUNC_NAME = 'allocate'
143
+ DEALLOC_FUNC_NAME = 'deallocate'
144
+ MEMCOUNT_FUNC_NAME = 'memcount'
145
+ GET_STRUCT_FUNC_NAME = 'get_struct'
146
+
147
+ # Maps regexes to the type of the variable for conversion from literal
148
+ # to the correct type of Ruby object.
149
+ LITERAL_MAPPINGS = {
150
+ /'.\'/ => Rubex::DataType::Char,
151
+ /-?\d+/ => Rubex::DataType::Int,
152
+ /-?\d+\.\d+/ => Rubex::DataType::F64
16
153
  }
17
- end
154
+ end
@@ -1,15 +1,678 @@
1
1
  module Rubex
2
2
  module DataType
3
+ # Citations
4
+ # Printf arguments:
5
+ # http://www.thinkage.ca/english/gcos/expl/c/lib/printf.html
6
+ module Helpers
7
+ include ::Comparable
8
+ [
9
+ :float?, :float32?, :float64?,
10
+ :int?, :int8?, :int16?, :int32?, :int64?,
11
+ :uint?, :uint8?, :uint16?, :uint32?, :uint64?,
12
+ :lint?, :ulint?, :llint?, :ullint?,
13
+ :char?, :object?, :bool?, :carray?, :cbool?,
14
+ :cptr?, :nil_type?, :struct_or_union?,
15
+ :alias_type?, :string?, :cstr?, :ruby_class?,
16
+ :ruby_method?, :c_function?, :ruby_constant?, :void?,
17
+ :ruby_string?, :uchar?, :ruby_array?, :ruby_hash?
18
+ ].each do |dtype|
19
+ define_method(dtype) { return false }
20
+ end
21
+
22
+ def == other
23
+ self.class == other.class
24
+ end
25
+
26
+ def to_ruby_object(arg); arg; end
27
+
28
+ def from_ruby_object(arg); arg; end
29
+
30
+ def base_type; self; end
31
+
32
+ # Helper function to know if a dtype is a char pointer.
33
+ def char_ptr?
34
+ if self.cptr? && self.base_type.char?
35
+ true
36
+ else
37
+ false
38
+ end
39
+ end
40
+
41
+ def c_function_ptr?
42
+ if self.cptr? && self.base_type.c_function?
43
+ true
44
+ else
45
+ false
46
+ end
47
+ end
48
+ end
49
+
50
+ module IntHelpers
51
+ include Helpers
52
+ def to_ruby_object(arg); "INT2NUM(#{arg})"; end
53
+ end
54
+
55
+ module UIntHelpers
56
+ include Helpers
57
+ def to_ruby_object(arg); "UINT2NUM(#{arg})"; end
58
+ end
59
+
60
+ module FloatHelpers
61
+ include Helpers
62
+ end
63
+
64
+ class Void
65
+ include Helpers
66
+
67
+ def void?; true; end
68
+
69
+ def to_s; "void"; end
70
+ end
71
+
3
72
  class RubyObject
73
+ include Helpers
4
74
  def to_s; "VALUE"; end
75
+
76
+ def object?; true; end
77
+
78
+ def p_formatter; "%s"; end
79
+ end
80
+
81
+ class RubySymbol < RubyObject
82
+ def ruby_symbol?; true; end
83
+ end
84
+
85
+ class RubyString < RubyObject
86
+ def ruby_string?; true; end
87
+ end
88
+
89
+ class RubyArray < RubyObject
90
+ def ruby_array?; true; end
91
+ end
92
+
93
+ class RubyHash < RubyObject
94
+ def ruby_hash?; true; end
95
+ end
96
+
97
+ class Char
98
+ include Helpers
99
+ def to_s; "char"; end
100
+
101
+ def to_ruby_object(arg, literal=false)
102
+ "#{Rubex::C_FUNC_CHAR2RUBYSTR}(#{arg})"
103
+ end
104
+
105
+ def from_ruby_object(arg); "(char)NUM2INT(#{arg})"; end
106
+
107
+ def p_formatter; "%c"; end
108
+
109
+ def char?; true; end
110
+
111
+ def <=> other
112
+ if other.char?
113
+ return 0
114
+ else
115
+ return 1
116
+ end
117
+ end
118
+ end
119
+
120
+ class UChar
121
+ include Helpers
122
+
123
+ def to_s; "unsigned char"; end
124
+
125
+ def from_ruby_object(arg); "(unsigned char)NUM2INT(#{arg})"; end
126
+
127
+ def p_formatter; "%d"; end
128
+
129
+ def uchar?; true; end
130
+
131
+ def <=> other
132
+ if other.char? || other.uchar?
133
+ return 0
134
+ else
135
+ return 1
136
+ end
137
+ end
138
+ end
139
+
140
+ class Int8
141
+ include IntHelpers
142
+
143
+ def to_s; "int8_t"; end
144
+
145
+ def from_ruby_object(arg); "(int8_t)NUM2INT(#{arg})"; end
146
+
147
+ def int8?; true; end
148
+
149
+ def p_formatter; "%d"; end
150
+
151
+ def <=> other
152
+ if other.char?
153
+ return 1
154
+ elsif other.int8?
155
+ return 0
156
+ else
157
+ return -1
158
+ end
159
+ end
160
+ end
161
+
162
+ class Int16
163
+ include IntHelpers
164
+ def to_s; "int16_t"; end
165
+
166
+ def from_ruby_object(arg); "(int16_t)NUM2INT(#{arg})"; end
167
+
168
+ def int16?; true; end
169
+
170
+ def p_formatter; "%d"; end
171
+
172
+ def <=> other
173
+ if other.char? || other.int8?
174
+ return 1
175
+ elsif other.int16?
176
+ return 0
177
+ else
178
+ return -1
179
+ end
180
+ end
5
181
  end
6
182
 
7
- class CInt32
183
+ class Int32
184
+ include IntHelpers
8
185
  def to_s; "int32_t"; end
9
186
 
10
- def to_ruby_function; "INT2NUM"; end
187
+ def from_ruby_object(arg); "(int32_t)NUM2INT(#{arg})"; end
188
+
189
+ def int32?; true; end
190
+
191
+ def p_formatter; "%d"; end
192
+
193
+ def <=> other
194
+ if other.char? || other.int8? || other.int16?
195
+ return 1
196
+ elsif other.int32? || other.int?
197
+ return 0
198
+ else
199
+ return -1
200
+ end
201
+ end
202
+ end
203
+
204
+ class Int64
205
+ include IntHelpers
206
+ def to_s; "int64_t"; end
207
+
208
+ def to_ruby_object(arg); "LONG2NUM(#{arg})"; end
209
+
210
+ def from_ruby_object(arg); "(int64_t)NUM2LONG(#{arg})"; end
211
+
212
+ def p_formatter; "%ld"; end
213
+
214
+ def int64?; true; end
215
+
216
+ def <=> other
217
+ if other.char? || other.int8? || other.int16? || other.int32? ||
218
+ other.int?
219
+ return 1
220
+ elsif other.int64?
221
+ return 0
222
+ else
223
+ return -1
224
+ end
225
+ end
226
+ end
227
+
228
+ class UInt8
229
+ include UIntHelpers
230
+ def to_s; "uint8_t"; end
231
+
232
+ def from_ruby_object(arg); "(uint8_t)NUM2UINT(#{arg})"; end
233
+
234
+ def uint8?; true; end
235
+
236
+ def p_formatter; "%u"; end
237
+ end
238
+
239
+ class UInt16
240
+ include UIntHelpers
241
+ def to_s; "uint16_t"; end
242
+
243
+ def from_ruby_object(arg); "(uint16_t)NUM2UINT(#{arg})"; end
244
+
245
+ def uint16?; true; end
246
+
247
+ def p_formatter; "%u"; end
248
+ end
249
+
250
+ class UInt32
251
+ include UIntHelpers
252
+ def to_s; "uint32_t"; end
253
+
254
+ def from_ruby_object(arg); "(int32_t)NUM2UINT(#{arg})"; end
255
+
256
+ def uint32?; true; end
257
+
258
+ def p_formatter; "%u"; end
259
+ end
260
+
261
+ class UInt64
262
+ include UIntHelpers
263
+ def to_s; "uint64_t"; end
264
+
265
+ def to_ruby_object(arg); "ULONG2NUM(#{arg})"; end
266
+
267
+ def from_ruby_object(arg); "(int64_t)NUM2UINT(#{arg})"; end
268
+
269
+ def uint64?; true; end
270
+
271
+ def p_formatter; "%lu"; end
272
+ end
273
+
274
+ class Int
275
+ include IntHelpers
276
+ def to_s; "int"; end
277
+
278
+ def from_ruby_object(arg); "NUM2INT(#{arg})"; end
279
+
280
+ def int?; true; end
281
+
282
+ def p_formatter; "%d"; end
283
+
284
+ def <=> other
285
+ if other.char? || other.int8? || other.int16?
286
+ return 1
287
+ elsif other.int? || other.int32?
288
+ return 0
289
+ else # other is int64 or greater
290
+ return -1
291
+ end
292
+ end
293
+ end
294
+
295
+ class CBoolean < Int
296
+ def cbool?; true; end
297
+
298
+ def to_ruby_object arg
299
+ Rubex::C_MACRO_INT2BOOL + "(" + arg + ")"
300
+ end
301
+ end
302
+
303
+ class UInt
304
+ include UIntHelpers
305
+ def to_s; "unsigned int"; end
306
+
307
+ def from_ruby_object(arg); "(unsigned int)NUM2UINT(#{arg})"; end
308
+
309
+ def uint?; true; end
310
+
311
+ def p_formatter; "%u"; end
312
+
313
+ def <=> other
314
+ if other.char? || other.int8? || other.int16? || other.uint8? || other.uint16?
315
+ return 1
316
+ elsif other.uint? || other.int? || other.int32? || other.uint32?
317
+ return 0
318
+ else
319
+ return -1
320
+ end
321
+ end
322
+ end
323
+
324
+ class LInt
325
+ include IntHelpers
326
+ def to_s; "long int"; end
11
327
 
12
- def from_ruby_function; "NUM2INT"; end
328
+ def to_ruby_object(arg); "LONG2NUM(#{arg})"; end
329
+
330
+ def from_ruby_object(arg); "NUM2LONG(#{arg})"; end
331
+
332
+ def lint?; true; end
333
+
334
+ def p_formatter; "%ld"; end
335
+
336
+ def <=> other
337
+ if other.char? || other.int8? || other.int16? || other.int32? ||
338
+ other .int64? || other.uint8? || other.uint16? || other.uint32? ||
339
+ other.int?
340
+ return 1
341
+ elsif other.lint?
342
+ return 0
343
+ else
344
+ return -1
345
+ end
346
+ end
347
+ end
348
+
349
+ class ULInt
350
+ include UIntHelpers
351
+ def to_s; "unsigned long int"; end
352
+
353
+ def to_ruby_object(arg); "ULONG2NUM(#{arg})"; end
354
+
355
+ def from_ruby_object(arg); "NUM2ULONG(#{arg})"; end
356
+
357
+ def ulint?; true; end
358
+
359
+ def p_formatter; "%lu"; end
360
+
361
+ def <=> other
362
+ if other.char? || other.int8? || other.int16? || other.int32? ||
363
+ other .int64? || other.uint8? || other.uint16? || other.uint32? ||
364
+ other.int?
365
+ return 1
366
+ elsif other.ulint?
367
+ return 0
368
+ else
369
+ return -1
370
+ end
371
+ end
372
+ end
373
+
374
+ class Size_t < ULInt
375
+ def to_s
376
+ "size_t"
377
+ end
378
+ end
379
+
380
+ class LLInt
381
+ include IntHelpers
382
+ def to_s; "long long int"; end
383
+
384
+ def to_ruby_object(arg); "LL2NUM(#{arg})"; end
385
+
386
+ def from_ruby_object(arg); "NUM2LL(#{arg})"; end
387
+
388
+ def llint?; true; end
389
+
390
+ def p_formatter; "%ll"; end
391
+ end
392
+
393
+ class ULLInt
394
+ include UIntHelpers
395
+ def to_s; "unsigned long long int"; end
396
+
397
+ def to_ruby_object(arg); "ULL2NUM(#{arg})"; end
398
+
399
+ def from_ruby_object(arg); "NUM2ULL(#{arg})"; end
400
+
401
+ def ullint?; true; end
402
+
403
+ def p_formatter; "%llu"; end
404
+ end
405
+
406
+ class F32
407
+ include FloatHelpers
408
+ def to_s; "float"; end
409
+
410
+ def to_ruby_object(arg); "rb_float_new((double)(#{arg}))"; end
411
+
412
+ def from_ruby_object(arg); "(float)NUM2DBL(#{arg})"; end
413
+
414
+ def float32?; true; end
415
+
416
+ def p_formatter; "%f"; end
417
+
418
+ def <=> other
419
+ if other.char? || other.int8? || other.int16? || other.int32? ||
420
+ other.int64? || other.int? || other.uint8? || other.uint16?||
421
+ other.uint32? || other.uint64?
422
+ return 1
423
+ elsif other.float32?
424
+ return 0
425
+ else # other is float64
426
+ return -1
427
+ end
428
+ end
429
+
430
+ end
431
+
432
+ class F64
433
+ include FloatHelpers
434
+ def to_s; "double"; end
435
+
436
+ def to_ruby_object(arg); "rb_float_new(#{arg})"; end
437
+
438
+ def from_ruby_object(arg); "NUM2DBL(#{arg})"; end
439
+
440
+ def float64?; true; end
441
+
442
+ def p_formatter; "%f"; end
443
+
444
+ def <=> other
445
+ if other.char? || other.int8? || other.int16? || other.int32? ||
446
+ other.int64? || other.int? || other.uint8? || other.uint16?||
447
+ other.uint32? || other.uint64? || other.float32?
448
+ return 1
449
+ elsif other.float64?
450
+ return 0
451
+ else
452
+ return -1
453
+ end
454
+ end
455
+ end
456
+
457
+ class CArray
458
+ include Helpers
459
+ # Dimension of the array
460
+ attr_reader :dimension
461
+ # Type of elements stored in array
462
+ attr_reader :type # FIXME: Make this base_type to make it more explicit.
463
+
464
+ def initialize dimension, type
465
+ @dimension, @type = dimension, type
466
+ end
467
+
468
+ def carray?; true; end
469
+
470
+ def <=> other
471
+ if self.class == other.class
472
+ @type <=> other.type
473
+ else
474
+ @type <=> other
475
+ end
476
+ end
477
+
478
+ def base_type
479
+ @type
480
+ end
481
+ end
482
+
483
+ class CPtr
484
+ include Helpers
485
+ # The data type that this pointer is pointing to.
486
+ attr_reader :type
487
+
488
+ def initialize type
489
+ @type = type
490
+ end
491
+
492
+ def p_formatter
493
+ "%s" if char_ptr?
494
+ end
495
+
496
+ def cptr?; true; end
497
+
498
+ def to_s
499
+ base_type = @type.base_type
500
+ if base_type.c_function?
501
+ ptr = ptr_level
502
+
503
+ str = "#{base_type.type.to_s} (#{ptr} #{base_type.c_name.to_s})"
504
+ str << "(" + base_type.arg_list.map { |e| e.type.to_s }.join(',') + ")"
505
+ else
506
+ t = @type
507
+ str = "*"
508
+ if t.cptr?
509
+ str << "*"
510
+ t = t.type
511
+ end
512
+ str.prepend t.to_s
513
+ str
514
+ end
515
+ end
516
+
517
+ def base_type
518
+ return @type if !@type.is_a?(self.class)
519
+ return @type.base_type
520
+ end
521
+
522
+ def ptr_level
523
+ temp = @type
524
+ ptr = "*"
525
+ while temp.cptr?
526
+ ptr << "*"
527
+ temp = @type.type
528
+ end
529
+
530
+ ptr
531
+ end
532
+
533
+ # from a Ruby function get a pointer to some value.
534
+ def from_ruby_object arg
535
+ return "StringValueCStr(#{arg})" if @type.char?
536
+ arg
537
+ end
538
+
539
+ def to_ruby_object arg
540
+ return "rb_str_new2(#{arg})" if @type.char?
541
+ arg
542
+ end
543
+
544
+ def <=> other
545
+ return -1
546
+ end
547
+ end
548
+
549
+ class Boolean < RubyObject
550
+ include Helpers
551
+
552
+ def bool?; true; end
553
+ end
554
+
555
+ class TrueType < Boolean; end
556
+
557
+ class FalseType < Boolean; end
558
+
559
+ class NilType < RubyObject
560
+ def nil_type?; true; end
561
+ end
562
+
563
+ class CStructOrUnion
564
+ include Helpers
565
+ attr_reader :kind, :name, :c_name, :scope
566
+
567
+ def initialize kind, name, c_name, scope
568
+ @kind, @name, @c_name, @scope = kind, name, c_name, scope
569
+ end
570
+
571
+ def struct_or_union?; true; end
572
+
573
+ def to_s; "#{@c_name}"; end
13
574
  end
575
+
576
+ # FIXME: Find out a better way to generically find the old type of a typedef
577
+ # when the new type is encountered. Should cover cases where the new type
578
+ # is aliased with some other name too. In other words, reach the actual
579
+ # type in the most generic way possible without too many checks.
580
+ class TypeDef
581
+ # include Helpers
582
+ attr_reader :type, :old_type, :new_type
583
+
584
+ def initialize old_type, new_type, type
585
+ @old_type, @new_type, @type = old_type, new_type, type
586
+ end
587
+
588
+ def alias_type?; true; end
589
+
590
+ def to_s
591
+ @new_type.to_s
592
+ end
593
+
594
+ def base_type
595
+ @old_type
596
+ end
597
+
598
+ def method_missing meth, *args, &block
599
+ @old_type.send(meth, *args, &block)
600
+ end
601
+ end
602
+
603
+ class CStr
604
+ include Helpers
605
+
606
+ def cstr?; true; end
607
+
608
+ def p_formatter; "%s"; end
609
+
610
+ def from_ruby_object arg
611
+ "StringValueCStr(#{arg})"
612
+ end
613
+
614
+ def to_ruby_object arg
615
+ "rb_str_new_cstr(#{arg})"
616
+ end
617
+ end
618
+
619
+ class RubyConstant < RubyObject
620
+ attr_reader :name, :type
621
+
622
+ def initialize name
623
+ @name = name
624
+ # FIXME: make this flexible so that consts set to primitive types can be
625
+ # easily converted to C types.
626
+ @type = RubyObject.new
627
+ end
628
+
629
+ def ruby_constant?; true; end
630
+ end
631
+
632
+ class RubyClass < RubyConstant
633
+ attr_reader :name, :c_name, :scope, :ancestor
634
+
635
+ def initialize name, c_name, scope, ancestor
636
+ @name, @c_name, @scope, @ancestor = name, c_name, scope, ancestor
637
+ end
638
+
639
+ def ruby_class?; true; end
640
+ end
641
+
642
+ class RubyMethod
643
+ include Helpers
644
+
645
+ attr_reader :name, :c_name, :type
646
+ attr_accessor :scope, :arg_list
647
+
648
+ def initialize name, c_name, scope, arg_list
649
+ @name, @c_name, @scope, @arg_list = name, c_name, scope, arg_list
650
+ @type = RubyObject.new
651
+ end
652
+
653
+ def ruby_method?; true; end
654
+ end
655
+
656
+ class CFunction
657
+ include Helpers
658
+ attr_reader :name, :type, :c_name
659
+ attr_accessor :scope, :arg_list
660
+
661
+ # FIXME: all attributes should be initialized upon class creation to maintain
662
+ # sanity and consistency.
663
+ def initialize name, c_name, arg_list, type, scope
664
+ @name, @c_name, @arg_list, @type, @scope = name, c_name, arg_list, type, scope
665
+ end
666
+
667
+ def c_function?; true; end
668
+ end
669
+ # TODO: How to store this in a Ruby class? Use BigDecimal?
670
+ # class LF64
671
+ # def to_s; "long double"; end
672
+
673
+ # def to_ruby_object(arg); "INT2NUM"; end
674
+
675
+ # def from_ruby_object(arg); "(int32_t)NUM2INT"; end
676
+ # end
14
677
  end
15
- end
678
+ end