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 module dmdscript.ddeclaredfunction;
19 
20 import std.stdio;
21 import core.stdc.stdlib;
22 import std.exception;
23 import dmdscript.script;
24 import dmdscript.dobject;
25 import dmdscript.dfunction;
26 import dmdscript.darguments;
27 import dmdscript.opcodes;
28 import dmdscript.ir;
29 import dmdscript.identifier;
30 import dmdscript.value;
31 import dmdscript.functiondefinition;
32 import dmdscript.text;
33 import dmdscript.property;
34 
35 /* ========================== DdeclaredFunction ================== */
36 
37 class DdeclaredFunction : Dfunction
38 {
39     FunctionDefinition fd;
40 
41     this(CallContext* cc, FunctionDefinition fd)
42     {
43         super(cc, cast(uint)fd.parameters.length, Dfunction.getPrototype(cc));
44         assert(Dfunction.getPrototype(cc));
45         assert(internal_prototype);
46         this.fd = fd;
47 
48         Dobject o;
49 
50         // ECMA 3 13.2
51         o = new Dobject(cc, Dobject.getPrototype(cc));        // step 9
52         Put(cc, TEXT_prototype, o, DontEnum);               // step 11
53         o.Put(cc, TEXT_constructor, this, DontEnum);        // step 10
54     }
55 
56     override void *Call(CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
57     {
58         // 1. Create activation object per ECMA 10.1.6
59         // 2. Instantiate function variables as properties of
60         //    activation object
61         // 3. The 'this' value is the activation object
62 
63         Dobject actobj;         // activation object
64         Darguments args;
65         Value[] locals;
66         uint i;
67         void *result;
68 
69         //writefln("DdeclaredFunction.Call() '%s'", toString());
70         //writefln("this.scopex.length = %d", this.scopex.length);
71         //writefln("\tinstantiate(this = %x, fd = %x)", cast(uint)cast(void*)this, cast(uint)cast(void*)fd);
72 
73         // if it's an empty function, just return
74         if(fd.code[0].opcode == IRret)
75         {
76             return null;
77         }
78 
79         // Generate the activation object
80         // ECMA v3 10.1.6
81         actobj = new Dobject(cc, null);
82         
83         Value vtmp;//should not be referenced by the end of func
84         if(fd.name){ 
85            vtmp.putVobject(this);
86            actobj.Put(cc, fd.name,&vtmp,DontDelete);
87         }
88         // Instantiate the parameters
89         {
90             uint a = 0;
91             foreach(Identifier* p; fd.parameters)
92             {
93                 Value* v = (a < arglist.length) ? &arglist[a++] : &vundefined;
94                 actobj.Put(cc, p.toString(), v, DontDelete);
95             }
96         }
97 
98         // Generate the Arguments Object
99         // ECMA v3 10.1.8
100         args = new Darguments(cc, cc.caller, this, actobj, fd.parameters, arglist);
101 
102         actobj.Put(cc, TEXT_arguments, args, DontDelete);
103 
104         // The following is not specified by ECMA, but seems to be supported
105         // by jscript. The url www.grannymail.com has the following code
106         // which looks broken to me but works in jscript:
107         //
108         //	    function MakeArray() {
109         //	      this.length = MakeArray.arguments.length
110         //	      for (var i = 0; i < this.length; i++)
111         //		  this[i+1] = arguments[i]
112         //	    }
113         //	    var cardpic = new MakeArray("LL","AP","BA","MB","FH","AW","CW","CV","DZ");
114         Put(cc, TEXT_arguments, args, DontDelete);          // make grannymail bug work
115 
116         
117         
118 
119         Dobject[] newScopex;
120         newScopex = this.scopex.dup;//copy this function object scope chain
121         assert(newScopex.length != 0);
122         newScopex ~= actobj;//and put activation object on top of it
123         
124         fd.instantiate(cc, newScopex, actobj, DontDelete);
125 
126         Dobject[] scopesave = cc.scopex;
127         cc.scopex = newScopex; 
128         auto scoperootsave = cc.scoperoot;
129         cc.scoperoot++;//to accaunt extra activation object on scopex chain
130         Dobject variablesave = cc.variable;
131         cc.variable = actobj;
132         auto callersave = cc.caller;
133         cc.caller = this;
134         auto callerfsave = cc.callerf;
135         cc.callerf = fd;
136 
137         Value[] p1;
138         Value* v;
139         if(fd.nlocals < 128)
140             v = cast(Value*)alloca(fd.nlocals * Value.sizeof);
141         if(v)
142             locals = v[0 .. fd.nlocals];
143         else
144         {
145             p1 = new Value[fd.nlocals];
146             locals = p1;
147         }
148 
149         result = IR.call(cc, othis, fd.code, ret, locals.ptr);
150 
151         destroy(p1);
152 
153         cc.callerf = callerfsave;
154         cc.caller = callersave;
155         cc.variable = variablesave;
156         cc.scopex = scopesave;
157         cc.scoperoot = scoperootsave;
158 
159         // Remove the arguments object
160         //Value* v;
161         //v=Get(TEXT_arguments);
162         //writef("1v = %x, %s, v.object = %x\n", v, v.getType(), v.object);
163         Put(cc, TEXT_arguments, &vundefined, 0);
164         //actobj.Put(TEXT_arguments, &vundefined, 0);
165 
166         version(none)
167         {
168             writef("args = %x, actobj = %x\n", args, actobj);
169             v = Get(TEXT_arguments);
170             writef("2v = %x, %s, v.object = %x\n", v, v.getType(), v.object);
171             v.object = null;
172 
173             {
174                 uint *p = cast(uint *)0x40a49a80;
175                 uint i;
176                 for(i = 0; i < 16; i++)
177                 {
178                     writef("p[%x] = %x\n", &p[i], p[i]);
179                 }
180             }
181         }
182 
183         return result;
184     }
185 
186     override void *Construct(CallContext *cc, Value *ret, Value[] arglist)
187     {
188         // ECMA 3 13.2.2
189         Dobject othis;
190         Dobject proto;
191         Value* v;
192         void *result;
193 
194         v = Get(TEXT_prototype);
195         if(v.isPrimitive())
196             proto = Dobject.getPrototype(cc);
197         else
198             proto = v.toObject(cc);
199         othis = new Dobject(cc, proto);
200         result = Call(cc, othis, ret, arglist);
201         if(!result)
202         {
203             if(ret.isPrimitive())
204                 ret.putVobject(othis);
205         }
206         return result;
207     }
208 
209     override string toString()
210     {
211         char[] s;
212 
213         //writef("DdeclaredFunction.toString()\n");
214         fd.toBuffer(s);
215         return assumeUnique(s);
216     }
217 }
218 
219