1 #include "jsapi.h"
2 
3 #include "ADM_assert.h"
4 #include "SpiderMonkeyEngine.h"
5 #include "SpiderMonkeyScriptWriter.h"
6 
7 #include "src_dialogFactory/ADM_JSDFMenu.h"
8 #include "src_dialogFactory/ADM_JSDFToggle.h"
9 #include "src_dialogFactory/ADM_JSDFInteger.h"
10 #include "src_dialogFactory/ADM_JSDialogFactory.h"
11 
12 #include "ADM_scriptDFMenu.h"
13 #include "ADM_scriptDFToggle.h"
14 #include "ADM_scriptDFInteger.h"
15 #include "ADM_scriptDialogFactory.h"
16 
17 using namespace std;
18 
19 extern "C"
20 {
21     JSFunctionSpec *jsGetIfFunctions(void);
22     JSFunctionSpec *jsGetTestFunctions(void);
23     JSFunctionSpec *jsGetAdmFunctions(void);
24     JSFunctionSpec *jsGetEditFunctions(void);
25     JSFunctionSpec *jsGetDialogFactoryFunctions(void);
26     JSObject *jsEditorInit(JSContext *cx, JSObject *obj);
27     JSObject *jsAvidemuxInit(JSContext *cx, JSObject *obj);
28 
createEngine()29     IScriptEngine* createEngine()
30     {
31         return new SpiderMonkeyEngine();
32     }
33 }
34 
35 JSClass SpiderMonkeyEngine::_globalClass =
36 {
37     "global", JSCLASS_GLOBAL_FLAGS,
38     JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
39     JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
40     JSCLASS_NO_OPTIONAL_MEMBERS
41 };
42 
~SpiderMonkeyEngine()43 SpiderMonkeyEngine::~SpiderMonkeyEngine()
44 {
45     this->callEventHandlers(IScriptEngine::Information, NULL, -1, "Closing Spidermonkey");
46 
47     JS_DestroyContext(_jsContext);
48     JS_DestroyRuntime(_jsRuntime);
49 }
50 
name()51 string SpiderMonkeyEngine::name()
52 {
53     return "SpiderMonkey";
54 }
55 
initialise(IEditor * editor)56 void SpiderMonkeyEngine::initialise(IEditor *editor)
57 {
58     ADM_assert(editor);
59 
60     _editor = editor;
61 
62     _jsRuntime = JS_NewRuntime(1000000L);
63     ADM_assert(_jsRuntime);
64 
65     _jsContext = JS_NewContext(_jsRuntime, 8192);
66     ADM_assert(_jsContext);
67 
68     JS_SetContextPrivate(_jsContext, this);
69 
70     _jsObject = JS_NewObject(_jsContext, &_globalClass, 0, 0);
71     ADM_assert(_jsObject);
72 
73     ADM_assert(JS_InitStandardClasses(_jsContext, _jsObject) == JS_TRUE);
74 
75     JS_SetErrorReporter(_jsContext, SpiderMonkeyEngine::printError);
76 
77     this->registerFunctions(_jsContext, _jsObject);
78     this->registerDialogFunctions(_jsContext, _jsObject);
79     this->callEventHandlers(IScriptEngine::Information, NULL, -1, "Spidermonkey initialised");
80 }
81 
registerFunctions(JSContext * cx,JSObject * obj)82 void SpiderMonkeyEngine::registerFunctions(JSContext *cx, JSObject *obj)
83 {
84     this->registerFunctionGroup("Debug", "", jsGetIfFunctions(), cx, obj);
85     this->registerFunctionGroup("Test", "", jsGetTestFunctions(), cx, obj);
86 
87     // Register also our class (for  help() )
88     JsHook h;
89     h.name = "adm";
90     h.text = "Please prefix this with adm.";
91     h.jsFunctions = jsGetAdmFunctions();
92 
93     jsHooks.push_back(h);
94     jsAvidemuxInit(cx, obj);
95 
96     // Register also edit
97     h.name = "editor";
98     h.text = "Please prefix this with editor.";
99     h.jsFunctions = jsGetEditFunctions();
100     jsEditorInit(cx, obj);
101     jsHooks.push_back(h);
102 }
103 
registerDialogFunctions(JSContext * cx,JSObject * obj)104 void SpiderMonkeyEngine::registerDialogFunctions(JSContext *cx, JSObject *obj)
105 {
106     ADM_assert(ADM_JSDialogFactory::JSInit(cx, obj) != NULL);
107     ADM_assert(ADM_JSDFMenu::JSInit(cx, obj) != NULL);
108     ADM_assert(ADM_JSDFToggle::JSInit(cx, obj) != NULL);
109     ADM_assert(ADM_JSDFInteger::JSInit(cx, obj) != NULL);
110 
111     this->callEventHandlers(IScriptEngine::Information, NULL, -1, "Registered DialogFactory classes");
112 }
113 
registerFunctionGroup(const char * name,const char * text,JSFunctionSpec * s,JSContext * cx,JSObject * obj)114 void SpiderMonkeyEngine::registerFunctionGroup(const char *name, const char *text, JSFunctionSpec *s, JSContext *cx, JSObject *obj)
115 {
116     assert(JS_DefineFunctions(cx, obj, s) == JS_TRUE);
117 
118     this->callEventHandlers(IScriptEngine::Information, NULL, -1,
119                             (string("Registered ") + string(name) + string(" functions")).c_str());
120 
121     JsHook h;
122 
123     h.name = name;
124     h.text = text;
125     h.jsFunctions = s;
126 
127     jsHooks.push_back(h);
128 }
129 
printError(JSContext * cx,const char * message,JSErrorReport * report)130 void SpiderMonkeyEngine::printError(JSContext *cx, const char *message, JSErrorReport *report)
131 {
132     SpiderMonkeyEngine *engine = (SpiderMonkeyEngine*)JS_GetContextPrivate(cx);
133 
134     engine->callEventHandlers(IScriptEngine::Error, report->filename, report->lineno, message);
135 }
136 
registerEventHandler(eventHandlerFunc * func)137 void SpiderMonkeyEngine::registerEventHandler(eventHandlerFunc *func)
138 {
139     _eventHandlerSet.insert(func);
140 }
141 
unregisterEventHandler(eventHandlerFunc * func)142 void SpiderMonkeyEngine::unregisterEventHandler(eventHandlerFunc *func)
143 {
144     _eventHandlerSet.erase(func);
145 }
146 
callEventHandlers(EventType eventType,const char * fileName,int lineNo,const char * message)147 void SpiderMonkeyEngine::callEventHandlers(EventType eventType, const char *fileName, int lineNo, const char *message)
148 {
149     EngineEvent event = { this, eventType, fileName, lineNo, message };
150     set<eventHandlerFunc*>::iterator it;
151 
152     for (it = _eventHandlerSet.begin(); it != _eventHandlerSet.end(); ++it)
153     {
154         (*it)(&event);
155     }
156 }
157 
runScript(string script,RunMode mode)158 bool SpiderMonkeyEngine::runScript(string script, RunMode mode)
159 {
160     jsval rval;
161 
162     return JS_EvaluateScript(_jsContext, _jsObject, script.c_str(), script.length(), "dummy", 1, &rval) == JSVAL_TRUE;
163 }
164 
runScriptFile(string name,RunMode mode)165 bool SpiderMonkeyEngine::runScriptFile(string name, RunMode mode)
166 {
167     jsval rval;
168     uintN lineno = 0;
169     bool success = false;
170 
171     this->callEventHandlers(IScriptEngine::Information, NULL, -1,
172                             (string("Compiling \"" + string(name) + string("\"...")).c_str()));
173     JSScript *pJSScript = JS_CompileFile(_jsContext, _jsObject, name.c_str());
174     this->callEventHandlers(IScriptEngine::Information, NULL, -1, "Done.");
175 
176     if (pJSScript != NULL)
177     {
178         this->callEventHandlers(IScriptEngine::Information, NULL, -1,
179                                 (string("Executing ") + string(name) + string("...")).c_str());
180 
181         JSBool ok = JS_ExecuteScript(_jsContext, _jsObject, pJSScript, &rval);
182         JS_DestroyScript(_jsContext, pJSScript);
183 
184         this->callEventHandlers(IScriptEngine::Information, NULL, -1, "Done");
185     }
186 
187     JS_GC(_jsContext);
188 
189     return success;
190 }
191 
editor()192 IEditor* SpiderMonkeyEngine::editor()
193 {
194     return _editor;
195 }
196 
capabilities()197 IScriptEngine::Capabilities SpiderMonkeyEngine::capabilities()
198 {
199     return IScriptEngine::None;
200 }
201 
createScriptWriter()202 IScriptWriter* SpiderMonkeyEngine::createScriptWriter()
203 {
204     return new SpiderMonkeyScriptWriter();
205 }
206 
openDebuggerShell()207 void SpiderMonkeyEngine::openDebuggerShell() {}
208 
defaultFileExtension()209 string SpiderMonkeyEngine::defaultFileExtension()
210 {
211     return "js";
212 }
213 
maturityRanking()214 int SpiderMonkeyEngine::maturityRanking()
215 {
216     return 0;
217 }
218 
referenceUrl()219 string SpiderMonkeyEngine::referenceUrl()
220 {
221     return "";
222 }
223