ffidb 0.12.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +7 -0
  2. data/AUTHORS +1 -0
  3. data/CHANGES.md +7 -0
  4. data/CREDITS.md +2 -0
  5. data/README.md +201 -0
  6. data/UNLICENSE +24 -0
  7. data/VERSION +1 -0
  8. data/bin/ffidb +387 -0
  9. data/etc/mappings/dart.yaml +35 -0
  10. data/etc/mappings/java.yaml +36 -0
  11. data/etc/mappings/lisp.yaml +35 -0
  12. data/etc/mappings/python.yaml +35 -0
  13. data/etc/mappings/ruby.yaml +35 -0
  14. data/etc/templates/c.erb +46 -0
  15. data/etc/templates/cpp.erb +45 -0
  16. data/etc/templates/dart.erb +64 -0
  17. data/etc/templates/go.erb +50 -0
  18. data/etc/templates/java.erb +56 -0
  19. data/etc/templates/lisp.erb +49 -0
  20. data/etc/templates/python.erb +59 -0
  21. data/etc/templates/ruby.erb +48 -0
  22. data/lib/ffidb.rb +34 -0
  23. data/lib/ffidb/enum.rb +37 -0
  24. data/lib/ffidb/errors.rb +64 -0
  25. data/lib/ffidb/exporter.rb +141 -0
  26. data/lib/ffidb/exporters.rb +28 -0
  27. data/lib/ffidb/exporters/c.rb +52 -0
  28. data/lib/ffidb/exporters/cpp.rb +13 -0
  29. data/lib/ffidb/exporters/csharp.rb +6 -0
  30. data/lib/ffidb/exporters/csv.rb +24 -0
  31. data/lib/ffidb/exporters/dart.rb +60 -0
  32. data/lib/ffidb/exporters/go.rb +16 -0
  33. data/lib/ffidb/exporters/haskell.rb +3 -0
  34. data/lib/ffidb/exporters/java.rb +39 -0
  35. data/lib/ffidb/exporters/json.rb +38 -0
  36. data/lib/ffidb/exporters/julia.rb +3 -0
  37. data/lib/ffidb/exporters/lisp.rb +41 -0
  38. data/lib/ffidb/exporters/luajit.rb +3 -0
  39. data/lib/ffidb/exporters/nim.rb +4 -0
  40. data/lib/ffidb/exporters/nodejs.rb +4 -0
  41. data/lib/ffidb/exporters/ocaml.rb +4 -0
  42. data/lib/ffidb/exporters/php.rb +4 -0
  43. data/lib/ffidb/exporters/python.rb +35 -0
  44. data/lib/ffidb/exporters/racket.rb +3 -0
  45. data/lib/ffidb/exporters/ruby.rb +33 -0
  46. data/lib/ffidb/exporters/rust.rb +5 -0
  47. data/lib/ffidb/exporters/yaml.rb +31 -0
  48. data/lib/ffidb/exporters/zig.rb +3 -0
  49. data/lib/ffidb/function.rb +70 -0
  50. data/lib/ffidb/glob.rb +28 -0
  51. data/lib/ffidb/header.rb +19 -0
  52. data/lib/ffidb/header_parser.rb +339 -0
  53. data/lib/ffidb/library.rb +120 -0
  54. data/lib/ffidb/library_parser.rb +132 -0
  55. data/lib/ffidb/location.rb +17 -0
  56. data/lib/ffidb/parameter.rb +35 -0
  57. data/lib/ffidb/registry.rb +87 -0
  58. data/lib/ffidb/release.rb +14 -0
  59. data/lib/ffidb/struct.rb +41 -0
  60. data/lib/ffidb/symbol_table.rb +90 -0
  61. data/lib/ffidb/symbolic.rb +67 -0
  62. data/lib/ffidb/sysexits.rb +21 -0
  63. data/lib/ffidb/type.rb +214 -0
  64. data/lib/ffidb/typedef.rb +38 -0
  65. data/lib/ffidb/union.rb +37 -0
  66. data/lib/ffidb/version.rb +21 -0
  67. metadata +197 -0
@@ -0,0 +1,52 @@
1
+ # This is free and unencumbered software released into the public domain.
2
+
3
+ require_relative '../exporter'
4
+
5
+ module FFIDB::Exporters
6
+ ##
7
+ # Code generator for the C programming language.
8
+ class C < FFIDB::Exporter
9
+ SYMBOL_INDENT = 0
10
+ EXTERN_QUALIFIER = 'extern'
11
+
12
+ def finish
13
+ puts self.render_template('c.erb')
14
+ end
15
+
16
+ def _export_function(function, **kwargs)
17
+ parameters = function.parameters.each_value.map do |p|
18
+ p_type = case
19
+ when p.type.function_pointer?
20
+ p.type.to_s.sub('(*)', "(*#{p.name})")
21
+ when self.options[:parameter_names] == false
22
+ p.type.to_s.gsub(' *', '*')
23
+ else "#{p.type.to_s.gsub(' *', '*')} #{p.name}"
24
+ end
25
+ p_type.gsub('const char *const[]', 'const char* const*') # FIXME
26
+ end
27
+ print ' '*self.symbol_indent if self.symbol_indent.nonzero?
28
+ print self.extern_qualifier, ' ' if self.extern_qualifier
29
+ if function.type.function_pointer?
30
+ print function.type.to_s.sub('(*)', "(*#{function.name}(#{parameters.join(', ')}))")
31
+ else
32
+ print function.type, ' ', function.name, '('
33
+ parameters.each_with_index do |p, i|
34
+ print ', ' if i.nonzero?
35
+ print p
36
+ end
37
+ print ')'
38
+ end
39
+ puts (self.options[:semicolon] == false ? '' : ';')
40
+ end
41
+
42
+ protected
43
+
44
+ def symbol_indent
45
+ self.class.const_get(:SYMBOL_INDENT)
46
+ end
47
+
48
+ def extern_qualifier
49
+ self.class.const_get(:EXTERN_QUALIFIER)
50
+ end
51
+ end # C
52
+ end # FFIDB::Exporters
@@ -0,0 +1,13 @@
1
+ # This is free and unencumbered software released into the public domain.
2
+
3
+ require_relative 'c'
4
+
5
+ module FFIDB::Exporters
6
+ ##
7
+ # Code generator for the C++ programming language.
8
+ class Cpp < C
9
+ def finish
10
+ puts self.render_template('cpp.erb')
11
+ end
12
+ end # Cpp
13
+ end # FFIDB::Exporters
@@ -0,0 +1,6 @@
1
+ # This is free and unencumbered software released into the public domain.
2
+
3
+ # TODO: https://docs.microsoft.com/en-us/dotnet/framework/interop/platform-invoke-examples
4
+ # TODO: https://docs.microsoft.com/en-us/dotnet/framework/interop/
5
+ # TODO: https://docs.microsoft.com/en-us/dotnet/framework/interop/consuming-unmanaged-dll-functions
6
+ # TODO: https://docs.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.dllimportattribute
@@ -0,0 +1,24 @@
1
+ # This is free and unencumbered software released into the public domain.
2
+
3
+ require_relative '../exporter'
4
+
5
+ module FFIDB::Exporters
6
+ ##
7
+ # Code generator for the CSV file format.
8
+ class CSV < FFIDB::Exporter
9
+ DELIMITER = ','
10
+
11
+ def begin
12
+ puts [:library, :kind, :name].join(DELIMITER) # TODO: definition
13
+ end
14
+
15
+ def export_symbol(symbol, **kwargs)
16
+ puts [@library&.name, symbol.kind, symbol.name].join(DELIMITER)
17
+ end
18
+ alias_method :export_typedef, :export_symbol
19
+ alias_method :export_enum, :export_symbol
20
+ alias_method :export_struct, :export_symbol
21
+ alias_method :export_union, :export_symbol
22
+ alias_method :export_function, :export_symbol
23
+ end # CSV
24
+ end # FFIDB::Exporters
@@ -0,0 +1,60 @@
1
+ # This is free and unencumbered software released into the public domain.
2
+
3
+ require_relative '../exporter'
4
+
5
+ module FFIDB::Exporters
6
+ ##
7
+ # Code generator for the Dart programming language.
8
+ #
9
+ # @see https://dart.dev/guides/libraries/c-interop
10
+ # @see https://flutter.dev/docs/development/platform-integration/c-interop
11
+ # @see https://api.dart.dev/dev/dart-ffi/dart-ffi-library.html
12
+ class Dart < FFIDB::Exporter
13
+ TYPE_MAP_FFI = ::YAML.load(File.read(File.expand_path("../../../etc/mappings/dart.yaml", __dir__)))
14
+ .freeze
15
+
16
+ # @see https://dart.dev/guides/language/language-tour
17
+ TYPE_MAP_DART = {
18
+ :Void => :void,
19
+ :Int8 => :int,
20
+ :Int16 => :int,
21
+ :Int32 => :int,
22
+ :Int64 => :int,
23
+ :Uint8 => :int,
24
+ :Uint16 => :int,
25
+ :Uint32 => :int,
26
+ :Uint64 => :int,
27
+ :Float => :double,
28
+ :Double => :double,
29
+ :IntPtr => :int,
30
+ 'Pointer<Int8>' => 'Pointer<Int8>',
31
+ nil => 'Pointer<Void>',
32
+ }
33
+
34
+ def finish
35
+ puts self.render_template('dart.erb')
36
+ end
37
+
38
+ protected
39
+
40
+ ##
41
+ # @param [FFIDB::Type] c_type
42
+ # @return [#to_s]
43
+ def dart_param_type(c_type)
44
+ TYPE_MAP_DART[self.ffi_param_type(c_type)] || TYPE_MAP_DART[nil]
45
+ end
46
+ alias_method :dart_struct_type, :dart_param_type
47
+
48
+ ##
49
+ # @param [FFIDB::Type] c_type
50
+ # @return [#to_s]
51
+ def ffi_param_type(c_type)
52
+ case
53
+ #when c_type.array? then # TODO: https://github.com/dart-lang/sdk/issues/35763
54
+ when c_type.enum? then :Int32
55
+ else TYPE_MAP_FFI[c_type.to_s] || TYPE_MAP_FFI['void *']
56
+ end
57
+ end
58
+ alias_method :ffi_struct_type, :ffi_param_type
59
+ end # Dart
60
+ end # FFIDB::Exporters
@@ -0,0 +1,16 @@
1
+ # This is free and unencumbered software released into the public domain.
2
+
3
+ require_relative 'c'
4
+
5
+ module FFIDB::Exporters
6
+ ##
7
+ # Code generator for the Go programming language (using Cgo).
8
+ #
9
+ # @see https://golang.org/cmd/cgo/
10
+ # @see https://github.com/golang/go/wiki/cgo
11
+ class Go < C
12
+ def finish
13
+ puts self.render_template('go.erb')
14
+ end
15
+ end # Go
16
+ end # FFIDB::Exporters
@@ -0,0 +1,3 @@
1
+ # This is free and unencumbered software released into the public domain.
2
+
3
+ # TODO: https://wiki.haskell.org/Foreign_Function_Interface
@@ -0,0 +1,39 @@
1
+ # This is free and unencumbered software released into the public domain.
2
+
3
+ require_relative '../exporter'
4
+
5
+ module FFIDB::Exporters
6
+ ##
7
+ # Code generator for the Java programming language (using JNA).
8
+ #
9
+ # @see https://github.com/java-native-access/jna/blob/master/www/GettingStarted.md
10
+ class Java < FFIDB::Exporter
11
+ TYPE_MAP = ::YAML.load(File.read(File.expand_path("../../../etc/mappings/java.yaml", __dir__)))
12
+ .freeze
13
+
14
+ def begin_library(library)
15
+ if library
16
+ interface_name = self.options[:module] || library.name.capitalize
17
+ library.define_singleton_method(:interface_name) { interface_name }
18
+ end
19
+ super(library)
20
+ end
21
+
22
+ def finish
23
+ puts self.render_template('java.erb')
24
+ end
25
+
26
+ protected
27
+
28
+ ##
29
+ # @param [FFIDB::Type] c_type
30
+ # @return [#to_s]
31
+ def param_type(c_type)
32
+ case
33
+ when c_type.enum? then :int
34
+ else TYPE_MAP[c_type.to_s] || TYPE_MAP['void *']
35
+ end
36
+ end
37
+ alias_method :struct_type, :param_type
38
+ end # Java
39
+ end # FFIDB::Exporters
@@ -0,0 +1,38 @@
1
+ # This is free and unencumbered software released into the public domain.
2
+
3
+ require_relative '../exporter'
4
+
5
+ require 'json'
6
+
7
+ module FFIDB::Exporters
8
+ ##
9
+ # Code generator for the JSON data interchange language.
10
+ class JSON < FFIDB::Exporter
11
+ def begin
12
+ # No header, because JSON doesn't support comments
13
+ @json = {}
14
+ end
15
+
16
+ def begin_library(library)
17
+ @library = library
18
+ @json[@library&.name] ||= {}
19
+ end
20
+
21
+ def export_symbol(symbol, **kwargs)
22
+ @json[@library&.name][symbol.name] = {kind: symbol.kind.to_s}.merge!(symbol.to_h)
23
+ end
24
+ alias_method :export_typedef, :export_symbol
25
+ alias_method :export_enum, :export_symbol
26
+ alias_method :export_struct, :export_symbol
27
+ alias_method :export_union, :export_symbol
28
+ alias_method :export_function, :export_symbol
29
+
30
+ def finish_library
31
+ @library = nil
32
+ end
33
+
34
+ def finish
35
+ puts ::JSON.pretty_generate(@json)
36
+ end
37
+ end # JSON
38
+ end # FFIDB::Exporters
@@ -0,0 +1,3 @@
1
+ # This is free and unencumbered software released into the public domain.
2
+
3
+ # TODO: https://docs.julialang.org/en/v1/manual/calling-c-and-fortran-code/
@@ -0,0 +1,41 @@
1
+ # This is free and unencumbered software released into the public domain.
2
+
3
+ require_relative '../exporter'
4
+
5
+ module FFIDB::Exporters
6
+ ##
7
+ # Code generator for the Common Lisp programming language (using CFFI).
8
+ #
9
+ # @see https://common-lisp.net/project/cffi/
10
+ class Lisp < FFIDB::Exporter
11
+ TYPE_MAP = ::YAML.load(File.read(File.expand_path("../../../etc/mappings/lisp.yaml", __dir__)))
12
+ .transform_values(&:to_sym)
13
+ .freeze
14
+
15
+ def finish
16
+ puts self.render_template('lisp.erb')
17
+ end
18
+
19
+ protected
20
+
21
+ ##
22
+ # @param [FFIDB::Type] c_type
23
+ # @return [#inspect]
24
+ def struct_type(c_type)
25
+ case
26
+ when c_type.array? then [c_type.array_type.to_s.to_sym, :count, c_type.array_size]
27
+ else [self.param_type(c_type)]
28
+ end
29
+ end
30
+
31
+ ##
32
+ # @param [FFIDB::Type] c_type
33
+ # @return [#inspect]
34
+ def param_type(c_type)
35
+ case
36
+ when c_type.enum? then :int
37
+ else TYPE_MAP[c_type.to_s] || TYPE_MAP['void *']
38
+ end
39
+ end
40
+ end # Lisp
41
+ end # FFIDB::Exporters
@@ -0,0 +1,3 @@
1
+ # This is free and unencumbered software released into the public domain.
2
+
3
+ # TODO: https://luajit.org/ext_ffi.html
@@ -0,0 +1,4 @@
1
+ # This is free and unencumbered software released into the public domain.
2
+
3
+ # TODO: https://nim-lang.org/docs/manual.html#foreign-function-interface
4
+ # TODO: https://livebook.manning.com/book/nim-in-action/chapter-8/
@@ -0,0 +1,4 @@
1
+ # This is free and unencumbered software released into the public domain.
2
+
3
+ # TODO: https://github.com/node-ffi/node-ffi
4
+ # TODO: https://github.com/node-ffi/node-ffi/wiki/Node-FFI-Tutorial
@@ -0,0 +1,4 @@
1
+ # This is free and unencumbered software released into the public domain.
2
+
3
+ # TODO: https://ocamlverse.github.io/content/ffi.html
4
+ # TODO: http://ocamllabs.io/ocaml-ctypes/PosixTypes.html
@@ -0,0 +1,4 @@
1
+ # This is free and unencumbered software released into the public domain.
2
+
3
+ # TODO: https://wiki.php.net/rfc/ffi
4
+ # TODO: https://www.php.net/manual/en/book.ffi.php
@@ -0,0 +1,35 @@
1
+ # This is free and unencumbered software released into the public domain.
2
+
3
+ require_relative '../exporter'
4
+
5
+ module FFIDB::Exporters
6
+ ##
7
+ # Code generator for the Python programming language (using ctypes).
8
+ #
9
+ # @see https://docs.python.org/3/library/ctypes.html
10
+ class Python < FFIDB::Exporter
11
+ TYPE_MAP = ::YAML.load(File.read(File.expand_path("../../../etc/mappings/python.yaml", __dir__)))
12
+ .freeze
13
+
14
+ def finish
15
+ puts self.render_template('python.erb')
16
+ end
17
+
18
+ protected
19
+
20
+ ##
21
+ # @param [FFIDB::Type] c_type
22
+ # @return [#to_s]
23
+ def param_type(c_type)
24
+ case
25
+ when c_type.enum? then 'ctypes.c_int'
26
+ when c_type.array? then [self.param_type(c_type.array_type), '*', c_type.array_size].join(' ')
27
+ else case py_type = TYPE_MAP[c_type.to_s] || TYPE_MAP['void *']
28
+ when 'None' then py_type
29
+ else "ctypes.#{py_type}"
30
+ end
31
+ end
32
+ end
33
+ alias_method :struct_type, :param_type
34
+ end # Python
35
+ end # FFIDB::Exporters
@@ -0,0 +1,3 @@
1
+ # This is free and unencumbered software released into the public domain.
2
+
3
+ # TODO: https://docs.racket-lang.org/foreign/intro.html
@@ -0,0 +1,33 @@
1
+ # This is free and unencumbered software released into the public domain.
2
+
3
+ require_relative '../exporter'
4
+
5
+ module FFIDB::Exporters
6
+ ##
7
+ # Code generator for the Ruby programming language (using FFI).
8
+ #
9
+ # @see https://github.com/ffi/ffi/wiki
10
+ class Ruby < FFIDB::Exporter
11
+ TYPE_MAP = ::YAML.load(File.read(File.expand_path("../../../etc/mappings/ruby.yaml", __dir__)))
12
+ .transform_values(&:to_sym)
13
+ .freeze
14
+
15
+ def finish
16
+ puts self.render_template('ruby.erb')
17
+ end
18
+
19
+ protected
20
+
21
+ ##
22
+ # @param [FFIDB::Type] c_type
23
+ # @return [#inspect]
24
+ def param_type(c_type)
25
+ case
26
+ when c_type.enum? then :int
27
+ when c_type.array? then [self.param_type(c_type.array_type), c_type.array_size]
28
+ else TYPE_MAP[c_type.to_s] || TYPE_MAP['void *']
29
+ end
30
+ end
31
+ alias_method :struct_type, :param_type
32
+ end # Ruby
33
+ end # FFIDB::Exporters
@@ -0,0 +1,5 @@
1
+ # This is free and unencumbered software released into the public domain.
2
+
3
+ # TODO: https://doc.rust-lang.org/nomicon/ffi.html
4
+ # TODO: https://doc.rust-lang.org/1.0.0/book/ffi.html
5
+ # TODO: https://rust-embedded.github.io/book/interoperability/c-with-rust.html
@@ -0,0 +1,31 @@
1
+ # This is free and unencumbered software released into the public domain.
2
+
3
+ require_relative '../exporter'
4
+
5
+ module FFIDB::Exporters
6
+ ##
7
+ # Code generator for the YAML markup language.
8
+ class YAML < FFIDB::Exporter
9
+ def begin
10
+ puts "# #{FFIDB.header}" if self.header?
11
+ puts if self.header?
12
+ end
13
+
14
+ def begin_library(library) end
15
+
16
+ def export_symbol(symbol, **kwargs)
17
+ @counter ||= 0
18
+ puts unless @counter.zero?
19
+ puts "# #{symbol.instance_variable_get(:@debug)}" if self.debug? && symbol.instance_variable_get(:@debug)
20
+ puts symbol.to_yaml
21
+ @counter += 1
22
+ end
23
+ alias_method :export_typedef, :export_symbol
24
+ alias_method :export_enum, :export_symbol
25
+ alias_method :export_struct, :export_symbol
26
+ alias_method :export_union, :export_symbol
27
+ alias_method :export_function, :export_symbol
28
+
29
+ def finish_library() end
30
+ end # YAML
31
+ end # FFIDB::Exporters