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 }