-
Notifications
You must be signed in to change notification settings - Fork 11
/
repl.c
151 lines (132 loc) · 5.19 KB
/
repl.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include "gracelib.h"
Object repl_module = NULL;
Object visitor = NULL;
Object module_ast_init();
Object module_ast;
Object module_interactive_init();
Object module_interactive;
Object Object_asString(Object, int, int*, Object*, int);
// This function will receive the name and target object of a method,
// create the appropriate interactive objects for the interpreter and then
// call back to the interpreter with them. This way the actual method gets
// executed in the interpreter and we don't have to create functions at
// runtime.
Object trampoline(Object self, Object realself, int nparts, int *argcv,
Object *args, int flags) {
int pos = (flags >> 16) & 255;
Object callinfo = getdatum(self, pos, 0);
int largcv[] = {1};
Object idx1 = alloc_Integer32(1);
Object idx2 = alloc_Integer32(2);
Object objname = callmethod(callinfo, "at", 1, largcv, &idx1);
Object methname = callmethod(callinfo, "at", 1, largcv, &idx2);
Object replobjclass = callmethod(module_interactive, "replObj", 0, NULL, NULL);
Object kind = alloc_String("value");
Object roargs[] = {kind, self};
int roargcv[] = {2};
Object selfreplobj = callmethod(replobjclass, "new", 1, roargcv, roargs);
gc_root(selfreplobj);
Object idclass = callmethod(module_ast, "identifierNode", 0, NULL, NULL);
Object idargs[] = {objname, alloc_Boolean(0)};
int idargcv[] = {2};
Object selfid = callmethod(idclass, "new", 1, idargcv, idargs);
gc_root(selfid);
Object memberclass = callmethod(module_ast, "memberNode", 0, NULL, NULL);
Object memberargs[] = {methname, selfid};
int memberargcv[] = {2};
Object methmember = callmethod(memberclass, "new",
1, memberargcv, memberargs);
gc_root(methmember);
Object withclass = callmethod(module_ast, "callWithPart", 0, NULL, NULL);
Object with = alloc_List();
int i, j;
int k = 0;
int pushargcv[] = {1};
int withargcv[] = {2};
for (i = 0; i < nparts; i++) {
Object curpart = alloc_List();
for (j = 0; j < argcv[i]; j++) {
Object curarg = args[k];
callmethod(curpart, "push", 1, pushargcv, &curarg);
k++;
}
Object withargs[] = {alloc_String(""), curpart};
Object withpart = callmethod(withclass, "new", 1, withargcv, withargs);
gc_root(withpart);
callmethod(with, "push", 1, pushargcv, &withpart);
}
gc_root(with);
Object callclass = callmethod(module_ast, "callNode", 0, NULL, NULL);
Object nodeargs[] = {methmember, with};
int nodeargcv[] = {2};
Object callnode = callmethod(callclass, "new", 1, nodeargcv, nodeargs);
gc_root(callnode);
int acceptargcv[] = {1};
callmethod(callnode, "accept", 1, acceptargcv, &visitor);
Object replvar = callmethod(visitor, "_result", 0, NULL, NULL);
return callmethod(replvar, "val", 0, NULL, NULL);
}
// This has to be called before the first method call so the trampoline
// methods knows where to call back to.
Object repl_registerVisitor(Object self, int nparts, int *argcv, Object *args,
int flags) {
if (nparts != 1 && argcv[0] != 1)
gracedie("registerVisitor requires exactly one argument");
gc_pause(); // temporary
visitor = args[0];
return alloc_done();
}
Object repl_createobject(Object self, int nparts, int *argcv, Object *args,
int flags) {
int nummethods = integerfromAny(args[0]);
int numfields = integerfromAny(args[1]);
return alloc_userobj(nummethods, numfields);
}
// Add a wrapper for the named method that actually points to the trampoline
// function so that the function will call back to the interpreter to actually
// execute the method.
Object repl_addmethod(Object self, int nparts, int *argcv, Object *args,
int flags) {
Object o = args[0];
Object objname = args[1];
gc_root(objname);
Object methname = args[2];
gc_root(methname);
int pos = integerfromAny(args[3]);
Object(*func)(Object, int, int*, Object*, int);
func = (Object(*)(Object, int, int*, Object*, int))trampoline;
Method *m = add_Method(o->class, cstringfromString(methname), func);
m->flags &= ~MFLAG_REALSELFONLY;
m->flags |= MFLAG_REALSELFALSO;
m->pos = pos;
Object callinfo = alloc_List();
gc_root(callinfo); // ugly workaround
gc_pause();
int largcv[] = {1};
callmethod(callinfo, "push", 1, largcv, &objname);
callmethod(callinfo, "push", 1, largcv, &methname);
gc_unpause();
adddatum2(o, callinfo, pos);
return alloc_done();
}
Object module_repl_init() {
if (repl_module != NULL)
return repl_module;
ClassData c = alloc_class("Module<repl>", 12);
add_Method(c, "asString", &Object_asString);
add_Method(c, "registerVisitor", &repl_registerVisitor);
add_Method(c, "createobject", &repl_createobject);
add_Method(c, "addmethod", &repl_addmethod);
Object o = alloc_newobj(0, c);
repl_module = o;
gc_root(repl_module);
if (module_ast == NULL)
module_ast = module_ast_init();
if (module_interactive == NULL)
module_interactive = module_interactive_init();
return o;
}