1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
|
# frozen_string_literal: true
=begin
require_relative "FelBind/version"
require_relative "FelBind/backend/uctags.rb"
require_relative "FelBind/frontend/mruby.rb"
=end
module FelBind
class Error < StandardError; end
# Your code goes here...
# Binding C to mruby
class BindGem
attr_accessor :gem_name
def initialize(gem_name:)
self.gem_name = gem_name
end
def add_class(name)
class_names.push name
end
def add_function(class_name:, function_name:, &block)
functions.push Function.new(class_name: class_name, function_name: function_name)
block.call(functions.last)
end
private
def functions
@functions ||= []
end
def class_names
@class_names ||= []
end
# function
class Function
attr_accessor :content, :name, :class_name, :return_call_val, :args
def initialize(class_name:, function_name:)
self.class_name = class_name
self.name = function_name
end
def return_call(&block)
self.return_call_val = ReturnCall.new
block.call(return_call_val)
end
def build_get_vars
result = ""
expect = ""
addresses = ""
args.arguments.each do |param|
if param.first == :int
result += "mrb_int #{arg(param.last)};\n"
expect += "i"
addresses += ", &#{arg(param.last)}"
end
end
addresses.delete_prefix! ", "
result += "mrb_get_args(mrb, \"#{expect}\", #{addresses});\n"
end
def build
function = "static mrb_value\n"
function += "felbind_#{name}(mrb_state *mrb, mrb_value self){\n"
function += build_get_vars
function += "#{content}\n"
function += "#{return_call_val.build}"
function += "}\n"
function
end
def arg(name)
"felflame_var_#{name}"
end
def get_args(&block)
self.args = Args.new
block.call(args)
end
# args
class Args
def arguments
@arguments ||= []
end
def int(name)
arguments.push [:int, name]
end
end
# return call
class ReturnCall
attr_accessor :type, :val
def build
if type == "nil"
"return mrb_nil_value();\n"
elsif type == "int"
"return mrb_fixnum_value(#{val});\n"
end
end
end
end
end
# bind gem
class BindGem
def build
result = ""
result += insert_includes
functions.each do |func_obj|
result += func_obj.build
end
result += build_init
result += build_final
result
end
private
def insert_includes
"#include <mruby.h>\n#include <stdio.h>\n"
end
def build_init
result = ""
result += "void mrb_#{gem_name}_gem_init(mrb_state* mrb) {\n"
class_names.each do |class_name|
result += "struct RClass *#{class_name}_class = mrb_define_module(mrb, \"#{class_name}\");\n"
end
functions.each do |func|
result += "mrb_define_class_method(mrb, #{func.class_name}_class, \"#{func.name}\", felbind_#{func.name},"
if(func.args.arguments.size.zero?)
result += " MRB_ARGS_NONE()"
else
result += " MRB_ARGS_REQ(#{func.args.arguments.size})"
end
result += ");\n"
end
result += "}\n"
result
end
def build_final
"void mrb_#{gem_name}_gem_final(mrb_state* mrb) {}\n"
end
end
end
|