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 }