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.functiondefinition;
20 
21 import std.stdio;
22 
23 import dmdscript.script;
24 import dmdscript.identifier;
25 import dmdscript.statement;
26 import dmdscript.dfunction;
27 import dmdscript.scopex;
28 import dmdscript.irstate;
29 import dmdscript.opcodes;
30 import dmdscript.ddeclaredfunction;
31 import dmdscript.symbol;
32 import dmdscript.dobject;
33 import dmdscript.ir;
34 import dmdscript.errmsgs;
35 import dmdscript.value;
36 import dmdscript.property;
37 
38 /* ========================== FunctionDefinition ================== */
39 
40 class FunctionDefinition : TopStatement
41 {
42     // Maybe the following two should be done with derived classes instead
43     int isglobal;                 // !=0 if the global anonymous function
44     int isliteral;                // !=0 if function literal
45     int iseval;                   // !=0 if eval function
46 
47     Identifier* name;             // null for anonymous function
48     Identifier*[] parameters;     // array of Identifier's
49     TopStatement[] topstatements; // array of TopStatement's
50 
51     Identifier*[] varnames;       // array of Identifier's
52     FunctionDefinition[] functiondefinitions;
53     FunctionDefinition enclosingFunction;
54     int nestDepth;
55     int withdepth;              // max nesting of ScopeStatement's
56 
57     SymbolTable *labtab;        // symbol table for LabelSymbol's
58 
59     IR *code;
60     uint nlocals;
61 
62 
63     this(TopStatement[] topstatements)
64     {
65         super(0);
66         st = FUNCTIONDEFINITION;
67         this.isglobal = 1;
68         this.topstatements = topstatements;
69     }
70 
71     this(Loc loc, int isglobal,
72          Identifier * name, Identifier *[] parameters,
73          TopStatement[] topstatements)
74     {
75         super(loc);
76 
77         //writef("FunctionDefinition('%ls')\n", name ? name.string : L"");
78         st = FUNCTIONDEFINITION;
79         this.isglobal = isglobal;
80         this.name = name;
81         this.parameters = parameters;
82         this.topstatements = topstatements;
83     }
84     
85     int isAnonymous() { return name is null; }
86         
87     override Statement semantic(Scope *sc)
88     {
89         uint i;
90         TopStatement ts;
91         FunctionDefinition fd;
92 
93         //writef("FunctionDefinition::semantic(%s)\n", this);
94 
95         // Log all the FunctionDefinition's so we can rapidly
96         // instantiate them at runtime
97         fd = enclosingFunction = sc.funcdef;
98 
99         // But only push it if it is not already in the array
100         for(i = 0;; i++)
101         {
102             if(i == fd.functiondefinitions.length)      // not in the array
103             {
104                 fd.functiondefinitions ~= this;
105                 break;
106             }
107             if(fd.functiondefinitions[i] is this)       // already in the array
108                 break;
109         }
110 
111         //writefln("isglobal = %d, isanonymous = %d\n", isglobal, isanonymous);
112         if(!isglobal)
113         {
114             sc = sc.push(this);
115             sc.nestDepth++;
116         }
117         nestDepth = sc.nestDepth;
118         //writefln("nestDepth = %d", nestDepth);
119 
120         if(topstatements.length)
121         {
122             for(i = 0; i < topstatements.length; i++)
123             {
124                 ts = topstatements[i];
125                 //writefln("calling semantic routine %d which is %x\n",i, cast(uint)cast(void*)ts);
126                 if(!ts.done)
127                 {
128                     ts = ts.semantic(sc);
129                     if(sc.errinfo.message)
130                         break;
131 
132                     if(iseval)
133                     {
134                         // There's an implied "return" on the last statement
135                         if((i + 1) == topstatements.length)
136                         {
137                             ts = ts.ImpliedReturn();
138                         }
139                     }
140                     topstatements[i] = ts;
141                     ts.done = 1;
142                 }
143             }
144 
145             // Make sure all the LabelSymbol's are defined
146             if(labtab)
147             {
148                 foreach(Symbol s; labtab.members)
149                 {
150                     LabelSymbol ls = cast(LabelSymbol)s;
151                     if(!ls.statement)
152                         error(sc, errmsgtbl[ERR_UNDEFINED_LABEL],
153                               ls.toString(), toString());
154                 }
155             }
156         }
157 
158         if(!isglobal)
159             sc.pop();
160 
161         FunctionDefinition fdx = this;
162         return cast(Statement)cast(void*)fdx;
163     }
164 
165     override void toBuffer(ref tchar[] buf)
166     {
167         uint i;
168 
169         //writef("FunctionDefinition::toBuffer()\n");
170         if(!isglobal)
171         {
172             buf ~= "function ";
173             if(isAnonymous)
174                 buf ~= "anonymous";
175             else if(name)
176                 buf ~= name.toString();
177             buf ~= '(';
178             for(i = 0; i < parameters.length; i++)
179             {
180                 if(i)
181                     buf ~= ',';
182                 buf ~= parameters[i].toString();
183             }
184             buf ~= ")\n{ \n";
185         }
186         if(topstatements)
187         {
188             for(i = 0; i < topstatements.length; i++)
189             {
190                 topstatements[i].toBuffer(buf);
191             }
192         }
193         if(!isglobal)
194         {
195             buf ~= "}\n";
196         }
197     }
198 
199     override void toIR(IRstate *ignore)
200     {
201         IRstate irs;
202         uint i;
203 
204         //writefln("FunctionDefinition.toIR() done = %d", done);
205         irs.ctor();
206         if(topstatements.length)
207         {
208             for(i = 0; i < topstatements.length; i++)
209             {
210                 TopStatement ts;
211                 FunctionDefinition fd;
212 
213                 ts = topstatements[i];
214                 if(ts.st == FUNCTIONDEFINITION)
215                 {
216                     fd = cast(FunctionDefinition)ts;
217                     if(fd.code)
218                         continue;
219                 }
220                 ts.toIR(&irs);
221             }
222 
223             // Don't need parse trees anymore, release to garbage collector
224             topstatements[] = null;
225             topstatements = null;
226             labtab = null;                      // maybe delete it?
227         }
228         irs.gen0(0, IRret);
229         irs.gen0(0, IRend);
230 
231         //irs.validate();
232 
233         irs.doFixups();
234         irs.optimize();
235 
236         code = cast(IR *)irs.codebuf.data;
237         irs.codebuf.data = null;
238         nlocals = irs.nlocals;
239     }
240 
241     void instantiate(CallContext* cc, Dobject[] scopex, Dobject actobj, uint attributes)
242     {
243         //writefln("FunctionDefinition.instantiate() %s nestDepth = %d", name ? name.toString() : "", nestDepth);
244 
245         // Instantiate all the Var's per 10.1.3
246         foreach(Identifier* name; varnames)
247         {
248             // If name is already declared, don't override it
249             //writefln("\tVar Put(%s)", name.toString());
250             actobj.Put(cc, name.toString(), &vundefined, Instantiate | DontOverride | attributes);
251         }
252 
253         // Instantiate the Function's per 10.1.3
254         foreach(FunctionDefinition fd; functiondefinitions)
255         {
256             // Set [[Scope]] property per 13.2 step 7
257             Dfunction fobject = new DdeclaredFunction(cc, fd);
258             fobject.scopex = scopex;
259 
260             if(fd.name !is null && !fd.isliteral)        // skip anonymous functions
261             {
262                 //writefln("\tFunction Put(%s)", fd.name.toString());
263                 actobj.Put(cc, fd.name.toString(), fobject, Instantiate | attributes);
264             }
265         }
266         //writefln("-FunctionDefinition.instantiate()");
267     }
268 }