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 import dmdscript.protoerror; 38 39 class Program 40 { 41 uint errors; // if any errors in file 42 CallContext *callcontext; 43 FunctionDefinition globalfunction; 44 bool threadInitTableRan = false; 45 46 // Locale info 47 uint lcid; // current locale 48 d_string slist; // list separator 49 50 this() 51 { 52 initContext(); 53 } 54 55 void initContext() 56 { 57 //writefln("Program.initContext()"); 58 if(callcontext) // if already done 59 return; 60 61 callcontext = new CallContext(); 62 63 CallContext *cc = callcontext; 64 65 initErrors(cc); 66 67 // Do object inits 68 dobject_init(cc); 69 70 cc.prog = this; 71 72 // Create global object 73 cc.global = new Dglobal(cc, null); 74 75 Dobject[] scopex; 76 scopex ~= cc.global; 77 78 cc.variable = cc.global; 79 cc.scopex = scopex; 80 cc.scoperoot++; 81 cc.globalroot++; 82 83 assert(cc.tc.Ddate_prototype.proptable.table.length != 0); 84 } 85 86 /************************************************** 87 * Two ways of calling this: 88 * 1. with text representing group of topstatements (pfd == null) 89 * 2. with text representing a function name & body (pfd != null) 90 */ 91 92 void compile(d_string progIdentifier, d_string srctext, FunctionDefinition *pfd) 93 { 94 // initialize methods registered by dscript.extending 95 if (!threadInitTableRan) 96 { 97 threadInitTableRan = true; 98 foreach(fpinit; threadInitTable) 99 fpinit(callcontext); 100 } 101 102 TopStatement[] topstatements; 103 d_string msg; 104 105 //writef("parse_common()\n"); 106 Parser p = new Parser(progIdentifier, srctext, 1); 107 108 ErrInfo errinfo; 109 if(p.parseProgram(topstatements, &errinfo)) 110 { 111 topstatements[] = null; 112 throw new ScriptException(&errinfo); 113 } 114 115 if(pfd) 116 { // If we are expecting a function, we should have parsed one 117 assert(p.lastnamedfunc); 118 *pfd = p.lastnamedfunc; 119 } 120 121 // Build empty function definition array 122 // Make globalfunction an anonymous one (by passing in null for name) so 123 // it won't get instantiated as a property 124 globalfunction = new FunctionDefinition(0, 1, null, null, null); 125 126 // Any functions parsed in topstatements wind up in the global 127 // object (cc.global), where they are found by normal property lookups. 128 // Any global new top statements only get executed once, and so although 129 // the previous group of topstatements gets lost, it does not matter. 130 131 // In essence, globalfunction encapsulates the *last* group of topstatements 132 // passed to script, and any previous version of globalfunction, along with 133 // previous topstatements, gets discarded. 134 135 globalfunction.topstatements = topstatements; 136 137 // If pfd, it is not really necessary to create a global function just 138 // so we can do the semantic analysis, we could use p.lastnamedfunc 139 // instead if we're careful to insure that p.lastnamedfunc winds up 140 // as a property of the global object. 141 142 Scope sc; 143 sc.ctor(this, globalfunction); // create global scope 144 sc.src = srctext; 145 globalfunction.semantic(&sc); 146 147 msg = sc.errinfo.message; 148 if(msg) // if semantic() failed 149 { 150 globalfunction.topstatements[] = null; 151 globalfunction.topstatements = null; 152 globalfunction = null; 153 throw new ScriptException(&sc.errinfo); 154 } 155 156 if(pfd) 157 // If expecting a function, that is the only topstatement we should 158 // have had 159 (*pfd).toIR(null); 160 else 161 { 162 globalfunction.toIR(null); 163 } 164 165 // Don't need parse trees anymore, so null'ing the pointer allows 166 // the garbage collector to find & free them. 167 globalfunction.topstatements[] = null; 168 globalfunction.topstatements = null; 169 } 170 171 /******************************* 172 * Execute program. 173 * Throw ScriptException on error. 174 */ 175 176 void execute(d_string[] args) 177 { 178 // ECMA 10.2.1 179 //writef("Program.execute(argc = %d, argv = %p)\n", argc, argv); 180 //writef("Program.execute()\n"); 181 182 initContext(); 183 184 Value[] locals; 185 Value ret; 186 Value* result; 187 CallContext *cc = callcontext; 188 Darray arguments; 189 Dobject dglobal = cc.global; 190 //Program program_save; 191 192 // Set argv and argc for execute 193 arguments = new Darray(cc); 194 dglobal.Put(cc, TEXT_arguments, arguments, DontDelete | DontEnum); 195 arguments.length.putVnumber(args.length); 196 for(int i = 0; i < args.length; i++) 197 { 198 arguments.Put(cc, i, args[i], DontEnum); 199 } 200 201 Value[] p1; 202 Value* v; 203 version(Win32) // eh and alloca() not working under linux 204 { 205 if(globalfunction.nlocals < 128) 206 v = cast(Value*)alloca(globalfunction.nlocals * Value.sizeof); 207 } 208 if(v) 209 locals = v[0 .. globalfunction.nlocals]; 210 else 211 { 212 p1 = new Value[globalfunction.nlocals]; 213 locals = p1; 214 } 215 216 // Instantiate global variables as properties of global 217 // object with 0 attributes 218 globalfunction.instantiate(cc, cc.scopex, cc.variable, DontDelete); 219 220 // cc.scopex.reserve(globalfunction.withdepth + 1); 221 222 ret.putVundefined(); 223 result = cast(Value*)IR.call(cc, cc.global, globalfunction.code, &ret, locals.ptr); 224 if(result) 225 { 226 ErrInfo errinfo; 227 228 result.getErrInfo(cc, &errinfo, cc.linnum); 229 cc.linnum = 0; 230 destroy(p1); 231 throw new ScriptException(&errinfo); 232 } 233 //writef("-Program.execute()\n"); 234 235 236 destroy(p1); 237 } 238 239 void toBuffer(ref tchar[] buf) 240 { 241 if(globalfunction) 242 globalfunction.toBuffer(buf); 243 } 244 }