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 | } |
---|