wruby 0.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: e868c3c2d079107e665b0de7bb170c4ba9c68b69b505364eabc5435060083c20
4
+ data.tar.gz: 192c37b854e25974f1da3dd3ed451827982eb9ef4f87789d3b96673859ca70b8
5
+ SHA512:
6
+ metadata.gz: 4c9c383325bea8bbb76fb4b9c08dc02c4da95cf60ef3b90e24cacd5663ac0d2a304dbeaa02bf10f74bf0429f6bae543aae3d66de649e8ce79fca0afde55544a1
7
+ data.tar.gz: 4f712a63f78ecb3bd88adaf8bc32804ba92b8382c8fac90a52b37898b406af68c248e678cd9d4e1605e1516583a3a25ae618e201c732f91b30fa723759a28bb5
@@ -0,0 +1,5 @@
1
+ module WRuby
2
+ class FormatError < StandardError
3
+
4
+ end
5
+ end
@@ -0,0 +1,154 @@
1
+ require "wruby/format_error"
2
+ module WRuby
3
+ class MetaData
4
+ class UnrecognizedTypeError < StandardError
5
+ def initialize(name)
6
+ super("Unrecognized type: #{name}")
7
+ end
8
+ end
9
+
10
+
11
+ def self.parse(data)
12
+ me = self.new
13
+ data["includes"].each {|f| add_header(f)}
14
+ data["typedefs"].each do |name, wrappings|
15
+ aliased = wrappings.key?("alias")
16
+ wrapped = wrappings.key?("wrap")
17
+ unwrapped = wrappings.key?("unwrap")
18
+ unless aliased || wrapped || unwrapped
19
+ raise FormatError, "Type with no deifnition: #{name}"
20
+ end
21
+ if aliased && (wrapped || unwrapped)
22
+ raise FormatError, "Ambiguous type definition: #{name}"
23
+ end
24
+ if wrapped ^ unwrapped
25
+ raise FormatError, "Incomplete type definition: #{name}"
26
+ end
27
+
28
+ if aliased
29
+ register_alias(name, wrappings["alias"])
30
+ elsif wrapped || unwrapped
31
+ register_wrapping(name, wrappings["wrap"], wrappings["unwrap"])
32
+ end
33
+ end
34
+ data["wrapped_classes"].each {|name| register_class(name)}
35
+ end
36
+
37
+ def initialize
38
+ @headers = []
39
+ @types = {}
40
+ @aliases = {}
41
+ @aliases.default_proc = proc {|h, k| k}
42
+
43
+ @classes = {}
44
+ end
45
+
46
+ attr_reader :headers, :classes
47
+
48
+ def add_header(file_name)
49
+ @headers << file_name unless @headers.include?(file_name)
50
+ end
51
+
52
+ def register_class(class_name)
53
+ return unless @classes.key?(class_name)
54
+ @classes[class_name] << Class.new do
55
+ def alloc
56
+ "#{class_name}_alloc"
57
+ end
58
+ def ctype
59
+ "#{class_name}_type"
60
+ end
61
+ end
62
+ end
63
+
64
+ def register_alias(alias_name, type)
65
+ @aliases[alias_name.to_s] = type.to_s
66
+ end
67
+
68
+ def register_wrapping(type, wrapping, unwrapping)
69
+ @types[type.to_s] = {wrap: wrapping, unwrap: unwrapping}
70
+ end
71
+
72
+ def wrap(code, type)
73
+ raise UnrecognizedTypeError.new(type) unless @types.key?(type) || @aliases.key?(type)
74
+ resolved_type = @aliases[type.to_s]
75
+ @types[resolved_type.to_s][:wrap].gsub(/\bthis\b/, code)
76
+ end
77
+
78
+ def unwrap(code, type)
79
+ raise UnrecognizedTypeError.new(type) unless @types.key?(type) || @aliases.key?(type)
80
+ resolved_type = @aliases[type.to_s]
81
+ @types[resolved_type.to_s][:unwrap].gsub(/\bthis\b/, code)
82
+ end
83
+
84
+ def alias_valid?(type)
85
+ @aliases.key?(type) && @types.key?(@aliases[type])
86
+ end
87
+
88
+ def has_type?(type)
89
+ @types.key?(type) || alias_valid?(type)
90
+ end
91
+
92
+ def each_class(&block)
93
+ return to_enum(__method__) unless block_given?
94
+ @wrapped_classes.each(&block)
95
+ end
96
+
97
+ private
98
+ def self.register_default_wrappings
99
+ # Basic integer types
100
+ register_wrapping("char", "INT2NUM(this)", "NUM2CHR(this)")
101
+ register_wrapping("short", "INT2NUM(this)", "NUM2SHORT(this)")
102
+ register_wrapping("int", "INT2NUM(this)", "NUM2INT(this)")
103
+ register_wrapping("long", "LONG2NUM(this)", "NUM2LONG(this)")
104
+ register_wrapping("long long", "LL2NUM(this)", "NUM2LL(this)")
105
+ # Basic unsigned integer types
106
+ register_wrapping("unsigned char", "UINT2NUM(this)", "NUM2UCHR(this)")
107
+ register_wrapping("unsigned short", "UINT2NUM(this)", "NUM2USHORT(this)")
108
+ register_wrapping("unsigned int", "UINT2NUM(this)", "NUM2UINT(this)")
109
+ register_wrapping("unsigned long", "ULONG2NUM(this)", "NUM2ULONG(this)")
110
+ register_wrapping("unsigned long long", "ULL2NUM(this)", "NUM2ULL(this)")
111
+ # unsigned abbreviations
112
+ register_alias("uchar", "unsigned char")
113
+ register_alias("ushort", "unsigned short")
114
+ register_alias("uint", "unsigned int")
115
+ register_alias("ulong", "unsigned long")
116
+ register_alias("long ulong", "unsigned long long") # This one is weird, but it makes more sense than ulong long
117
+
118
+ # Fixed integer types
119
+ register_wrapping("int8_t", "INT2NUM(this)", "(int8_t)NUM2CHR(this)")
120
+ register_wrapping("int16_t", "INT2NUM(this)", "(int16_t)NUM2SHORT(this)")
121
+ register_wrapping("int32_t", "INT2NUM(this)", "(int32_t)NUM2INT(this)")
122
+ register_wrapping("int64_t", "LONG2NUM(this)", "(int64_t)NUM2LONG(this)")
123
+ register_wrapping("uint8_t", "UINT2NUM(this)", "(int8_t)NUM2UINT(this)")
124
+ register_wrapping("uint16_t", "UINT2NUM(this)", "(int16_t)NUM2UINT(this)")
125
+ register_wrapping("uint32_t", "UINT2NUM(this)", "(int32_t)NUM2UINT(this)")
126
+ register_wrapping("uint64_t", "ULONG2NUM(this)", "(int64_t)NUM2ULONG(this)")
127
+ register_alias("int8", "int8_t")
128
+ register_alias("int16", "int16_t")
129
+ register_alias("int32", "int32_t")
130
+ register_alias("int64", "int64_t")
131
+ register_alias("uint8", "uint8_t")
132
+ register_alias("uint16", "uint16_t")
133
+ register_alias("uint32", "uint32_t")
134
+ register_alias("uint64", "uint64_t")
135
+
136
+ # Floating-point types
137
+ register_wrapping("float", "DBL2NUM(this)", "(float)NUM2DBL(this)")
138
+ register_wrapping("double", "DBL2NUM(this)", "NUM2DBL(this)")
139
+ # Fixed-size floating-point aliases
140
+ register_alias("float32", "float")
141
+ register_alias("float64", "double")
142
+
143
+ # Boolean type
144
+ register_wrapping("bool", "(this ? QTrue : QFalse)", "RTEST(this)")
145
+
146
+ # String types
147
+ # C-style strings
148
+ register_wrapping("char*", "rb_str_new_cstr(this)", "StringValueCStr(this)")
149
+ register_alias("cstring", "char*")
150
+ register_alias("cstr", "char*")
151
+ # Non-C-style strings are not handled here, as it's more complex than a simple inline
152
+ end
153
+ end
154
+ end
@@ -0,0 +1,11 @@
1
+ require "wruby/format_error"
2
+ module WRuby::Util
3
+ module RequireHash
4
+ def require(key, failure_message = "")
5
+ raise WRuby::FormatError, failure_message unless self.key?(key)
6
+ self[key]
7
+ end
8
+ end
9
+ end
10
+
11
+ Hash.prepend(WRuby::Util::RequireHash)
@@ -0,0 +1,9 @@
1
+ module WRuby
2
+ def self.rubify_name(name)
3
+ case name
4
+ when /\?/ then "is_#{name[...(name.size - 1)]}"
5
+ when /!/ then name[...(name.size - 1)]
6
+ else name
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,94 @@
1
+ module WRuby
2
+ @@types = {}
3
+ @@aliases = {}
4
+ @@aliases.default_proc = proc {|h, k| k}
5
+
6
+ class UnrecognizedTypeError < StandardError
7
+ def initialize(name)
8
+ super("Unrecognized type: #{name}")
9
+ end
10
+ end
11
+
12
+ def self.register_alias(alias_name, type)
13
+ @@aliases[alias_name.to_s] = type.to_s
14
+ end
15
+
16
+ def self.register_wrapping(type, wrapping, unwrapping)
17
+ @@types[type.to_s] = {wrap: wrapping, unwrap: unwrapping}
18
+ end
19
+
20
+ def self.wrap(code, type)
21
+ raise UnrecognizedTypeError.new(type) unless @@types.key?(type) || @@aliases.key?(type)
22
+ resolved_type = @@aliases[type.to_s]
23
+ @@types[resolved_type.to_s][:wrap].gsub(/\bthis\b/, code)
24
+ end
25
+
26
+ def self.unwrap(code, type)
27
+ raise UnrecognizedTypeError.new(type) unless @@types.key?(type) || @@aliases.key?(type)
28
+ resolved_type = @@aliases[type.to_s]
29
+ @@types[resolved_type.to_s][:unwrap].gsub(/\bthis\b/, code)
30
+ end
31
+
32
+ def self.allocator_for(name)
33
+ "#{name}_alloc"
34
+ end
35
+
36
+ def self.native_name_for(name)
37
+ "#{name}_type"
38
+ end
39
+
40
+ # Basic integer types
41
+ register_wrapping("char", "INT2NUM(this)", "NUM2CHR(this)")
42
+ register_wrapping("short", "INT2NUM(this)", "NUM2SHORT(this)")
43
+ register_wrapping("int", "INT2NUM(this)", "NUM2INT(this)")
44
+ register_wrapping("long", "LONG2NUM(this)", "NUM2LONG(this)")
45
+ register_wrapping("long long", "LL2NUM(this)", "NUM2LL(this)")
46
+ # Basic unsigned integer types
47
+ register_wrapping("unsigned char", "UINT2NUM(this)", "NUM2UCHR(this)")
48
+ register_wrapping("unsigned short", "UINT2NUM(this)", "NUM2USHORT(this)")
49
+ register_wrapping("unsigned int", "UINT2NUM(this)", "NUM2UINT(this)")
50
+ register_wrapping("unsigned long", "ULONG2NUM(this)", "NUM2ULONG(this)")
51
+ register_wrapping("unsigned long long", "ULL2NUM(this)", "NUM2ULL(this)")
52
+ # unsigned abbreviations
53
+ register_alias("uchar", "unsigned char")
54
+ register_alias("ushort", "unsigned short")
55
+ register_alias("uint", "unsigned int")
56
+ register_alias("ulong", "unsigned long")
57
+ register_alias("long ulong", "unsigned long long") # This one is weird, but it makes more sense than ulong long
58
+
59
+ # Fixed integer types
60
+ register_wrapping("int8_t", "INT2NUM(this)", "(int8_t)NUM2CHR(this)")
61
+ register_wrapping("int16_t", "INT2NUM(this)", "(int16_t)NUM2SHORT(this)")
62
+ register_wrapping("int32_t", "INT2NUM(this)", "(int32_t)NUM2INT(this)")
63
+ register_wrapping("int64_t", "LONG2NUM(this)", "(int64_t)NUM2LONG(this)")
64
+ register_wrapping("uint8_t", "UINT2NUM(this)", "(int8_t)NUM2UINT(this)")
65
+ register_wrapping("uint16_t", "UINT2NUM(this)", "(int16_t)NUM2UINT(this)")
66
+ register_wrapping("uint32_t", "UINT2NUM(this)", "(int32_t)NUM2UINT(this)")
67
+ register_wrapping("uint64_t", "ULONG2NUM(this)", "(int64_t)NUM2ULONG(this)")
68
+ register_alias("int8", "int8_t")
69
+ register_alias("int16", "int16_t")
70
+ register_alias("int32", "int32_t")
71
+ register_alias("int64", "int64_t")
72
+ register_alias("uint8", "uint8_t")
73
+ register_alias("uint16", "uint16_t")
74
+ register_alias("uint32", "uint32_t")
75
+ register_alias("uint64", "uint64_t")
76
+
77
+ # Floating-point types
78
+ register_wrapping("float", "DBL2NUM(this)", "(float)NUM2DBL(this)")
79
+ register_wrapping("double", "DBL2NUM(this)", "NUM2DBL(this)")
80
+ # Fixed-size floating-point aliases
81
+ register_alias("float32", "float")
82
+ register_alias("float64", "double")
83
+
84
+ # Boolean type
85
+ register_wrapping("bool", "(this ? QTrue : QFalse)", "RTEST(this)")
86
+
87
+ # String types
88
+ # C-style strings
89
+ register_wrapping("char*", "rb_str_new_cstr(this)", "StringValueCStr(this)")
90
+ register_alias("cstring", "char*")
91
+ register_alias("cstr", "char*")
92
+ # Non-C-style strings are not handled here, as it's more complex than a simple inline
93
+
94
+ end
@@ -0,0 +1,118 @@
1
+ require "wruby/util/hash"
2
+ require "wruby/parameter_definition"
3
+ require "wruby/return_definition"
4
+ require "wruby/util/normalize"
5
+ module WRuby
6
+ class MethodDefinition
7
+
8
+ attr_reader :name, :parameters, :return, :method_type, :wrapper, :wrapped_function, :definition, :alias
9
+
10
+ def initialize(data)
11
+ @name = data.require("name", "Method definition missing name")
12
+ @parameters = data.require("parameters", "Method \'#{data["name"]}' missing 'parameters' field")
13
+ @parameters.map!{|e| ParameterDefinition.new(e)} unless @parameters.nil?
14
+ @return = data.require("return", "Method \'#{data["name"]}' missing 'return' field")
15
+ @return = ReturnDefinition.new(@return) unless @return.nil?
16
+ @method_type = data.require("method_type", "Method \'#{data["name"]}' missing 'method_type' field")
17
+ raise FormatError, "method_type '#{@method_type}' unsupported" unless ["constructor", "method", "module", "singleton"].include?(@method_type)
18
+ @wrapper = data.key? "wrapped_function"
19
+ if @wrapper
20
+ @wrapped_function = data.require("wrapped_function", "Method \'#{data["name"]}' missing wrapped_function")
21
+ else
22
+ @definition = data.require("definition", "Method \'#{data["name"]}' missing definition")
23
+ end
24
+ @alias = data["alias"]
25
+ end
26
+
27
+ def param_count(include_out = false)
28
+ return -1 if optional_params?
29
+ @parameters.filter{|p| include_out || !p.out?}.count
30
+ end
31
+
32
+ def optional_params?
33
+ @parameters.any?{|p| p.optional?}
34
+ end
35
+
36
+ def out_params
37
+ @parameters.filter{|p| p.out?}
38
+ end
39
+
40
+ def aliased?
41
+ !@alias.nil?
42
+ end
43
+
44
+ def qualified_name(klass_name)
45
+ "#{klass_name}#{(module? || singleton?) ? "_m" : ""}_#{WRuby::normalize_ruby_name(name)}"
46
+ end
47
+
48
+ def render(klass_spec)
49
+ "#{render_signature(klass_spec.qualified_name)} + {#{render_body(klass_spec)}}"
50
+ end
51
+
52
+ def render_signature(klass_name)
53
+ param_list = @parameters.filter{|p| !p.out?}.map do |param|
54
+ "VALUE #{param.name}"
55
+ end.join(", ")
56
+ "VALUE #{qualified_name(klass_name)}(VALUE self#{", #{param_list}" unless param_list.empty?})"
57
+ end
58
+
59
+ def render_body(klass_spec)
60
+ if method?
61
+ render_method
62
+ elsif module?
63
+ render_module_function
64
+ elsif singleton?
65
+ render_singleton_function
66
+ elsif constructor?
67
+ render_constructor
68
+ end
69
+ end
70
+
71
+ def singleton?
72
+ @method_type == "singleton"
73
+ end
74
+
75
+ def module?
76
+ @method_type == "module"
77
+ end
78
+
79
+ def method?
80
+ @method_type == "method"
81
+ end
82
+
83
+ def constructor?
84
+ @method_type == "constructor"
85
+ end
86
+
87
+
88
+ private
89
+ def render_method(klass_spec)
90
+ ""
91
+ end
92
+
93
+ def render_module_function(klass_spec)
94
+ ""
95
+ end
96
+
97
+ def render_singleton_function(klass_spec)
98
+ ""
99
+ end
100
+
101
+ def render_constructor(klass_spec)
102
+ ""
103
+ end
104
+
105
+ def declare_out_variables
106
+ out_params.map do |p|
107
+ "#{p.type} #{p.name};\n"
108
+ end
109
+ end
110
+
111
+ def get_self(klass_spec)
112
+ <<-SELF
113
+ #{klass_spec.underlying_type}* that;
114
+ TypedData_Get_Struct(self, #{klass_spec.underlying_type}, &#{klass_spec.type_name}, that);
115
+ SELF
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,46 @@
1
+ require "wruby/util/hash"
2
+ require "wruby/method_definition"
3
+ module WRuby
4
+ class ModuleDefinition
5
+ attr_reader :name
6
+ def initialize(data)
7
+ @name = data.require("name", "Module definition requires a name")
8
+ @methods = data["methods"]
9
+ @methods&.map!{|e| MethodDefinition.new(e)}
10
+ @free_method = data["free"]
11
+ end
12
+
13
+ def render_methods
14
+ @methods.map do |m|
15
+ m.render_signature(qualified_name)
16
+ end.join("\n\n")
17
+ end
18
+
19
+ def qualified_name
20
+ return "m#{@name}"
21
+ end
22
+
23
+ def render_definitions(module_name)
24
+ module_def = "VALUE #{qualified_name} = rb_define_module"
25
+ module_def += module_name.nil? ? "(" : "_under(#{module_name}, "
26
+ module_def += "\"#{@name}\");\n"
27
+
28
+ definitions = @methods.map do |m|
29
+ rb_method = case m.method_type
30
+ when "singleton"
31
+ "rb_define_singleton_method"
32
+ else
33
+ "rb_define_method"
34
+ end
35
+ rb_method += "(#{qualified_name}, \"#{m.name}\", #{m.qualified_name(qualified_name)}, #{m.param_count});"
36
+ if m.aliased? && m.method_type != "singleton"
37
+ rb_method += "\nrb_define_alias(#{qualified_name}, \"#{m.alias}\", \"#{m.name}\""
38
+ end
39
+
40
+ rb_method;
41
+ end.join("\n")
42
+
43
+ module_def + definitions
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,23 @@
1
+ require "wruby/util/hash"
2
+ module WRuby
3
+ class ParameterDefinition
4
+ attr_accessor :name, :type, :default
5
+
6
+ def initialize(data)
7
+ @name = data.require("name", "Parameter definition missing name")
8
+ raise FormatError, "Parameter cannot be named 'self'" if @name == "self"
9
+ @type = data.require("type", "Parameter #{@name} missing its type")
10
+ @default = data["default"]
11
+ @optional = data["optional"] || !!@default
12
+ @out_param = !!data["out"]
13
+ end
14
+
15
+ def out?
16
+ @out_param
17
+ end
18
+
19
+ def optional?
20
+ @optional
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,14 @@
1
+ require "wruby/util/hash"
2
+ module WRuby
3
+ class ReturnDefinition
4
+ attr_accessor :type, :base_type
5
+
6
+ def initialize(data)
7
+ @type = data
8
+ end
9
+
10
+ def uses_typedef?
11
+ instance_variable_defined?("@base_type")
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,110 @@
1
+ require "wruby/util/hash"
2
+ require "wruby/method_definition"
3
+ module WRuby
4
+ class StructureDefinition
5
+ attr_reader :name
6
+ def initialize(data)
7
+ @type = data.require("type", "Structure definition requires a type (module or class)")
8
+ @name = data.require("name", "Structure definition requires a name")
9
+ @methods = data["methods"]
10
+ @methods.map!{|e| MethodDefinition.new(e)} unless @methods.nil?
11
+ @parent = data["parent"]
12
+ @underlying_type = data.require("basetype", "Class requires an underlying type") if @type == "class"
13
+ @free_function = data["free"]
14
+ raise FormatError, "Modules do not require freeing" if @free_method && @type == "module"
15
+ end
16
+
17
+ def render_methods
18
+ @methods.map do |m|
19
+ m.render(self)
20
+ end.join("\n\n")
21
+ end
22
+
23
+ def qualified_name
24
+ case @type
25
+ when "class" then "c#{name}"
26
+ when "module" then "m#{name}"
27
+ end
28
+ end
29
+
30
+ def camel_case(_name = @name)
31
+ _name.gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
32
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
33
+ downcase
34
+ end
35
+
36
+ def render_definitions(module_name)
37
+
38
+ module_def = "VALUE #{qualified_name} = rb_define_#{@type}"
39
+ module_def += module_name.nil? ? "(" : "_under(#{module_name}, "
40
+ module_def += "\"#{@name}\""
41
+ module_def += case @type
42
+ when "class" then ", #{@parent || "rb_cObject"}"
43
+ when "module" then ""
44
+ end + ");\n"
45
+
46
+ definitions = @methods.map do |m|
47
+ rb_method = case m.method_type
48
+ when "singleton"
49
+ "rb_define_singleton_method"
50
+ when "method", "constructor"
51
+ "rb_define_method"
52
+ when "module"
53
+ "rb_define_module_function"
54
+ end
55
+ rb_method += "(#{qualified_name}, \"#{m.name}\", #{m.qualified_name(qualified_name)}, #{m.param_count});"
56
+ if m.aliased? && !m.singleton?
57
+ rb_method += "\nrb_define_alias(#{qualified_name}, \"#{m.alias}\", \"#{m.name}\");"
58
+ end
59
+
60
+ rb_method;
61
+ end.join("\n")
62
+
63
+ module_def + definitions
64
+ end
65
+
66
+ def render_free
67
+ free_func = "void #{camel_case}_free(void* data) {\n"
68
+ free_func +=" #{@underlying_type}* self = (#{@underlying_type}*)data;\n"
69
+ if @free_function
70
+ free_func += if @free_function.start_with?(".")
71
+ " self->~#{@underlying_type}();\n"
72
+ else
73
+ " #{@free_function}(self);\n"
74
+ end
75
+ end
76
+ free_func += " free(self);\n}\n"
77
+
78
+ end
79
+
80
+ def render_size
81
+ <<-SIZE
82
+ size_t #{camel_case}_size(const void*) {
83
+ return sizeof(#{@underlying_type});
84
+ }
85
+ SIZE
86
+ end
87
+
88
+ def type_name
89
+ "#{camel_case}_type"
90
+ end
91
+
92
+ def render_type(namespace = "")
93
+ <<-DEF
94
+ const rb_data_type_t #{type_name}} = {
95
+ .wrap_struct_name = "#{namespace}_#{@name}",
96
+ .function = {
97
+ .dmark = NULL,
98
+ .dfree = #{camel_case}_free,
99
+ .dsize = #{camel_case}_size,
100
+ },
101
+ .parent = #{@parent ? "&#{camel_case(@parent)}_type" : "NULL"},
102
+ .data = NULL,
103
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY
104
+ };
105
+ DEF
106
+ end
107
+
108
+
109
+ end
110
+ end
@@ -0,0 +1,11 @@
1
+ require "wruby/format_error"
2
+ module WRuby::Util
3
+ module RequireHash
4
+ def require(key, failure_message = "")
5
+ raise WRuby::FormatError, failure_message unless self.key?(key)
6
+ self[key]
7
+ end
8
+ end
9
+ end
10
+
11
+ Hash.prepend(WRuby::Util::RequireHash)
@@ -0,0 +1,9 @@
1
+ module WRuby
2
+ def self.rubify_name(name)
3
+ case name
4
+ when /\?/ then "is_#{name[...(name.size - 1)]}"
5
+ when /!/ then name[...(name.size - 1)]
6
+ else name
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,13 @@
1
+ module WRuby
2
+ def self.generalize_type(type_name)
3
+ case type_name
4
+ when /u.*64/ then "ulong"
5
+ when /64/ then "long"
6
+ when /^uint/ then "uint"
7
+ when /^int/ then "int"
8
+ when /char\*/ then "string"
9
+ when "float" then "double"
10
+ else type_name
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,77 @@
1
+ module WRuby
2
+ @@types = {}
3
+ @@aliases = {}
4
+ @@aliases.default_proc = proc {|h, k| k}
5
+
6
+ class UnrecognizedTypeError < StandardError
7
+ def initialize(name)
8
+ super("Unrecognized type: #{name}")
9
+ end
10
+ end
11
+
12
+ def self.register_alias(alias_name, type)
13
+ @@aliases[alias_name.to_s] = type.to_s
14
+ end
15
+
16
+ def self.register_wrapping(type, wrapping, unwrapping)
17
+ @@types[type.to_s] = {wrap: wrapping, unwrap: unwrapping}
18
+ end
19
+
20
+ def self.wrap(name, type)
21
+ raise UnrecognizedTypeError.new(type) unless @@types.key?(type) || @@aliases.key?(type)
22
+ @@types[type.to_s][:wrap].gsub(/\wthis\w/, name)
23
+ end
24
+
25
+ def self.unwrap(name, type)
26
+ raise UnrecognizedTypeError.new(type) unless @@types.key?(type) || @@aliases.key?(type)
27
+ resolved_name = @@aliases[type.to_s]
28
+ @@types[resolved_name.to_s][:unwrap].gsub(/\wthis\w/, name)
29
+ end
30
+
31
+ # Basic integer types
32
+ register_wrapping("char", "INT2NUM(this)", "NUM2CHR(this)")
33
+ register_wrapping("short", "INT2NUM(this)", "NUM2SHORT(this)")
34
+ register_wrapping("int", "INT2NUM(this)", "NUM2INT(this)")
35
+ register_wrapping("long", "LONG2NUM(this)", "NUM2LONG(this)")
36
+ register_wrapping("long long", "LL2NUM(this)", "NUM2LL(this)")
37
+ # Basic unsigned integer types
38
+ register_wrapping("unsigned char", "UINT2NUM(this)", "NUM2UCHR(this)")
39
+ register_wrapping("unsigned short", "UINT2NUM(this)", "NUM2USHORT(this)")
40
+ register_wrapping("unsigned int", "UINT2NUM(this)", "NUM2UINT(this)")
41
+ register_wrapping("unsigned long", "ULONG2NUM(this)", "NUM2ULONG(this)")
42
+ register_wrapping("unsigned long long", "ULL2NUM(this)", "NUM2ULL(this)")
43
+ # unsigned abbreviations
44
+ register_alias("uchar", "unsigned char")
45
+ register_alias("ushort", "unsigned short")
46
+ register_alias("uint", "unsigned int")
47
+ register_alias("ulong", "unsigned long")
48
+ register_alias("long ulong", "unsigned long long") # This one is weird, but it makes more sense than ulong long
49
+
50
+ # Fixed integer types
51
+ register_wrapping("int8_t", "INT2NUM(this)", "(int8_t)NUM2CHR(this)")
52
+ register_wrapping("int16_t", "INT2NUM(this)", "(int16_t)NUM2SHORT(this)")
53
+ register_wrapping("int32_t", "INT2NUM(this)", "(int32_t)NUM2INT(this)")
54
+ register_wrapping("int64_t", "LONG2NUM(this)", "(int64_t)NUM2LONG(this)")
55
+ register_wrapping("uint8_t", "UINT2NUM(this)", "(int8_t)NUM2UINT(this)")
56
+ register_wrapping("uint16_t", "UINT2NUM(this)", "(int16_t)NUM2UINT(this)")
57
+ register_wrapping("uint32_t", "UINT2NUM(this)", "(int32_t)NUM2UINT(this)")
58
+ register_wrapping("uint64_t", "ULONG2NUM(this)", "(int64_t)NUM2ULONG(this)")
59
+
60
+ # Floating-point types
61
+ register_wrapping("float", "DBL2NUM(this)", "(float)NUM2DBL(this)")
62
+ register_wrapping("double", "DBL2NUM(this)", "NUM2DBL(this)")
63
+ # Fixed-size floating-point aliases
64
+ register_alias("float32", "float")
65
+ register_alias("float64", "double")
66
+
67
+ # Boolean type
68
+ register_wrapping("bool", "(this ? QTrue : QFalse)", "RTEST(this)")
69
+
70
+ # String types
71
+ # C-style strings
72
+ register_wrapping("char*", "rb_str_new_cstr(this)", "StringValueCStr(this)")
73
+ register_alias("cstring", "char*")
74
+ register_alias("cstr", "char*")
75
+ # Non-C-style strings are not handled here, as it's more complex than a simple inline
76
+
77
+ end
@@ -0,0 +1,38 @@
1
+ require "psych"
2
+
3
+ require "wruby/structure_definition"
4
+ require "wruby/module_definition"
5
+ require "wruby/format_error"
6
+
7
+ module WRuby
8
+ def self.parse(source)
9
+ data = Psych.load_stream(source)
10
+ raise FormatError, "Specification too short" if data.size < 2
11
+ data[1..].map do |d|
12
+ StructureDefinition.new(d)
13
+ end.unshift(data[0])
14
+ end
15
+
16
+ def self.parse_file(file)
17
+ parse(File.read(file))
18
+ end
19
+
20
+ def self.render_functions(spec)
21
+ spec[1..].map do |mspec|
22
+ mspec.render_methods
23
+ end
24
+ end
25
+
26
+ def self.render_ruby_definitions(spec)
27
+ spec[1..].map.with_index do |mspec, i|
28
+ parent = nil
29
+ parent = spec[i].qualified_name unless i == 0
30
+ mspec.render_definitions(parent)
31
+ end
32
+
33
+ end
34
+
35
+ def self.render(spec)
36
+
37
+ end
38
+ end
data/lib/wruby.rb ADDED
@@ -0,0 +1,3 @@
1
+ module WRuby
2
+
3
+ end
metadata ADDED
@@ -0,0 +1,58 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: wruby
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Kellen Watt
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2022-11-27 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Generates code for C/C++ code based on YAML sepcifications.
14
+ email:
15
+ executables: []
16
+ extensions: []
17
+ extra_rdoc_files: []
18
+ files:
19
+ - lib/wruby.old/lib/method_definition.rb
20
+ - lib/wruby.old/lib/module_definition.rb
21
+ - lib/wruby.old/lib/parameter_definition.rb
22
+ - lib/wruby.old/lib/return_definition.rb
23
+ - lib/wruby.old/lib/structure_definition.rb
24
+ - lib/wruby.old/lib/util/hash.rb
25
+ - lib/wruby.old/lib/util/normalize.rb
26
+ - lib/wruby.old/lib/util/type_matchup.rb
27
+ - lib/wruby.old/lib/util/type_wrap.rb
28
+ - lib/wruby.old/wruby.rb
29
+ - lib/wruby.rb
30
+ - lib/wruby/format_error.rb
31
+ - lib/wruby/metadata.rb
32
+ - lib/wruby/util/hash.rb
33
+ - lib/wruby/util/normalize.rb
34
+ - lib/wruby/util/type_wrap.rb
35
+ homepage:
36
+ licenses:
37
+ - MIT
38
+ metadata: {}
39
+ post_install_message:
40
+ rdoc_options: []
41
+ require_paths:
42
+ - lib
43
+ required_ruby_version: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ required_rubygems_version: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: '0'
53
+ requirements: []
54
+ rubygems_version: 3.3.7
55
+ signing_key:
56
+ specification_version: 4
57
+ summary: Name reservation for a future project
58
+ test_files: []