Skip to content

Commit 826482e

Browse files
committed
Added methods and static methods to ruby loader.
1 parent 87adf67 commit 826482e

File tree

2 files changed

+86
-57
lines changed

2 files changed

+86
-57
lines changed

source/loaders/rb_loader/source/rb_loader_impl.c

Lines changed: 82 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,9 @@ typedef struct loader_impl_rb_module_eval_protect_type
9494
VALUE module;
9595
} * loader_impl_rb_module_eval_protect;
9696

97-
class_interface rb_class_interface_singleton();
98-
object_interface rb_object_interface_singleton();
97+
static class_interface rb_class_interface_singleton(void);
98+
static object_interface rb_object_interface_singleton(void);
99+
static void rb_loader_impl_discover_methods(klass c, VALUE cls, const char *class_name_str, const char *method_type_str, VALUE methods, int (*register_method)(klass, method));
99100

100101
int function_rb_interface_create(function func, function_impl impl)
101102
{
@@ -1347,6 +1348,73 @@ loader_impl_rb_function rb_function_create(loader_impl_rb_module rb_module, ID i
13471348
return NULL;
13481349
}
13491350

1351+
void rb_loader_impl_discover_methods(klass c, VALUE cls, const char *class_name_str, const char *method_type_str, VALUE methods, int (*register_method)(klass, method))
1352+
{
1353+
VALUE methods_v_size = rb_funcall(methods, rb_intern("size"), 0);
1354+
int method_index, methods_size = FIX2INT(methods_v_size);
1355+
1356+
for (method_index = 0; method_index < methods_size; ++method_index)
1357+
{
1358+
VALUE rb_method = rb_ary_entry(methods, method_index);
1359+
VALUE name = rb_funcall(rb_method, rb_intern("id2name"), 0);
1360+
const char *method_name_str = RSTRING_PTR(name);
1361+
1362+
VALUE instance_method = rb_funcall(cls, rb_intern(method_type_str), 1, rb_method);
1363+
VALUE parameters = rb_funcall(instance_method, rb_intern("parameters"), 0);
1364+
size_t args_it, args_count = RARRAY_LEN(parameters);
1365+
1366+
log_write("metacall", LOG_LEVEL_DEBUG, "Method '%s' inside '%s' of type %s with %" PRIuS " parameters", method_name_str, class_name_str, method_type_str, args_count);
1367+
1368+
/*
1369+
* TODO:
1370+
* Another alternative (for supporting types), which is not used in the current implementation,
1371+
* but it can simplify the parser, it's the following:
1372+
*
1373+
* - For classes: origin_file, definition_line = MyClass.instance_method(:foo).source_location
1374+
* - For plain functions: origin_file, definition_line = method(:foo).source_location
1375+
*
1376+
* Then:
1377+
* method_signature = IO.readlines(origin_file)[definition_line.pred]
1378+
*
1379+
* Now we have only the method signature, this is going to be less problematic than parsing
1380+
* the whole file as we are doing now (although for multi-line signatures it's going to be
1381+
* a little bit more complicated...)
1382+
*
1383+
* We can switch to completely duck typed approach (refactoring the tests) or we can use this
1384+
* simplified parsing approach and maintain types
1385+
*/
1386+
1387+
method m = method_create(c,
1388+
method_name_str,
1389+
args_count,
1390+
(method_impl)instance_method,
1391+
VISIBILITY_PUBLIC, /* TODO: Check previous TODO inside this function */
1392+
SYNCHRONOUS, /* There is not async functions in Ruby */
1393+
NULL);
1394+
1395+
signature s = method_signature(m);
1396+
1397+
for (args_it = 0; args_it < args_count; ++args_it)
1398+
{
1399+
VALUE parameter_pair = rb_ary_entry(parameters, args_it);
1400+
1401+
if (RARRAY_LEN(parameter_pair) == 2)
1402+
{
1403+
VALUE parameter_name_id = rb_ary_entry(parameter_pair, 1);
1404+
VALUE parameter_name = rb_funcall(parameter_name_id, rb_intern("id2name"), 0);
1405+
const char *parameter_name_str = RSTRING_PTR(parameter_name);
1406+
1407+
signature_set(s, args_it, parameter_name_str, NULL);
1408+
}
1409+
}
1410+
1411+
if (register_method(c, m) == 0)
1412+
{
1413+
log_write("metacall", LOG_LEVEL_ERROR, "Ruby failed to register method '%s'", method_name_str);
1414+
}
1415+
}
1416+
}
1417+
13501418
int rb_loader_impl_discover_module(loader_impl impl, loader_impl_rb_module rb_module, context ctx)
13511419
{
13521420
log_write("metacall", LOG_LEVEL_DEBUG, "Ruby loader discovering:");
@@ -1357,9 +1425,7 @@ int rb_loader_impl_discover_module(loader_impl impl, loader_impl_rb_module rb_mo
13571425
}
13581426

13591427
VALUE instance_methods = rb_funcall(rb_module->module, rb_intern("instance_methods"), 0);
1360-
13611428
VALUE methods_size = rb_funcall(instance_methods, rb_intern("size"), 0);
1362-
13631429
int index, size = FIX2INT(methods_size);
13641430

13651431
for (index = 0; index < size; ++index)
@@ -1411,9 +1477,7 @@ int rb_loader_impl_discover_module(loader_impl impl, loader_impl_rb_module rb_mo
14111477

14121478
/* Now discover classes */
14131479
VALUE constants = rb_funcall(rb_module->module, rb_intern("constants"), 0);
1414-
14151480
VALUE constants_size = rb_funcall(constants, rb_intern("size"), 0);
1416-
14171481
size = FIX2INT(constants_size);
14181482

14191483
for (index = 0; index < size; index++)
@@ -1426,63 +1490,24 @@ int rb_loader_impl_discover_module(loader_impl impl, loader_impl_rb_module rb_mo
14261490
{
14271491
VALUE class_name = rb_funcall(constant, rb_intern("id2name"), 0);
14281492
const char *class_name_str = RSTRING_PTR(class_name);
1429-
VALUE class = rb_const_get_from(rb_module->module, rb_intern(class_name_str));
1493+
VALUE cls = rb_const_get_from(rb_module->module, rb_intern(class_name_str));
14301494
loader_impl_rb_class rb_cls = malloc(sizeof(struct loader_impl_rb_class_type));
14311495
klass c = class_create(class_name_str, rb_cls, &rb_class_interface_singleton);
14321496

14331497
rb_cls->impl = impl;
1434-
rb_cls->class = class;
1435-
1436-
// TODO:
1437-
// rb_obj_private_methods, rb_obj_protected_methods, rb_obj_public_methods and
1438-
// rb_obj_singleton_methods, can be used instead of rb_class_instance_methods
1498+
rb_cls->class = cls;
14391499

1440-
VALUE argv[1] = { Qtrue }; // include_superclasses ? Qtrue : Qfalse;
1441-
VALUE methods = rb_class_instance_methods(1, argv, class); // argc, argv, class
1442-
VALUE load_path_array_size = rb_funcall(methods, rb_intern("size"), 0);
1443-
int method_index, methods_size = FIX2INT(load_path_array_size);
1500+
/*
1501+
* TODO:
1502+
* rb_obj_private_methods, rb_obj_protected_methods, rb_obj_public_methods and
1503+
* rb_obj_singleton_methods, can be used instead of rb_class_instance_methods
1504+
*/
1505+
VALUE argv[1] = { Qtrue }; /* include_superclasses ? Qtrue : Qfalse; */
1506+
VALUE methods = rb_class_instance_methods(1, argv, cls); /* argc, argv, class */
1507+
rb_loader_impl_discover_methods(c, cls, class_name_str, "instance_method", methods, &class_register_method);
14441508

1445-
for (method_index = 0; method_index < methods_size; method_index++)
1446-
{
1447-
VALUE rb_method = rb_ary_entry(methods, method_index);
1448-
VALUE name = rb_funcall(rb_method, rb_intern("id2name"), 0);
1449-
const char *method_name_str = RSTRING_PTR(name);
1450-
1451-
log_write("metacall", LOG_LEVEL_DEBUG, "Method inside '%s' %s", class_name_str, method_name_str);
1452-
1453-
/* TODO */
1454-
/*
1455-
method m = method_create(c,
1456-
method_name_str,
1457-
args_count, // TODO: method(:foo).parameters.length
1458-
rb_method,
1459-
VISIBILITY_PUBLIC, // TODO: Check line 1434 of this file
1460-
SYNCHRONOUS, // There is not async functions in Ruby
1461-
NULL);
1462-
1463-
signature s = method_signature(m);
1464-
1465-
// TODO: Iterate through each parameter (method(:foo).parameters),
1466-
// get each pair second element and store the name, the arguments of the methods
1467-
// can be without types, so there's no need to use the parser
1468-
1469-
// Another alternative (for maintaining types), which is not used in the current implementation,
1470-
// but it can simplify the parser, it's the following:
1471-
//
1472-
// - For classes: origin_file, definition_line = MyClass.instance_method(:foo).source_location
1473-
// - For plain functions: origin_file, definition_line = method(:foo).source_location
1474-
//
1475-
// Then:
1476-
// method_signature = IO.readlines(origin_file)[definition_line.pred]
1477-
//
1478-
// Now we have only the method signature, this is going to be less problematic than parsing
1479-
// the whole file as we are doing now (although for multi-line signatures it's going to be
1480-
// a little bit more complicated...)
1481-
//
1482-
// We can switch to completely duck typed approach (refactoring the tests) or we can use this
1483-
// simplified parsing approach and maintain types
1484-
*/
1485-
}
1509+
methods = rb_obj_singleton_methods(1, argv, cls); /* argc, argv, class */
1510+
rb_loader_impl_discover_methods(c, cls, class_name_str, "singleton_method", methods, &class_register_static_method);
14861511

14871512
/* Define default constructor. Ruby only supports one constructor, a
14881513
* method called 'initialize'. It can have arguments but when inspected via

source/scripts/ruby/klass/source/klass.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ def return_bye(value)
1717
puts(result)
1818
return result
1919
end
20+
21+
def many_parameters(a, b, c, d, e, f, g, h)
22+
puts(a, b, c, d, e, f, g, h)
23+
end
2024

2125
def self.static_hello(value)
2226
result = 'Hello static ' + value + '!'

0 commit comments

Comments
 (0)