You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucy.apache.org by nw...@apache.org on 2013/05/30 22:36:30 UTC
[lucy-commits] [12/26] git commit: refs/heads/separate-clownfish-wip2 - Support
object types from other parcels without prefix
Support object types from other parcels without prefix
Resolve types after all classes have been parsed.
This means that caching of C representations has to be postponed. For
now, the C representations are cached after the types have been
resolved. This is error-prone and requires some hacks for methods. It
might be better to move to a scheme where the C strings are not cached
until they're used for the first time.
TODO: Add Perl bindings and fix Perl tests
Project: http://git-wip-us.apache.org/repos/asf/lucy/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucy/commit/fa4918d2
Tree: http://git-wip-us.apache.org/repos/asf/lucy/tree/fa4918d2
Diff: http://git-wip-us.apache.org/repos/asf/lucy/diff/fa4918d2
Branch: refs/heads/separate-clownfish-wip2
Commit: fa4918d2c11e1cf600579a977f8e752227dc5d2f
Parents: cecd524
Author: Nick Wellnhofer <we...@aevum.de>
Authored: Mon May 20 01:36:52 2013 +0200
Committer: Nick Wellnhofer <we...@aevum.de>
Committed: Thu May 30 22:30:17 2013 +0200
----------------------------------------------------------------------
clownfish/compiler/src/CFCClass.c | 16 +++
clownfish/compiler/src/CFCClass.h | 5 +
clownfish/compiler/src/CFCDumpable.c | 13 ++-
clownfish/compiler/src/CFCFunction.c | 6 +
clownfish/compiler/src/CFCFunction.h | 6 +
clownfish/compiler/src/CFCHierarchy.c | 3 +
clownfish/compiler/src/CFCMethod.c | 30 ++++--
clownfish/compiler/src/CFCMethod.h | 3 +
clownfish/compiler/src/CFCParamList.c | 14 ++-
clownfish/compiler/src/CFCParamList.h | 4 +
clownfish/compiler/src/CFCTest.c | 6 +
clownfish/compiler/src/CFCTestClass.c | 15 +++-
clownfish/compiler/src/CFCTestFile.c | 22 ++++-
clownfish/compiler/src/CFCTestMethod.c | 12 ++-
clownfish/compiler/src/CFCTestParamList.c | 10 ++-
clownfish/compiler/src/CFCTestParser.c | 15 +++-
clownfish/compiler/src/CFCTestType.c | 36 +++++++-
clownfish/compiler/src/CFCTestVariable.c | 10 ++-
clownfish/compiler/src/CFCType.c | 123 ++++++++++++++++--------
clownfish/compiler/src/CFCType.h | 6 +
clownfish/compiler/src/CFCVariable.c | 18 +++-
clownfish/compiler/src/CFCVariable.h | 4 +
22 files changed, 303 insertions(+), 74 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/lucy/blob/fa4918d2/clownfish/compiler/src/CFCClass.c
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCClass.c b/clownfish/compiler/src/CFCClass.c
index e5022ac..0567ca4 100644
--- a/clownfish/compiler/src/CFCClass.c
+++ b/clownfish/compiler/src/CFCClass.c
@@ -459,6 +459,22 @@ CFCClass_fresh_method(CFCClass *self, const char *sym) {
return NULL;
}
+void
+CFCClass_resolve_types(CFCClass *self, CFCClass **classes) {
+ for (size_t i = 0; self->functions[i] != NULL; i++) {
+ CFCFunction_resolve_types(self->functions[i], classes);
+ }
+ for (size_t i = 0; self->methods[i] != NULL; i++) {
+ CFCMethod_resolve_types(self->methods[i], classes);
+ }
+ for (size_t i = 0; self->member_vars[i] != NULL; i++) {
+ CFCVariable_resolve_type(self->member_vars[i], classes);
+ }
+ for (size_t i = 0; self->inert_vars[i] != NULL; i++) {
+ CFCVariable_resolve_type(self->inert_vars[i], classes);
+ }
+}
+
// Pass down member vars to from parent to children.
static void
S_bequeath_member_vars(CFCClass *self) {
http://git-wip-us.apache.org/repos/asf/lucy/blob/fa4918d2/clownfish/compiler/src/CFCClass.h
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCClass.h b/clownfish/compiler/src/CFCClass.h
index fd38149..cb484d8 100644
--- a/clownfish/compiler/src/CFCClass.h
+++ b/clownfish/compiler/src/CFCClass.h
@@ -150,6 +150,11 @@ CFCClass_fresh_method(CFCClass *self, const char *sym);
struct CFCMethod*
CFCClass_find_novel_method(CFCClass *self, const char *sym);
+/** Find the actual class of all object variables without prefix.
+ */
+void
+CFCClass_resolve_types(CFCClass *self, CFCClass **classes);
+
/** Bequeath all inherited methods and members to children.
*/
void
http://git-wip-us.apache.org/repos/asf/lucy/blob/fa4918d2/clownfish/compiler/src/CFCDumpable.c
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCDumpable.c b/clownfish/compiler/src/CFCDumpable.c
index 7fd2616..006f62a 100644
--- a/clownfish/compiler/src/CFCDumpable.c
+++ b/clownfish/compiler/src/CFCDumpable.c
@@ -110,14 +110,15 @@ CFCDumpable_add_dumpables(CFCDumpable *self, CFCClass *klass) {
static CFCMethod*
S_make_method_obj(CFCClass *klass, const char *method_name) {
- const char *klass_struct_sym = CFCClass_get_struct_sym(klass);
+ const char *klass_full_struct_sym = CFCClass_full_struct_sym(klass);
const char *klass_name = CFCClass_get_class_name(klass);
const char *klass_cnick = CFCClass_get_cnick(klass);
CFCParcel *klass_parcel = CFCClass_get_parcel(klass);
CFCType *return_type
- = CFCType_new_object(CFCTYPE_INCREMENTED, klass_parcel, "Obj", 1);
- CFCType *self_type = CFCType_new_object(0, klass_parcel, klass_struct_sym, 1);
+ = CFCType_new_object(CFCTYPE_INCREMENTED, klass_parcel, "lucy_Obj", 1);
+ CFCType *self_type = CFCType_new_object(0, klass_parcel,
+ klass_full_struct_sym, 1);
CFCVariable *self_var = CFCVariable_new(NULL, NULL, NULL, NULL, "self",
self_type, false);
CFCParamList *param_list = NULL;
@@ -127,7 +128,8 @@ S_make_method_obj(CFCClass *klass, const char *method_name) {
CFCParamList_add_param(param_list, self_var, NULL);
}
else if (strcmp(method_name, "Load") == 0) {
- CFCType *dump_type = CFCType_new_object(0, klass_parcel, "Obj", 1);
+ CFCType *dump_type = CFCType_new_object(0, klass_parcel, "lucy_Obj",
+ 1);
CFCVariable *dump_var = CFCVariable_new(NULL, NULL, NULL, NULL, "dump",
dump_type, false);
param_list = CFCParamList_new(false);
@@ -143,6 +145,9 @@ S_make_method_obj(CFCClass *klass, const char *method_name) {
CFCMethod *method = CFCMethod_new(klass_parcel, "public", klass_name,
klass_cnick, method_name, return_type,
param_list, NULL, false, false);
+ // Hack
+ CFCClass *dummy_class = NULL;
+ CFCMethod_resolve_types(method, &dummy_class);
CFCBase_decref((CFCBase*)param_list);
CFCBase_decref((CFCBase*)self_type);
http://git-wip-us.apache.org/repos/asf/lucy/blob/fa4918d2/clownfish/compiler/src/CFCFunction.c
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCFunction.c b/clownfish/compiler/src/CFCFunction.c
index 7205622..6f781f4 100644
--- a/clownfish/compiler/src/CFCFunction.c
+++ b/clownfish/compiler/src/CFCFunction.c
@@ -84,6 +84,12 @@ CFCFunction_init(CFCFunction *self, CFCParcel *parcel, const char *exposure,
}
void
+CFCFunction_resolve_types(CFCFunction *self, struct CFCClass **classes) {
+ CFCType_resolve(self->return_type, classes);
+ CFCParamList_resolve_types(self->param_list, classes);
+}
+
+void
CFCFunction_destroy(CFCFunction *self) {
CFCBase_decref((CFCBase*)self->return_type);
CFCBase_decref((CFCBase*)self->param_list);
http://git-wip-us.apache.org/repos/asf/lucy/blob/fa4918d2/clownfish/compiler/src/CFCFunction.h
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCFunction.h b/clownfish/compiler/src/CFCFunction.h
index e69b632..baab2c7 100644
--- a/clownfish/compiler/src/CFCFunction.h
+++ b/clownfish/compiler/src/CFCFunction.h
@@ -29,6 +29,7 @@ struct CFCParcel;
struct CFCType;
struct CFCDocuComment;
struct CFCParamList;
+struct CFCClass;
#ifdef CFC_NEED_FUNCTION_STRUCT_DEF
#define CFC_NEED_SYMBOL_STRUCT_DEF
@@ -110,6 +111,11 @@ CFCFunction_micro_sym(CFCFunction *self);
int
CFCFunction_public(CFCFunction *self);
+/** Find the actual class of all object variables without prefix.
+ */
+void
+CFCFunction_resolve_types(CFCFunction *self, struct CFCClass **classes);
+
#ifdef __cplusplus
}
#endif
http://git-wip-us.apache.org/repos/asf/lucy/blob/fa4918d2/clownfish/compiler/src/CFCHierarchy.c
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCHierarchy.c b/clownfish/compiler/src/CFCHierarchy.c
index b8ba423..5c5b192 100644
--- a/clownfish/compiler/src/CFCHierarchy.c
+++ b/clownfish/compiler/src/CFCHierarchy.c
@@ -197,6 +197,9 @@ CFCHierarchy_build(CFCHierarchy *self) {
for (size_t i = 0; self->includes[i] != NULL; i++) {
S_parse_cf_files(self, self->includes[i], 1);
}
+ for (int i = 0; self->classes[i] != NULL; i++) {
+ CFCClass_resolve_types(self->classes[i], self->classes);
+ }
S_connect_classes(self);
for (size_t i = 0; self->trees[i] != NULL; i++) {
CFCClass_grow_tree(self->trees[i]);
http://git-wip-us.apache.org/repos/asf/lucy/blob/fa4918d2/clownfish/compiler/src/CFCMethod.c
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCMethod.c b/clownfish/compiler/src/CFCMethod.c
index a9f0063..f659323 100644
--- a/clownfish/compiler/src/CFCMethod.c
+++ b/clownfish/compiler/src/CFCMethod.c
@@ -105,12 +105,30 @@ CFCMethod_init(CFCMethod *self, CFCParcel *parcel, const char *exposure,
docucomment, false);
FREEMEM(micro_sym);
+ self->macro_sym = CFCUtil_strdup(macro_sym);
+ self->is_final = is_final;
+ self->is_abstract = is_abstract;
+
+ self->full_override_sym = NULL;
+
+ // Assume that this method is novel until we discover when applying
+ // inheritance that it overrides another.
+ self->is_novel = true;
+
+ return self;
+}
+
+void
+CFCMethod_resolve_types(CFCMethod *self, struct CFCClass **classes) {
+ CFCFunction_resolve_types((CFCFunction*)self, classes);
+
// Verify that the first element in the arg list is a self.
- CFCVariable **args = CFCParamList_get_variables(param_list);
+ CFCVariable **args = CFCParamList_get_variables(self->function.param_list);
if (!args[0]) { CFCUtil_die("Missing 'self' argument"); }
CFCType *type = CFCVariable_get_type(args[0]);
const char *specifier = CFCType_get_specifier(type);
const char *prefix = CFCMethod_get_prefix(self);
+ const char *class_name = CFCMethod_get_class_name(self);
const char *last_colon = strrchr(class_name, ':');
const char *struct_sym = last_colon ? last_colon + 1 : class_name;
char *wanted = CFCUtil_sprintf("%s%s", prefix, struct_sym);
@@ -121,19 +139,9 @@ CFCMethod_init(CFCMethod *self, CFCParcel *parcel, const char *exposure,
class_name, specifier);
}
- self->macro_sym = CFCUtil_strdup(macro_sym);
- self->is_final = is_final;
- self->is_abstract = is_abstract;
-
// Derive more symbols.
const char *full_func_sym = CFCMethod_implementing_func_sym(self);
self->full_override_sym = CFCUtil_sprintf("%s_OVERRIDE", full_func_sym);
-
- // Assume that this method is novel until we discover when applying
- // inheritance that it overrides another.
- self->is_novel = true;
-
- return self;
}
void
http://git-wip-us.apache.org/repos/asf/lucy/blob/fa4918d2/clownfish/compiler/src/CFCMethod.h
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCMethod.h b/clownfish/compiler/src/CFCMethod.h
index b7f01dd..cdceb6a 100644
--- a/clownfish/compiler/src/CFCMethod.h
+++ b/clownfish/compiler/src/CFCMethod.h
@@ -71,6 +71,9 @@ CFCMethod_init(CFCMethod *self, struct CFCParcel *parcel,
int is_abstract);
void
+CFCMethod_resolve_types(CFCMethod *self, struct CFCClass **classes);
+
+void
CFCMethod_destroy(CFCMethod *self);
/** Returns true if the methods have signatures and attributes which allow one
http://git-wip-us.apache.org/repos/asf/lucy/blob/fa4918d2/clownfish/compiler/src/CFCParamList.c
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCParamList.c b/clownfish/compiler/src/CFCParamList.c
index 3e7bacf..2845480 100644
--- a/clownfish/compiler/src/CFCParamList.c
+++ b/clownfish/compiler/src/CFCParamList.c
@@ -55,11 +55,20 @@ CFCParamList_init(CFCParamList *self, int variadic) {
self->num_vars = 0;
self->variables = (CFCVariable**)CALLOCATE(1, sizeof(void*));
self->values = (char**)CALLOCATE(1, sizeof(char*));
- S_generate_c_strings(self);
+ self->c_string = CFCUtil_strdup("");
+ self->name_list = CFCUtil_strdup("");
return self;
}
void
+CFCParamList_resolve_types(CFCParamList *self, struct CFCClass **classes) {
+ for (size_t i = 0; self->variables[i]; ++i) {
+ CFCVariable_resolve_type(self->variables[i], classes);
+ }
+ S_generate_c_strings(self);
+}
+
+void
CFCParamList_add_param(CFCParamList *self, CFCVariable *variable,
const char *value) {
CFCUTIL_NULL_CHECK(variable);
@@ -72,8 +81,6 @@ CFCParamList_add_param(CFCParamList *self, CFCVariable *variable,
self->values[self->num_vars - 1] = value ? CFCUtil_strdup(value) : NULL;
self->variables[self->num_vars] = NULL;
self->values[self->num_vars] = NULL;
-
- S_generate_c_strings(self);
}
void
@@ -153,7 +160,6 @@ CFCParamList_num_vars(CFCParamList *self) {
void
CFCParamList_set_variadic(CFCParamList *self, int variadic) {
self->variadic = !!variadic;
- S_generate_c_strings(self);
}
int
http://git-wip-us.apache.org/repos/asf/lucy/blob/fa4918d2/clownfish/compiler/src/CFCParamList.h
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCParamList.h b/clownfish/compiler/src/CFCParamList.h
index 23cc0e3..886fdfe 100644
--- a/clownfish/compiler/src/CFCParamList.h
+++ b/clownfish/compiler/src/CFCParamList.h
@@ -25,6 +25,7 @@ extern "C" {
#endif
typedef struct CFCParamList CFCParamList;
+struct CFCClass;
struct CFCVariable;
/**
@@ -37,6 +38,9 @@ CFCParamList*
CFCParamList_init(CFCParamList *self, int variadic);
void
+CFCParamList_resolve_types(CFCParamList *self, struct CFCClass **classes);
+
+void
CFCParamList_destroy(CFCParamList *self);
/** Add a parameter to the ParamList.
http://git-wip-us.apache.org/repos/asf/lucy/blob/fa4918d2/clownfish/compiler/src/CFCTest.c
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCTest.c b/clownfish/compiler/src/CFCTest.c
index 2fd9933..21cff48 100644
--- a/clownfish/compiler/src/CFCTest.c
+++ b/clownfish/compiler/src/CFCTest.c
@@ -19,6 +19,7 @@
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
@@ -297,6 +298,11 @@ S_format_cfish_vtest_result(int pass, int test_num, const char *fmt,
vprintf(fmt, args);
printf("\n");
}
+ else if (getenv("CFCTEST_VERBOSE")) {
+ printf(" Passed test %d: ", test_num);
+ vprintf(fmt, args);
+ printf("\n");
+ }
}
static void
http://git-wip-us.apache.org/repos/asf/lucy/blob/fa4918d2/clownfish/compiler/src/CFCTestClass.c
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCTestClass.c b/clownfish/compiler/src/CFCTestClass.c
index 67097d6..9f841f9 100644
--- a/clownfish/compiler/src/CFCTestClass.c
+++ b/clownfish/compiler/src/CFCTestClass.c
@@ -39,7 +39,7 @@ S_has_symbol(CFCSymbol **symbols, const char *micro_sym);
const CFCTestBatch CFCTEST_BATCH_CLASS = {
"Clownfish::CFC::Model::Class",
- 83,
+ 87,
S_run_tests
};
@@ -49,6 +49,10 @@ S_run_tests(CFCTest *test) {
CFCParcel *neato = CFCParcel_new("Neato", NULL, NULL);
CFCFileSpec *file_spec = CFCFileSpec_new(".", "Foo/FooJr", 0);
+ CFCClass *thing_class
+ = CFCTest_parse_class(test, parser, "class Thing {}");
+ CFCClass *widget_class
+ = CFCTest_parse_class(test, parser, "class Widget {}");
CFCVariable *thing;
CFCVariable *widget;
@@ -119,6 +123,13 @@ S_run_tests(CFCTest *test) {
= CFCTest_parse_method(test, parser, "void Do_Stuff(Foo *self);");
CFCClass_add_method(foo, do_stuff);
+ CFCClass *class_list[6] = {
+ foo, foo_jr, final_foo, thing_class, widget_class, NULL
+ };
+ CFCClass_resolve_types(foo, class_list);
+ CFCClass_resolve_types(foo_jr, class_list);
+ CFCClass_resolve_types(final_foo, class_list);
+
CFCClass_add_child(foo, foo_jr);
CFCClass_add_child(foo_jr, final_foo);
CFCClass_grow_tree(foo);
@@ -330,6 +341,8 @@ S_run_tests(CFCTest *test) {
CFCBase_decref((CFCBase*)parser);
CFCBase_decref((CFCBase*)neato);
CFCBase_decref((CFCBase*)file_spec);
+ CFCBase_decref((CFCBase*)thing_class);
+ CFCBase_decref((CFCBase*)widget_class);
CFCBase_decref((CFCBase*)thing);
CFCBase_decref((CFCBase*)widget);
CFCBase_decref((CFCBase*)tread_water);
http://git-wip-us.apache.org/repos/asf/lucy/blob/fa4918d2/clownfish/compiler/src/CFCTestFile.c
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCTestFile.c b/clownfish/compiler/src/CFCTestFile.c
index 2e1edc5..f62b919 100644
--- a/clownfish/compiler/src/CFCTestFile.c
+++ b/clownfish/compiler/src/CFCTestFile.c
@@ -21,6 +21,7 @@
#include "CFCClass.h"
#include "CFCFile.h"
#include "CFCFileSpec.h"
+#include "CFCParcel.h"
#include "CFCParser.h"
#include "CFCTest.h"
#include "CFCType.h"
@@ -32,7 +33,7 @@ S_run_tests(CFCTest *test);
const CFCTestBatch CFCTEST_BATCH_FILE = {
"Clownfish::CFC::Model::File",
- 19,
+ 21,
S_run_tests
};
@@ -50,6 +51,8 @@ S_run_tests(CFCTest *test) {
" Foo *foo;\n"
" Bar *bar;\n"
"}\n"
+ "class Foo {}\n"
+ "class Bar {}\n"
"__C__\n"
"int foo;\n"
"__END_C__\n";
@@ -88,13 +91,17 @@ S_run_tests(CFCTest *test) {
FREEMEM(h_path);
CFCClass **classes = CFCFile_classes(file);
- OK(test, classes[0] != NULL && classes[1] == NULL,
+ OK(test,
+ classes[0] != NULL && classes[1] != NULL && classes[2] != NULL
+ && classes[3] == NULL,
"classes() filters blocks");
CFCVariable **member_vars = CFCClass_member_vars(classes[0]);
CFCType *foo_type = CFCVariable_get_type(member_vars[0]);
+ CFCType_resolve(foo_type, classes);
STR_EQ(test, CFCType_get_specifier(foo_type), "stuff_Foo",
"file production picked up parcel def");
CFCType *bar_type = CFCVariable_get_type(member_vars[1]);
+ CFCType_resolve(bar_type, classes);
STR_EQ(test, CFCType_get_specifier(bar_type), "stuff_Bar",
"parcel def is sticky");
@@ -104,8 +111,12 @@ S_run_tests(CFCTest *test) {
STR_EQ(test, CFCBase_get_cfc_class(blocks[1]),
"Clownfish::CFC::Model::Class", "blocks[1]");
STR_EQ(test, CFCBase_get_cfc_class(blocks[2]),
- "Clownfish::CFC::Model::CBlock", "blocks[2]");
- OK(test, blocks[3] == NULL, "blocks[3]");
+ "Clownfish::CFC::Model::Class", "blocks[2]");
+ STR_EQ(test, CFCBase_get_cfc_class(blocks[3]),
+ "Clownfish::CFC::Model::Class", "blocks[3]");
+ STR_EQ(test, CFCBase_get_cfc_class(blocks[4]),
+ "Clownfish::CFC::Model::CBlock", "blocks[4]");
+ OK(test, blocks[5] == NULL, "blocks[5]");
CFCBase_decref((CFCBase*)file);
}
@@ -128,5 +139,8 @@ S_run_tests(CFCTest *test) {
CFCBase_decref((CFCBase*)file_spec);
CFCBase_decref((CFCBase*)parser);
+
+ CFCClass_clear_registry();
+ CFCParcel_reap_singletons();
}
http://git-wip-us.apache.org/repos/asf/lucy/blob/fa4918d2/clownfish/compiler/src/CFCTestMethod.c
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCTestMethod.c b/clownfish/compiler/src/CFCTestMethod.c
index 7122786..a805228 100644
--- a/clownfish/compiler/src/CFCTestMethod.c
+++ b/clownfish/compiler/src/CFCTestMethod.c
@@ -16,6 +16,7 @@
#define CFC_USE_TEST_MACROS
#include "CFCBase.h"
+#include "CFCClass.h"
#include "CFCMethod.h"
#include "CFCParamList.h"
#include "CFCParcel.h"
@@ -41,7 +42,7 @@ S_run_final_tests(CFCTest *test);
const CFCTestBatch CFCTEST_BATCH_METHOD = {
"Clownfish::CFC::Model::Method",
- 66,
+ 70,
S_run_tests
};
@@ -225,6 +226,11 @@ S_run_final_tests(CFCTest *test) {
CFCParser *parser = CFCParser_new();
CFCParcel *neato_parcel
= CFCTest_parse_parcel(test, parser, "parcel Neato;");
+ CFCClass *obj_class
+ = CFCTest_parse_class(test, parser, "class Obj {}");
+ CFCClass *foo_class
+ = CFCTest_parse_class(test, parser, "class Neato::Foo {}");
+ CFCClass *class_list[3] = { obj_class, foo_class, NULL };
CFCType *return_type = CFCTest_parse_type(test, parser, "Obj*");
CFCParamList *param_list
= CFCTest_parse_param_list(test, parser, "(Foo *self)");
@@ -233,6 +239,7 @@ S_run_final_tests(CFCTest *test) {
= CFCMethod_new(neato_parcel, NULL, "Neato::Foo", "Foo",
"Return_An_Obj", return_type, param_list,
NULL, 0, 0);
+ CFCMethod_resolve_types(not_final, class_list);
CFCMethod *final = CFCMethod_finalize(not_final);
OK(test, CFCMethod_compatible(not_final, final),
"finalize clones properly");
@@ -241,11 +248,14 @@ S_run_final_tests(CFCTest *test) {
CFCBase_decref((CFCBase*)parser);
CFCBase_decref((CFCBase*)neato_parcel);
+ CFCBase_decref((CFCBase*)obj_class);
+ CFCBase_decref((CFCBase*)foo_class);
CFCBase_decref((CFCBase*)return_type);
CFCBase_decref((CFCBase*)param_list);
CFCBase_decref((CFCBase*)not_final);
CFCBase_decref((CFCBase*)final);
+ CFCClass_clear_registry();
CFCParcel_reap_singletons();
}
http://git-wip-us.apache.org/repos/asf/lucy/blob/fa4918d2/clownfish/compiler/src/CFCTestParamList.c
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCTestParamList.c b/clownfish/compiler/src/CFCTestParamList.c
index 0fd552c..29ff226 100644
--- a/clownfish/compiler/src/CFCTestParamList.c
+++ b/clownfish/compiler/src/CFCTestParamList.c
@@ -16,6 +16,7 @@
#define CFC_USE_TEST_MACROS
#include "CFCBase.h"
+#include "CFCClass.h"
#include "CFCParamList.h"
#include "CFCParcel.h"
#include "CFCParser.h"
@@ -27,7 +28,7 @@ S_run_tests(CFCTest *test);
const CFCTestBatch CFCTEST_BATCH_PARAM_LIST = {
"Clownfish::CFC::Model::ParamList",
- 21,
+ 23,
S_run_tests
};
@@ -36,10 +37,13 @@ S_run_tests(CFCTest *test) {
CFCParser *parser = CFCParser_new();
CFCParcel *neato_parcel
= CFCTest_parse_parcel(test, parser, "parcel Neato;");
+ CFCClass *obj_class = CFCTest_parse_class(test, parser, "class Obj {}");
+ CFCClass *class_list[2] = { obj_class, NULL };
{
CFCParamList *param_list
= CFCTest_parse_param_list(test, parser, "(Obj *self, int num)");
+ CFCParamList_resolve_types(param_list, class_list);
OK(test, !CFCParamList_variadic(param_list), "not variadic");
STR_EQ(test, CFCParamList_to_c(param_list), "neato_Obj* self, int num",
"to_c");
@@ -53,6 +57,7 @@ S_run_tests(CFCTest *test) {
CFCParamList *param_list
= CFCTest_parse_param_list(test, parser,
"(Obj *self=NULL, int num, ...)");
+ CFCParamList_resolve_types(param_list, class_list);
OK(test, CFCParamList_variadic(param_list), "variadic");
STR_EQ(test, CFCParamList_to_c(param_list),
"neato_Obj* self, int num, ...", "to_c");
@@ -72,6 +77,7 @@ S_run_tests(CFCTest *test) {
{
CFCParamList *param_list
= CFCTest_parse_param_list(test, parser, "()");
+ CFCParamList_resolve_types(param_list, class_list);
STR_EQ(test, CFCParamList_to_c(param_list), "void", "to_c");
INT_EQ(test, CFCParamList_num_vars(param_list), 0, "num_vars");
CFCVariable **variables = CFCParamList_get_variables(param_list);
@@ -82,7 +88,9 @@ S_run_tests(CFCTest *test) {
CFCBase_decref((CFCBase*)parser);
CFCBase_decref((CFCBase*)neato_parcel);
+ CFCBase_decref((CFCBase*)obj_class);
+ CFCClass_clear_registry();
CFCParcel_reap_singletons();
}
http://git-wip-us.apache.org/repos/asf/lucy/blob/fa4918d2/clownfish/compiler/src/CFCTestParser.c
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCTestParser.c b/clownfish/compiler/src/CFCTestParser.c
index 35d38ab..46611dd 100644
--- a/clownfish/compiler/src/CFCTestParser.c
+++ b/clownfish/compiler/src/CFCTestParser.c
@@ -37,7 +37,7 @@ S_test_initial_value(CFCTest *test, CFCParser *parser,
const CFCTestBatch CFCTEST_BATCH_PARSER = {
"Clownfish::CFC::Model::Parser",
- 189,
+ 203,
S_run_tests
};
@@ -108,17 +108,30 @@ S_run_tests(CFCTest *test) {
static const char *const class_names[7] = {
"ByteBuf", "Obj", "ANDMatcher", "Foo", "FooJr", "FooIII", "Foo4th"
};
+ CFCClass *class_list[8];
+ for (int i = 0; i < 7; ++i) {
+ char *class_code = CFCUtil_sprintf("class %s {}", class_names[i]);
+ CFCClass *klass = CFCTest_parse_class(test, parser, class_code);
+ class_list[i] = klass;
+ FREEMEM(class_code);
+ }
+ class_list[7] = NULL;
for (int i = 0; i < 7; ++i) {
const char *class_name = class_names[i];
char *src = CFCUtil_sprintf("%s*", class_name);
char *expected = CFCUtil_sprintf("crust_%s", class_name);
CFCType *type = CFCTest_parse_type(test, parser, src);
+ CFCType_resolve(type, class_list);
STR_EQ(test, CFCType_get_specifier(type), expected,
"object_type_specifier: %s", class_name);
FREEMEM(src);
FREEMEM(expected);
CFCBase_decref((CFCBase*)type);
}
+ for (int i = 0; i < 7; ++i) {
+ CFCBase_decref((CFCBase*)class_list[i]);
+ }
+ CFCClass_clear_registry();
}
{
http://git-wip-us.apache.org/repos/asf/lucy/blob/fa4918d2/clownfish/compiler/src/CFCTestType.c
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCTestType.c b/clownfish/compiler/src/CFCTestType.c
index 8751eb8..759aa42 100644
--- a/clownfish/compiler/src/CFCTestType.c
+++ b/clownfish/compiler/src/CFCTestType.c
@@ -16,12 +16,18 @@
#define CFC_USE_TEST_MACROS
#include "CFCBase.h"
+#include "CFCClass.h"
#include "CFCParcel.h"
#include "CFCParser.h"
#include "CFCTest.h"
#include "CFCType.h"
#include "CFCUtil.h"
+#ifndef true
+ #define true 1
+ #define false 0
+#endif
+
static void
S_run_tests(CFCTest *test);
@@ -54,7 +60,7 @@ S_run_composite_tests(CFCTest *test);
const CFCTestBatch CFCTEST_BATCH_TYPE = {
"Clownfish::CFC::Model::Type",
- 353,
+ 361,
S_run_tests
};
@@ -287,11 +293,17 @@ S_run_object_tests(CFCTest *test) {
for (int i = 0; i < 4; ++i) {
const char *specifier = specifiers[i];
+ char *class_code = CFCUtil_sprintf("class %s {}", specifier);
+ CFCClass *klass = CFCTest_parse_class(test, parser, class_code);
+ CFCClass *class_list[2] = { klass, NULL };
+ FREEMEM(class_code);
+
static const char *prefixes[2] = { "", "neato_" };
char *expect = CFCUtil_sprintf("neato_%s", specifier);
for (int j = 0; j < 2; ++j) {
char *src = CFCUtil_sprintf("%s%s*", prefixes[j], specifier);
CFCType *type = CFCTest_parse_type(test, parser, src);
+ CFCType_resolve(type, class_list);
STR_EQ(test, CFCType_get_specifier(type), expect,
"object_type_specifier: %s", src);
OK(test, CFCType_is_object(type), "%s is_object", src);
@@ -312,16 +324,26 @@ S_run_object_tests(CFCTest *test) {
FREEMEM(src);
CFCBase_decref((CFCBase*)type);
}
+
+ CFCBase_decref((CFCBase*)klass);
+ CFCClass_clear_registry();
}
CFCBase_decref((CFCBase*)neato_parcel);
CFCBase_decref((CFCBase*)parser);
}
+ CFCParcel *neato_parcel = CFCParcel_new("Neato", NULL, NULL);
+ CFCClass *foo_class
+ = CFCClass_create(neato_parcel, NULL, "Foo", NULL, NULL, NULL, NULL,
+ NULL, false, false);
+ CFCClass *class_list[2] = { foo_class, NULL };
CFCType *foo = CFCType_new_object(0, NULL, "Foo", 1);
+ CFCType_resolve(foo, class_list);
{
CFCType *another_foo = CFCType_new_object(0, NULL, "Foo", 1);
+ CFCType_resolve(another_foo, class_list);
OK(test, CFCType_equals(foo, another_foo), "equals");
CFCBase_decref((CFCBase*)another_foo);
}
@@ -335,13 +357,18 @@ S_run_object_tests(CFCTest *test) {
{
CFCParcel *foreign_parcel = CFCParcel_new("Foreign", NULL, NULL);
- CFCParcel_register(foreign_parcel);
+ CFCClass *foreign_foo_class
+ = CFCClass_create(foreign_parcel, NULL, "Foo", NULL, NULL, NULL,
+ NULL, NULL, false, false);
+ CFCClass *foreign_class_list[2] = { foreign_foo_class, NULL };
CFCType *foreign_foo = CFCType_new_object(0, foreign_parcel, "Foo", 1);
+ CFCType_resolve(foreign_foo, foreign_class_list);
OK(test, !CFCType_equals(foo, foreign_foo),
"different parcel spoils equals");
STR_EQ(test, CFCType_get_specifier(foreign_foo), "foreign_Foo",
"prepend parcel prefix to specifier");
CFCBase_decref((CFCBase*)foreign_parcel);
+ CFCBase_decref((CFCBase*)foreign_foo_class);
CFCBase_decref((CFCBase*)foreign_foo);
}
@@ -366,8 +393,11 @@ S_run_object_tests(CFCTest *test) {
CFCBase_decref((CFCBase*)string_type);
}
+ CFCBase_decref((CFCBase*)neato_parcel);
+ CFCBase_decref((CFCBase*)foo_class);
CFCBase_decref((CFCBase*)foo);
+ CFCClass_clear_registry();
CFCParcel_reap_singletons();
}
@@ -485,7 +515,9 @@ S_run_composite_tests(CFCTest *test) {
}
{
+ CFCClass *class_list[1] = { NULL };
CFCType *foo_array = CFCTest_parse_type(test, parser, "foo_t[]");
+ CFCType_resolve(foo_array, class_list);
STR_EQ(test, CFCType_get_array(foo_array), "[]", "get_array");
STR_EQ(test, CFCType_to_c(foo_array), "foo_t",
"array subscripts not included by to_c");
http://git-wip-us.apache.org/repos/asf/lucy/blob/fa4918d2/clownfish/compiler/src/CFCTestVariable.c
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCTestVariable.c b/clownfish/compiler/src/CFCTestVariable.c
index fd7f291..f0cbcac 100644
--- a/clownfish/compiler/src/CFCTestVariable.c
+++ b/clownfish/compiler/src/CFCTestVariable.c
@@ -16,6 +16,7 @@
#define CFC_USE_TEST_MACROS
#include "CFCBase.h"
+#include "CFCClass.h"
#include "CFCParcel.h"
#include "CFCParser.h"
#include "CFCSymbol.h"
@@ -28,7 +29,7 @@ S_run_tests(CFCTest *test);
const CFCTestBatch CFCTEST_BATCH_VARIABLE = {
"Clownfish::CFC::Model::Variable",
- 27,
+ 29,
S_run_tests
};
@@ -37,11 +38,14 @@ S_run_tests(CFCTest *test) {
CFCParser *parser = CFCParser_new();
CFCParcel *neato_parcel
= CFCTest_parse_parcel(test, parser, "parcel Neato;");
+ CFCClass *foo_class = CFCTest_parse_class(test, parser, "class Foo {}");
+ CFCClass *class_list[2] = { foo_class, NULL };
{
CFCType *type = CFCTest_parse_type(test, parser, "float*");
CFCVariable *var
= CFCVariable_new(NULL, NULL, NULL, NULL, "foo", type, 0);
+ CFCVariable_resolve_type(var, class_list);
STR_EQ(test, CFCVariable_local_c(var), "float* foo", "local_c");
STR_EQ(test, CFCVariable_local_declaration(var), "float* foo;",
"local_declaration");
@@ -55,6 +59,7 @@ S_run_tests(CFCTest *test) {
CFCType *type = CFCTest_parse_type(test, parser, "float[1]");
CFCVariable *var
= CFCVariable_new(NULL, NULL, NULL, NULL, "foo", type, 0);
+ CFCVariable_resolve_type(var, class_list);
STR_EQ(test, CFCVariable_local_c(var), "float foo[1]",
"to_c appends array to var name rather than type specifier");
@@ -68,6 +73,7 @@ S_run_tests(CFCTest *test) {
= CFCVariable_new(neato_parcel, NULL,
"Crustacean::Lobster::LobsterClaw", "LobClaw",
"foo", type, 0);
+ CFCVariable_resolve_type(var, class_list);
STR_EQ(test, CFCVariable_global_c(var), "neato_Foo* neato_LobClaw_foo",
"global_c");
@@ -94,7 +100,9 @@ S_run_tests(CFCTest *test) {
CFCBase_decref((CFCBase*)parser);
CFCBase_decref((CFCBase*)neato_parcel);
+ CFCBase_decref((CFCBase*)foo_class);
+ CFCClass_clear_registry();
CFCParcel_reap_singletons();
}
http://git-wip-us.apache.org/repos/asf/lucy/blob/fa4918d2/clownfish/compiler/src/CFCType.c
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCType.c b/clownfish/compiler/src/CFCType.c
index 549dff1..0494f93 100644
--- a/clownfish/compiler/src/CFCType.c
+++ b/clownfish/compiler/src/CFCType.c
@@ -26,6 +26,7 @@
#define CFC_NEED_BASE_STRUCT_DEF
#include "CFCBase.h"
#include "CFCType.h"
+#include "CFCClass.h"
#include "CFCParcel.h"
#include "CFCSymbol.h"
#include "CFCUtil.h"
@@ -92,15 +93,8 @@ CFCType_init(CFCType *self, int flags, struct CFCParcel *parcel,
self->width = 0;
self->array = NULL;
self->child = NULL;
- if (flags & CFCTYPE_OBJECT) {
- self->vtable_var = CFCUtil_strdup(specifier);
- for (int i = 0; self->vtable_var[i] != 0; i++) {
- self->vtable_var[i] = toupper(self->vtable_var[i]);
- }
- }
- else {
- self->vtable_var = NULL;
- }
+ self->vtable_var = NULL;
+
return self;
}
@@ -216,14 +210,8 @@ CFCType_new_object(int flags, CFCParcel *parcel, const char *specifier,
flags |= CFCTYPE_STRING_TYPE;
}
- char full_specifier[MAX_SPECIFIER_LEN + 1];
char small_specifier[MAX_SPECIFIER_LEN + 1];
if (isupper(*specifier)) {
- const char *prefix = CFCParcel_get_prefix(parcel);
- if (strlen(prefix) + strlen(specifier) > MAX_SPECIFIER_LEN) {
- CFCUtil_die("Specifier and/or parcel prefix too long");
- }
- sprintf(full_specifier, "%s%s", prefix, specifier);
strcpy(small_specifier, specifier);
}
else if (!isalpha(*specifier)) {
@@ -243,7 +231,6 @@ CFCType_new_object(int flags, CFCParcel *parcel, const char *specifier,
}
probe++;
}
- strcpy(full_specifier, specifier);
strcpy(small_specifier, probe);
}
@@ -251,15 +238,6 @@ CFCType_new_object(int flags, CFCParcel *parcel, const char *specifier,
CFCUtil_die("Invalid specifier: '%s'", specifier);
}
- // Cache C representation.
- char c_string[MAX_SPECIFIER_LEN + 10];
- if (flags & CFCTYPE_CONST) {
- sprintf(c_string, "const %s*", full_specifier);
- }
- else {
- sprintf(c_string, "%s*", full_specifier);
- }
-
int acceptable_flags = CFCTYPE_OBJECT
| CFCTYPE_STRING_TYPE
| CFCTYPE_CONST
@@ -268,7 +246,7 @@ CFCType_new_object(int flags, CFCParcel *parcel, const char *specifier,
| CFCTYPE_DECREMENTED;
S_check_flags(flags, acceptable_flags, "Object");
- return CFCType_new(flags, parcel, full_specifier, 1, c_string);
+ return CFCType_new(flags, parcel, specifier, 1, NULL);
}
#define MAX_COMPOSITE_LEN 256
@@ -282,22 +260,8 @@ CFCType_new_composite(int flags, CFCType *child, int indirection,
flags |= CFCTYPE_COMPOSITE;
S_check_flags(flags, CFCTYPE_COMPOSITE | CFCTYPE_NULLABLE, "Composite");
- // Cache C representation.
- // NOTE: Array postfixes are NOT included.
- const char *child_c_string = CFCType_to_c(child);
- size_t child_c_len = strlen(child_c_string);
- size_t amount = child_c_len + indirection;
- if (amount > MAX_COMPOSITE_LEN) {
- CFCUtil_die("C representation too long");
- }
- char c_string[MAX_COMPOSITE_LEN + 1];
- strcpy(c_string, child_c_string);
- for (int i = 0; i < indirection; i++) {
- strncat(c_string, "*", 1);
- }
-
CFCType *self = CFCType_new(flags, NULL, CFCType_get_specifier(child),
- indirection, c_string);
+ indirection, NULL);
self->child = (CFCType*)CFCBase_incref((CFCBase*)child);
// Record array spec.
@@ -335,6 +299,83 @@ CFCType_new_arbitrary(CFCParcel *parcel, const char *specifier) {
}
void
+CFCType_resolve(CFCType *self, CFCClass **classes) {
+ if (CFCType_is_composite(self)) {
+ CFCType_resolve(self->child, classes);
+
+ // Cache C representation.
+ // NOTE: Array postfixes are NOT included.
+ const char *child_c_string = CFCType_to_c(self->child);
+ size_t child_c_len = strlen(child_c_string);
+ size_t amount = child_c_len + self->indirection;
+ if (amount > MAX_COMPOSITE_LEN) {
+ CFCUtil_die("C representation too long");
+ }
+ char c_string[MAX_COMPOSITE_LEN + 1];
+ strcpy(c_string, child_c_string);
+ for (int i = 0; i < self->indirection; i++) {
+ strncat(c_string, "*", 1);
+ }
+ FREEMEM(self->c_string);
+ self->c_string = CFCUtil_strdup(c_string);
+
+ return;
+ }
+ if (!CFCType_is_object(self)) {
+ return;
+ }
+
+ if (isupper(self->specifier[0])) {
+ // Try to find class from class list.
+ const char *specifier = self->specifier;
+ CFCClass *klass = NULL;
+
+ for (size_t i = 0; classes[i]; ++i) {
+ CFCClass *maybe_class = classes[i];
+ const char *struct_sym = CFCClass_get_struct_sym(maybe_class);
+
+ if (strcmp(specifier, struct_sym) == 0) {
+ if (klass) {
+ CFCUtil_die("Type '%s' is ambigious", specifier);
+ }
+ klass = maybe_class;
+ }
+ }
+
+ if (!klass) {
+ CFCUtil_die("No class found for type '%s'", specifier);
+ }
+
+ // Create actual specifier with prefix.
+ const char *prefix = CFCClass_get_prefix(klass);
+ if (strlen(prefix) + strlen(specifier) > MAX_SPECIFIER_LEN) {
+ CFCUtil_die("Specifier and/or parcel prefix too long");
+ }
+ char full_specifier[MAX_SPECIFIER_LEN + 1];
+ sprintf(full_specifier, "%s%s", prefix, specifier);
+ FREEMEM(self->specifier);
+ self->specifier = CFCUtil_strdup(full_specifier);
+ }
+
+ // Cache C representation.
+ char c_string[MAX_SPECIFIER_LEN + 10];
+ if (CFCType_const(self)) {
+ sprintf(c_string, "const %s*", self->specifier);
+ }
+ else {
+ sprintf(c_string, "%s*", self->specifier);
+ }
+ FREEMEM(self->c_string);
+ self->c_string = CFCUtil_strdup(c_string);
+
+ // Cache name of VTable variable.
+ self->vtable_var = CFCUtil_strdup(self->specifier);
+ for (int i = 0; self->vtable_var[i] != 0; i++) {
+ self->vtable_var[i] = toupper(self->vtable_var[i]);
+ }
+}
+
+void
CFCType_destroy(CFCType *self) {
if (self->child) {
CFCBase_decref((CFCBase*)self->child);
http://git-wip-us.apache.org/repos/asf/lucy/blob/fa4918d2/clownfish/compiler/src/CFCType.h
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCType.h b/clownfish/compiler/src/CFCType.h
index 5c1354b..937ae94 100644
--- a/clownfish/compiler/src/CFCType.h
+++ b/clownfish/compiler/src/CFCType.h
@@ -25,6 +25,7 @@ extern "C" {
#endif
typedef struct CFCType CFCType;
+struct CFCClass;
struct CFCParcel;
#define CFCTYPE_CONST 0x00000001
@@ -173,6 +174,11 @@ CFCType_new_va_list(void);
CFCType*
CFCType_new_arbitrary(struct CFCParcel *parcel, const char *specifier);
+/** Find the actual class of an object variable without prefix.
+ */
+void
+CFCType_resolve(CFCType *self, struct CFCClass **classes);
+
void
CFCType_destroy(CFCType *self);
http://git-wip-us.apache.org/repos/asf/lucy/blob/fa4918d2/clownfish/compiler/src/CFCVariable.c
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCVariable.c b/clownfish/compiler/src/CFCVariable.c
index adf743b..54c2a17 100644
--- a/clownfish/compiler/src/CFCVariable.c
+++ b/clownfish/compiler/src/CFCVariable.c
@@ -74,18 +74,30 @@ CFCVariable_init(CFCVariable *self, struct CFCParcel *parcel,
self->type = (CFCType*)CFCBase_incref((CFCBase*)type);
self->inert = !!inert;
- // Cache various C string representations.
+ self->local_c = NULL;
+ self->local_dec = NULL;
+ self->global_c = NULL;
+
+ return self;
+}
+
+// Cache various C string representations. Will be called after type has
+// been resolved.
+void
+CFCVariable_resolve_type(CFCVariable *self, struct CFCClass **classes) {
+ CFCType *type = self->type;
+ CFCType_resolve(type, classes);
+
const char *type_str = CFCType_to_c(type);
const char *postfix = "";
if (CFCType_is_composite(type) && CFCType_get_array(type) != NULL) {
postfix = CFCType_get_array(type);
}
+ const char *micro_sym = CFCVariable_micro_sym(self);
self->local_c = CFCUtil_sprintf("%s %s%s", type_str, micro_sym, postfix);
self->local_dec = CFCUtil_sprintf("%s;", self->local_c);
const char *full_sym = CFCVariable_full_sym(self);
self->global_c = CFCUtil_sprintf("%s %s%s", type_str, full_sym, postfix);
-
- return self;
}
void
http://git-wip-us.apache.org/repos/asf/lucy/blob/fa4918d2/clownfish/compiler/src/CFCVariable.h
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCVariable.h b/clownfish/compiler/src/CFCVariable.h
index 2d3fcfc..7263de7 100644
--- a/clownfish/compiler/src/CFCVariable.h
+++ b/clownfish/compiler/src/CFCVariable.h
@@ -34,6 +34,7 @@ extern "C" {
#endif
typedef struct CFCVariable CFCVariable;
+struct CFCClass;
struct CFCParcel;
struct CFCType;
@@ -56,6 +57,9 @@ CFCVariable_init(CFCVariable *self, struct CFCParcel *parcel,
struct CFCType *type, int inert);
void
+CFCVariable_resolve_type(CFCVariable *self, struct CFCClass **classes);
+
+void
CFCVariable_destroy(CFCVariable *self);
int