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 core.stdc.stdlib; 23 import core.stdc.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.threadcontext; 86 import dmdscript.functiondefinition; 87 88 struct CallContext 89 { 90 Dobject[] scopex; // current scope chain 91 Dobject variable; // object for variable instantiation 92 Dobject global; // global object 93 uint scoperoot; // number of entries in scope[] starting from 0 94 // to copy onto new scopes 95 uint globalroot; // number of entries in scope[] starting from 0 96 // that are in the "global" context. Always <= scoperoot 97 void* lastnamedfunc; // points to the last named function added as an event 98 Program prog; 99 Dobject callerothis; // caller's othis 100 Dobject caller; // caller function object 101 FunctionDefinition callerf; 102 103 Value value; // place to store exception; must be same size as Value 104 uint linnum; // source line number of exception (1 based, 0 if not available) 105 106 int Interrupt; // !=0 if cancelled due to interrupt 107 108 // these used to be TLS variables and are now tied to the context 109 ThreadContext tc; 110 } 111 112 struct Global 113 { 114 string copyright = "Copyright (c) 1999-2010 by Digital Mars"; 115 string written = "by Walter Bright"; 116 } 117 118 immutable Global global; 119 120 string banner() 121 { 122 return "DMDSsript-2 v0.1rc1\n" ~ 123 "Compiled by Digital Mars DMD D compiler\n" ~ 124 "http://www.digitalmars.com\n" ~ 125 "Fork of the original DMDScript 1.16\n" ~ 126 global.written ~ "\n" ~ 127 global.copyright; 128 } 129 130 int isStrWhiteSpaceChar(dchar c) 131 { 132 switch(c) 133 { 134 case ' ': 135 case '\t': 136 case 0xA0: // <NBSP> 137 case '\f': 138 case '\v': 139 case '\r': 140 case '\n': 141 case 0x2028: // <LS> 142 case 0x2029: // <PS> 143 case 0x2001: // <USP> 144 case 0x2000: // should we do this one? 145 return 1; 146 147 default: 148 break; 149 } 150 return 0; 151 } 152 153 154 /************************ 155 * Convert d_string to an index, if it is one. 156 * Returns: 157 * true it's an index, and *index is set 158 * false it's not an index 159 */ 160 161 int StringToIndex(d_string name, out d_uint32 index) 162 { 163 if(name.length) 164 { 165 d_uint32 i = 0; 166 167 for(uint j = 0; j < name.length; j++) 168 { 169 tchar c = name[j]; 170 171 switch(c) 172 { 173 case '0': 174 case '1': 175 case '2': 176 case '3': 177 case '4': 178 case '5': 179 case '6': 180 case '7': 181 case '8': 182 case '9': 183 if((i == 0 && j) || // if leading zeros 184 i >= 0xFFFFFFFF / 10) // or overflow 185 goto Lnotindex; 186 i = i * 10 + c - '0'; 187 break; 188 189 default: 190 goto Lnotindex; 191 } 192 } 193 index = i; 194 return true; 195 } 196 197 Lnotindex: 198 return false; 199 } 200 201 202 /******************************** 203 * Parse string numeric literal into a number. 204 * Input: 205 * parsefloat 0: convert per ECMA 9.3.1 206 * 1: convert per ECMA 15.1.2.3 (global.parseFloat()) 207 */ 208 209 d_number StringNumericLiteral(d_string string, out size_t endidx, int parsefloat) 210 { 211 import core.stdc.stdlib : strtod; 212 213 // Convert StringNumericLiteral using ECMA 9.3.1 214 d_number number; 215 int sign = 0; 216 size_t i; 217 size_t len; 218 size_t eoff; 219 if(!string.length) 220 return 0; 221 // Skip leading whitespace 222 eoff = string.length; 223 foreach(size_t j, dchar c; string) 224 { 225 if(!isStrWhiteSpaceChar(c)) 226 { 227 eoff = j; 228 break; 229 } 230 } 231 string = string[eoff .. $]; 232 len = string.length; 233 234 // Check for [+|-] 235 i = 0; 236 if(len) 237 { 238 switch(string[0]) 239 { 240 case '+': 241 sign = 0; 242 i++; 243 break; 244 245 case '-': 246 sign = 1; 247 i++; 248 break; 249 250 default: 251 sign = 0; 252 break; 253 } 254 } 255 256 size_t inflen = TEXT_Infinity.length; 257 if(len - i >= inflen && 258 string[i .. i + inflen] == TEXT_Infinity) 259 { 260 number = sign ? -d_number.infinity : d_number.infinity; 261 endidx = eoff + i + inflen; 262 } 263 else if(len - i >= 2 && 264 string[i] == '0' && (string[i + 1] == 'x' || string[i + 1] == 'X')) 265 { 266 // Check for 0[x|X]HexDigit... 267 number = 0; 268 if(parsefloat) 269 { // Do not recognize the 0x, treat it as if it's just a '0' 270 i += 1; 271 } 272 else 273 { 274 i += 2; 275 for(; i < len; i++) 276 { 277 tchar c; 278 279 c = string[i]; // don't need to decode UTF here 280 if('0' <= c && c <= '9') 281 number = number * 16 + (c - '0'); 282 else if('a' <= c && c <= 'f') 283 number = number * 16 + (c - 'a' + 10); 284 else if('A' <= c && c <= 'F') 285 number = number * 16 + (c - 'A' + 10); 286 else 287 break; 288 } 289 } 290 if(sign) 291 number = -number; 292 endidx = eoff + i; 293 } 294 else 295 { 296 const(char)* endptr; 297 const (char) * s = std..string.toStringz(string[i .. len]); 298 299 //endptr = s;//Fixed: No need to fill endptr prior to stdtod 300 number = strtod(s, &endptr); 301 endidx = (endptr - s) + i; 302 303 //printf("s = '%s', endidx = %d, eoff = %d, number = %g\n", s, endidx, eoff, number); 304 305 // Correctly produce a -0 for the 306 // string "-1e-2000" 307 if(sign) 308 number = -number; 309 if(endidx == i && (parsefloat || i != 0)) 310 number = d_number.nan; 311 endidx += eoff; 312 } 313 314 return number; 315 } 316 317 318 319 320 int localeCompare(CallContext *cc, d_string s1, d_string s2) 321 { // no locale support here 322 return std..string.cmp(s1, s2); 323 } 324