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