1 module wren.optional.meta;
2 import wren.value;
3 import wren.vm;
4 
5 private static const(char)[] metaModuleSource = import("optional/wren_opt_meta.wren");
6 
7 void metaCompile(WrenVM* vm) @nogc
8 {
9     const(char)* source = wrenGetSlotString(vm, 1);
10     bool isExpression = wrenGetSlotBool(vm, 2);
11     bool printErrors = wrenGetSlotBool(vm, 3);
12 
13     // TODO: Allow passing in module?
14     // Look up the module surrounding the callsite. This is brittle. The -2 walks
15     // up the callstack assuming that the meta module has one level of
16     // indirection before hitting the user's code. Any change to meta may require
17     // this constant to be tweaked.
18     ObjFiber* currentFiber = vm.fiber;
19     ObjFn* fn = currentFiber.frames[currentFiber.numFrames - 2].closure.fn;
20     ObjString* module_ = fn.module_.name;
21 
22     ObjClosure* closure = wrenCompileSource(vm, module_.value.ptr, source,
23                                             isExpression, printErrors);
24     
25     // Return the result. We can't use the public API for this since we have a
26     // bare ObjClosure*.
27     if (closure == null)
28     {
29         vm.apiStack[0] = NULL_VAL;
30     }
31     else
32     {
33         vm.apiStack[0] = OBJ_VAL(closure);
34     }
35 }
36 
37 void metaGetModuleVariables(WrenVM* vm) @nogc
38 {
39     wrenEnsureSlots(vm, 3);
40     
41     Value moduleValue = wrenMapGet(vm.modules, vm.apiStack[1]);
42     if (IS_UNDEFINED(moduleValue))
43     {
44         vm.apiStack[0] = NULL_VAL;
45         return;
46     }
47         
48     ObjModule* module_ = AS_MODULE(moduleValue);
49     ObjList* names = wrenNewList(vm, module_.variableNames.count);
50     vm.apiStack[0] = OBJ_VAL(names);
51 
52     // Initialize the elements to null in case a collection happens when we
53     // allocate the strings below.
54     for (int i = 0; i < names.elements.count; i++)
55     {
56         names.elements.data[i] = NULL_VAL;
57     }
58     
59     for (int i = 0; i < names.elements.count; i++)
60     {
61         names.elements.data[i] = OBJ_VAL(module_.variableNames.data[i]);
62     }
63 }
64 
65 const(char)[] wrenMetaSource() @nogc {
66     return metaModuleSource;
67 }
68 
69 WrenForeignMethodFn wrenMetaBindForeignMethod(WrenVM* vm,
70                                               const(char)* className,
71                                               bool isStatic,
72                                               const(char)* signature) @nogc
73 {
74     import core.stdc.string : strcmp;
75     // There is only one foreign method in the meta module.
76     assert(strcmp(className, "Meta") == 0, "Should be in Meta class.");
77     assert(isStatic, "Should be static.");
78     
79     if (strcmp(signature, "compile_(_,_,_)") == 0)
80     {
81         return &metaCompile;
82     }
83     
84     if (strcmp(signature, "getModuleVariables_(_)") == 0)
85     {
86         return &metaGetModuleVariables;
87     }
88     
89     assert(false, "Unknown method.");
90 }