[JSFunctionAttribute (JSFunctionAttributeEnum.HasVarArgs)]
public ArrayObject Invoke (params Object [] args)
{
- return (ArrayObject) GetMethod ("CreateInstance", BindingFlags.Static | BindingFlags.Public).Invoke (null, args);
+ return CreateInstance (args);
}
}
}
internal ArrayObject (object o)
{
IConvertible ic = o as IConvertible;
- TypeCode tc = ic.GetTypeCode ();
+ TypeCode tc = Convert.GetTypeCode (o, ic);
try {
- if (tc == TypeCode.Int32 || ic.ToDouble (null) < Int32.MaxValue) {
+ if (Convert.IsNumberTypeCode (tc)) {
int size = ic.ToInt32 (null);
if (size > 0) {
length = o;
protected void SpliceSlowly (uint start, uint deleteCount, object [] args, ArrayObject outArray, uint oldLength, uint newLength)
{
- throw new NotImplementedException ();
+ ArrayPrototype.splice (outArray, null, start, deleteCount, args);
}
internal override object GetDefaultValue (Type hint)
public class ArrayPrototype : ArrayObject {
- [JSFunctionAttribute (JSFunctionAttributeEnum.HasThisObject | JSFunctionAttributeEnum.HasVarArgs | JSFunctionAttributeEnum.HasEngine, JSBuiltin.Array_concat)]
+ [JSFunctionAttribute (JSFunctionAttributeEnum.HasThisObject | JSFunctionAttributeEnum.HasEngine |
+ JSFunctionAttributeEnum.HasVarArgs, JSBuiltin.Array_concat)]
public static ArrayObject concat (object thisObj, VsaEngine engine,
params object [] args)
{
object cur_obj = thisObj;
ArrayObject cur_ary;
- while (arg_idx < arg_count) {
+ while (cur_obj != null) {
if (cur_obj is ArrayObject) {
cur_ary = (ArrayObject) cur_obj;
int n = (int) cur_ary.length;
for (int j = 0; j < n; j++, i++)
- result [i] = cur_ary [j];
-
- cur_obj = args [arg_idx++];
+ result.elems [i] = cur_ary.elems [j];
} else
- result [++i] = cur_obj;
+ result.elems [i++] = cur_obj;
+
+ arg_idx++;
+ cur_obj = arg_idx < arg_count ? args [arg_idx] : null;
}
+
+ result.length = i;
+
return result;
}
else
_separator = Convert.ToString (separator);
- Hashtable elems = array_obj.Elements;
+ Hashtable elems = array_obj.elems;
+ int n = (int) array_obj.length;
StringBuilder str = new StringBuilder ();
bool first = true;
- foreach (DictionaryEntry entry in elems) {
+ for (int i = 0; i < n; i++) {
if (!first)
str.Append (_separator);
first = false;
- str.Append (Convert.ToString (entry.Value));
+ object elem = elems [i];
+ if (elem != null)
+ str.Append (Convert.ToString (elem));
}
return str.ToString ();
}
if (end == null)
_end = array_len;
else {
- _end = (int) (double) end;
+ _end = Convert.ToInt32 (end);
if (_end < 0)
_end += array_len;
double start, double deleteCnt,
params object [] args)
{
- throw new NotImplementedException ();
+ // TODO: Shouldn't this be generic!?
+ SemanticAnalyser.assert_type (thisObj, typeof (ArrayObject));
+ ArrayObject array_obj = (ArrayObject) thisObj;
+ ArrayObject result = new ArrayObject ();
+ Hashtable elems = array_obj.elems;
+ Hashtable del_elems = result.elems;
+
+ int old_length = (int) array_obj.length;
+ start = (int) start;
+ if (start < 0)
+ start = Math.Max (start + old_length, 0);
+ else
+ start = Math.Min (old_length, start);
+
+ deleteCnt = (int) deleteCnt;
+ deleteCnt = Math.Min (Math.Max (deleteCnt, 0), old_length - start);
+
+ int arg_length = args.Length;
+ int add_length = arg_length - (int) deleteCnt;
+ add_length = Math.Max (add_length, -old_length);
+ int del_length = -add_length;
+ int new_length = old_length + add_length;
+
+ int i, j, m;
+ // First let's make some free space for the new items (if needed)
+ if (add_length > 0) {
+ i = old_length - 1;
+ j = i + add_length;
+ for (; i >= start; i--, j--)
+ elems [j] = elems [i];
+ }
+
+ // Then insert the new items in the now free space / replace existing ones
+ j = m = 0;
+ int old_start = (int) start + add_length;
+ for (i = (int) start; j < arg_length; i++, j++) {
+ if (i >= old_start && elems.ContainsKey (i)) {
+ del_elems [m] = elems [i];
+ m++;
+ elems.Remove (i);
+ }
+
+ if (j < arg_length)
+ elems [i] = args [j];
+ }
+
+ // Finally, delete elements which have no replacement elements
+ if (add_length < 0) {
+ int last_elem_idx = i + del_length;
+ for (int k = 0; k < del_length; i++, j++, k++) {
+ if (elems.ContainsKey (i)) {
+ del_elems [m] = elems [i];
+ m++;
+ elems.Remove (i);
+ }
+ }
+
+ // And move up trailing elements
+ int l = last_elem_idx - del_length;
+ for (int k = last_elem_idx; l < old_length; k++, l++) {
+ if (elems.ContainsKey (k))
+ elems [l] = elems [k];
+ else if (elems.ContainsKey (l))
+ elems.Remove (l);
+ }
+ }
+
+ array_obj.length = new_length;
+ result.length = (int) deleteCnt;
+ return result;
}
[JSFunctionAttribute (JSFunctionAttributeEnum.HasThisObject, JSBuiltin.Array_toLocaleString)]
+2005-07-17 Florian Gross <flgr@ccan.de>
+ * DateConstructor.cs: Implemented UTC
+ * ScriptObject.cs: Implemented GetMethod, CallMethod
+ * JSObject.cs: Implemented fallback ToString, more ClassName cases and
+ fallback GetDefaultValue
+ * ArrayPrototype.cs: Fixed concat, join and added splice
+ * RegExpPrototype.cs: Implemented compile, exec, test
+ * expression.cs: Emit JS undef instead of JS null for missing args
+ * StringPrototype.cs: changed lastIndexOf to be compatible with JSC.
+ Implemented match, replace (no replacement closure), search, split.
+ No longer uses assert_type for ensuring right type of thisObj
+ * ArrayObject.cs: Better length argument handling in constructor. Added
+ SpliceSlowly
+ * DatePrototype.cs: Added setDate, setFullYear, setHours, setMinutes,
+ setMilliseconds, setMonth, setSeconds, setTime, setUTCDate,
+ setUTCFullYear, setUTCHours, setUTCMinutes, setUTCMilliseconds,
+ setUTCMonth, setUTCSeconds, setYear
+ * FunctionObject.cs: Moved MethodAttributes to ScriptFunction. Added
+ MethodInfo-taking constructor
+ * Convert.cs: Added IsNumber, IsString, ToRegExp. More cases in
+ ToNumber. Refactored ToString
+ * ScriptEquality.cs: More cases
+ * LateBindings.cs: Big refactoring. Introduced assemble_args. Handles
+ missing arguments. build_args can pass null as engine. More CallValue,
+ GetNonMissingValue cases
+ * Plus.cs: Heavily refactored EvaluatePlus from 90 to 12 lines
+ * GlobalObject.cs: Added CollectGarbage
+ * NumberPrototype.cs: No longer uses assert_type for unsuring right
+ type of thisObj
+ * RegExpObject: Added lastIndex, Initialize, stores compiled Regex
+ * SemanticAnalizer: Added missing prototypes. Made assert_type work
+ with derived types
+ * ScriptFunction.cs: Moved MethodAttributes from FunctionObject. Added
+ MethodInfo. Implemented Invoke for built-in functions.
+
2005-07-07 Florian Gross <flgr@ccan.de>
* MathObject.cs: Implemented max and min (untested)
throw new NotImplementedException ();
}
+ internal static bool IsNumber (object value)
+ {
+ IConvertible ic = value as IConvertible;
+ TypeCode tc = Convert.GetTypeCode (value, ic);
+
+ switch (tc) {
+ case TypeCode.Char:
+ case TypeCode.Byte:
+ case TypeCode.SByte:
+ case TypeCode.UInt16:
+ case TypeCode.UInt32:
+ case TypeCode.Int16:
+ case TypeCode.Int32:
+ case TypeCode.Single:
+ case TypeCode.Double:
+ return true;
+
+ case TypeCode.Object:
+ if (value is NumberObject)
+ return true;
+ break;
+ }
+
+ return false;
+ }
+
+ internal static bool IsString (object value)
+ {
+ IConvertible ic = value as IConvertible;
+ TypeCode tc = Convert.GetTypeCode (value, ic);
+
+ switch (tc) {
+ case TypeCode.String:
+ return true;
+
+ case TypeCode.Object:
+ if (value is StringObject)
+ return true;
+ break;
+ }
+
+ return false;
+ }
+
internal static bool IsNumberTypeCode (TypeCode tc)
{
switch (tc) {
throw new NotImplementedException ();
}
-
public static int ToInt32 (object value)
{
IConvertible ic = value as IConvertible;
case TypeCode.UInt32:
case TypeCode.Int16:
case TypeCode.Int32:
- return (double) value;
+ return ic.ToDouble (null);
case TypeCode.Single:
case TypeCode.Double:
case TypeCode.String:
return GlobalObject.parseFloat (value);
- default:
- Console.WriteLine ("\nToNumber: value.GetType = {0}", value.GetType ());
+ case TypeCode.Object:
+ if (value is NumberObject)
+ return ((NumberObject) value).value;
break;
}
+ Console.WriteLine ("\nToNumber: value.GetType = {0}", value.GetType ());
throw new NotImplementedException ();
}
switch (tc) {
case TypeCode.Empty:
- return "";
+ return "undefined";
case TypeCode.DBNull:
return "null";
case TypeCode.Char:
return ic.ToInt16 (null).ToString ();
- case TypeCode.Byte:
- case TypeCode.SByte:
- case TypeCode.UInt16:
- case TypeCode.UInt32:
- case TypeCode.Int16:
- case TypeCode.Int32:
case TypeCode.String:
- case TypeCode.Double:
- return ic.ToString (CultureInfo.InvariantCulture);
+ return ic.ToString (null);
case TypeCode.Object:
- if (value is ArrayObject)
- return ArrayPrototype.toString (value);
- else if (value is BooleanObject)
- return BooleanPrototype.toString (value);
- else if (value is DateObject)
- return DatePrototype.toString (value);
- else if (value is ErrorObject)
- return ErrorPrototype.toString (value);
- else if (value is FunctionObject)
- return FunctionPrototype.toString (value);
- else if (value is NumberObject)
- return NumberPrototype.toString (value, 10);
- else if (value is ObjectPrototype)
- return ObjectPrototype.toString (value);
- else if (value is RegExpObject)
- return RegExpPrototype.toString (value);
- else if (value is StringObject)
- return StringPrototype.toString (value);
- else if (value is FunctionWrapper)
- return FunctionPrototype.toString (value);
+ if (value is StringObject)
+ return ((StringObject) value).value;
+ else if (value is Closure)
+ return FunctionPrototype.toString (((Closure) value).func);
+ else if (value is ScriptObject)
+ return (string) ((ScriptObject) value).CallMethod ("toString");
+
Console.WriteLine ("value.GetType = {0}", value.GetType ());
throw new NotImplementedException ();
+
default:
+ if (IsNumberTypeCode (tc))
+ return ic.ToString (CultureInfo.InvariantCulture);
+
Console.WriteLine ("tc = {0}", tc);
throw new NotImplementedException ();
}
}
+ internal static RegExpObject ToRegExp (object regExp)
+ {
+ if (regExp is RegExpObject)
+ return (RegExpObject) regExp;
+ else
+ return RegExpConstructor.Ctr.Invoke (regExp);
+ }
+
public static string ToString (bool b)
{
return b ? "true" : "false";
//
// find UTC time from given date... no 1900 correction!
//
- static double msec_from_date (double year, double mon, double mday, double hour, double min, double sec, double msec)
+ internal static double msec_from_date (double year, double mon, double mday, double hour, double min, double sec, double msec)
{
double day, time, result;
day = MakeDay (year, mon, mday);
return result;
}
- static double MakeDay (double year, double month, double date)
+ internal static double MakeDay (double year, double month, double date)
{
year += Math.Floor (month / 12);
month = month % 12;
return year_day + month_day + date - 1;
}
- static double MakeTime (double hour, double min, double sec, double ms)
+ internal static double MakeTime (double hour, double min, double sec, double ms)
{
return ((hour * MINUTES_PER_HOUR + min) * SECONDS_PER_MINUTE + sec) * MS_PER_SECOND + ms;
}
- static double MakeDate (double day, double time)
+ internal static double MakeDate (double day, double time)
{
return day * MS_PER_DAY + time;
}
- static double TimeFromYear (double y)
+ internal static double TimeFromYear (double y)
{
return DayFromYear (y) * MS_PER_DAY;
}
- static double DayFromYear (double y)
+ internal static double DayFromYear (double y)
{
return ((365 * ((y) - 1970) + Math.Floor (((y) - 1969) / 4.0) - Math.Floor(((y) - 1901) / 100.0) + Math.Floor (((y) - 1601) / 400.0)));
}
- static double DayFromMonth (int m , int year)
+ internal static double DayFromMonth (int m, int year)
{
int day = m * 30;
return day;
}
- static bool IsLeapYear (int year)
+ internal static bool IsLeapYear (int year)
{
return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
}
public static double UTC (Object year, Object month, Object date,
Object hours, Object minutes, Object seconds, Object ms)
{
- throw new NotImplementedException ();
+ double _year = 0, _month = 0, _date = 1, _hours = 0, _minutes = 0, _seconds = 0, _ms = 0;
+
+ if (year == null && month == null) {
+ DateTime now = DateTime.Now;
+ _year = now.Year;
+ _month = now.Month - 1;
+ _date = now.Day;
+ _hours = now.Hour;
+ _minutes = now.Minute;
+ _seconds = now.Second;
+ _ms = now.Millisecond;
+ _ms -= TimeZone.CurrentTimeZone.GetUtcOffset (now).TotalMilliseconds;
+ goto done;
+ }
+
+ _year = Convert.ToNumber (year);
+ if (month != null)
+ _month = Convert.ToNumber (month);
+ if (date != null)
+ _date = Convert.ToNumber (date);
+ if (hours != null)
+ _hours = Convert.ToNumber (hours);
+ if (minutes != null)
+ _minutes = Convert.ToNumber (minutes);
+ if (seconds != null)
+ _seconds = Convert.ToNumber (seconds);
+ if (ms != null)
+ _ms = Convert.ToNumber (ms);
+
+ if (!Double.IsNaN (_year) && _year >= 0 && _year <= 99)
+ _year += 1900;
+
+done:
+ return TimeClip (msec_from_date (_year, _month, _date, _hours, _minutes, _seconds, _ms));
+ }
+
+ internal static double TimeClip (double p)
+ {
+ if (Double.IsInfinity (p) || Double.IsNaN (p) || Math.Abs (p) > 8.64e15)
+ return Double.NaN;
+ else
+ return p;
}
/* Ported from Rhino. */
DateTime dt = new DateTime (year, month + 1, date, hours, minutes, seconds);
return t + TimeZone.CurrentTimeZone.GetUtcOffset (dt).TotalMilliseconds;
}
+
+ internal static double ToUTC (double t)
+ {
+ int year = YearFromTime (t);
+ int month = MonthFromTime (t);
+ int date = DateFromTime (t);
+ int hours = HourFromTime (t);
+ int minutes = MinFromTime (t);
+ int seconds = SecFromTime (t);
+ DateTime dt = new DateTime (year, month + 1, date, hours, minutes, seconds);
+ return t - TimeZone.CurrentTimeZone.GetUtcOffset (dt).TotalMilliseconds;
+ }
}
}
[JSFunctionAttribute (JSFunctionAttributeEnum.HasThisObject, JSBuiltin.Date_setDate)]
public static double setDate (object thisObj, double ddate)
{
- throw new NotImplementedException ();
+ SemanticAnalyser.assert_type (thisObj, typeof (DateObject));
+ DateObject date = (DateObject) thisObj;
+ double t = DateConstructor.LocalTime (date.ms);
+ double day = DateConstructor.MakeDay ((double) DateConstructor.YearFromTime (t),
+ (double) DateConstructor.MonthFromTime (t), ddate);
+ double new_val = DateConstructor.ToUTC (DateConstructor.MakeDate (day, t % DateConstructor.MS_PER_DAY));
+ date.ms = DateConstructor.TimeClip (new_val);
+ return date.ms;
}
[JSFunctionAttribute (JSFunctionAttributeEnum.HasThisObject, JSBuiltin.Date_setFullYear)]
public static double setFullYear (object thisObj, double dyear,
object month, object date)
{
- throw new NotImplementedException ();
+ SemanticAnalyser.assert_type (thisObj, typeof (DateObject));
+ DateObject dt = (DateObject) thisObj;
+ double t = DateConstructor.LocalTime (dt.ms);
+ if (Double.IsNaN (t))
+ t = 0;
+
+ double new_month;
+ if (month == null)
+ new_month = DateConstructor.MonthFromTime (t);
+ else
+ new_month = Convert.ToNumber (month);
+
+ double new_date;
+ if (date == null)
+ new_date = DateConstructor.DateFromTime (t);
+ else
+ new_date = Convert.ToNumber (date);
+
+ double day = DateConstructor.MakeDay (dyear, new_month, new_date);
+ double new_val = DateConstructor.ToUTC (DateConstructor.MakeDate (day, t % DateConstructor.MS_PER_DAY));
+ dt.ms = DateConstructor.TimeClip (new_val);
+ return dt.ms;
}
[JSFunctionAttribute (JSFunctionAttributeEnum.HasThisObject, JSBuiltin.Date_setHours)]
public static double setHours (object thisObj, double dhour, object min,
object sec, object msec)
{
- throw new NotImplementedException ();
+ SemanticAnalyser.assert_type (thisObj, typeof (DateObject));
+ DateObject date = (DateObject) thisObj;
+ double t = DateConstructor.LocalTime (date.ms);
+
+ double new_min;
+ if (min == null)
+ new_min = DateConstructor.MinFromTime (t);
+ else
+ new_min = Convert.ToNumber (min);
+
+ double new_sec;
+ if (sec == null)
+ new_sec = DateConstructor.SecFromTime (t);
+ else
+ new_sec = Convert.ToNumber (sec);
+
+ double new_ms;
+ if (msec == null)
+ new_ms = DateConstructor.msFromTime (t);
+ else
+ new_ms = Convert.ToNumber (msec);
+
+ double time = DateConstructor.MakeTime (dhour, new_min, new_sec, new_ms);
+ double day = Math.Floor (t / DateConstructor.MS_PER_DAY);
+ double new_val = DateConstructor.ToUTC (DateConstructor.MakeDate (day, time));
+ date.ms = DateConstructor.TimeClip (new_val);
+ return date.ms;
}
[JSFunctionAttribute (JSFunctionAttributeEnum.HasThisObject, JSBuiltin.Date_setMinutes)]
public static double setMinutes (object thisObj, double dmin,
object sec, object msec)
{
- throw new NotImplementedException ();
+ SemanticAnalyser.assert_type (thisObj, typeof (DateObject));
+ DateObject date = (DateObject) thisObj;
+ double t = DateConstructor.LocalTime (date.ms);
+
+ double new_sec;
+ if (sec == null)
+ new_sec = DateConstructor.SecFromTime (t);
+ else
+ new_sec = Convert.ToNumber (sec);
+
+ double new_ms;
+ if (msec == null)
+ new_ms = DateConstructor.msFromTime (t);
+ else
+ new_ms = Convert.ToNumber (msec);
+
+ double time = DateConstructor.MakeTime (DateConstructor.HourFromTime (t), dmin, new_sec, new_ms);
+ double day = Math.Floor (t / DateConstructor.MS_PER_DAY);
+ double new_val = DateConstructor.ToUTC (DateConstructor.MakeDate (day, time));
+ date.ms = DateConstructor.TimeClip (new_val);
+ return date.ms;
}
[JSFunctionAttribute (JSFunctionAttributeEnum.HasThisObject, JSBuiltin.Date_setMilliseconds)]
public static double setMilliseconds (object thisObj, double dmsec)
{
- throw new NotImplementedException ();
+ SemanticAnalyser.assert_type (thisObj, typeof (DateObject));
+ DateObject date = (DateObject) thisObj;
+ double t = DateConstructor.LocalTime (date.ms);
+ double time = DateConstructor.MakeTime (DateConstructor.HourFromTime (t), DateConstructor.MinFromTime (t),
+ DateConstructor.SecFromTime (t), dmsec);
+ double day = Math.Floor (t / DateConstructor.MS_PER_DAY);
+ double new_val = DateConstructor.ToUTC (DateConstructor.MakeDate (day, time));
+ date.ms = DateConstructor.TimeClip (new_val);
+ return date.ms;
}
[JSFunctionAttribute (JSFunctionAttributeEnum.HasThisObject, JSBuiltin.Date_setMonth)]
public static double setMonth (object thisObj, double dmonth,
object date)
{
- throw new NotImplementedException ();
+ SemanticAnalyser.assert_type (thisObj, typeof (DateObject));
+ DateObject dt = (DateObject) thisObj;
+ double t = DateConstructor.LocalTime (dt.ms);
+
+ double new_date;
+ if (date == null)
+ new_date = DateConstructor.DateFromTime (t);
+ else
+ new_date = Convert.ToNumber (date);
+
+ double day = DateConstructor.MakeDay ((double) DateConstructor.YearFromTime (t),
+ dmonth, new_date);
+ double new_val = DateConstructor.ToUTC (DateConstructor.MakeDate (day, t % DateConstructor.MS_PER_DAY));
+ dt.ms = DateConstructor.TimeClip (new_val);
+ return dt.ms;
}
- [JSFunctionAttribute (JSFunctionAttributeEnum.HasThisObject, JSBuiltin.Date_setSeconds)]
+ [JSFunctionAttribute (JSFunctionAttributeEnum.HasThisObject,
+ JSBuiltin.Date_setSeconds)]
public static double setSeconds (object thisObj, double dsec, object msec)
{
- throw new NotImplementedException ();
+ SemanticAnalyser.assert_type (thisObj, typeof (DateObject));
+ DateObject date = (DateObject) thisObj;
+ double t = DateConstructor.LocalTime (date.ms);
+
+ double new_ms;
+ if (msec == null)
+ new_ms = DateConstructor.msFromTime (t);
+ else
+ new_ms = Convert.ToNumber (msec);
+
+ double time = DateConstructor.MakeTime (DateConstructor.HourFromTime (t), DateConstructor.MinFromTime (t),
+ dsec, new_ms);
+ double day = Math.Floor (t / DateConstructor.MS_PER_DAY);
+ double new_val = DateConstructor.ToUTC (DateConstructor.MakeDate (day, time));
+ date.ms = DateConstructor.TimeClip (new_val);
+ return date.ms;
}
[JSFunctionAttribute (JSFunctionAttributeEnum.HasThisObject, JSBuiltin.Date_setTime)]
public static double setTime (object thisObj, double time)
{
- throw new NotImplementedException ();
+ SemanticAnalyser.assert_type (thisObj, typeof (DateObject));
+ DateObject date = (DateObject) thisObj;
+ date.ms = DateConstructor.TimeClip (time);
+ return date.ms;
}
[JSFunctionAttribute (JSFunctionAttributeEnum.HasThisObject, JSBuiltin.Date_setUTCDate)]
public static double setUTCDate (object thisObj, double ddate)
{
- throw new NotImplementedException ();
+ SemanticAnalyser.assert_type (thisObj, typeof (DateObject));
+ DateObject date = (DateObject) thisObj;
+ double t = date.ms;
+ double day = DateConstructor.MakeDay ((double) DateConstructor.YearFromTime (t),
+ (double) DateConstructor.MonthFromTime (t), ddate);
+ double new_val = DateConstructor.MakeDate (day, t % DateConstructor.MS_PER_DAY);
+ date.ms = DateConstructor.TimeClip (new_val);
+ return date.ms;
}
[JSFunctionAttribute (JSFunctionAttributeEnum.HasThisObject, JSBuiltin.Date_setUTCFullYear)]
public static double setUTCFullYear (object thisObj, double dyear,
object month, object date)
{
- throw new NotImplementedException ();
+ SemanticAnalyser.assert_type (thisObj, typeof (DateObject));
+ DateObject dt = (DateObject) thisObj;
+ double t = dt.ms;
+ if (Double.IsNaN (t))
+ t = 0;
+
+ double new_month;
+ if (month == null)
+ new_month = DateConstructor.MonthFromTime (t);
+ else
+ new_month = Convert.ToNumber (month);
+
+ double new_date;
+ if (date == null)
+ new_date = DateConstructor.DateFromTime (t);
+ else
+ new_date = Convert.ToNumber (date);
+
+ double day = DateConstructor.MakeDay (dyear, new_month, new_date);
+ double new_val = DateConstructor.MakeDate (day, t % DateConstructor.MS_PER_DAY);
+ dt.ms = DateConstructor.TimeClip (new_val);
+ return dt.ms;
}
[JSFunctionAttribute (JSFunctionAttributeEnum.HasThisObject, JSBuiltin.Date_setUTCHours)]
public static double setUTCHours (object thisObj, double dhour,
object min, object sec, object msec)
{
- throw new NotImplementedException ();
+ SemanticAnalyser.assert_type (thisObj, typeof (DateObject));
+ DateObject date = (DateObject) thisObj;
+ double t = date.ms;
+
+ double new_min;
+ if (min == null)
+ new_min = DateConstructor.MinFromTime (t);
+ else
+ new_min = Convert.ToNumber (min);
+
+ double new_sec;
+ if (sec == null)
+ new_sec = DateConstructor.SecFromTime (t);
+ else
+ new_sec = Convert.ToNumber (sec);
+
+ double new_ms;
+ if (msec == null)
+ new_ms = DateConstructor.msFromTime (t);
+ else
+ new_ms = Convert.ToNumber (msec);
+
+ double time = DateConstructor.MakeTime (dhour, new_min, new_sec, new_ms);
+ double day = Math.Floor (t / DateConstructor.MS_PER_DAY);
+ double new_val = DateConstructor.MakeDate (day, time);
+ date.ms = DateConstructor.TimeClip (new_val);
+ return date.ms;
}
[JSFunctionAttribute (JSFunctionAttributeEnum.HasThisObject, JSBuiltin.Date_setUTCMinutes)]
public static double setUTCMinutes (object thisObj, double dmin,
object sec, object msec)
{
- throw new NotImplementedException ();
+ SemanticAnalyser.assert_type (thisObj, typeof (DateObject));
+ DateObject date = (DateObject) thisObj;
+ double t = date.ms;
+
+ double new_sec;
+ if (sec == null)
+ new_sec = DateConstructor.SecFromTime (t);
+ else
+ new_sec = Convert.ToNumber (sec);
+
+ double new_ms;
+ if (msec == null)
+ new_ms = DateConstructor.msFromTime (t);
+ else
+ new_ms = Convert.ToNumber (msec);
+
+ double time = DateConstructor.MakeTime (DateConstructor.HourFromTime (t), dmin, new_sec, new_ms);
+ double day = Math.Floor (t / DateConstructor.MS_PER_DAY);
+ double new_val = DateConstructor.MakeDate (day, time);
+ date.ms = DateConstructor.TimeClip (new_val);
+ return date.ms;
}
[JSFunctionAttribute (JSFunctionAttributeEnum.HasThisObject, JSBuiltin.Date_setUTCMilliseconds)]
public static double setUTCMilliseconds (object thisObj, double msec)
{
- throw new NotImplementedException ();
+ SemanticAnalyser.assert_type (thisObj, typeof (DateObject));
+ DateObject date = (DateObject) thisObj;
+ double t = date.ms;
+ double time = DateConstructor.MakeTime (DateConstructor.HourFromTime (t), DateConstructor.MinFromTime (t),
+ DateConstructor.SecFromTime (t), msec);
+ double day = Math.Floor (t / DateConstructor.MS_PER_DAY);
+ double new_val = DateConstructor.MakeDate (day, time);
+ date.ms = DateConstructor.TimeClip (new_val);
+ return date.ms;
}
[JSFunctionAttribute (JSFunctionAttributeEnum.HasThisObject, JSBuiltin.Date_setUTCMonth)]
public static double setUTCMonth (object thisObj, double dmonth, object date)
{
- throw new NotImplementedException ();
+ SemanticAnalyser.assert_type (thisObj, typeof (DateObject));
+ DateObject dt = (DateObject) thisObj;
+ double t = dt.ms;
+
+ double new_date;
+ if (date == null)
+ new_date = DateConstructor.DateFromTime (t);
+ else
+ new_date = Convert.ToNumber (date);
+
+ double day = DateConstructor.MakeDay ((double) DateConstructor.YearFromTime (t),
+ dmonth, new_date);
+ double new_val = DateConstructor.MakeDate (day, t % DateConstructor.MS_PER_DAY);
+ dt.ms = DateConstructor.TimeClip (new_val);
+ return dt.ms;
}
[JSFunctionAttribute (JSFunctionAttributeEnum.HasThisObject, JSBuiltin.Date_setUTCSeconds)]
public static double setUTCSeconds (object thisObj, double dsec, object msec)
{
- throw new NotImplementedException ();
+ SemanticAnalyser.assert_type (thisObj, typeof (DateObject));
+ DateObject date = (DateObject) thisObj;
+ double t = date.ms;
+
+ double new_ms;
+ if (msec == null)
+ new_ms = DateConstructor.msFromTime (t);
+ else
+ new_ms = Convert.ToNumber (msec);
+
+ double time = DateConstructor.MakeTime (DateConstructor.HourFromTime (t), DateConstructor.MinFromTime (t),
+ dsec, new_ms);
+ double day = Math.Floor (t / DateConstructor.MS_PER_DAY);
+ double new_val = DateConstructor.MakeDate (day, time);
+ date.ms = DateConstructor.TimeClip (new_val);
+ return date.ms;
}
+ /* Note: See Note for GetYear() for an explanation why we do not emulate obsolete behavior here. */
[JSFunctionAttribute (JSFunctionAttributeEnum.HasThisObject, JSBuiltin.Date_setYear)]
public static double setYear (object thisObj, double dyear)
{
- throw new NotImplementedException ();
+ return setFullYear (thisObj, dyear, null, null);
}
[JSFunctionAttribute (JSFunctionAttributeEnum.HasThisObject, JSBuiltin.Date_toDateString)]
[JSFunctionAttribute(JSFunctionAttributeEnum.HasVarArgs)]
public Object Invoke (params Object [] args)
{
- return GetMethod ("CreateInstance", BindingFlags.Static | BindingFlags.Public).Invoke (null, args);
+ return CreateInstance (args);
}
}
}
[JSFunctionAttribute(JSFunctionAttributeEnum.HasVarArgs)]
public ScriptFunction Invoke(params Object [] args)
{
- return (ScriptFunction) GetMethod ("CreateInstance", BindingFlags.Static | BindingFlags.Public).Invoke (null, args);
+ return CreateInstance (args);
}
}
}
bool hasArgumentsObjects, string text,
Object declaringObject, VsaEngine engine)
{
- FunctionObject f = null;
+ FunctionObject f = new FunctionObject (name, null, null, null);
return new Closure (f);
}
public class FunctionObject : ScriptFunction {
- internal MethodAttributes attr;
internal string name;
internal string type_annot;
internal Type return_type;
this.name = name;
}
+ internal FunctionObject (MethodInfo info)
+ {
+ this.method = info;
+ this.name = info.Name;
+ this.attr = info.Attributes;
+ this.return_type = info.ReturnType;
+ }
+
internal FunctionObject (string name, FormalParameterList p, string ret_type, Block body)
{
//
[JSFunctionAttribute (0, JSBuiltin.Global_CollectGarbage)]
public static void CollectGarbage ()
{
- throw new NotImplementedException ();
+ GC.Collect ();
}
public static DateConstructor Date {
//
- // ECMA 3, 15.1.3 URI hnadling Function Properties
+ // ECMA 3, 15.1.3 URI handling Function Properties
//
// The following are implementations of the algorithms
// given in the ECMA specification for the hidden functions
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
-namespace Microsoft.JScript {
+using System;
+namespace Microsoft.JScript {
+ [FlagsAttribute]
public enum JSFunctionAttributeEnum {
HasArguments = 0x01,
HasThisObject = 0x02,
internal JSFieldInfo GetField (string name)
{
object res = elems [name];
-
- if (res == null)
- throw new Exception ("JSObject.GetField: search somewhere else");
+
if (res is JSFieldInfo)
return (JSFieldInfo) res;
return null;
public override string ToString ()
{
- throw new NotImplementedException ();
+ return String.Format ("[{0}]", ClassName);
}
internal string ClassName {
- get {
+ get {
if (this is ObjectPrototype)
- return "Object";
+ return "Object";
+ else if (this is ArrayPrototype)
+ return "Array";
+ else if (this is StringPrototype)
+ return "String";
+ else if (this is NumberPrototype)
+ return "Number";
+ else if (this is DatePrototype)
+ return "Date";
else
- throw new NotImplementedException ();
+ return this.GetType ().ToString ();
}
}
internal virtual object GetDefaultValue (Type hint)
{
- throw new NotImplementedException ();
+ return ObjectPrototype.toString (this);
}
}
}
return "Array length must be zero or a positive integer";
else if (error_number == JSError.PrecisionOutOfRange)
return "The number of fractional digits is out of range";
+ else if (error_number == JSError.RegExpSyntax)
+ return "Syntax error in regular expression";
else {
Console.WriteLine ("JScriptException:get_Message: unknown error_number {0}", error_number);
throw new NotImplementedException ();
if (obj is JSObject)
type = SemanticAnalyser.map_to_prototype ((JSObject) obj);
- MethodInfo method = type.GetMethod (right_hand_side, BindingFlags.Public | BindingFlags.Static);
- JSFunctionAttribute [] custom_attrs = (JSFunctionAttribute [])
- method.GetCustomAttributes (typeof (JSFunctionAttribute), true);
- //
- // We need to iterate through the JSFunctionAttributes to find out whether the function wants
- // to get passed the vsaEngine or not so we can pass the right arguments to it.
- //
- object [] args = null;
- bool has_engine = false;
- bool has_var_args = false;
- foreach (JSFunctionAttribute attr in custom_attrs) {
- JSFunctionAttributeEnum flags = attr.GetAttributeValue ();
- if ((flags & JSFunctionAttributeEnum.HasEngine) != 0)
- has_engine = true;
- if ((flags & JSFunctionAttributeEnum.HasVarArgs) != 0)
- has_var_args = true;
- }
-
- if (has_var_args) {
- // 1 for length to last idx + 1 for thisObj = 2
- int va_idx = method.GetParameters ().Length - 2;
- if (has_engine)
- va_idx--;
- int va_count = arguments.Length - va_idx;
-
- ArrayList arg_list = new ArrayList (arguments);
- object [] var_args = arg_list.GetRange (va_idx, va_count).ToArray ();
- arg_list.RemoveRange (va_idx, va_count);
- arg_list.Add (var_args);
- arguments = arg_list.ToArray ();
- }
-
- if (has_engine)
- args = build_args (arguments, engine);
- else
- args = build_args (arguments, null);
-
- // TODO: Debug logging should be removed
- string arg_str = "";
- foreach (object arg in args)
- arg_str += arg.GetType ().ToString () + ", ";
-
- //System.Console.WriteLine("\nInvoking {0}.{1} with args {2}", obj.GetType(), method.Name, arg_str);
+ if (type == null)
+ Console.WriteLine ("LateBinding:Call: type is null for {0}.{1}!", obj, right_hand_side);
+ string name = right_hand_side == "lastIndexOf" ? "lastIndexOfGood" : right_hand_side;
+ MethodInfo method = type.GetMethod (name, BindingFlags.Public | BindingFlags.Static);
+ if (method == null)
+ Console.WriteLine ("LateBinding:Call: method is null for {0}.{1}!", obj, right_hand_side);
+
+ object [] args = assemble_args (obj, method, arguments, engine);
return method.Invoke (type, args);
}
}
throw new NotImplementedException ();
}
- private object [] build_args (object [] arguments, VsaEngine engine)
+ internal static object [] assemble_args (object obj, MethodInfo method, object [] arguments, VsaEngine engine)
+ {
+ JSFunctionAttribute [] custom_attrs = (JSFunctionAttribute [])
+ method.GetCustomAttributes (typeof (JSFunctionAttribute), true);
+ //
+ // We need to iterate through the JSFunctionAttributes to find out whether the function wants
+ // to get passed the vsaEngine or not so we can pass the right arguments to it.
+ //
+ bool has_engine = false;
+ bool has_var_args = false;
+ foreach (JSFunctionAttribute attr in custom_attrs) {
+ JSFunctionAttributeEnum flags = attr.GetAttributeValue ();
+ if ((flags & JSFunctionAttributeEnum.HasEngine) != 0)
+ has_engine = true;
+ if ((flags & JSFunctionAttributeEnum.HasVarArgs) != 0)
+ has_var_args = true;
+ }
+
+ return assemble_args (obj, has_var_args, has_engine, method.GetParameters ().Length, arguments, engine);
+ }
+
+ internal static object [] assemble_args (object obj, bool has_var_args, bool has_engine,
+ int target_argc, object [] arguments, VsaEngine engine)
+ {
+ ArrayList arg_list = new ArrayList (arguments);
+ int req_argc = target_argc - 1; /* -1 for thisObj */
+ if (has_engine)
+ req_argc--;
+ if (has_var_args)
+ req_argc--;
+
+ int missing_args = req_argc - arg_list.Count;
+ for (int i = 0; i < missing_args; i++)
+ arg_list.Add (null);
+
+ if (has_var_args) {
+ int va_idx = req_argc;
+ int va_count = arg_list.Count - va_idx;
+
+ object [] var_args = new object [va_count];
+
+ int j = va_idx;
+ object arg;
+ for (int i = 0; i < va_count; i++, j++) {
+ arg = arg_list [j];
+ if (arg != null)
+ var_args [i] = arg;
+ }
+
+ arg_list.RemoveRange (va_idx, va_count);
+ arg_list.Add (var_args);
+ }
+
+ return build_args (obj, arg_list.ToArray (), engine, has_engine);
+ }
+
+ internal static object [] build_args (object obj, object [] arguments, VsaEngine engine, bool has_engine)
{
ArrayList args = new ArrayList ();
if (obj != null)
args.Add (obj);
- if (engine != null)
+ if (has_engine)
args.Add (engine);
foreach (object o in arguments)
args.Add (o);
{
if (construct) {
if (brackets) {
- throw new NotImplementedException ();
}
- throw new NotImplementedException ();
} else if (brackets) {
if (!(val is JSObject))
throw new Exception ("val has to be a JSObject");
object res = js_val.GetField (Convert.ToString (arguments [0]));
if (res is JSFieldInfo)
return ((JSFieldInfo) res).GetValue (arguments [0]);
- else
- throw new NotImplementedException ();
+ else {
+ res = js_val.elems [Convert.ToInt32 (arguments [0])];
+ if (res != null)
+ return res;
+ }
+ if (res == null)
+ Console.WriteLine ("res is null!");
} else {
- Console.WriteLine ("CallValue -- no brackes, no construct, this = {0}, val = {1}", thisObj.GetType(), val);
- throw new NotImplementedException ();
+ if (val is Closure)
+ return ((Closure) val).func.Invoke (thisObj, arguments);
+ else if (val is FunctionObject)
+ return ((FunctionObject) val).Invoke (thisObj, arguments);
}
+
+ Console.WriteLine ("CallValue: construct = {0}, brackets = {1}, this = {2}, val = {3} ({4})",
+ construct, brackets, thisObj.GetType (), val, val.GetType ());
+ throw new NotImplementedException ();
}
[DebuggerStepThroughAttribute]
public object GetNonMissingValue ()
{
Type type = obj.GetType ();
- if (obj is JSObject)
- type = SemanticAnalyser.map_to_prototype ((JSObject) obj);
MemberInfo [] members = type.GetMember (right_hand_side);
+ if (obj is JSObject && members.Length == 0) {
+ JSObject jsobj = obj as JSObject;
+ JSFieldInfo field = jsobj.GetField (right_hand_side);
+ if (field != null)
+ return field.GetValue (right_hand_side);
+
+ type = SemanticAnalyser.map_to_prototype ((JSObject) obj);
+ members = type.GetMember (right_hand_side);
+ }
+
if (members.Length > 0) {
MemberInfo member = members [0];
MemberTypes member_type = member.MemberType;
MethodInfo method = ((PropertyInfo) member).GetGetMethod ();
return method.Invoke (obj, new object [] { });
case MemberTypes.Method:
- return new FunctionObject (((MethodInfo) member).Name);
+ return new FunctionObject ((MethodInfo) member);
default:
- System.Console.WriteLine ("GetNonMissingValue: type = {0}, member_type = {1}", type, member_type);
+ Console.WriteLine ("GetNonMissingValue: type = {0}, member_type = {1}", type, member_type);
break;
}
}
+
+ Console.WriteLine ("members.Length = {0}, obj = {1}, type = {2}, rhs = {3}",
+ members.Length, obj, type, right_hand_side);
throw new NotImplementedException ();
}
[JSFunctionAttribute (JSFunctionAttributeEnum.HasThisObject, JSBuiltin.Number_toFixed)]
public static string toFixed (object thisObj, double fractionDigits)
{
- SemanticAnalyser.assert_type (thisObj, typeof (NumberObject));
- NumberObject no = thisObj as NumberObject;
+ if (!Convert.IsNumber (thisObj))
+ throw new JScriptException (JSError.NumberExpected);
+
+ double value = Convert.ToNumber (thisObj);
int prec = Convert.ToInt32 (fractionDigits);
if (prec < 0 || prec > 21)
throw new JScriptException (JSError.PrecisionOutOfRange);
- return no.value.ToString ("F" + prec, CultureInfo.InvariantCulture);
+ return value.ToString ("F" + prec, CultureInfo.InvariantCulture);
}
[JSFunctionAttribute (JSFunctionAttributeEnum.HasThisObject, JSBuiltin.Number_toLocaleString)]
public static string toLocaleString (object thisObj)
{
- SemanticAnalyser.assert_type (thisObj, typeof (NumberObject));
- NumberObject no = thisObj as NumberObject;
- return no.value.ToString ();
+ if (!Convert.IsNumber (thisObj))
+ throw new JScriptException (JSError.NumberExpected);
+ else
+ return Convert.ToNumber (thisObj).ToString ();
}
[JSFunctionAttribute (JSFunctionAttributeEnum.HasThisObject, JSBuiltin.Number_toPrecision)]
//
- // We aren't 100% compatible to MS JS.NET here,
- // because we sometimes produce slightly more of the
- // fractional digits. This shouldn't cause any
- // trouble.
+ // We aren't 100% compatible to MS JS.NET here, because we sometimes produce slightly more
+ // of the fractional digits. This shouldn't cause any trouble.
//
[JSFunctionAttribute (JSFunctionAttributeEnum.HasThisObject, JSBuiltin.Number_toString)]
public static string toString (object thisObj, object radix)
{
- SemanticAnalyser.assert_type (thisObj, typeof (NumberObject));
- NumberObject no = thisObj as NumberObject;
- double value = no.value;
+ if (!Convert.IsNumber (thisObj))
+ throw new JScriptException (JSError.NumberExpected);
+
+ double value = Convert.ToNumber (thisObj);
if (Double.IsNaN (value))
return "NaN";
[JSFunctionAttribute (JSFunctionAttributeEnum.HasThisObject, JSBuiltin.Number_valueOf)]
public static object valueOf (object thisObj)
{
- SemanticAnalyser.assert_type (thisObj, typeof (NumberObject));
- NumberObject no = thisObj as NumberObject;
- return no.value;
+ if (!Convert.IsNumber (thisObj))
+ throw new JScriptException (JSError.NumberExpected);
+ else
+ return Convert.ToNumber (thisObj);
}
}
}
[DebuggerHiddenAttribute]
public object EvaluatePlus (object v1, object v2)
{
- IConvertible ic1 = v1 as IConvertible;
- IConvertible ic2 = v2 as IConvertible;
-
- TypeCode tc1 = Convert.GetTypeCode (v1, ic1);
- TypeCode tc2 = Convert.GetTypeCode (v2, ic2);
-
- bool swapped = false;
- redo:
-
- switch (tc1) {
- case TypeCode.Empty:
- if (tc2 == TypeCode.Empty)
- return Double.NaN;
- break;
-
- case TypeCode.DBNull:
- if (tc2 == TypeCode.DBNull)
- return 0;
- break;
-
- case TypeCode.Double:
- switch (tc2) {
- case TypeCode.Boolean:
- case TypeCode.Double:
- return ic1.ToDouble (null) + ic2.ToDouble (null);
-
- case TypeCode.String:
- return ic1.ToString (CultureInfo.InvariantCulture) + ic2.ToString (null);
-
- case TypeCode.Empty:
- return Double.NaN;
-
- case TypeCode.DBNull:
- return ic1.ToDouble (null);
- }
- break;
-
- case TypeCode.String:
- switch (tc2) {
- case TypeCode.Boolean:
- return ic1.ToString (null) + Convert.ToString (ic2.ToBoolean (null));
-
- case TypeCode.Single:
- case TypeCode.Double:
- case TypeCode.Char:
- case TypeCode.Byte:
- case TypeCode.SByte:
- case TypeCode.Int16:
- case TypeCode.UInt16:
- case TypeCode.Int32:
- case TypeCode.UInt32:
- case TypeCode.Int64:
- case TypeCode.UInt64:
- case TypeCode.String:
- return ic1.ToString (null) + ic2.ToString (CultureInfo.InvariantCulture);
-
- case TypeCode.Empty:
- return ic1.ToString (null) + "undefined";
-
- case TypeCode.DBNull:
- return ic1.ToString (null) + "null";
- }
- break;
-
- case TypeCode.Boolean:
- switch (tc2) {
- case TypeCode.Double:
- return ic1.ToDouble (null) + ic2.ToDouble (null);
-
- case TypeCode.String:
- return Convert.ToString (ic1.ToBoolean (null)) + ic2.ToString (null);
-
- case TypeCode.Boolean:
- return ic1.ToInt32 (null) + ic2.ToInt32 (null);
-
- case TypeCode.DBNull:
- return ic1.ToInt32 (null);
- }
- break;
- default:
- if (!swapped) {
- IConvertible tic = ic1; ic1 = ic2; ic2 = tic;
- TypeCode ttc = tc1; tc1 = tc2; tc2 = ttc;
- swapped = true;
- goto redo;
- }
- break;
- }
-
- System.Console.WriteLine ("EvaluatePlus: tc1 = {0}, tc2 = {1}", tc1, tc2);
- throw new NotImplementedException ();
+ object val1 = Convert.ToPrimitive (v1, null);
+ object val2 = Convert.ToPrimitive (v2, null);
+ if (Convert.IsString (val1) || Convert.IsString (val2))
+ return Convert.ToString (val1) + Convert.ToString (val2);
+ else
+ return Convert.ToNumber (val1) + Convert.ToNumber (val2);
}
public static object DoOp (object v1, object v2)
{
double value = Convert.ToNumber (v);
int oper = (int) this.oper;
- if (oper % 2 == 1)
+ if (oper % 2 == 1) /* prefix? */
return value + 1;
else
return value - 1;
using System;
using System.Text;
+using System.Text.RegularExpressions;
namespace Microsoft.JScript {
private bool _ignoreCase;
private bool _global;
private bool _multiline;
+ private int _lastindex = 0;
+ internal Regex regex;
public override string ToString ()
{
}
public Object lastIndex {
- get { throw new NotImplementedException (); }
- set { throw new NotImplementedException (); }
+ get { return _lastindex; }
+ set { _lastindex = Convert.ToInt32 (value); }
}
- internal RegExpObject (string pattern, bool ignoreCase, bool global, bool multiLine)
+ internal RegExpObject (string pattern, bool ignoreCase, bool global, bool multiLine)
+ {
+ Initialize (pattern, ignoreCase, global, multiLine);
+ }
+
+ internal void Initialize (string pattern, bool ignoreCase, bool global, bool multiLine)
{
_source = pattern;
_ignoreCase = ignoreCase;
_global = global;
_multiline = multiLine;
+ RegexOptions options = RegexOptions.ECMAScript | RegexOptions.Compiled;
+ if (ignoreCase)
+ options |= RegexOptions.IgnoreCase;
+ if (multiLine)
+ options |= RegexOptions.Multiline;
+ try {
+ regex = new Regex (source, options);
+ } catch (ArgumentException) {
+ throw new JScriptException (JSError.RegExpSyntax);
+ }
}
}
}
//
using System;
+using System.Text.RegularExpressions;
+using System.Collections;
namespace Microsoft.JScript {
[JSFunctionAttribute (JSFunctionAttributeEnum.HasThisObject, JSBuiltin.RegExp_compile)]
public static RegExpObject compile (object thisObj, object source, object flags)
{
- throw new NotImplementedException ();
- }
+ //
+ // Note: We always compile RegExp internals so all this method is useful for is for
+ // changing the properties of the otherwise immutable RegExp objects.
+ //
+ RegExpObject re = Convert.ToRegExp (thisObj);
+ string flag_str = Convert.ToString (flags);
+ re.Initialize (Convert.ToString (source),
+ flag_str.IndexOfAny (new char [] { 'i' }) > -1,
+ flag_str.IndexOfAny (new char [] { 'g' }) > -1,
+ flag_str.IndexOfAny (new char [] { 'm' }) > -1);
+ return re;
+ }
public static RegExpConstructor constructor {
get { return RegExpConstructor.Ctr; }
[JSFunctionAttribute (JSFunctionAttributeEnum.HasThisObject, JSBuiltin.RegExp_exec)]
public static object exec (object thisObj, object input)
{
- throw new NotImplementedException ();
+ RegExpObject re = Convert.ToRegExp (thisObj);
+ string str = Convert.ToString (input);
+ bool global = re.global;
+ int lastIndex = global ? (int) re.lastIndex : 0;
+ bool success = lastIndex >= 0 && lastIndex <= str.Length;
+
+ Match md = null;
+ if (success) {
+ md = re.regex.Match (str, lastIndex);
+ success = md.Success;
+ }
+
+ if (!success) {
+ re.lastIndex = 0;
+ return DBNull.Value;
+ }
+
+ int index = md.Index;
+ int endIndex = index + md.Length;
+ if (global)
+ re.lastIndex = endIndex;
+
+ GroupCollection caps = md.Groups;
+ int len = caps.Count;
+ RegExpMatch result = new RegExpMatch ();
+
+ result.AddField ("index", index);
+ result.AddField ("input", input);
+ result.length = len;
+ for (int j = 0; j < len; j++)
+ result.elems [j] = caps [j].Value;
+
+ return result;
}
[JSFunctionAttribute (JSFunctionAttributeEnum.HasThisObject, JSBuiltin.RegExp_test)]
public static bool test (object thisObj, object input)
{
- throw new NotImplementedException ();
+ return exec (thisObj, input) != DBNull.Value;
}
[JSFunctionAttribute (JSFunctionAttributeEnum.HasThisObject, JSBuiltin.RegExp_toString)]
using System.Reflection;
using System.Diagnostics;
using System.Globalization;
+using System.Collections;
namespace Microsoft.JScript {
public abstract class ScriptFunction : JSObject {
+ internal MethodInfo method;
+ internal MethodAttributes attr;
+
[DebuggerStepThroughAttribute]
[DebuggerHiddenAttribute]
[JSFunctionAttribute (JSFunctionAttributeEnum.HasVarArgs)]
[JSFunctionAttribute (JSFunctionAttributeEnum.HasThisObject | JSFunctionAttributeEnum.HasVarArgs)]
public Object Invoke (Object thisOb, params Object [] args)
{
+ if (method != null) {
+ if ((attr & MethodAttributes.Static) != 0)
+ return method.Invoke (null, LateBinding.assemble_args (thisOb, method, args, null));
+ else
+ return method.Invoke (thisOb, LateBinding.assemble_args (null, method, args, null));
+ }
+
+ Console.WriteLine ("Called ScriptFunction:Invoke on user function");
throw new NotImplementedException ();
}
public MethodInfo GetMethod (string name, BindingFlags bindFlags)
{
- throw new NotImplementedException ();
+ Type prototype = SemanticAnalyser.map_to_prototype (this);
+ if (prototype != null)
+ return prototype.GetMethod (name, bindFlags | BindingFlags.Static);
+ else
+ throw new NotImplementedException ();
}
public MethodInfo GetMethod (string name, BindingFlags bindFlags,
public virtual Type UnderlyingSystemType {
get { throw new NotImplementedException (); }
}
+
+ internal object CallMethod (string name, params object [] args)
+ {
+ MethodInfo method = GetMethod (name, BindingFlags.InvokeMethod | BindingFlags.Public);
+ return CallMethod (method, args);
+ }
+
+ internal object CallMethod (MethodInfo method, params object [] args)
+ {
+ return method.Invoke (null, LateBinding.assemble_args (this, method, args, null));
+ }
}
}
prototypes.Add (typeof (NumberObject), typeof (NumberPrototype));
prototypes.Add (typeof (DateObject), typeof (DatePrototype));
prototypes.Add (typeof (RegExpObject), typeof (RegExpPrototype));
- // FIXME: Error objects missing
+ prototypes.Add (typeof (RegExpMatch), typeof (ArrayPrototype));
+ prototypes.Add (typeof (ErrorObject), typeof (ErrorPrototype));
+ prototypes.Add (typeof (EvalErrorObject), typeof (ErrorPrototype));
+ prototypes.Add (typeof (RangeErrorObject), typeof (ErrorPrototype));
+ prototypes.Add (typeof (SyntaxErrorObject), typeof (ErrorPrototype));
+ prototypes.Add (typeof (TypeErrorObject), typeof (ErrorPrototype));
+ prototypes.Add (typeof (URIErrorObject), typeof (ErrorPrototype));
}
internal static string ImplementationName (string name)
internal static void assert_type (object thisObj, Type expType)
{
- if (thisObj == null || thisObj.GetType () != expType)
+ if (thisObj == null || (thisObj.GetType () != expType && !thisObj.GetType ().IsSubclassOf (expType)))
throw new Exception ("Type error");
}
return null;
}
- internal static Type map_to_prototype (JSObject jsObj)
+ internal static Type map_to_prototype (ScriptObject jsObj)
{
if (jsObj == null)
throw new Exception ("jsObj can't be null");
case TypeCode.String:
return ic1.ToString (null) == ic2.ToString (null);
+ case TypeCode.Object:
+ return v1 == v2;
+
default:
if (both_numbers) {
double num1;
if (Convert.IsFloatTypeCode (tc1))
num1 = ic1.ToDouble (null);
else
- num1 = (double) ic1.ToInt32 (null);
+ num1 = (double) ic1.ToInt64 (null);
double num2;
if (Convert.IsFloatTypeCode (tc2))
num2 = ic2.ToDouble (null);
else
- num2 = (double) ic2.ToInt32 (null);
+ num2 = (double) ic2.ToInt64 (null);
return num1 == num2;
}
using System;
using Microsoft.JScript.Vsa;
using System.Globalization;
+using System.Text.RegularExpressions;
namespace Microsoft.JScript {
// with their signature, because position will
// automatically be forced to 0 in that case. Because
// of that we currently use 'object position' instead
- // of their 'double position'.
+ // of their 'double position' in lastIndexOfGood
+ // (which we use from our own compiler) and a wrapper
+ // around that for when we run MS IL.
//
- [JSFunctionAttribute (JSFunctionAttributeEnum.HasThisObject, JSBuiltin.String_lastIndexOf)]
- public static int lastIndexOf (object thisObj, object searchString, object position)
+ public static int lastIndexOfGood (object thisObj, object searchString, object position)
{
string string_obj = Convert.ToString (thisObj);
string search_obj = Convert.ToString (searchString);
return result;
}
+ [JSFunctionAttribute (JSFunctionAttributeEnum.HasThisObject, JSBuiltin.String_lastIndexOf)]
+ public static int lastIndexOf (object thisObj, object searchString, object position)
+ {
+ return lastIndexOfGood (thisObj, searchString, position);
+ }
+
+ public static int lastIndexOf (object thisObj, object searchString, double position)
+ {
+ return lastIndexOfGood (thisObj, searchString, position);
+ }
+
[JSFunctionAttribute (JSFunctionAttributeEnum.HasThisObject, JSBuiltin.String_link)]
public static string link (object thisObj, object linkRef)
{
[JSFunctionAttribute (JSFunctionAttributeEnum.HasThisObject | JSFunctionAttributeEnum.HasEngine, JSBuiltin.String_match)]
public static object match (object thisObj, VsaEngine engine, object regExp)
{
- throw new NotImplementedException ();
+ string string_obj = Convert.ToString (thisObj);
+ RegExpObject regex_obj = Convert.ToRegExp (regExp);
+ bool global = regex_obj.global;
+
+ if (!global)
+ return RegExpPrototype.exec (regex_obj, string_obj);
+
+ MatchCollection md = regex_obj.regex.Matches (string_obj);
+ int n = md.Count;
+ regex_obj.lastIndex = md [n - 1].Index + 1;
+
+ ArrayObject result = new ArrayObject ();
+ result.length = n;
+ for (int i = 0; i < n; i++)
+ result.elems [i] = md [i].Value;
+
+ return result;
}
[JSFunctionAttribute (JSFunctionAttributeEnum.HasThisObject, JSBuiltin.String_replace)]
public static string replace (object thisObj, object regExp, object replacement)
{
+ string string_obj = Convert.ToString (thisObj);
+
+ if (!(regExp is RegExpObject)) {
+ string match_str = Convert.ToString (regExp);
+ string replace_str = Convert.ToString (replacement);
+ int match_pos = string_obj.IndexOf (match_str);
+
+ if (match_pos == -1)
+ return string_obj;
+
+ return String.Concat (string_obj.Substring (0, match_pos), replace_str,
+ string_obj.Substring (match_pos + match_str.Length));
+ }
+
+ RegExpObject regex_obj = (RegExpObject) regExp;
+ int count = regex_obj.global ? -1 : 1;
+
+ if (!(replacement is FunctionObject))
+ return regex_obj.regex.Replace (string_obj, Convert.ToString (replacement), count);
+
throw new NotImplementedException ();
}
[JSFunctionAttribute (JSFunctionAttributeEnum.HasThisObject | JSFunctionAttributeEnum.HasEngine, JSBuiltin.String_search)]
public static int search (object thisObj, VsaEngine engine, object regExp)
{
- throw new NotImplementedException ();
+ string string_obj = Convert.ToString (thisObj);
+ RegExpObject regex_obj = Convert.ToRegExp (regExp);
+ Match md = regex_obj.regex.Match (string_obj);
+ /* Note: Microsoft's implementation updates the lastIndex property of regex_obj here, but
+ * ECMA-262, 15.5.4.12, NOTE 1 explicitely says not to do so. We do the ECMA-262 behavior. */
+ if (md.Success)
+ return md.Index;
+ else
+ return -1;
}
[JSFunctionAttribute (JSFunctionAttributeEnum.HasThisObject, JSBuiltin.String_slice)]
public static ArrayObject split (object thisObj, VsaEngine engine,
object separator, object limit)
{
- throw new NotImplementedException ();
+ string string_obj = Convert.ToString (thisObj);
+ int length = string_obj.Length;
+ int max_count = (limit != null) ? Convert.ToInt32 (limit) : -1;
+ ArrayObject result = new ArrayObject ();
+
+ if (separator == null) {
+ result.length = 1;
+ result.elems [0] = string_obj;
+ return result;
+ }
+
+ int start_pos = 0;
+ int end_pos = -1;
+ int match_len = 0;
+ int count = 0;
+ int sep_len = 0;
+
+ if (!(separator is RegExpObject)) {
+ string sep_str = Convert.ToString (separator);
+ sep_len = sep_str.Length;
+
+ if (string_obj.Length == 0) {
+ if (sep_len > 0) {
+ result.length = 1;
+ result.elems [0] = string_obj;
+ }
+
+ return result;
+ }
+
+ while (end_pos != length && (max_count == -1 || count < max_count)) {
+ end_pos = (length != 0) ? string_obj.IndexOf (sep_str, start_pos) : length;
+ if (end_pos == -1)
+ end_pos = length;
+ else if (sep_len == 0)
+ end_pos++;
+
+ match_len = end_pos - start_pos;
+ result.elems [count] = string_obj.Substring (start_pos, match_len);
+
+ start_pos += match_len + sep_len;
+ count++;
+ }
+
+ result.length = count;
+ return result;
+ }
+
+ RegExpObject sep_re = (RegExpObject) separator;
+ MatchCollection md = sep_re.regex.Matches (string_obj);
+ int n = md.Count;
+
+ Match match = null;
+ for (int i = 0; i < n; i++) {
+ match = md [i];
+ sep_len = match.Length;
+ end_pos = match.Index;
+ match_len = end_pos - start_pos;
+
+ if (start_pos != 0 || match_len > 0) {
+ result.elems [count] = string_obj.Substring (start_pos, match_len);
+ count++;
+ }
+
+ bool first_cap = true;
+ foreach (Capture cap in match.Groups) {
+ if (first_cap) {
+ first_cap = false;
+ continue;
+ }
+
+ result.elems [count] = cap.Value;
+ count++;
+ }
+
+ start_pos += match_len + sep_len;
+ }
+
+ if (n > 0) {
+ sep_re.lastIndex = match.Index + match.Length;
+
+ if (start_pos < length) {
+ result.elems [count] = string_obj.Substring (start_pos);
+ count++;
+ }
+ }
+
+ result.length = count;
+ return result;
}
[JSFunctionAttribute (JSFunctionAttributeEnum.HasThisObject, JSBuiltin.String_strike)]
if (end == null)
_end = string_len;
else {
- _end = (int) (double) end;
+ _end = Convert.ToInt32 (end);
if (_end == Double.NaN || _end < 0)
_end = 0;
[JSFunctionAttribute (JSFunctionAttributeEnum.HasThisObject, JSBuiltin.String_toString)]
public static string toString (object thisObj)
{
- SemanticAnalyser.assert_type (thisObj, typeof (StringObject));
- StringObject str_obj = thisObj as StringObject;
- return str_obj.value;
+ if (!Convert.IsString (thisObj))
+ throw new JScriptException (JSError.StringExpected);
+ else
+ return Convert.ToString (thisObj);
}
[MonoTODO ("I18N Needs checking -- contact flgr@ccan.de for details")]
{
IConvertible ic = value as IConvertible;
TypeCode tc = Convert.GetTypeCode (value, ic);
+
+ if (Convert.IsNumberTypeCode (tc))
+ return "number";
switch (tc) {
- case TypeCode.Char:
- case TypeCode.Int32:
- case TypeCode.Double:
- return "number";
-
case TypeCode.String:
return "string";
missing = params_info.Length - n;
for (int k = 0; k < missing; k++)
- ig.Emit (OpCodes.Ldsfld, typeof (DBNull).GetField ("Value"));
+ ig.Emit (OpCodes.Ldnull);
}
}