sweet-moon 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.
Files changed (70) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +2 -0
  3. data/.rspec +1 -0
  4. data/.rubocop.yml +40 -0
  5. data/Gemfile +12 -0
  6. data/Gemfile.lock +61 -0
  7. data/README.md +1149 -0
  8. data/components/api.rb +83 -0
  9. data/components/injections/injections_503.rb +21 -0
  10. data/components/injections/injections_514.rb +29 -0
  11. data/components/injections/injections_542.rb +49 -0
  12. data/components/injections.rb +11 -0
  13. data/components/interpreters/50/function.rb +52 -0
  14. data/components/interpreters/50/interpreter.rb +105 -0
  15. data/components/interpreters/50/reader.rb +65 -0
  16. data/components/interpreters/50/table.rb +99 -0
  17. data/components/interpreters/50/writer.rb +45 -0
  18. data/components/interpreters/51/function.rb +52 -0
  19. data/components/interpreters/51/interpreter.rb +104 -0
  20. data/components/interpreters/51/reader.rb +65 -0
  21. data/components/interpreters/51/table.rb +60 -0
  22. data/components/interpreters/51/writer.rb +45 -0
  23. data/components/interpreters/54/function.rb +52 -0
  24. data/components/interpreters/54/interpreter.rb +100 -0
  25. data/components/interpreters/54/reader.rb +65 -0
  26. data/components/interpreters/54/table.rb +60 -0
  27. data/components/interpreters/54/writer.rb +45 -0
  28. data/components/interpreters.rb +11 -0
  29. data/components/io.rb +11 -0
  30. data/config/tests.sample.yml +15 -0
  31. data/controllers/api.rb +143 -0
  32. data/controllers/cli/cli.rb +32 -0
  33. data/controllers/cli/help.rb +24 -0
  34. data/controllers/cli/signatures.rb +179 -0
  35. data/controllers/cli/version.rb +14 -0
  36. data/controllers/interpreter.rb +68 -0
  37. data/controllers/state.rb +74 -0
  38. data/dsl/api.rb +31 -0
  39. data/dsl/cache.rb +118 -0
  40. data/dsl/concerns/fennel.rb +13 -0
  41. data/dsl/concerns/packages.rb +37 -0
  42. data/dsl/errors.rb +28 -0
  43. data/dsl/fennel.rb +47 -0
  44. data/dsl/global.rb +42 -0
  45. data/dsl/state.rb +104 -0
  46. data/dsl/sweet_moon.rb +53 -0
  47. data/logic/api.rb +17 -0
  48. data/logic/interpreter.rb +84 -0
  49. data/logic/interpreters/interpreter_50.rb +34 -0
  50. data/logic/interpreters/interpreter_51.rb +37 -0
  51. data/logic/interpreters/interpreter_54.rb +41 -0
  52. data/logic/io.rb +6 -0
  53. data/logic/options.rb +14 -0
  54. data/logic/shared_object.rb +52 -0
  55. data/logic/signature.rb +258 -0
  56. data/logic/signatures/ffi_types.rb +27 -0
  57. data/logic/signatures/signatures_322.rb +418 -0
  58. data/logic/signatures/signatures_401.rb +243 -0
  59. data/logic/signatures/signatures_503.rb +575 -0
  60. data/logic/signatures/signatures_514.rb +460 -0
  61. data/logic/signatures/signatures_542.rb +591 -0
  62. data/logic/spec.rb +13 -0
  63. data/logic/tables.rb +32 -0
  64. data/ports/in/dsl/sweet-moon/errors.rb +3 -0
  65. data/ports/in/dsl/sweet-moon.rb +1 -0
  66. data/ports/in/shell/sweet-moon +5 -0
  67. data/ports/in/shell.rb +21 -0
  68. data/ports/out/shell.rb +9 -0
  69. data/sweet-moon.gemspec +35 -0
  70. metadata +137 -0
@@ -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