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