sweet-moon 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +2 -0
- data/.rspec +1 -0
- data/.rubocop.yml +40 -0
- data/Gemfile +12 -0
- data/Gemfile.lock +61 -0
- data/README.md +1149 -0
- data/components/api.rb +83 -0
- data/components/injections/injections_503.rb +21 -0
- data/components/injections/injections_514.rb +29 -0
- data/components/injections/injections_542.rb +49 -0
- data/components/injections.rb +11 -0
- data/components/interpreters/50/function.rb +52 -0
- data/components/interpreters/50/interpreter.rb +105 -0
- data/components/interpreters/50/reader.rb +65 -0
- data/components/interpreters/50/table.rb +99 -0
- data/components/interpreters/50/writer.rb +45 -0
- data/components/interpreters/51/function.rb +52 -0
- data/components/interpreters/51/interpreter.rb +104 -0
- data/components/interpreters/51/reader.rb +65 -0
- data/components/interpreters/51/table.rb +60 -0
- data/components/interpreters/51/writer.rb +45 -0
- data/components/interpreters/54/function.rb +52 -0
- data/components/interpreters/54/interpreter.rb +100 -0
- data/components/interpreters/54/reader.rb +65 -0
- data/components/interpreters/54/table.rb +60 -0
- data/components/interpreters/54/writer.rb +45 -0
- data/components/interpreters.rb +11 -0
- data/components/io.rb +11 -0
- data/config/tests.sample.yml +15 -0
- data/controllers/api.rb +143 -0
- data/controllers/cli/cli.rb +32 -0
- data/controllers/cli/help.rb +24 -0
- data/controllers/cli/signatures.rb +179 -0
- data/controllers/cli/version.rb +14 -0
- data/controllers/interpreter.rb +68 -0
- data/controllers/state.rb +74 -0
- data/dsl/api.rb +31 -0
- data/dsl/cache.rb +118 -0
- data/dsl/concerns/fennel.rb +13 -0
- data/dsl/concerns/packages.rb +37 -0
- data/dsl/errors.rb +28 -0
- data/dsl/fennel.rb +47 -0
- data/dsl/global.rb +42 -0
- data/dsl/state.rb +104 -0
- data/dsl/sweet_moon.rb +53 -0
- data/logic/api.rb +17 -0
- data/logic/interpreter.rb +84 -0
- data/logic/interpreters/interpreter_50.rb +34 -0
- data/logic/interpreters/interpreter_51.rb +37 -0
- data/logic/interpreters/interpreter_54.rb +41 -0
- data/logic/io.rb +6 -0
- data/logic/options.rb +14 -0
- data/logic/shared_object.rb +52 -0
- data/logic/signature.rb +258 -0
- data/logic/signatures/ffi_types.rb +27 -0
- data/logic/signatures/signatures_322.rb +418 -0
- data/logic/signatures/signatures_401.rb +243 -0
- data/logic/signatures/signatures_503.rb +575 -0
- data/logic/signatures/signatures_514.rb +460 -0
- data/logic/signatures/signatures_542.rb +591 -0
- data/logic/spec.rb +13 -0
- data/logic/tables.rb +32 -0
- data/ports/in/dsl/sweet-moon/errors.rb +3 -0
- data/ports/in/dsl/sweet-moon.rb +1 -0
- data/ports/in/shell/sweet-moon +5 -0
- data/ports/in/shell.rb +21 -0
- data/ports/out/shell.rb +9 -0
- data/sweet-moon.gemspec +35 -0
- metadata +137 -0
data/logic/signature.rb
ADDED
@@ -0,0 +1,258 @@
|
|
1
|
+
require_relative 'signatures/ffi_types'
|
2
|
+
|
3
|
+
module Logic
|
4
|
+
Signature = {
|
5
|
+
lua_to_ffi_types: Signatures::FFITypes,
|
6
|
+
|
7
|
+
to_ffi: ->(signature) {
|
8
|
+
result = [
|
9
|
+
signature[:name].to_sym,
|
10
|
+
signature[:input].map do |input|
|
11
|
+
input_type = Signature[:lua_to_ffi_types][input[:primitive].to_sym]
|
12
|
+
|
13
|
+
if input[:pointer]
|
14
|
+
:pointer
|
15
|
+
elsif input_type
|
16
|
+
input_type.to_sym
|
17
|
+
else
|
18
|
+
raise "missing primitive: #{input[:primitive]}"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
]
|
22
|
+
|
23
|
+
output_type = Signature[:lua_to_ffi_types][
|
24
|
+
signature[:output][:primitive].to_sym
|
25
|
+
]
|
26
|
+
|
27
|
+
result << if signature[:output][:pointer]
|
28
|
+
:pointer
|
29
|
+
elsif output_type
|
30
|
+
output_type.to_sym
|
31
|
+
else
|
32
|
+
raise "missing primitive: #{signature[:output][:primitive]}"
|
33
|
+
end
|
34
|
+
|
35
|
+
result[1].pop while result[1].last == :void
|
36
|
+
|
37
|
+
result
|
38
|
+
},
|
39
|
+
|
40
|
+
extract_from_nm: ->(output) {
|
41
|
+
output.lines.map do |line|
|
42
|
+
line.sub(/\S+\s\S+\s/, '').strip
|
43
|
+
end.uniq.sort
|
44
|
+
},
|
45
|
+
|
46
|
+
remove_comments: ->(source) {
|
47
|
+
source.gsub(%r{/\*([\s\S]*?)\*/}, '')
|
48
|
+
},
|
49
|
+
|
50
|
+
extract_type_from_source: ->(source) {
|
51
|
+
sanitized_source = Signature[:sanitize_source_name].(source)
|
52
|
+
|
53
|
+
parts = sanitized_source
|
54
|
+
.gsub(/[{()].*/, '').gsub('*', '').gsub(/\s+/, ' ')
|
55
|
+
.strip.split(/\s/)
|
56
|
+
|
57
|
+
return nil if parts.size < 3
|
58
|
+
|
59
|
+
base_index = 1
|
60
|
+
|
61
|
+
if %w[unsigned signed const].include? parts[base_index].gsub(';', '')
|
62
|
+
base_index += 1
|
63
|
+
return nil if parts.size < 4
|
64
|
+
end
|
65
|
+
|
66
|
+
primitive = parts[base_index].gsub(';', '')
|
67
|
+
type = parts[base_index + 1].gsub(';', '')
|
68
|
+
|
69
|
+
{ type: type, primitive: primitive }
|
70
|
+
},
|
71
|
+
|
72
|
+
extract_types_from_header: ->(source, types = {}) {
|
73
|
+
source = Signature[:remove_comments].(source)
|
74
|
+
|
75
|
+
# remove { ... }
|
76
|
+
source = source.gsub(/\{([\s\S]*?)\}/, '')
|
77
|
+
|
78
|
+
source.each_line do |line|
|
79
|
+
if line[/typedef/]
|
80
|
+
type = Signature[:extract_type_from_source].(line)
|
81
|
+
types[type[:type]] = type[:primitive] if type
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
types
|
86
|
+
},
|
87
|
+
|
88
|
+
extract_from_header: ->(source) {
|
89
|
+
source = Signature[:remove_comments].(source)
|
90
|
+
|
91
|
+
signatures = []
|
92
|
+
|
93
|
+
current_index = 0
|
94
|
+
|
95
|
+
source.each_line.with_index do |line, line_index|
|
96
|
+
next unless line_index > current_index - 1
|
97
|
+
|
98
|
+
line = line.strip
|
99
|
+
|
100
|
+
if line[/\w\)*\s*\(/] && !line[/typedef|^if\s/]
|
101
|
+
signature = line
|
102
|
+
|
103
|
+
current_index = line_index + 1
|
104
|
+
|
105
|
+
buffer = 100
|
106
|
+
|
107
|
+
while signature.scan(/\(/).size != signature.scan(/\)/).size &&
|
108
|
+
buffer.positive?
|
109
|
+
|
110
|
+
signature = "#{signature} #{source.lines[current_index]}"
|
111
|
+
current_index += 1
|
112
|
+
|
113
|
+
buffer -= 1
|
114
|
+
end
|
115
|
+
|
116
|
+
signature = signature.gsub(/\n/, ' ').gsub(/\s+/, ' ').strip
|
117
|
+
|
118
|
+
signatures << signature
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
signatures.uniq.sort
|
123
|
+
},
|
124
|
+
|
125
|
+
sanitize_source_name: ->(source) {
|
126
|
+
# int (*lorem) (lua_State *L, const void* p);
|
127
|
+
sanitized_source = source
|
128
|
+
|
129
|
+
candidate = sanitized_source[/\(\s*\**\s*\w+\s*\)\s*\(/]
|
130
|
+
|
131
|
+
if candidate
|
132
|
+
sanitized_source = sanitized_source.sub(
|
133
|
+
candidate, "#{candidate.gsub('(', '').gsub(')', '')}("
|
134
|
+
)
|
135
|
+
end
|
136
|
+
|
137
|
+
sanitized_source
|
138
|
+
},
|
139
|
+
|
140
|
+
is_macro?: ->(sanitized_source) {
|
141
|
+
function_source = sanitized_source.strip
|
142
|
+
|
143
|
+
if function_source[/^#define/] && function_source[/\)\s*\w*\(/]
|
144
|
+
function_source = function_source.gsub(/^#define\s*/, '')
|
145
|
+
function_source = function_source.sub(/\)\s*\w*\(.*/, ')')
|
146
|
+
return function_source
|
147
|
+
end
|
148
|
+
|
149
|
+
false
|
150
|
+
},
|
151
|
+
|
152
|
+
extract_macro_from_source: ->(function_source, sanitized_source) {
|
153
|
+
input = /\(([^()]+)\)/.match(sanitized_source)
|
154
|
+
|
155
|
+
input = if input
|
156
|
+
input[1].split(',').map(&:strip).map do |parameter|
|
157
|
+
Signature[:parse_parameter].(parameter, {})
|
158
|
+
end
|
159
|
+
else
|
160
|
+
[]
|
161
|
+
end
|
162
|
+
|
163
|
+
function = {
|
164
|
+
name: sanitized_source.gsub(/\(.*/, '').strip,
|
165
|
+
macro: true,
|
166
|
+
input: input.map { |parameter| { name: parameter[:type] } },
|
167
|
+
source: function_source
|
168
|
+
}
|
169
|
+
|
170
|
+
function
|
171
|
+
},
|
172
|
+
|
173
|
+
extract_from_source: ->(function_source, types = {}) {
|
174
|
+
sanitized_source = Signature[:sanitize_source_name].(function_source)
|
175
|
+
|
176
|
+
macro = Signature[:is_macro?].(sanitized_source)
|
177
|
+
|
178
|
+
return Signature[:extract_macro_from_source].(function_source, macro) if macro
|
179
|
+
|
180
|
+
begin
|
181
|
+
input = /\(([^()]+)\)/
|
182
|
+
.match(sanitized_source)[1].split(',').map(&:strip)
|
183
|
+
.map do |parameter|
|
184
|
+
Signature[:parse_parameter].(parameter,
|
185
|
+
types)
|
186
|
+
end
|
187
|
+
rescue StandardError
|
188
|
+
return nil
|
189
|
+
end
|
190
|
+
|
191
|
+
function = Signature[:parse_function].(
|
192
|
+
sanitized_source.sub(/\(([^()]+)\)/, '').sub(';', '').strip, types
|
193
|
+
)
|
194
|
+
|
195
|
+
return nil if function.nil?
|
196
|
+
|
197
|
+
input.last[:name] = nil if input.last[:name] == '...'
|
198
|
+
|
199
|
+
if input.last[:type] == '...' || input.last[:name] == '...'
|
200
|
+
input.last[:type] = 'va_list'
|
201
|
+
input.last[:primitive] = 'va_list'
|
202
|
+
end
|
203
|
+
|
204
|
+
function[:input] = input
|
205
|
+
function[:source] = function_source
|
206
|
+
|
207
|
+
function
|
208
|
+
},
|
209
|
+
|
210
|
+
parse_parameter: ->(raw_parameter, types = {}) {
|
211
|
+
parts = raw_parameter.split(/\s+/)
|
212
|
+
|
213
|
+
parameter = { pointer: false, name: nil, type: nil, constant: false }
|
214
|
+
|
215
|
+
parts.each do |part|
|
216
|
+
parameter[:constant] = true if part.gsub('*', '').strip == 'const'
|
217
|
+
|
218
|
+
parameter[:pointer] = true if part[/\*/]
|
219
|
+
end
|
220
|
+
|
221
|
+
parts = parts.reject do |part|
|
222
|
+
part.gsub('*', '').strip == 'const'
|
223
|
+
end
|
224
|
+
|
225
|
+
parameter[:name] = parts.pop if parts.size > 1
|
226
|
+
|
227
|
+
parameter[:type] = parts.pop
|
228
|
+
|
229
|
+
parameter[:name] = parameter[:name].sub(/\*/, '') if parameter[:name]
|
230
|
+
parameter[:type] = parameter[:type].sub(/\*/, '') if parameter[:type]
|
231
|
+
|
232
|
+
parameter[:primitive] = parameter[:type]
|
233
|
+
|
234
|
+
budget = 10_000
|
235
|
+
|
236
|
+
if parameter[:primitive]
|
237
|
+
while types[parameter[:primitive]] && budget.positive?
|
238
|
+
parameter[:primitive] = types[parameter[:primitive]]
|
239
|
+
budget -= 1
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
warn "Fail to find primitive: #{parameter[:primitive]}" if budget.zero?
|
244
|
+
|
245
|
+
parameter
|
246
|
+
},
|
247
|
+
|
248
|
+
parse_function: ->(raw_function, types) {
|
249
|
+
output = Signature[:parse_parameter].(raw_function, types)
|
250
|
+
|
251
|
+
function_name = output.delete(:name)
|
252
|
+
|
253
|
+
return nil if function_name.nil? || output[:type].nil?
|
254
|
+
|
255
|
+
{ name: function_name, output: output }
|
256
|
+
}
|
257
|
+
}
|
258
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# https://github.com/ffi/ffi/wiki/Types#types
|
2
|
+
|
3
|
+
module Logic
|
4
|
+
module Signatures
|
5
|
+
FFITypes = {
|
6
|
+
char: 'char',
|
7
|
+
double: 'double',
|
8
|
+
int: 'int',
|
9
|
+
long: 'long',
|
10
|
+
LUA_INTEGER: 'int',
|
11
|
+
LUA_KCONTEXT: 'int',
|
12
|
+
LUA_NUMBER: 'double',
|
13
|
+
LUA_UNSIGNED: 'uint',
|
14
|
+
ptrdiff_t: 'int',
|
15
|
+
size_t: 'ulong',
|
16
|
+
va_list: 'varargs',
|
17
|
+
void: 'void',
|
18
|
+
enum: 'int', # TODO
|
19
|
+
struct: 'int', # TODO
|
20
|
+
TObject: 'int', # TODO
|
21
|
+
|
22
|
+
# Lua Jit:
|
23
|
+
short: 'int', # TODO
|
24
|
+
unsigned: 'int' # TODO
|
25
|
+
}
|
26
|
+
end
|
27
|
+
end
|