| 1 | /* Copyright Vladiir Prus 2003. Distributed under the Boost */ |
|---|
| 2 | /* Software License, Version 1.0. (See accompanying */ |
|---|
| 3 | /* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) */ |
|---|
| 4 | |
|---|
| 5 | #include "class.h" |
|---|
| 6 | #include "strings.h" |
|---|
| 7 | #include "variable.h" |
|---|
| 8 | #include "frames.h" |
|---|
| 9 | #include "rules.h" |
|---|
| 10 | #include "newstr.h" |
|---|
| 11 | |
|---|
| 12 | #include "hash.h" |
|---|
| 13 | |
|---|
| 14 | static struct hash* classes = 0; |
|---|
| 15 | |
|---|
| 16 | static void check_defined(LIST* class_names) |
|---|
| 17 | { |
|---|
| 18 | for (; class_names; class_names = class_names->next) { |
|---|
| 19 | char** p = &class_names->string; |
|---|
| 20 | if (!hashcheck(classes, (HASHDATA**)&p)) { |
|---|
| 21 | printf("Class %s is not defined\n", class_names->string); |
|---|
| 22 | abort(); |
|---|
| 23 | } |
|---|
| 24 | } |
|---|
| 25 | } |
|---|
| 26 | |
|---|
| 27 | static char* class_module_name(char* declared_name) |
|---|
| 28 | { |
|---|
| 29 | string name[1]; |
|---|
| 30 | char* result; |
|---|
| 31 | |
|---|
| 32 | string_new(name); |
|---|
| 33 | string_append(name, "class@"); |
|---|
| 34 | string_append(name, declared_name); |
|---|
| 35 | |
|---|
| 36 | result = newstr(name->value); |
|---|
| 37 | string_free(name); |
|---|
| 38 | |
|---|
| 39 | return result; |
|---|
| 40 | } |
|---|
| 41 | |
|---|
| 42 | struct import_base_data { |
|---|
| 43 | char* base_name; |
|---|
| 44 | module_t* base_module; |
|---|
| 45 | module_t* class_module; |
|---|
| 46 | }; |
|---|
| 47 | |
|---|
| 48 | static void import_base_rule(void* r_, void* d_) |
|---|
| 49 | { |
|---|
| 50 | RULE* r = (RULE*)r_; |
|---|
| 51 | RULE* ir1; |
|---|
| 52 | RULE* ir2; |
|---|
| 53 | struct import_base_data* d = (struct import_base_data*)d_; |
|---|
| 54 | string qualified_name[1]; |
|---|
| 55 | int basename_lenght = strlen(d->base_name)+1; |
|---|
| 56 | |
|---|
| 57 | string_new(qualified_name); |
|---|
| 58 | string_append(qualified_name, d->base_name); |
|---|
| 59 | string_push_back(qualified_name, '.'); |
|---|
| 60 | string_append(qualified_name, r->name); |
|---|
| 61 | |
|---|
| 62 | ir1 = import_rule(r, d->class_module, r->name); |
|---|
| 63 | ir2 = import_rule(r, d->class_module, qualified_name->value); |
|---|
| 64 | |
|---|
| 65 | /* Copy 'exported' flag. */ |
|---|
| 66 | ir1->exported = ir2->exported = r->exported; |
|---|
| 67 | |
|---|
| 68 | /* If we're importing class method, localize it. */ |
|---|
| 69 | if (r->module == d->base_module |
|---|
| 70 | || r->module->class_module && r->module->class_module == d->base_module) { |
|---|
| 71 | ir1->module = ir2->module = d->class_module; |
|---|
| 72 | } |
|---|
| 73 | |
|---|
| 74 | string_free(qualified_name); |
|---|
| 75 | } |
|---|
| 76 | |
|---|
| 77 | /** For each exported rule 'n', declared in class module for base, |
|---|
| 78 | imports that rule in 'class' as 'n' and as 'base.n'. Imported |
|---|
| 79 | rules are localized and marked as exported. |
|---|
| 80 | */ |
|---|
| 81 | static void import_base_rules(module_t* class, char* base) |
|---|
| 82 | { |
|---|
| 83 | module_t* base_module = bindmodule(class_module_name(base)); |
|---|
| 84 | struct import_base_data d; |
|---|
| 85 | d.base_name = base; |
|---|
| 86 | d.base_module = base_module; |
|---|
| 87 | d.class_module = class; |
|---|
| 88 | |
|---|
| 89 | if (base_module->rules) |
|---|
| 90 | hashenumerate(base_module->rules, import_base_rule, &d); |
|---|
| 91 | |
|---|
| 92 | import_module( imported_modules(base_module), class ); |
|---|
| 93 | } |
|---|
| 94 | |
|---|
| 95 | char* make_class_module(LIST* xname, LIST* bases, FRAME* frame) |
|---|
| 96 | { |
|---|
| 97 | char* name = class_module_name(xname->string); |
|---|
| 98 | char** pp = &xname->string; |
|---|
| 99 | module_t* class_module = 0; |
|---|
| 100 | module_t* outer_module = frame->module; |
|---|
| 101 | |
|---|
| 102 | if (!classes) |
|---|
| 103 | classes = hashinit(sizeof(char*), "classes"); |
|---|
| 104 | |
|---|
| 105 | |
|---|
| 106 | if (hashcheck(classes, (HASHDATA**)&pp)) { |
|---|
| 107 | printf("Class %s already defined\n", xname->string); |
|---|
| 108 | abort(); |
|---|
| 109 | } else { |
|---|
| 110 | hashenter(classes, (HASHDATA**)&pp); |
|---|
| 111 | } |
|---|
| 112 | check_defined(bases); |
|---|
| 113 | |
|---|
| 114 | class_module = bindmodule(name); |
|---|
| 115 | |
|---|
| 116 | exit_module( outer_module ); |
|---|
| 117 | enter_module( class_module ); |
|---|
| 118 | |
|---|
| 119 | var_set("__name__", xname, VAR_SET); |
|---|
| 120 | var_set("__bases__", bases, VAR_SET); |
|---|
| 121 | |
|---|
| 122 | exit_module( class_module ); |
|---|
| 123 | enter_module( outer_module ); |
|---|
| 124 | |
|---|
| 125 | for(; bases; bases = bases->next) |
|---|
| 126 | import_base_rules(class_module, bases->string); |
|---|
| 127 | |
|---|
| 128 | |
|---|
| 129 | |
|---|
| 130 | return name; |
|---|
| 131 | } |
|---|