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.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 immutable Global global; 115 116 string banner() 117 { 118 return "DMDSsript-2 v0.1rc1\n" ~ 119 "Compiled by Digital Mars DMD D compiler\n" ~ 120 "http://www.digitalmars.com\n" ~ 121 "Fork of the original DMDScript 1.16\n" ~ 122 global.written ~ "\n" ~ 123 global.copyright; 124 } 125 126 int isStrWhiteSpaceChar(dchar c) 127 { 128 switch(c) 129 { 130 case ' ': 131 case '\t': 132 case 0xA0: // <NBSP> 133 case '\f': 134 case '\v': 135 case '\r': 136 case '\n': 137 case 0x2028: // <LS> 138 case 0x2029: // <PS> 139 case 0x2001: // <USP> 140 case 0x2000: // should we do this one? 141 return 1; 142 143 default: 144 break; 145 } 146 return 0; 147 } 148 149 150 /************************ 151 * Convert d_string to an index, if it is one. 152 * Returns: 153 * true it's an index, and *index is set 154 * false it's not an index 155 */ 156 157 int StringToIndex(d_string name, out d_uint32 index) 158 { 159 if(name.length) 160 { 161 d_uint32 i = 0; 162 163 for(uint j = 0; j < name.length; j++) 164 { 165 tchar c = name[j]; 166 167 switch(c) 168 { 169 case '0': 170 case '1': 171 case '2': 172 case '3': 173 case '4': 174 case '5': 175 case '6': 176 case '7': 177 case '8': 178 case '9': 179 if((i == 0 && j) || // if leading zeros 180 i >= 0xFFFFFFFF / 10) // or overflow 181 goto Lnotindex; 182 i = i * 10 + c - '0'; 183 break; 184 185 default: 186 goto Lnotindex; 187 } 188 } 189 index = i; 190 return true; 191 } 192 193 Lnotindex: 194 return false; 195 } 196 197 198 /******************************** 199 * Parse string numeric literal into a number. 200 * Input: 201 * parsefloat 0: convert per ECMA 9.3.1 202 * 1: convert per ECMA 15.1.2.3 (global.parseFloat()) 203 */ 204 205 d_number StringNumericLiteral(d_string string, out size_t endidx, int parsefloat) 206 { 207 import core.stdc.stdlib : strtod; 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 const(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 = 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