wrapture 0.2.2 → 0.3.0
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 +4 -4
- data/bin/wrapture +9 -4
- data/lib/wrapture.rb +24 -1
- data/lib/wrapture/action_spec.rb +81 -0
- data/lib/wrapture/class_spec.rb +359 -192
- data/lib/wrapture/constant_spec.rb +22 -5
- data/lib/wrapture/constants.rb +32 -0
- data/lib/wrapture/errors.rb +57 -0
- data/lib/wrapture/function_spec.rb +207 -36
- data/lib/wrapture/normalize.rb +62 -0
- data/lib/wrapture/rule_spec.rb +87 -0
- data/lib/wrapture/scope.rb +80 -0
- data/lib/wrapture/struct_spec.rb +127 -0
- data/lib/wrapture/version.rb +11 -1
- data/lib/wrapture/wrapped_function_spec.rb +117 -0
- metadata +17 -3
@@ -0,0 +1,87 @@
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0
|
2
|
+
|
3
|
+
# frozen_string_literal: true
|
4
|
+
|
5
|
+
# Copyright 2019-2020 Joel E. Anderson
|
6
|
+
#
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
8
|
+
# you may not use this file except in compliance with the License.
|
9
|
+
# You may obtain a copy of the License at
|
10
|
+
#
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
12
|
+
#
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
16
|
+
# See the License for the specific language governing permissions and
|
17
|
+
# limitations under the License.
|
18
|
+
|
19
|
+
require 'wrapture/constants'
|
20
|
+
require 'wrapture/errors'
|
21
|
+
|
22
|
+
module Wrapture
|
23
|
+
# A condition (or set of conditions) that a struct or its members must meet
|
24
|
+
# in order to conform to a given specification. This allows a single struct
|
25
|
+
# type to be equivalent to some class specifications, but not others.
|
26
|
+
class RuleSpec
|
27
|
+
# A list of valid condition strings.
|
28
|
+
CONDITIONS = %w[equals not-equals].freeze
|
29
|
+
|
30
|
+
# Normalizes a hash specification of a rule. Normalization checks for
|
31
|
+
# invalid keys and unrecognized conditions.
|
32
|
+
def self.normalize_spec_hash(spec)
|
33
|
+
normalized = spec.dup
|
34
|
+
|
35
|
+
required_keys = if spec.key?('member-name')
|
36
|
+
normalized['type'] = 'struct-member'
|
37
|
+
%w[member-name condition value].freeze
|
38
|
+
else
|
39
|
+
normalized['type'] = 'expression'
|
40
|
+
%w[left-expression condition right-expression].freeze
|
41
|
+
end
|
42
|
+
|
43
|
+
missing_keys = required_keys - spec.keys
|
44
|
+
unless missing_keys.empty?
|
45
|
+
missing_msg = "required keys are missing: #{missing_keys.join(', ')}"
|
46
|
+
raise(MissingSpecKey, missing_msg)
|
47
|
+
end
|
48
|
+
|
49
|
+
extra_keys = spec.keys - required_keys
|
50
|
+
unless extra_keys.empty?
|
51
|
+
extra_msg = "these keys are unrecognized: #{extra_keys.join(', ')}"
|
52
|
+
raise(InvalidSpecKey, extra_msg)
|
53
|
+
end
|
54
|
+
|
55
|
+
unless RuleSpec::CONDITIONS.include?(spec['condition'])
|
56
|
+
condition_msg = "#{spec['condition']} is an invalid condition"
|
57
|
+
raise(InvalidSpecKey, condition_msg)
|
58
|
+
end
|
59
|
+
|
60
|
+
normalized
|
61
|
+
end
|
62
|
+
|
63
|
+
# Creates a rule spec based on the provided spec.
|
64
|
+
#
|
65
|
+
# The hash must have the following keys:
|
66
|
+
# member-name:: the name of the struct member the rule applies to
|
67
|
+
# condition:: the condition this rule uses (supported values are held in the
|
68
|
+
# RuleSpec::CONDITIONS list)
|
69
|
+
# value:: the value to use in the condition check
|
70
|
+
def initialize(spec)
|
71
|
+
@spec = RuleSpec.normalize_spec_hash(spec)
|
72
|
+
end
|
73
|
+
|
74
|
+
# A string containing a check for a struct of the given name for this rule.
|
75
|
+
def check(variable: nil)
|
76
|
+
condition = @spec['condition'] == 'equals' ? '==' : '!='
|
77
|
+
|
78
|
+
if @spec['type'] == 'struct-member'
|
79
|
+
"#{variable}->#{@spec['member-name']} #{condition} #{@spec['value']}"
|
80
|
+
else
|
81
|
+
left = @spec['left-expression']
|
82
|
+
right = @spec['right-expression']
|
83
|
+
"#{left} #{condition} #{right}".sub(RETURN_VALUE_KEYWORD, 'return_val')
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0
|
2
|
+
|
3
|
+
# frozen_string_literal: true
|
4
|
+
|
5
|
+
# Copyright 2019 Joel E. Anderson
|
6
|
+
#
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
8
|
+
# you may not use this file except in compliance with the License.
|
9
|
+
# You may obtain a copy of the License at
|
10
|
+
#
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
12
|
+
#
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
16
|
+
# See the License for the specific language governing permissions and
|
17
|
+
# limitations under the License.
|
18
|
+
|
19
|
+
module Wrapture
|
20
|
+
# Describes a scope of one or more class specifications.
|
21
|
+
class Scope
|
22
|
+
# A list of classes currently in the scope.
|
23
|
+
attr_reader :classes
|
24
|
+
|
25
|
+
# Creates an empty scope with no classes in it.
|
26
|
+
def initialize(spec = nil)
|
27
|
+
@classes = []
|
28
|
+
|
29
|
+
return if spec.nil? || !spec.key?('classes')
|
30
|
+
|
31
|
+
@version = Wrapture.spec_version(spec)
|
32
|
+
spec['classes'].each do |class_hash|
|
33
|
+
ClassSpec.new(class_hash, scope: self)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Adds a class specification to the scope.
|
38
|
+
#
|
39
|
+
# This does not set the scope as the owner of the class. This must be done
|
40
|
+
# during the construction of the class spec.
|
41
|
+
def <<(spec)
|
42
|
+
@classes << spec if spec.is_a?(ClassSpec)
|
43
|
+
end
|
44
|
+
|
45
|
+
# Generates the wrapper class files for all classes in the scope.
|
46
|
+
def generate_wrappers
|
47
|
+
files = []
|
48
|
+
|
49
|
+
@classes.each do |class_spec|
|
50
|
+
files.concat(class_spec.generate_wrappers)
|
51
|
+
end
|
52
|
+
|
53
|
+
files
|
54
|
+
end
|
55
|
+
|
56
|
+
# A list of ClassSpecs in this scope that are overloads of the given class.
|
57
|
+
def overloads(parent)
|
58
|
+
@classes.select { |class_spec| class_spec.overloads?(parent) }
|
59
|
+
end
|
60
|
+
|
61
|
+
# True if there is an overload of the given class in this scope.
|
62
|
+
def overloads?(parent)
|
63
|
+
@classes.any? { |class_spec| class_spec.overloads?(parent) }
|
64
|
+
end
|
65
|
+
|
66
|
+
# Returns the ClassSpec for the given type in the scope.
|
67
|
+
def type(type)
|
68
|
+
@classes.find { |class_spec| class_spec.name == type }
|
69
|
+
end
|
70
|
+
|
71
|
+
# Returns true if the given type is in the scope.
|
72
|
+
def type?(type)
|
73
|
+
@classes.each do |class_spec|
|
74
|
+
return true if class_spec.name == type
|
75
|
+
end
|
76
|
+
|
77
|
+
false
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,127 @@
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0
|
2
|
+
|
3
|
+
# frozen_string_literal: true
|
4
|
+
|
5
|
+
# Copyright 2019 Joel E. Anderson
|
6
|
+
#
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
8
|
+
# you may not use this file except in compliance with the License.
|
9
|
+
# You may obtain a copy of the License at
|
10
|
+
#
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
12
|
+
#
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
16
|
+
# See the License for the specific language governing permissions and
|
17
|
+
# limitations under the License.
|
18
|
+
|
19
|
+
module Wrapture
|
20
|
+
# A description of a struct.
|
21
|
+
class StructSpec
|
22
|
+
# Normalizes a hash specification of a struct. Normalization will check for
|
23
|
+
# things like invalid keys, duplicate entries in include lists, and will set
|
24
|
+
# missing keys to their default value (for example, an empty list if no
|
25
|
+
# includes are given).
|
26
|
+
def self.normalize_spec_hash(spec)
|
27
|
+
normalized = spec.dup
|
28
|
+
normalized.default = []
|
29
|
+
|
30
|
+
normalized['includes'] = Wrapture.normalize_includes spec['includes']
|
31
|
+
|
32
|
+
normalized['members'] ||= []
|
33
|
+
|
34
|
+
normalized
|
35
|
+
end
|
36
|
+
|
37
|
+
# A list of rules defined for this struct.
|
38
|
+
attr_reader :rules
|
39
|
+
|
40
|
+
# Creates a struct spec based on the provided spec hash.
|
41
|
+
#
|
42
|
+
# The hash must have the following keys:
|
43
|
+
# name:: the name of the struct
|
44
|
+
#
|
45
|
+
# The following keys are optional:
|
46
|
+
# includes:: a list of includes required for the struct
|
47
|
+
# members:: a list of the members of the struct, each with a type and name
|
48
|
+
# field
|
49
|
+
# rules:: a list of conditions this struct and its members must meet (refer
|
50
|
+
# to the RuleSpec class for more details)
|
51
|
+
def initialize(spec)
|
52
|
+
@spec = StructSpec.normalize_spec_hash(spec)
|
53
|
+
|
54
|
+
@rules = @spec['rules'].map { |rule_spec| RuleSpec.new(rule_spec) }
|
55
|
+
end
|
56
|
+
|
57
|
+
# A declaration of the struct with the given variable name.
|
58
|
+
def declaration(name)
|
59
|
+
"struct #{@spec['name']} #{name}"
|
60
|
+
end
|
61
|
+
|
62
|
+
# A list of includes required for this struct.
|
63
|
+
def includes
|
64
|
+
@spec['includes'].dup
|
65
|
+
end
|
66
|
+
|
67
|
+
# A string containing the typed members of the struct, separated by commas.
|
68
|
+
def member_list
|
69
|
+
members = []
|
70
|
+
|
71
|
+
@spec['members'].each do |member|
|
72
|
+
members << ClassSpec.typed_variable(member['type'], member['name'])
|
73
|
+
end
|
74
|
+
|
75
|
+
members.join ', '
|
76
|
+
end
|
77
|
+
|
78
|
+
# A string containing the typed members of the struct, with their default
|
79
|
+
# values if provided, separated by commas.
|
80
|
+
def member_list_with_defaults
|
81
|
+
@spec['members'].map do |member|
|
82
|
+
member_str = ClassSpec.typed_variable(member['type'], member['name'])
|
83
|
+
|
84
|
+
if member.key?('default-value')
|
85
|
+
default_value = member['default-value']
|
86
|
+
|
87
|
+
member_str += ' = '
|
88
|
+
member_str += if member['type'] == 'const char *'
|
89
|
+
'"' + default_value + '"'
|
90
|
+
elsif member['type'].end_with?('char')
|
91
|
+
"'#{default_value}'"
|
92
|
+
else
|
93
|
+
default_value.to_s
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
member_str
|
98
|
+
end.join(', ')
|
99
|
+
end
|
100
|
+
|
101
|
+
# The members of the struct
|
102
|
+
def members
|
103
|
+
@spec['members']
|
104
|
+
end
|
105
|
+
|
106
|
+
# True if there are members included in the struct specification.
|
107
|
+
def members?
|
108
|
+
!@spec['members'].empty?
|
109
|
+
end
|
110
|
+
|
111
|
+
# The name of this struct
|
112
|
+
def name
|
113
|
+
@spec['name']
|
114
|
+
end
|
115
|
+
|
116
|
+
# A declaration of a pointer to the struct with the given variable name.
|
117
|
+
def pointer_declaration(name)
|
118
|
+
"struct #{@spec['name']} *#{name}"
|
119
|
+
end
|
120
|
+
|
121
|
+
# A string containing an expression that returns true if the struct with
|
122
|
+
# the given name meets all rules defined for this struct.
|
123
|
+
def rules_check(name)
|
124
|
+
@rules.map { |rule| rule.check(variable: name) }.join(' && ')
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
data/lib/wrapture/version.rb
CHANGED
@@ -1,5 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Wrapture
|
4
|
-
|
4
|
+
# the current version of Wrapture
|
5
|
+
VERSION = '0.3.0'
|
6
|
+
|
7
|
+
# Returns true if the version of the spec is supported by this version of
|
8
|
+
# Wrapture. Otherwise returns false.
|
9
|
+
def self.supports_version?(version)
|
10
|
+
wrapture_version = Gem::Version.new(Wrapture::VERSION)
|
11
|
+
spec_version = Gem::Version.new(version)
|
12
|
+
|
13
|
+
spec_version <= wrapture_version
|
14
|
+
end
|
5
15
|
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0
|
2
|
+
|
3
|
+
# frozen_string_literal: true
|
4
|
+
|
5
|
+
# Copyright 2019-2020 Joel E. Anderson
|
6
|
+
#
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
8
|
+
# you may not use this file except in compliance with the License.
|
9
|
+
# You may obtain a copy of the License at
|
10
|
+
#
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
12
|
+
#
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
16
|
+
# See the License for the specific language governing permissions and
|
17
|
+
# limitations under the License.
|
18
|
+
|
19
|
+
module Wrapture
|
20
|
+
# A description of a function to be wrapped by another language.
|
21
|
+
class WrappedFunctionSpec
|
22
|
+
# Normalizes a hash specification of a wrapped function. Normalization will
|
23
|
+
# check for things like invalid keys, duplicate entries in include lists,
|
24
|
+
# and will set missing keys to their default values (for example, an empty
|
25
|
+
# list if no includes are given).
|
26
|
+
def self.normalize_spec_hash(spec)
|
27
|
+
normalized = spec.dup
|
28
|
+
|
29
|
+
normalized['params'] ||= []
|
30
|
+
normalized['params'].each do |param_spec|
|
31
|
+
param_spec['value'] = param_spec['name'] if param_spec['value'].nil?
|
32
|
+
end
|
33
|
+
|
34
|
+
normalized['includes'] = Wrapture.normalize_includes(spec['includes'])
|
35
|
+
|
36
|
+
normalized['error-check'] ||= {}
|
37
|
+
normalized['error-check']['rules'] ||= []
|
38
|
+
|
39
|
+
unless spec.key?('return')
|
40
|
+
normalized['return'] = {}
|
41
|
+
normalized['return']['type'] = 'void'
|
42
|
+
end
|
43
|
+
|
44
|
+
normalized
|
45
|
+
end
|
46
|
+
|
47
|
+
# Creates a wrapped function spec based on the provided spec.
|
48
|
+
#
|
49
|
+
# The hash must have the following keys:
|
50
|
+
# name:: the name of the wrapped function
|
51
|
+
# params:: a list of parameters to supply when calling
|
52
|
+
#
|
53
|
+
# Each member of the params list must be a hash, with a mandatory key of
|
54
|
+
# 'value' holding the value to be supplied as the parameter. If only a
|
55
|
+
# 'name' key is provided, this will be used as the value. A 'type' may be
|
56
|
+
# supplied as well, and is necessary if an equivalent struct or pointer is
|
57
|
+
# to be supplied as the value so that casting can be performed correctly.
|
58
|
+
#
|
59
|
+
# The following key is optional:
|
60
|
+
# includes:: a list of includes needed for this function
|
61
|
+
def initialize(spec)
|
62
|
+
@spec = self.class.normalize_spec_hash(spec)
|
63
|
+
|
64
|
+
check = @spec['error-check']
|
65
|
+
|
66
|
+
@error_rules = check['rules'].map do |rule_spec|
|
67
|
+
RuleSpec.new(rule_spec)
|
68
|
+
end
|
69
|
+
|
70
|
+
action = check['error-action']
|
71
|
+
@error_action = ActionSpec.new(action) unless @error_rules.empty?
|
72
|
+
end
|
73
|
+
|
74
|
+
# Generates a function call from a provided FunctionSpec. Paremeters and
|
75
|
+
# types are resolved using this function's context.
|
76
|
+
def call_from(function_spec)
|
77
|
+
resolved_params = []
|
78
|
+
|
79
|
+
@spec['params'].each do |param|
|
80
|
+
resolved_params << function_spec.resolve_wrapped_param(param)
|
81
|
+
end
|
82
|
+
|
83
|
+
"#{@spec['name']}( #{resolved_params.join(', ')} )"
|
84
|
+
end
|
85
|
+
|
86
|
+
# Yields each line of the error check and any actions taken for this wrapped
|
87
|
+
# function. If this function does not have any error check defined, then
|
88
|
+
# this function returns without yielding anything.
|
89
|
+
def error_check
|
90
|
+
return if @error_rules.empty?
|
91
|
+
|
92
|
+
checks = @error_rules.map(&:check)
|
93
|
+
yield "if( #{checks.join(' && ')} ){"
|
94
|
+
yield " #{@error_action.take};"
|
95
|
+
yield '}'
|
96
|
+
end
|
97
|
+
|
98
|
+
# True if the wrapped function has an error check associated with it.
|
99
|
+
def error_check?
|
100
|
+
!@error_rules.empty?
|
101
|
+
end
|
102
|
+
|
103
|
+
# A list of includes required for this function call.
|
104
|
+
def includes
|
105
|
+
includes = @spec['includes'].dup
|
106
|
+
|
107
|
+
includes.concat(@error_action.includes) if error_check?
|
108
|
+
|
109
|
+
includes
|
110
|
+
end
|
111
|
+
|
112
|
+
# A string with the type of the return value.
|
113
|
+
def return_val_type
|
114
|
+
@spec['return']['type']
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: wrapture
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Joel Anderson
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-01-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -17,13 +17,19 @@ dependencies:
|
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: 1.6.4
|
20
|
-
|
20
|
+
- - "<"
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '2.2'
|
23
|
+
type: :development
|
21
24
|
prerelease: false
|
22
25
|
version_requirements: !ruby/object:Gem::Requirement
|
23
26
|
requirements:
|
24
27
|
- - ">="
|
25
28
|
- !ruby/object:Gem::Version
|
26
29
|
version: 1.6.4
|
30
|
+
- - "<"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '2.2'
|
27
33
|
description: Wraps C code in C++.
|
28
34
|
email: joelanderson333@gmail.com
|
29
35
|
executables:
|
@@ -33,10 +39,18 @@ extra_rdoc_files: []
|
|
33
39
|
files:
|
34
40
|
- bin/wrapture
|
35
41
|
- lib/wrapture.rb
|
42
|
+
- lib/wrapture/action_spec.rb
|
36
43
|
- lib/wrapture/class_spec.rb
|
37
44
|
- lib/wrapture/constant_spec.rb
|
45
|
+
- lib/wrapture/constants.rb
|
46
|
+
- lib/wrapture/errors.rb
|
38
47
|
- lib/wrapture/function_spec.rb
|
48
|
+
- lib/wrapture/normalize.rb
|
49
|
+
- lib/wrapture/rule_spec.rb
|
50
|
+
- lib/wrapture/scope.rb
|
51
|
+
- lib/wrapture/struct_spec.rb
|
39
52
|
- lib/wrapture/version.rb
|
53
|
+
- lib/wrapture/wrapped_function_spec.rb
|
40
54
|
homepage: http://rubygems.org/gems/wrapture
|
41
55
|
licenses:
|
42
56
|
- Apache-2.0
|