diff options
| -rw-r--r-- | .tool-versions | 1 | ||||
| -rw-r--r-- | Gemfile | 2 | ||||
| -rw-r--r-- | Gemfile.lock | 21 | ||||
| -rw-r--r-- | planning/structure.puml | 224 | ||||
| -rw-r--r-- | scan.rb | 83 | ||||
| -rw-r--r-- | src/backend/test.h | 12 | ||||
| -rw-r--r-- | src/backend/uctags.rb | 146 | ||||
| -rw-r--r-- | src/generate.rb (renamed from generate.rb) | 0 | ||||
| -rw-r--r-- | src/sample.config.rb (renamed from sample.config.rb) | 0 | ||||
| -rw-r--r-- | src/scan.rb | 85 | ||||
| -rw-r--r-- | src/templates.rb (renamed from templates.rb) | 0 |
11 files changed, 374 insertions, 200 deletions
diff --git a/.tool-versions b/.tool-versions new file mode 100644 index 0000000..0b2d858 --- /dev/null +++ b/.tool-versions @@ -0,0 +1 @@ +ruby 3.1.2 @@ -4,4 +4,4 @@ source "https://rubygems.org" # gem "rails" -gem "activerecord", "~> 7.0" +gem "cast", "~> 0.3.1" diff --git a/Gemfile.lock b/Gemfile.lock index 8184b71..c32dc74 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,28 +1,13 @@ GEM remote: https://rubygems.org/ specs: - activemodel (7.0.2.3) - activesupport (= 7.0.2.3) - activerecord (7.0.2.3) - activemodel (= 7.0.2.3) - activesupport (= 7.0.2.3) - activesupport (7.0.2.3) - concurrent-ruby (~> 1.0, >= 1.0.2) - i18n (>= 1.6, < 2) - minitest (>= 5.1) - tzinfo (~> 2.0) - concurrent-ruby (1.1.10) - i18n (1.10.0) - concurrent-ruby (~> 1.0) - minitest (5.15.0) - tzinfo (2.0.4) - concurrent-ruby (~> 1.0) + cast (0.3.1) PLATFORMS x86_64-linux DEPENDENCIES - activerecord (~> 7.0) + cast (~> 0.3.1) BUNDLED WITH - 2.3.7 + 2.3.20 diff --git a/planning/structure.puml b/planning/structure.puml index 67cc77f..817a3bd 100644 --- a/planning/structure.puml +++ b/planning/structure.puml @@ -1,107 +1,107 @@ @startuml - state Gem { - state Headers - state Structs #red { - state Struct_Type_Init - state Struct_Deinit #chocolate - state "Struct Getter Method" as Struct_Getter #lawngreen { - state fork_is_struct_getter <<fork>> - state "Unwrap Struct\nand Read Value" as Unwrap_Struct_Getter - state "Return Value" as Return_Struct_Getter - state "Handle If Value\nIs Struct" as Handle_Struct_Value_Getter - - [*] -d-> Unwrap_Struct_Getter - Unwrap_Struct_Getter -d-> fork_is_struct_getter - fork_is_struct_getter -d-> Return_Struct_Getter - fork_is_struct_getter -d-> Handle_Struct_Value_Getter - Handle_Struct_Value_Getter -d-> Return_Struct_Getter - } - state "Struct Setter Method" as Struct_Setter #darkorchid { - state "Initialize Vars" as Initialize_Vars_Setter - state "Get and Assign\nArg" as Get_Arg_Setter - state "Unwrap And Set" as Unwrap_Struct_Setter - state "Return Var" as Return_Setter - - [*] -d-> Initialize_Vars_Setter - Initialize_Vars_Setter -d-> Get_Arg_Setter - Get_Arg_Setter -d-> Unwrap_Struct_Setter - Unwrap_Struct_Setter -d-> Return_Setter - } - state Struct_Initializer as "Struct Initializer" #gold { - state "Initialize Vars" as Initialize_Vars_Struct_Init - state fork_kw_args_struct_init <<fork>> - state "Get and Assign\nArg" as Get_Arg_Struct_Init - state "Get and Assign\nKwargs" as Get_Kwargs_Struct_Init - state "Build Struct" as Build_Struct_Struct_Init - state "Wrap Struct" as Wrap_Struct_Struct_Init - state "Return Ruby Object" as Return_Struct_Init - - [*] -d-> Initialize_Vars_Struct_Init - - Initialize_Vars_Struct_Init -d-> fork_kw_args_struct_init - - fork_kw_args_struct_init -d-> Get_Arg_Struct_Init - - fork_kw_args_struct_init -d-> Get_Kwargs_Struct_Init - - Get_Arg_Struct_Init -d-> Build_Struct_Struct_Init - Get_Kwargs_Struct_Init -d-> Build_Struct_Struct_Init - - Build_Struct_Struct_Init -d-> Wrap_Struct_Struct_Init - - Wrap_Struct_Struct_Init -d-> Return_Struct_Init - } - - Struct_Type_Init --> Struct_Deinit +state Gem { + state Headers + state Structs #red { + state Struct_Type_Init + state Struct_Deinit #chocolate + state "Struct Getter Method" as Struct_Getter #lawngreen { + state fork_is_struct_getter <<fork>> + state "Unwrap Struct\nand Read Value" as Unwrap_Struct_Getter + state "Return Value" as Return_Struct_Getter + state "Handle If Value\nIs Struct" as Handle_Struct_Value_Getter + [*] -d-> Unwrap_Struct_Getter + Unwrap_Struct_Getter -d-> fork_is_struct_getter + fork_is_struct_getter -d-> Return_Struct_Getter + fork_is_struct_getter -d-> Handle_Struct_Value_Getter + Handle_Struct_Value_Getter -d-> Return_Struct_Getter } - state Methods #lightblue { - state "Initialize Vars" as Initialize_Vars_C_Function - state fork_kw_args_c_function <<fork>> - state "Get and Assign Arg" as Get_Arg_C_Function - state "Get and Assign Kwargs" as Get_Kwargs_C_Function - state "Call Function" as Call_C_Function - state fork_wrap_struct_c_function <<fork>> - state "Wrap Struct" as Wrap_Struct_C_Function - state "Return Value" as Return_C_Function - - [*] -d-> Initialize_Vars_C_Function - [*] -d-> Call_C_Function - - Initialize_Vars_C_Function -d-> fork_kw_args_c_function - - fork_kw_args_c_function -d-> Get_Arg_C_Function - - fork_kw_args_c_function -d-> Get_Kwargs_C_Function - - Get_Arg_C_Function -d-> Call_C_Function - Get_Kwargs_C_Function -d-> Call_C_Function - - Call_C_Function -d-> fork_wrap_struct_c_function - fork_wrap_struct_c_function -d-> Wrap_Struct_C_Function - - fork_wrap_struct_c_function -d-> Return_C_Function - Wrap_Struct_C_Function -d-> Return_C_Function + state "Struct Setter Method" as Struct_Setter #darkorchid { + state "Initialize Vars" as Initialize_Vars_Setter + state "Get and Assign\nArg" as Get_Arg_Setter + state "Unwrap And Set" as Unwrap_Struct_Setter + state "Return Var" as Return_Setter + + [*] -d-> Initialize_Vars_Setter + Initialize_Vars_Setter -d-> Get_Arg_Setter + Get_Arg_Setter -d-> Unwrap_Struct_Setter + Unwrap_Struct_Setter -d-> Return_Setter } - state Gem_Initializer as "Gem Initializer" { - state Define_Module as "Define Module" #crimson - state Define_Struct_Classes as "Define Classes" #darkorange - state Define_Struct_Methods as "Define Struct Methods" #hotpink - state Define_Functions as "Define Functions" #lightblue + state Struct_Initializer as "Struct Initializer" #gold { + state "Initialize Vars" as Initialize_Vars_Struct_Init + state fork_kw_args_struct_init <<fork>> + state "Get and Assign\nArg" as Get_Arg_Struct_Init + state "Get and Assign\nKwargs" as Get_Kwargs_Struct_Init + state "Build Struct" as Build_Struct_Struct_Init + state "Wrap Struct" as Wrap_Struct_Struct_Init + state "Return Ruby Object" as Return_Struct_Init + + [*] -d-> Initialize_Vars_Struct_Init + + Initialize_Vars_Struct_Init -d-> fork_kw_args_struct_init + + fork_kw_args_struct_init -d-> Get_Arg_Struct_Init + + fork_kw_args_struct_init -d-> Get_Kwargs_Struct_Init + + Get_Arg_Struct_Init -d-> Build_Struct_Struct_Init + Get_Kwargs_Struct_Init -d-> Build_Struct_Struct_Init + + Build_Struct_Struct_Init -d-> Wrap_Struct_Struct_Init + + Wrap_Struct_Struct_Init -d-> Return_Struct_Init } - state Gem_Finalizer as "Gem Finalizer" - - - Headers -d-> Structs - Structs -d-> Methods - Methods -d-> Gem_Initializer - Gem_Initializer -d-> Gem_Finalizer - - Define_Module -d-> Define_Struct_Classes - Define_Struct_Classes -r-> Define_Struct_Methods - Define_Struct_Classes -d-> Define_Functions + + Struct_Type_Init --> Struct_Deinit + } + state Methods #lightblue { + state "Initialize Vars" as Initialize_Vars_C_Function + state fork_kw_args_c_function <<fork>> + state "Get and Assign Arg" as Get_Arg_C_Function + state "Get and Assign Kwargs" as Get_Kwargs_C_Function + state "Call Function" as Call_C_Function + state fork_wrap_struct_c_function <<fork>> + state "Wrap Struct" as Wrap_Struct_C_Function + state "Return Value" as Return_C_Function + + [*] -d-> Initialize_Vars_C_Function + [*] -d-> Call_C_Function + + Initialize_Vars_C_Function -d-> fork_kw_args_c_function + + fork_kw_args_c_function -d-> Get_Arg_C_Function + + fork_kw_args_c_function -d-> Get_Kwargs_C_Function + + Get_Arg_C_Function -d-> Call_C_Function + Get_Kwargs_C_Function -d-> Call_C_Function + + Call_C_Function -d-> fork_wrap_struct_c_function + fork_wrap_struct_c_function -d-> Wrap_Struct_C_Function + + fork_wrap_struct_c_function -d-> Return_C_Function + Wrap_Struct_C_Function -d-> Return_C_Function + } + state Gem_Initializer as "Gem Initializer" { + state Define_Module as "Define Module" #crimson + state Define_Struct_Classes as "Define Classes" #darkorange + state Define_Struct_Methods as "Define Struct Methods" #hotpink + state Define_Functions as "Define Functions" #lightblue + } + state Gem_Finalizer as "Gem Finalizer" + + + Headers -d-> Structs + Structs -d-> Methods + Methods -d-> Gem_Initializer + Gem_Initializer -d-> Gem_Finalizer + + Define_Module -d-> Define_Struct_Classes + Define_Struct_Classes -r-> Define_Struct_Methods + Define_Struct_Classes -d-> Define_Functions +} state Build_State as "Build State Hash" { state BS_C_Gemname as "Gem Name" #crimson : string @@ -137,7 +137,35 @@ state Build_State as "Build State Hash" { BS_C_Function_Name -d[hidden]-> BS_C_Struct_Name } +state UCTags as "Universal Ctags Identifier" { + state UCT_KindIsProto as "Tag Kind Is\nPrototype" + state UCT_KindIsTypedef as "Tag Kind Is\nTypedef" + state UCT_KindIsMember as "Tag Kind Is\nMember" + + state UCT_TyperefIsTypename as "Tag Typeref is\n'typename:{something}'" + state UCT_TyperefIsStruct as "Tag Typeref is\n'struct:{something}'" + + state UCT_IsFunction as "It's a Function" + state UCT_IsStructParam as "It's a Struct\nParameter" + state UCT_IsTypedef as "It's an Alias\n(Typedef)" + state UCT_IsStruct as "It's a Struct" + + [*] -d-> UCT_KindIsProto + [*] -d-> UCT_KindIsTypedef + [*] -d-> UCT_KindIsMember + + UCT_KindIsProto -d-> UCT_IsFunction + UCT_KindIsMember -d-> UCT_IsStructParam + + UCT_KindIsTypedef -d-> UCT_TyperefIsTypename + UCT_KindIsTypedef -d-> UCT_TyperefIsStruct + UCT_TyperefIsTypename -d-> UCT_IsStruct + UCT_TyperefIsStruct -d-> UCT_IsTypedef + +} + + + - @enduml diff --git a/scan.rb b/scan.rb deleted file mode 100644 index 38dd95b..0000000 --- a/scan.rb +++ /dev/null @@ -1,83 +0,0 @@ -require 'json' - -#file_to_scan = 'raylib.h' - -class Scan - class << self - # ctags --list-kinds=c - # p function prototypes - # s structure names - # z function parameters inside function or prototype definitions - # m struct, and union members - def ctag(file) - `ctags --output-format=json --c-kinds=pm --fields=+S --language-force=c #{file}` - end - #File.write('json.json', parse) - #$garbage = [] - - def param_strip(signature) - signature[1...-1].split(',') - end - - - def parse_header(path) - parse = `ctags --output-format=json --c-kinds=pm --fields=+S --language-force=c #{path}` - structs = {} - functions = {} - failed = [] - parse.each_line do |line| - json_line = JSON.parse line - if json_line['kind'] == 'prototype' - functions["#{json_line['typeref'].sub(/^[^ ][^ ]* /,'')} #{json_line['name']}"] = param_strip(json_line['signature']) - elsif json_line['kind'] == 'member' - if json_line['scopeKind'] == 'struct' - structs[json_line['scope']] ||= [] - structs[json_line['scope']].push "#{json_line['typeref'].delete_prefix('typename:')} #{json_line['name']}" - else - failed.push json_line - end - elsif json_line['kind'] == 'struct' - structs[json_line['name']] = json_line - else - failed.push json_line - end - end - [functions, structs, failed] - end - - - def debug_show(type, hash) - puts "#{type.upcase}:" - puts '---' - hash.each do |key, params| - puts "#{type.capitalize}: #{key}" - params.each do |param| - puts param - end - puts '---' - end - puts - end - - def scan(file, destination) - functions, structs, failed = parse_header(file) - debug_show('functions', functions) - debug_show('structs', structs) - - if !failed.empty? - puts "-- Failed: --" - pp failed - puts - end - - puts "Functions: #{functions.size}" - puts "Structs: #{structs.size}" - puts "Failed: #{failed.size}" - puts - - result = [functions, structs] - - File.write(destination, JSON.generate(result)) - end - end -end diff --git a/src/backend/test.h b/src/backend/test.h new file mode 100644 index 0000000..c7b5ea9 --- /dev/null +++ b/src/backend/test.h @@ -0,0 +1,12 @@ +void InitWindow(int width, int height, const char *title); + +typedef struct Rectangle { + float height; // Rectangle height +} Rectangle; + +typedef struct Texture { + unsigned int id; // OpenGL texture id + int format; // Data format (PixelFormat type) +} Texture; + +typedef Texture Texture2D; diff --git a/src/backend/uctags.rb b/src/backend/uctags.rb new file mode 100644 index 0000000..0cfa3ee --- /dev/null +++ b/src/backend/uctags.rb @@ -0,0 +1,146 @@ +require 'json' + +module FelBind + module Backends + class Intermediate < Hash + + def initialize + self[:GemName] = '' + self[:Typedefs] = {} + self[:CFunctions] = {} + self[:CStructs] = {} + end + + def add_function(name:, ruby_name: , ruby_class:, param_as_self: '') + #TODO + end + + def add_struct + #TODO + end + + def add_typedef + #TODO + end + + def add_struct_param + #TODO + end + + end + + module UCTags + class << self + + # ctags --list-kinds=c + # --c-kinds: + # p function prototypes + # (s structure names) + # (z function parameters inside function or prototype definitions) + # m struct, and union members + # t typedef + # --fields: + # S signature + def ctag(file) + `ctags --output-format=json --c-kinds=pmt --fields=+S --language-force=c #{file}` + end + + def parse(file) + ctags_output = self.ctag(file).each_line.map do |tag| + JSON.parse tag + end + intermediate = FelBind::Backends::Intermediate.new + + ctags_output.each do |tag| + if tag["kind"] == "prototype" + # its a function + puts 'its a function' #TODO remove + elsif tag["kind"] == "typedef" + if tag["typeref"].split(':').first == "typename" + # is a typedef + puts 'its an alias(typedef)' #TODO remove + elsif tag["typeref"].split(':').first == "struct" + # is a struct + puts 'its a struct' #TODO remove + else + puts "warning: no match" #TODO better errors + end + elsif tag['kind'] == 'member' + # is struct param + puts 'its a param' #TODO remove + else + puts "warning: no match" #TODO better errors + end + end + + end + +=begin +def param_strip(signature) + signature[1...-1].split(',') + end + + def parse_header(path) + parse = `ctags --output-format=json --c-kinds=pm --fields=+S --language-force=c #{path}` + structs = {} + functions = {} + failed = [] + parse.each_line do |line| + json_line = JSON.parse line + if json_line['kind'] == 'prototype' + functions["#{json_line['typeref'].sub(/^[^ ][^ ]* /,'')} #{json_line['name']}"] = param_strip(json_line['signature']) + elsif json_line['kind'] == 'member' + if json_line['scopeKind'] == 'struct' + structs[json_line['scope']] ||= [] + structs[json_line['scope']].push "#{json_line['typeref'].delete_prefix('typename:')} #{json_line['name']}" + else + failed.push json_line + end + elsif json_line['kind'] == 'struct' + structs[json_line['name']] = json_line + else + failed.push json_line + end + end + [functions, structs, failed] + end + + + def debug_show(type, hash) + puts "#{type.upcase}:" + puts '---' + hash.each do |key, params| + puts "#{type.capitalize}: #{key}" + params.each do |param| + puts param + end + puts '---' + end + puts + end + + def scan(file, destination) + functions, structs, failed = parse_header(file) + debug_show('functions', functions) + debug_show('structs', structs) + + if !failed.empty? + puts "-- Failed: --" + pp failed + puts + end + + puts "Functions: #{functions.size}" + puts "Structs: #{structs.size}" + puts "Failed: #{failed.size}" + puts + + result = [functions, structs] + + File.write(destination, JSON.generate(result)) + end +=end + end + end + end +end diff --git a/generate.rb b/src/generate.rb index 4fa41be..4fa41be 100644 --- a/generate.rb +++ b/src/generate.rb diff --git a/sample.config.rb b/src/sample.config.rb index 91d883b..91d883b 100644 --- a/sample.config.rb +++ b/src/sample.config.rb diff --git a/src/scan.rb b/src/scan.rb new file mode 100644 index 0000000..9f9aede --- /dev/null +++ b/src/scan.rb @@ -0,0 +1,85 @@ +require 'json' +require 'cast' + +#file_to_scan = 'raylib.h' +module FelBind + class Scan + class << self + # ctags --list-kinds=c + # p function prototypes + # s structure names + # z function parameters inside function or prototype definitions + # m struct, and union members + def ctag(file) + `ctags --output-format=json --c-kinds=pm --fields=+S --language-force=c #{file}` + end + #File.write('json.json', parse) + #$garbage = [] + + def param_strip(signature) + signature[1...-1].split(',') + end + + + def parse_header(path) + parse = `ctags --output-format=json --c-kinds=pm --fields=+S --language-force=c #{path}` + structs = {} + functions = {} + failed = [] + parse.each_line do |line| + json_line = JSON.parse line + if json_line['kind'] == 'prototype' + functions["#{json_line['typeref'].sub(/^[^ ][^ ]* /,'')} #{json_line['name']}"] = param_strip(json_line['signature']) + elsif json_line['kind'] == 'member' + if json_line['scopeKind'] == 'struct' + structs[json_line['scope']] ||= [] + structs[json_line['scope']].push "#{json_line['typeref'].delete_prefix('typename:')} #{json_line['name']}" + else + failed.push json_line + end + elsif json_line['kind'] == 'struct' + structs[json_line['name']] = json_line + else + failed.push json_line + end + end + [functions, structs, failed] + end + + + def debug_show(type, hash) + puts "#{type.upcase}:" + puts '---' + hash.each do |key, params| + puts "#{type.capitalize}: #{key}" + params.each do |param| + puts param + end + puts '---' + end + puts + end + + def scan(file, destination) + functions, structs, failed = parse_header(file) + debug_show('functions', functions) + debug_show('structs', structs) + + if !failed.empty? + puts "-- Failed: --" + pp failed + puts + end + + puts "Functions: #{functions.size}" + puts "Structs: #{structs.size}" + puts "Failed: #{failed.size}" + puts + + result = [functions, structs] + + File.write(destination, JSON.generate(result)) + end + end + end +end diff --git a/templates.rb b/src/templates.rb index 7d88876..7d88876 100644 --- a/templates.rb +++ b/src/templates.rb |
