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