# cat foobar.cr
#require "symbolx"
require "big"
@[Link(ldflags: "-lruby -dynamic -bundle")]
lib Rb
fun defineGlobalFunction="rb_define_global_function"(LibC::Char*, PV, LibC::Int) : Void
fun string="rb_string_value_ptr"(V*): UInt8*
fun symbol="rb_sym2str"(V) : V
fun hashKeys="rb_hash_keys"(V) : V
fun hashValue="rb_hash_fetch"(V, V) : V
fun raise="rb_raise"(V, V)
fun error= "rb_invalid_str"(LibC::Char*, LibC::Char*) : V
fun getConst="rb_const_get"(V, V) : V
fun outString="rb_str_new_cstr"(LibC::Char*) : V
fun id="rb_to_id"(V) : V #it's actually an ID
fun big="rb_big2str"(V, Int32) : V
struct Two
a : V
b : V
end
end
struct Five
property a= V.null
property b= V.null
property c= V.null
property d= V.null
property e= V.null
def inspect
"Fiver: a 0x#{a.address.to_s 16} b 0x#{b.address.to_s 16} c 0x#{c.address.to_s 16} d 0x#{d.address.to_s 16} e 0x#{e.address.to_s 16}"
end
def inspect (io)
io << inspect
end
end
class Sym
def initialize (@s : String)
end
def inspect
":#{@s}"
end
def to_s
@s
end
def inspect (io)
io.print inspect
end
end
class String
def to_sym
Sym.new self
end
def v
Rb.outString self
end
end
struct Pointer(T)
def inspect
return "'#{v(self).inspect}" if self.is_a? V
"Pointer(#{T})"
end
def v
return v self if self.is_a? V
V.new self.address
end
def inspect (io)
io << inspect
end
end
struct UInt64
def v
V.new self
end
end
def § (s)
return Sym.new s if s.is_a? String
raise "damn"
end
enum RbType
None
Object
Class
Module
Float
String
Regexp
Array
Hash
Struct
Bignum
File
Data
Math
Complex
Rational= 15
Nil= 17
True
False
Symbol
Fixnum
Undef= 22
IMemo= 26
Node
IClass
Zombie
Moved
Mask= 31
end
alias PV= Proc(V*, V*, V*, V*, V*, V*, V*, V*, V*, V*, V*, V*, V*, V*, V*, V*, V*, V*, V*, V*, V*, V*, V*, V*, V*, V)
alias V= Pointer(Void)
Qnil=Pointer(Void).new(8)
def v (x : V)
x= x.address
if x==0
false
elsif x==8
nil
elsif x==20
true
elsif x&1==1
(x.unsafe_as Int64)>>1
elsif x&3==2
b= x>>63
n= ((b^1)<<1)|b|(x&~0x03)
Box(Float64).unbox Box.box((n>>3)|((n&7)<<61))
elsif x&12==12 # that's ONE type of symbol (it was used first via :symbol)
# § v Rb.symbol V.new x
nil
else
t= RbType.from_value? Pointer(UInt64).new(x).value&0x1F
if t== RbType::String
s= Pointer(Five).new(x).value
ptr= Pointer(Void).new x
String.new Pointer(UInt8).new((Rb.string pointerof(ptr)).address), (s.a.address&8192>0 ? s.c.address : (s.a.address&0x7c000)>>14)
elsif t== RbType::Symbol # that's ANOTHER type of symbol (it was used first via 'symbol'.to_sym)
# s= (v Rb.symbol V.new x)
# s.to_sym if s.is_a? String
nil
elsif t==RbType::Array
a= Tuple.new
s= Pointer(Five).new(x).value
if s.a.address&8192>0
(s.a.address>>15).times{|i| a+= Tuple.new Pointer(V).new(x+(i+2)*8).value.v}
else
s.c.address.times{|i| a+= Tuple.new Pointer(V).new(s.e.address+i*8).value.v}
end
# if s.a.address&8192>0
# (s.a.address>>15).times{|i| a<< Pointer(V).new(x+(i+2)*8).value}
# else
# s.c.address.times{|i| a<< Pointer(V).new(s.e.address+i*8).value}
# end
a
elsif t==RbType::Hash
a= Hash(V, V).new
Rb.hashKeys(x.v).v.unsafe_as(Array(V)).each{|k| a[k]= Rb.hashValue x.v, k}
a
elsif t==RbType::Bignum
BigInt.new Rb.big(x.v, 10).v.unsafe_as String
else
p x
Rb.error "not implemented", "argument of type #{t}. crubystal doesn't handle them and right now there are no plans to do so in the future either. If you think this type should be implemented, you can try to convince me and I might do so. Error"
nil
end
end
end
def rv (x) : Pointer(Void)
if x.nil?
Pointer(Void).new 8
elsif x==true
Pointer(Void).new 20
elsif x==false
Pointer(Void).new 0
else
Box.box x
end
end
fun extInit="Init_foobar"
main 0, Pointer(Pointer(UInt8)).null
end
def addGlobalMethod(name, &b : PV)
Rb.defineGlobalFunction name, b, -2
end
###### 👇 below this line the real stuff happens
addGlobalMethod "foo" do |_, a, b, c|
p a.v
rv true
end
Like this it should give you Error: tuple size cannot be greater than 300 (size is 301)
after just a few seconds of compiling
Insert “break if i==300;” into the blocks in lines 160 and 164 and the compiler accepts it but crashes after try so hard for almost an hour.