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.script; 19 20 import std.ascii; 21 import std..string; 22 import std.c.stdlib; 23 import std.c.stdarg; 24 25 /* =================== Configuration ======================= */ 26 27 const uint MAJOR_VERSION = 5; // ScriptEngineMajorVersion 28 const uint MINOR_VERSION = 5; // ScriptEngineMinorVersion 29 30 const uint BUILD_VERSION = 1; // ScriptEngineBuildVersion 31 32 const uint JSCRIPT_CATCH_BUG = 1; // emulate Jscript's bug in scoping of 33 // catch objects in violation of ECMA 34 const uint JSCRIPT_ESCAPEV_BUG = 0; // emulate Jscript's bug where \v is 35 // not recognized as vertical tab 36 37 //=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 38 39 alias char tchar; 40 41 alias ulong number_t; 42 alias double real_t; 43 44 alias uint Loc; // file location (line number) 45 46 struct ErrInfo 47 { 48 d_string message; // error message (null if no error) 49 d_string srcline; // string of source line (null if not known) 50 uint linnum; // source line number (1 based, 0 if not available) 51 int charpos; // character position (1 based, 0 if not available) 52 int code; // error code (0 if not known) 53 } 54 55 class ScriptException : Exception 56 { 57 ErrInfo ei; 58 59 this(d_string msg) 60 { ei.message = msg; 61 super(msg); } 62 63 this(ErrInfo * pei) 64 { 65 ei = *pei; 66 super(ei.message); 67 } 68 } 69 70 int logflag; // used for debugging 71 72 73 // Aliases for script primitive types 74 alias uint d_boolean; 75 alias double d_number; 76 alias int d_int32; 77 alias uint d_uint32; 78 alias ushort d_uint16; 79 alias immutable(char)[] d_string; 80 81 import dmdscript.value; 82 import dmdscript.dobject; 83 import dmdscript.program; 84 import dmdscript.text; 85 import dmdscript.functiondefinition; 86 87 struct CallContext 88 { 89 Dobject[] scopex; // current scope chain 90 Dobject variable; // object for variable instantiation 91 Dobject global; // global object 92 uint scoperoot; // number of entries in scope[] starting from 0 93 // to copy onto new scopes 94 uint globalroot; // number of entries in scope[] starting from 0 95 // that are in the "global" context. Always <= scoperoot 96 void* lastnamedfunc; // points to the last named function added as an event 97 Program prog; 98 Dobject callerothis; // caller's othis 99 Dobject caller; // caller function object 100 FunctionDefinition callerf; 101 102 Value value; // place to store exception; must be same size as Value 103 uint linnum; // source line number of exception (1 based, 0 if not available) 104 105 int Interrupt; // !=0 if cancelled due to interrupt 106 } 107 108 struct Global 109 { 110 string copyright = "Copyright (c) 1999-2010 by Digital Mars"; 111 string written = "by Walter Bright"; 112 } 113 114 Global global; 115 116 string banner() 117 { 118 return std..string.format( 119 "DMDSsript-2 v0.1rc1\n", 120 "Compiled by Digital Mars DMD D compiler\n" 121 "http://www.digitalmars.com\n", 122 "Fork of the original DMDScript 1.16\n", 123 global.written,"\n", 124 global.copyright 125 ); 126 } 127 128 int isStrWhiteSpaceChar(dchar c) 129 { 130 switch(c) 131 { 132 case ' ': 133 case '\t': 134 case 0xA0: // <NBSP> 135 case '\f': 136 case '\v': 137 case '\r': 138 case '\n': 139 case 0x2028: // <LS> 140 case 0x2029: // <PS> 141 case 0x2001: // <USP> 142 case 0x2000: // should we do this one? 143 return 1; 144 145 default: 146 break; 147 } 148 return 0; 149 } 150 151 152 /************************ 153 * Convert d_string to an index, if it is one. 154 * Returns: 155 * true it's an index, and *index is set 156 * false it's not an index 157 */ 158 159 int StringToIndex(d_string name, out d_uint32 index) 160 { 161 if(name.length) 162 { 163 d_uint32 i = 0; 164 165 for(uint j = 0; j < name.length; j++) 166 { 167 tchar c = name[j]; 168 169 switch(c) 170 { 171 case '0': 172 case '1': 173 case '2': 174 case '3': 175 case '4': 176 case '5': 177 case '6': 178 case '7': 179 case '8': 180 case '9': 181 if((i == 0 && j) || // if leading zeros 182 i >= 0xFFFFFFFF / 10) // or overflow 183 goto Lnotindex; 184 i = i * 10 + c - '0'; 185 break; 186 187 default: 188 goto Lnotindex; 189 } 190 } 191 index = i; 192 return true; 193 } 194 195 Lnotindex: 196 return false; 197 } 198 199 200 /******************************** 201 * Parse string numeric literal into a number. 202 * Input: 203 * parsefloat 0: convert per ECMA 9.3.1 204 * 1: convert per ECMA 15.1.2.3 (global.parseFloat()) 205 */ 206 207 d_number StringNumericLiteral(d_string string, out size_t endidx, int parsefloat) 208 { 209 // Convert StringNumericLiteral using ECMA 9.3.1 210 d_number number; 211 int sign = 0; 212 size_t i; 213 size_t len; 214 size_t eoff; 215 if(!string.length) 216 return 0; 217 // Skip leading whitespace 218 eoff = string.length; 219 foreach(size_t j, dchar c; string) 220 { 221 if(!isStrWhiteSpaceChar(c)) 222 { 223 eoff = j; 224 break; 225 } 226 } 227 string = string[eoff .. $]; 228 len = string.length; 229 230 // Check for [+|-] 231 i = 0; 232 if(len) 233 { 234 switch(string[0]) 235 { 236 case '+': 237 sign = 0; 238 i++; 239 break; 240 241 case '-': 242 sign = 1; 243 i++; 244 break; 245 246 default: 247 sign = 0; 248 break; 249 } 250 } 251 252 size_t inflen = TEXT_Infinity.length; 253 if(len - i >= inflen && 254 string[i .. i + inflen] == TEXT_Infinity) 255 { 256 number = sign ? -d_number.infinity : d_number.infinity; 257 endidx = eoff + i + inflen; 258 } 259 else if(len - i >= 2 && 260 string[i] == '0' && (string[i + 1] == 'x' || string[i + 1] == 'X')) 261 { 262 // Check for 0[x|X]HexDigit... 263 number = 0; 264 if(parsefloat) 265 { // Do not recognize the 0x, treat it as if it's just a '0' 266 i += 1; 267 } 268 else 269 { 270 i += 2; 271 for(; i < len; i++) 272 { 273 tchar c; 274 275 c = string[i]; // don't need to decode UTF here 276 if('0' <= c && c <= '9') 277 number = number * 16 + (c - '0'); 278 else if('a' <= c && c <= 'f') 279 number = number * 16 + (c - 'a' + 10); 280 else if('A' <= c && c <= 'F') 281 number = number * 16 + (c - 'A' + 10); 282 else 283 break; 284 } 285 } 286 if(sign) 287 number = -number; 288 endidx = eoff + i; 289 } 290 else 291 { 292 char* endptr; 293 const (char) * s = std..string.toStringz(string[i .. len]); 294 295 //endptr = s;//Fixed: No need to fill endptr prior to stdtod 296 number = std.c.stdlib.strtod(s, &endptr); 297 endidx = (endptr - s) + i; 298 299 //printf("s = '%s', endidx = %d, eoff = %d, number = %g\n", s, endidx, eoff, number); 300 301 // Correctly produce a -0 for the 302 // string "-1e-2000" 303 if(sign) 304 number = -number; 305 if(endidx == i && (parsefloat || i != 0)) 306 number = d_number.nan; 307 endidx += eoff; 308 } 309 310 return number; 311 } 312 313 314 315 316 int localeCompare(CallContext *cc, d_string s1, d_string s2) 317 { // no locale support here 318 return std..string.cmp(s1, s2); 319 } 320