0
|
1
|
|
2 /* Digital Mars DMDScript source code.
|
|
3 * Copyright (c) 2000-2002 by Chromium Communications
|
|
4 * D version Copyright (c) 2004-2005 by Digital Mars
|
|
5 * All Rights Reserved
|
|
6 * written by Walter Bright
|
|
7 * www.digitalmars.com
|
|
8 * Use at your own risk. There is no warranty, express or implied.
|
|
9 * License for redistribution is by the GNU General Public License in gpl.txt.
|
|
10 *
|
|
11 * A binary, non-exclusive license for commercial use can be
|
|
12 * purchased from www.digitalmars.com/dscript/buy.html.
|
|
13 *
|
|
14 * DMDScript is implemented in the D Programming Language,
|
|
15 * www.digitalmars.com/d/
|
|
16 *
|
|
17 * For a C++ implementation of DMDScript, including COM support,
|
|
18 * see www.digitalmars.com/dscript/cppscript.html.
|
|
19 */
|
|
20
|
|
21
|
|
22 module dmdscript.program;
|
|
23
|
|
24 import std.stdio;
|
|
25 import std.c.stdlib;
|
|
26
|
|
27 import dmdscript.script;
|
|
28 import dmdscript.dobject;
|
|
29 import dmdscript.dglobal;
|
|
30 import dmdscript.functiondefinition;
|
|
31 import dmdscript.statement;
|
|
32 import dmdscript.threadcontext;
|
|
33 import dmdscript.value;
|
|
34 import dmdscript.opcodes;
|
|
35 import dmdscript.darray;
|
|
36 import dmdscript.parse;
|
|
37 import dmdscript.scopex;
|
|
38 import dmdscript.text;
|
|
39 import dmdscript.property;
|
|
40
|
|
41 class Program
|
|
42 {
|
|
43 uint errors; // if any errors in file
|
|
44 CallContext *callcontext;
|
|
45 FunctionDefinition globalfunction;
|
|
46
|
|
47 // Locale info
|
|
48 uint lcid; // current locale
|
|
49 tchar[] slist; // list separator
|
|
50
|
|
51 this()
|
|
52 {
|
|
53 initContext();
|
|
54 }
|
|
55
|
|
56 void initContext()
|
|
57 {
|
|
58 //writefln("Program.initContext()");
|
|
59 if (callcontext) // if already done
|
|
60 return;
|
|
61
|
|
62 callcontext = new CallContext();
|
|
63
|
|
64 CallContext *cc = callcontext;
|
|
65
|
|
66 // Do object inits
|
|
67 ThreadContext *tc = ThreadContext.getThreadContext();
|
|
68 assert(tc);
|
|
69
|
|
70 dobject_init(tc);
|
|
71
|
|
72 cc.prog = this;
|
|
73
|
|
74 // Create global object
|
|
75 cc.global = new Dglobal(null);
|
|
76
|
|
77 Dobject[] scopex;
|
|
78 scopex ~= cc.global;
|
|
79
|
|
80 cc.variable = cc.global;
|
|
81 cc.scopex = scopex;
|
|
82 cc.scoperoot++;
|
|
83 cc.globalroot++;
|
|
84
|
|
85 assert(tc.Ddate_prototype.proptable.table.length != 0);
|
|
86 }
|
|
87
|
|
88 /**************************************************
|
|
89 * Two ways of calling this:
|
|
90 * 1. with text representing group of topstatements (pfd == null)
|
|
91 * 2. with text representing a function name & body (pfd != null)
|
|
92 */
|
|
93
|
|
94 void compile(char[] progIdentifier, tchar[] srctext, FunctionDefinition *pfd)
|
|
95 {
|
|
96 TopStatement[] topstatements;
|
|
97 tchar[] msg;
|
|
98
|
|
99 //writef("parse_common()\n");
|
|
100 Parser p = new Parser(progIdentifier, srctext, 1);
|
|
101
|
|
102 ErrInfo errinfo;
|
|
103 if (p.parseProgram(topstatements, &errinfo))
|
|
104 {
|
|
105 topstatements[] = null;
|
|
106 throw new ScriptException(&errinfo);
|
|
107 }
|
|
108
|
|
109 if (pfd)
|
|
110 { // If we are expecting a function, we should have parsed one
|
|
111 assert(p.lastnamedfunc);
|
|
112 *pfd = p.lastnamedfunc;
|
|
113 }
|
|
114
|
|
115 // Build empty function definition array
|
|
116 // Make globalfunction an anonymous one (by passing in null for name) so
|
|
117 // it won't get instantiated as a property
|
|
118 globalfunction = new FunctionDefinition(0, 1, null, null, null);
|
|
119
|
|
120 // Any functions parsed in topstatements wind up in the global
|
|
121 // object (cc.global), where they are found by normal property lookups.
|
|
122 // Any global new top statements only get executed once, and so although
|
|
123 // the previous group of topstatements gets lost, it does not matter.
|
|
124
|
|
125 // In essence, globalfunction encapsulates the *last* group of topstatements
|
|
126 // passed to script, and any previous version of globalfunction, along with
|
|
127 // previous topstatements, gets discarded.
|
|
128
|
|
129 globalfunction.topstatements = topstatements;
|
|
130
|
|
131 // If pfd, it is not really necessary to create a global function just
|
|
132 // so we can do the semantic analysis, we could use p.lastnamedfunc
|
|
133 // instead if we're careful to insure that p.lastnamedfunc winds up
|
|
134 // as a property of the global object.
|
|
135
|
|
136 Scope sc;
|
|
137 sc.ctor(this, globalfunction); // create global scope
|
|
138 sc.src = srctext;
|
|
139 globalfunction.semantic(&sc);
|
|
140
|
|
141 msg = sc.errinfo.message;
|
|
142 if (msg) // if semantic() failed
|
|
143 {
|
|
144 globalfunction.topstatements[] = null;
|
|
145 globalfunction.topstatements = null;
|
|
146 globalfunction = null;
|
|
147 throw new ScriptException(&sc.errinfo);
|
|
148 }
|
|
149
|
|
150 if (pfd)
|
|
151 // If expecting a function, that is the only topstatement we should
|
|
152 // have had
|
|
153 (*pfd).toIR(null);
|
|
154 else
|
|
155 {
|
|
156 globalfunction.toIR(null);
|
|
157 }
|
|
158
|
|
159 // Don't need parse trees anymore, so null'ing the pointer allows
|
|
160 // the garbage collector to find & free them.
|
|
161 globalfunction.topstatements[] = null;
|
|
162 globalfunction.topstatements = null;
|
|
163 }
|
|
164
|
|
165 /*******************************
|
|
166 * Execute program.
|
|
167 * Throw ScriptException on error.
|
|
168 */
|
|
169
|
|
170 void execute(char[][] args)
|
|
171 {
|
|
172 // ECMA 10.2.1
|
|
173 //writef("Program.execute(argc = %d, argv = %p)\n", argc, argv);
|
|
174 //writef("Program.execute()\n");
|
|
175
|
|
176 initContext();
|
|
177
|
|
178 Value[] locals;
|
|
179 Value ret;
|
|
180 Value* result;
|
|
181 CallContext *cc = callcontext;
|
|
182 Darray arguments;
|
|
183 Dobject dglobal = cc.global;
|
|
184 Program program_save;
|
|
185
|
|
186 // Set argv and argc for execute
|
|
187 arguments = new Darray();
|
|
188 dglobal.Put(TEXT_arguments, arguments, DontDelete | DontEnum);
|
|
189 arguments.length.putVnumber(args.length);
|
|
190 for (int i = 0; i < args.length; i++)
|
|
191 {
|
|
192 arguments.Put(i, args[i], DontEnum);
|
|
193 }
|
|
194
|
|
195 Value[] p1;
|
|
196 Value* v;
|
|
197 version (Win32) // eh and alloca() not working under linux
|
|
198 {
|
|
199 if (globalfunction.nlocals < 128)
|
|
200 v = cast(Value*)alloca(globalfunction.nlocals * Value.sizeof);
|
|
201 }
|
|
202 if (v)
|
|
203 locals = v[0 .. globalfunction.nlocals];
|
|
204 else
|
|
205 {
|
|
206 p1 = new Value[globalfunction.nlocals];
|
|
207 locals = p1;
|
|
208 }
|
|
209
|
|
210 // Instantiate global variables as properties of global
|
|
211 // object with 0 attributes
|
|
212 globalfunction.instantiate(cc.scopex, cc.variable, 0);
|
|
213
|
|
214 // cc.scopex.reserve(globalfunction.withdepth + 1);
|
|
215
|
|
216 // The 'this' value is the global object
|
|
217 //printf("cc.scopex.ptr = %x, cc.scopex.length = %d\n", cc.scopex.ptr, cc.scopex.length);
|
|
218 program_save = getProgram();
|
|
219 try
|
|
220 {
|
|
221 setProgram(this);
|
|
222 ret.putVundefined();
|
|
223 result = cast(Value*)IR.call(cc, cc.global, globalfunction.code, &ret, locals.ptr);
|
|
224 }
|
|
225 finally
|
|
226 {
|
|
227 setProgram(program_save);
|
|
228 }
|
|
229 //writef("-Program.execute()\n");
|
|
230 if (result)
|
|
231 {
|
|
232 ErrInfo errinfo;
|
|
233
|
|
234 result.getErrInfo(&errinfo, cc.linnum);
|
|
235 cc.linnum = 0;
|
|
236 delete p1;
|
|
237 throw new ScriptException(&errinfo);
|
|
238 }
|
|
239
|
|
240 delete p1;
|
|
241 }
|
|
242
|
|
243 void toBuffer(inout tchar[] buf)
|
|
244 {
|
|
245 if (globalfunction)
|
|
246 globalfunction.toBuffer(buf);
|
|
247 }
|
|
248
|
|
249 /***********************************************
|
|
250 * Get/Set Program associated with this thread.
|
|
251 * This enables multiple scripts (Programs) running simultaneously
|
|
252 * in different threads.
|
|
253 * It is needed because which Program is being run is essentially
|
|
254 * global data - and this makes it thread local data.
|
|
255 */
|
|
256
|
|
257 static Program getProgram()
|
|
258 {
|
|
259 ThreadContext *tc;
|
|
260
|
|
261 tc = ThreadContext.getThreadContext();
|
|
262 assert(tc != null);
|
|
263 return tc.program;
|
|
264 }
|
|
265
|
|
266 static void setProgram(Program p)
|
|
267 {
|
|
268 ThreadContext *tc;
|
|
269
|
|
270 tc = ThreadContext.getThreadContext();
|
|
271
|
|
272 assert(tc != null);
|
|
273 tc.program = p;
|
|
274 }
|
|
275
|
|
276 }
|