src/core/scripting.c (view raw)
1/* Copyright (c) 2013-2017 Jeffrey Pfau
2 *
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6#include <mgba/core/scripting.h>
7
8#include <mgba-util/table.h>
9#include <mgba-util/vfs.h>
10
11struct mScriptBridge {
12 struct Table engines;
13 struct mDebugger* debugger;
14};
15
16struct mScriptInfo {
17 const char* name;
18 struct VFile* vf;
19 bool success;
20};
21
22struct mScriptSymbol {
23 const char* name;
24 int32_t* out;
25 bool success;
26};
27
28static void _seDeinit(void* value) {
29 struct mScriptEngine* se = value;
30 se->deinit(se);
31}
32
33static void _seTryLoad(const char* key, void* value, void* user) {
34 UNUSED(key);
35 struct mScriptEngine* se = value;
36 struct mScriptInfo* si = user;
37 if (!si->success && se->isScript(se, si->name, si->vf)) {
38 si->success = se->loadScript(se, si->name, si->vf);
39 }
40}
41
42static void _seLookupSymbol(const char* key, void* value, void* user) {
43 UNUSED(key);
44 struct mScriptEngine* se = value;
45 struct mScriptSymbol* si = user;
46 if (!si->success) {
47 si->success = se->lookupSymbol(se, si->name, si->out);
48 }
49}
50
51static void _seRun(const char* key, void* value, void* user) {
52 UNUSED(key);
53 UNUSED(user);
54 struct mScriptEngine* se = value;
55 se->run(se);
56}
57
58#ifdef USE_DEBUGGERS
59struct mScriptDebuggerEntry {
60 enum mDebuggerEntryReason reason;
61 struct mDebuggerEntryInfo* info;
62};
63
64static void _seDebuggerEnter(const char* key, void* value, void* user) {
65 UNUSED(key);
66 struct mScriptEngine* se = value;
67 struct mScriptDebuggerEntry* entry = user;
68 se->debuggerEntered(se, entry->reason, entry->info);
69}
70#endif
71
72struct mScriptBridge* mScriptBridgeCreate(void) {
73 struct mScriptBridge* sb = malloc(sizeof(*sb));
74 HashTableInit(&sb->engines, 0, _seDeinit);
75 sb->debugger = NULL;
76 return sb;
77}
78
79void mScriptBridgeDestroy(struct mScriptBridge* sb) {
80 HashTableDeinit(&sb->engines);
81 free(sb);
82}
83
84void mScriptBridgeInstallEngine(struct mScriptBridge* sb, struct mScriptEngine* se) {
85 if (!se->init(se, sb)) {
86 return;
87 }
88 const char* name = se->name(se);
89 HashTableInsert(&sb->engines, name, se);
90}
91
92#ifdef USE_DEBUGGERS
93void mScriptBridgeSetDebugger(struct mScriptBridge* sb, struct mDebugger* debugger) {
94 sb->debugger = debugger;
95 debugger->bridge = sb;
96}
97
98struct mDebugger* mScriptBridgeGetDebugger(struct mScriptBridge* sb) {
99 return sb->debugger;
100}
101
102void mScriptBridgeDebuggerEntered(struct mScriptBridge* sb, enum mDebuggerEntryReason reason, struct mDebuggerEntryInfo* info) {
103 struct mScriptDebuggerEntry entry = {
104 .reason = reason,
105 .info = info
106 };
107 HashTableEnumerate(&sb->engines, _seDebuggerEnter, &entry);
108}
109#endif
110
111void mScriptBridgeRun(struct mScriptBridge* sb) {
112 HashTableEnumerate(&sb->engines, _seRun, NULL);
113}
114
115bool mScriptBridgeLoadScript(struct mScriptBridge* sb, const char* name) {
116 struct VFile* vf = VFileOpen(name, O_RDONLY);
117 if (!vf) {
118 return false;
119 }
120 struct mScriptInfo info = {
121 .name = name,
122 .vf = vf,
123 .success = false
124 };
125 HashTableEnumerate(&sb->engines, _seTryLoad, &info);
126 vf->close(vf);
127 return info.success;
128}
129
130bool mScriptBridgeLookupSymbol(struct mScriptBridge* sb, const char* name, int32_t* out) {
131 struct mScriptSymbol info = {
132 .name = name,
133 .out = out,
134 .success = false
135 };
136 HashTableEnumerate(&sb->engines, _seLookupSymbol, &info);
137 return info.success;
138}