The base variable class, should be used for [bool, float, string] by-reference thread-safe
Inheritance: IKeyed
Beispiel #1
0
		internal Personality(VM vm, string name, string id)
		{
			VM = vm;
			// These variables MUST always be set:
			variables["name"] = name_var = new Variable(name);
			variables["id"] = id_var = new Variable(id) { Readonly = true };
			variables["enabled_user"] = enabledUser_var = new Variable(true);
			variables["birthday"] = new Variable(new VType.Date(DateTime.MinValue));

			// readonly age, returns DateTime.Now - BirthDay
			variables["age"] = new VariableFunc(() =>
			{
				try
				{
					var span = DateTime.Now - ((VType.Date)variables["birthday"].Value).Value;
					return (float)(new DateTime(1, 1, 1) + span).Year - 1f;
				}
				catch (ArgumentOutOfRangeException)
				{
					return -1f;
				}
			}, null);

			// ToDo 5: Add mood variables.
		}
Beispiel #2
0
		private static Variable elseif(Context sender, Variable[] args)
		{
			if (sender.LastIf == true)
				return new Variable(false);

			return @if(sender, args);
		}
Beispiel #3
0
		private static Variable @else(Context sender, Variable[] args)
		{
			if (args.Length != 0)
				sender.Root.Log.ErrorF(StringsScripting.Formatted_Function_arguments_not_empty, "Else");
			sender.ExitLine = sender.LastIf;
			sender.LastIf = !sender.ExitLine;
			return new Variable(sender.LastIf);
		}
Beispiel #4
0
		private static float toNumber(Variable v)
		{
			float result = 0f;
			if (v != null && v.IsSet)
				float.TryParse(v.Value.ToString(), out result);
			// ToDo 9: Log error if not number.
			return result;
		}
Beispiel #5
0
		private static Variable wait(Context sender, Variable[] args)
		{
			if (args.Length == 0)
				sender.Root.Log.WarningF(StringsScripting.Formatted_Function_arguments_empty, "Wait");
			else if (args.Length == 1)
				sender.Controller.Add(new Scripting.Events.Timed(new TimeSpan(0, 0, (int)toNumber(args[0])), false));
			else
				sender.Root.Log.WarningF(StringsScripting.Formatted_Function_arguments_more_than_one, "Wait");
			return null;
		}
Beispiel #6
0
		private static Variable restart(Context sender, Variable[] args)
		{
			if (args.Length != 0)
				sender.Root.Log.WarningF(StringsScripting.Formatted_Function_arguments_not_empty, "Restart");
			if (sender.Root.Valid == BlockBase.Validation.Passed)
			{
				sender.Repeat = true;
				sender.Line = 0;
			}
			return null;
		}
Beispiel #7
0
		public Variable Get(Key key, Logger log = null)
		{
			if (key.NextIf("local"))
			{
				Variable result;
				if (!Variables.TryGetValue(key.Peek, out result))
					Variables[key.Peek] = result = new Variable();
				return result;
			}
			else
				return Controller.Get(key, Root.Log);
		}
Beispiel #8
0
		private static Variable isSet(Context sender, Variable[] args)
		{
			if (args.Length == 0)
			{
				sender.Root.Log.WarningF(StringsScripting.Formatted_Function_arguments_empty, "IsSet");
				return new Variable(false);
			}
			foreach (var arg in args)
			{
				if (!arg.IsSet)
					return new Variable(false);
			}
			return new Variable(true);
		}
Beispiel #9
0
		private static Variable @if(Context sender, Variable[] args)
		{
			sender.ExitLine = false;
			foreach (var arg in args)
			{
				if (arg.IsSet == false)
					sender.ExitLine = true;
				else if (arg.Value is bool == false)
				{
					sender.Root.Log.ErrorF(StringsScripting.Formatted_Function_invalid_type, "If", arg.Value.GetType().Name, typeof(bool).Name);
					sender.ExitLine = true;
				}
				else if ((bool)arg.Value == false)
					sender.ExitLine = true;
			}

			sender.LastIf = !sender.ExitLine;
			return new Variable(sender.LastIf);
		}
Beispiel #10
0
		private static Variable random(Context sender, Variable[] args)
		{
			if (args.Length == 0)
				return new Variable((float)Random.NextDouble());

			int min = 0;
			int max = 0;
			if (args.Length == 1)
				max = (int)toNumber(args[0]);
			else if (args.Length == 2)
			{
				min = (int)toNumber(args[0]);
				max = (int)toNumber(args[1]);
			}
			else
				// ToDo : Add to strings:
				sender.Root.Log.WarningF("{0} Only accepts 0-2 arguments!", "Random");

			return new Variable((float)Random.Next(min, max));
		}
Beispiel #11
0
		private static Variable @goto(Context sender, Variable[] args)
		{
			if (args.Length == 0)
			{
				sender.Root.Log.ErrorF(StringsScripting.Formatted_Function_arguments_empty, "GoTo");
				return null;
			}
			int i = -1;
			foreach (var arg in args)
			{
				++i;
				if (!arg.IsSet)
					continue;

				BlockBase script = null;

				object value = arg.Value;
				if (value is BlockBase)
					script = (BlockBase)value;
				else if (value is VType.Query)
					script = sender.Controller.VM.QueryScript((VType.Query)value, sender.Root.Log);
				else if (value is string) // string can be a single query key.
					script = sender.Controller.VM.QueryScript((string)value, sender.Root.Log);
				else
					sender.Root.Log.ErrorF(StringsScripting.Formatted_Function_invalid_type, "GoTo", arg.Value.GetType().Name, typeof(Script).Name);

				if (script != null)
				{
					if (ReferenceEquals(script, sender.Root))
						sender.Root.Log.Error(StringsScripting.FunctionGoTo_cannot_goto_self);
					else if (sender.Root.Valid != BlockBase.Validation.Running)
						sender.Controller.Add(script);
				}
			}
			return null;
		}
Beispiel #12
0
		/// <summary> gets key and parentheses as args. </summary>
		/// <param name="i"> indexer, expected to start on the first character of the key. </param>
		/// <param name="key"> set to null if no key. </param>
		/// <param name="args"> never null </param>
		internal void execSplitCommand(Context sender, string str, ref int i, out string key, out Variable[] args)
		{
			args = null;
			var sb = new StringBuilder();
			char c;
			while (i < str.Length)
			{
				c = str[i];
				if (c == ' ')
					break;
				else if (c == '(')
				{
					++i;
					args = execParentheses(sender, str, ref i);
					break;
				}
				else
					++i;
				sb.Append(c);
			}
			if (sb.Length > 0)
			{
				bool isFloat;
				bool isPercent;
				key = KeyClean(sb.ToString(), out isFloat, out isPercent, sender.Root.Log);
				if (isFloat || isPercent)
					sender.Root.Log.Warning(string.Format(StringsScripting.Formatted_Expected_key_got_number, key));
			}
			else
				key = null;
			if (args == null)
				args = new Variable[0];
		}
Beispiel #13
0
		public Script QueryScript(Variable query, Logger log)
		{
			if (query == null || !query.IsSet)
				log.Error(StringsScripting.Query_empty);
			else if (query.Value is VType.Query)
				return QueryScript((VType.Query)query.Value, log);
			else if (query.Value is string)
				return QueryScript((string)query.Value, log);
			else
				log.ErrorF(StringsScripting.Formatted_Invalid_Type, "Query", query.Value.GetType().Name);
			return null;
		}
Beispiel #14
0
		public bool ChangePersonalityID(Personality p, string newID)
		{
			newID = KeyClean(newID);
			if (personalities.ContainsKey(newID))
				return false;
			Dirty = true;
			Variable<Personality> var;
			if (personalities.TryRemove(p.ID, out var))
				personalities[newID] = var;
			else
				personalities[newID] = new Variable<Personality>(p);
			p.ID = newID;
			return true;
		}
Beispiel #15
0
		/// <summary>
		/// Craete a new personality with given name.
		/// </summary>
		/// <param name="name"></param>
		/// <returns>New Personality or null if name already exits.</returns>
		public Personality CreatePersonality(string name)
		{
			var id = KeyClean(name);
			Dirty = true;
			// If personality with id already exists, add number.
			if (personalities.ContainsKey(id))
			{
				int num = 1;
				while (personalities.ContainsKey(id + (++num)))
				{ }
				id = id + num;
			}

			var p = new Personality(this, name, id);
			personalities[id] = new Variable<Personality>(p);
			return p;
		}
Beispiel #16
0
		/// <summary>
		/// Recursively parses and executes everything in the parentheses, then returns variable array.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="str"></param>
		/// <param name="i"> indexer, must be equal to the char after '(' </param>
		/// <returns></returns>
		private Variable[] execParentheses(Context sender, string str, ref int i)
		{
			var log = sender.Root.Log;
			int start = i;
			var outArgs = new List<Variable>();
			outArgs.Add(null); // Set to the output before return.
			var items = new List<execParenthItem>();

			// Split in to lists of values and operators.
			var sb = new StringBuilder();
			bool finished = false;
			char c;
			while (i < str.Length && !finished)
			{
				c = str[i];
				switch (c)
				{
					// string
					case '"':
						execParenthCheckAdd(sender, items, sb);
						++i;
						items.Add(new Variable(parseStringQuoted(str, ref i, log)));
						continue;

					// finish parentheses
					case ')':
						finished = true;
						break;
					// sub parentheses
					case '(':
						{
							int count = items.Count;
							execParenthCheckAdd(sender, items, sb);
							// check if it's attached to a function
							bool funcParenth = false;
							if (count < items.Count && items[items.Count - 1].IsValue)
							{
								var v = items[items.Count - 1].Value;
								funcParenth = v.IsSet && v.Value is Function;
							}

							++i;
							var _char = i;
							var args = execParentheses(sender, str, ref i);

							if (funcParenth) // simply add the whole array as-is.
								items.Add(new Variable(args));
							else if (args.Length == 0)
								log.Warning(StringsScripting.Sub_parentheses_zero_arguments, -1, _char);
							else
							{
								items.Add(args[0]); // sense it's not for a function, we only care about the first arg.
								if (args.Length > 1)
									log.Warning(StringsScripting.Sub_parentheses_too_many_arguments, -1, _char);
							}
						}
						continue;

					// new arg
					case ',':
						execParenthCheckAdd(sender, items, sb);
						++i;
						outArgs.AddRange(execParentheses(sender, str, ref i));
						finished = true; // finished, sense execParentheses will go until end.
						continue;

					// white-space separates stuffs
					case ' ':
					case '\t':
						execParenthCheckAdd(sender, items, sb);
						break;

					// equal and assign
					case '=':
						execParenthCheckAdd(sender, items, sb);
						// (a=b) is not equal to (a==b). The first assigns b to a and returns a, second returns bool if a equals b.
						// so we must use different operators.
						if (i + 1 < str.Length && str[i + 1] == '=') // ==
						{ ++i; items.Add(Operators.Equal); }
						else // just a single =
							items.Add(Operators.Assign);
						break;

					// math
					case '*':
						execParenthCheckAdd(sender, items, sb);
						items.Add(Operators.Multiply);
						break;
					case '/':
						execParenthCheckAdd(sender, items, sb);
						items.Add(Operators.Divide);
						break;
					case '+':
						execParenthCheckAdd(sender, items, sb);
						items.Add(Operators.Add);
						break;
					case '-':
						execParenthCheckAdd(sender, items, sb);
						items.Add(Operators.Subtract);
						break;

					// logic
					// "and" "or" are handled in execParenthCheckAdd 
					case '>':
						execParenthCheckAdd(sender, items, sb);
						items.Add(Operators.More);
						break;
					case '<':
						execParenthCheckAdd(sender, items, sb);
						items.Add(Operators.Less);
						break;

					default:
						sb.Append(c);
						break;
				}
				++i;
			}
			execParenthCheckAdd(sender, items, sb);
			log.SetId(-1, start);

			// check if empty
			if (items.Count == 0)
			{
				log.Warning(StringsScripting.Parentheses_empty);
				return new Variable[0];
			}
			else if (items[0].IsValue == false && items[0].Operator != Operators.Not)
			{
				log.Error(StringsScripting.Parentheses_first_item_is_not_variable);
				return new Variable[0];
			}

			// Evaluate
			int j;

			// Operator precedence
			// 1. Parentheses          ( )
			// 2. Execute functions
			// 3. Logic Not            not
			// 4. Multiply & Divide    * /
			// 5. Add & Subtract       + -
			// 6. logic 1              > < ==
			// 7. logic 2             and or
			// 8. Assignment          =
			//Note: 'not' and assignment goes right to left.

			// 1. Done when we parse
			// 2. Execute functions
			j = 0;
			for (; j < items.Count; ++j)
			{
				if (items[j].IsValue)
				{
					var func = items[j].Value.Value as Function;
					if (func == null)
						continue;
					Variable[] args = null;
					// check if args is next item
					if (j + 1 < items.Count && items[j + 1].IsValue)
					{
						var argvar = items[j + 1].Value.Value as Variable[];
						if (argvar == null)
						{
							log.Error(StringsScripting.Parentheses_Expected_function_arguments);
							return new Variable[0];
						}
						args = argvar;
						items.RemoveAt(j + 1);
					}
					if (args == null)
						args = new Variable[0];
					items[j] = func(sender, args);
				}
			}

			// 3. Logic not
			j = items.Count - 2;
			while (j >= 0)
			{
				if (!items[j].IsValue && items[j].Operator == Operators.Not)
				{
					var r = items[j + 1].Value;
					items[j] = Variable.Evaluate(sender, null, Operators.Not, r);
					items.RemoveAt(j + 1);
				}
				--j;
			}

			// At this point it is required that there is exactly one operator inbetween each variable.
			j = 0;
			while (j + 2 < items.Count)
			{
				var l = items[j];
				var o = items[j + 1];
				var r = items[j + 2];
				if (!l.IsValue || !r.IsValue)
				{
					if (!l.IsValue)
						log.ErrorF(StringsScripting.Formatted_Expected_variable_got_operator, l.Operator);
					if (!r.IsValue)
						log.ErrorF(StringsScripting.Formatted_Expected_variable_got_operator, r.Operator);
					return new Variable[0];
				}
				else if (o.IsValue)
				{
					log.Error(StringsScripting.Expected_operator_got_variable);
					return new Variable[0];
				}
				else if (o.Operator == Operators.Not)
				{
					log.ErrorF(StringsScripting.Formatted_Unexpected_Operator, o.ToString());
					return new Variable[0];
				}
				j += 2;
			}

			// 4. Multiply & Divide
			j = 0;
			while (j + 2 < items.Count)
			{
				var l = items[j].Value;
				var op = items[j + 1].Operator;
				var r = items[j + 2].Value;
				if (op == Operators.Multiply || op == Operators.Divide)
				{
					items[j] = Variable.Evaluate(sender, l, op, r);
					items.RemoveRange(j + 1, 2);
				}
				else
					j += 2;
			}
			// 5. Add & Subtract
			j = 0;
			while (j + 2 < items.Count)
			{
				var l = items[j].Value;
				var op = items[j + 1].Operator;
				var r = items[j + 2].Value;
				if (op == Operators.Add || op == Operators.Subtract)
				{
					items[j] = Variable.Evaluate(sender, l, op, r);
					items.RemoveRange(j + 1, 2);
				}
				else
					j += 2;
			}
			// 6. logic 1
			j = 0;
			while (j + 2 < items.Count)
			{
				var l = items[j].Value;
				var op = items[j + 1].Operator;
				var r = items[j + 2].Value;
				if (op == Operators.More || op == Operators.Less || op == Operators.Equal)
				{
					items[j] = Variable.Evaluate(sender, l, op, r);
					items.RemoveRange(j + 1, 2);
				}
				else
					j += 2;
			}
			// 7. logic 2
			j = 0;
			while (j + 2 < items.Count)
			{
				var l = items[j].Value;
				var op = items[j + 1].Operator;
				var r = items[j + 2].Value;
				if (op == Operators.And || op == Operators.Or)
				{
					items[j] = Variable.Evaluate(sender, l, op, r);
					items.RemoveRange(j + 1, 2);
				}
				else
					j += 2;
			}
			// 8. Assignment
			j = items.Count - 1;
			while (j - 2 >= 0)
			{
				var l = items[j - 2].Value;
				var op = items[j - 1].Operator;
				var r = items[j - 0].Value;
				if (op == Operators.Assign)
				{
					items[j - 2] = Variable.Evaluate(sender, l, op, r);
					items.RemoveRange(j - 1, 2);
				}
				j -= 2;
			}

			// finily finished
			if (items.Count != 1)
			{
				// ToDo : probley just return a array of the items? (if not add to StringsScripting.txt)
				log.Error(string.Format("execParentheses items.Count is {0}, expecting a count of 1!", items.Count));
				return new Variable[0];
			}
			outArgs[0] = items[0].Value;
			return outArgs.ToArray();
		}
Beispiel #17
0
		private void writeValue(string prefix, StringBuilder sb, string key, Variable v)
		{
			if (v == null || !v.CanWriteValue())
				return;
			sb.Append(prefix);
			sb.Append("#(.");
			sb.Append(key);
			sb.Append("=");
			v.WriteValue(sb);
			sb.AppendLine(")");
		}
Beispiel #18
0
		public static Variable Evaluate(Context sender, Variable left, Operators op, Variable right)
		{
			var log = sender.Root.Log;
			bool validating = sender.Root.Valid == BlockBase.Validation.Running;
			object l = null, r;


			// make sure variable is not null.
			if (right == null)
			{
				log.Error(StringsScripting.Evaluate_null_variable);
				return null;
			}
			r = right.Value;
			if (op != Operators.Not) // "Not" doesn't use left variable.
			{
				if (left == null)
				{
					log.Error(StringsScripting.Evaluate_null_variable);
					return null;
				}
				l = left.Value;
			}

			// allow equals to work on unset variables.
			if (op == Operators.Equal)
			{
				if (l == null || r == null)
					return new Variable(l == null && r == null);
			}

			// make sure variable is set.
			if (!right.IsSet)
			{
				log.Error(string.Format(StringsScripting.Formatted_Evaluate_Operator_unset_variable, op.ToString())); // ToDo : Different error?
				return null;
			}
			if (op != Operators.Not && op != Operators.Assign) // "Not" and "Assign" can use a unset left variable.
			{
				if (!left.IsSet)
				{
					log.Error(string.Format(StringsScripting.Formatted_Evaluate_Operator_unset_variable, op.ToString())); // ToDo : Different error?
					return null;
				}
			}

			// Do not allow assign to readonly variables.
			if (op == Operators.Assign && left.Readonly)
			{
				log.Error(StringsScripting.Evaluate_Assign_Readonly);
				return null;
			}


			// try to evaluate the viriable value directly. 
			if (l is IVType)
			{
				var results = ((IVType)l).Evaluate(sender, left, op, right);
				if (results != null)
					return results;
			}
			if (r is IVType)
			{
				var results = ((IVType)r).Evaluate(sender, left, op, right);
				if (results != null)
					return results;
			}

			switch (op)
			{
				// logic not
				case Operators.Not:
					object value = right.Value;
					if (value is bool)
						return new Variable(!(bool)value);
					if (value is string)
						return new Variable(Query.Not((string)value));

					log.Error(string.Format(StringsScripting.Formatted_Evaluate_Operator_type_invalid, op.ToString(), "", value.GetType().Name));
					return null;

				// assign
				case Operators.Assign:
					if (left.IsSet)
					{
						if (l.GetType() == r.GetType())
						{
							if (!validating) // Don't change variable if we are validating.
								left.Value = r;
						}
						else
						{
							log.Error(string.Format(StringsScripting.Formatted_Evaluate_Assign_type_mismatch, l.GetType().Name, r.GetType().Name));
							return null;
						}
					}
					else
					{
						if (validating)
							left.Value = getDefault(right.Value.GetType());
						else
							left.Value = right.Value;
					}
					return left;


				// Math
				case Operators.Add:
					if (l is float && r is float)
						return new Variable((float)l + (float)r);
					if (l is string && r is string)
						return new Variable(string.Concat(l, r));
					log.Error(string.Format(StringsScripting.Formatted_Evaluate_Operator_type_invalid, op.ToString(), l.GetType().Name, r.GetType().Name));
					return null;

				case Operators.Subtract:
					if (l is float && r is float)
						return new Variable((float)l - (float)r);
					if (l is string && r is string)
						return new Variable(((string)l).Replace((string)r, ""));
					log.Error(string.Format(StringsScripting.Formatted_Evaluate_Operator_type_invalid, op.ToString(), l.GetType().Name, r.GetType().Name));
					return null;

				case Operators.Multiply:
					if (l is float && r is float)
						return new Variable((float)l * (float)r);
					if (l is float && r is bool)
						return new Variable((float)l * ((bool)r ? 1f : 0f));
					log.Error(string.Format(StringsScripting.Formatted_Evaluate_Operator_type_invalid, op.ToString(), l.GetType().Name, r.GetType().Name));
					return null;

				case Operators.Divide:
					if (l is float && r is float)
					{
						if (validating)
							return new Variable(default(float));
						float fl = (float)l;
						float fr = (float)r;
						if (fr == 0)
						{
							log.Warning(StringsScripting.Divide_by_zero);
							fr = 1;
						}
						return new Variable(fl / fr);
					}
					log.Error(string.Format(StringsScripting.Formatted_Evaluate_Operator_type_invalid, op.ToString(), l.GetType().Name, r.GetType().Name));
					return null;

				// Logic
				case Operators.Equal:
					if (l is string && r is string) // for strings we want to ignore the case.
						return new Variable((l as string).Equals((string)r, StringComparison.InvariantCultureIgnoreCase));
					return new Variable(l.Equals(r));
				case Operators.More:
					if (l is float && r is float)
						return new Variable((float)l > (float)r);
					log.Error(string.Format(StringsScripting.Formatted_Evaluate_Operator_type_invalid, op.ToString(), l.GetType().Name, r.GetType().Name));
					return null;
				case Operators.Less:
					if (l is float && r is float)
						return new Variable((float)l < (float)r);
					log.Error(string.Format(StringsScripting.Formatted_Evaluate_Operator_type_invalid, op.ToString(), l.GetType().Name, r.GetType().Name));
					return null;
				case Operators.And:
					if (l is bool && r is bool)
						return new Variable((bool)l && (bool)r);
					if (l is string && r is string)
						return new Variable(new Query((string)l, op, (string)r));
					log.Error(string.Format(StringsScripting.Formatted_Evaluate_Operator_type_invalid, op.ToString(), l.GetType().Name, r.GetType().Name));
					return null;
				case Operators.Or:
					if (l is bool && r is bool)
						return new Variable((bool)l || (bool)r);
					if (l is string && r is string)
						return new Variable(new Query((string)l, op, (string)r));
					log.Error(string.Format(StringsScripting.Formatted_Evaluate_Operator_type_invalid, op.ToString(), l.GetType().Name, r.GetType().Name));
					return null;
			}
			log.Error(string.Format(StringsScripting.Formatted_Evaluate_Invalid_operator, op.ToString()));
			return null;
		}
Beispiel #19
0
		public Variable(Variable[] value)
		{ _value = value; }
Beispiel #20
0
		private static Variable date(Context sender, Variable[] args)
		{
			if (args.Length == 0)
				return new Variable(new Date(DateTime.Now));
			if (args.Length == 1)
			{
				if (!args[0].IsSet)
					sender.Root.Log.ErrorF(StringsScripting.Formatted_Function_argument_unset, "Date", "");
				else if (args[0].Value is string)
				{
					DateTime result;
					try
					{
						if (DateTime.TryParse((string)args[0].Value, out result))
							return new Variable(new Date(result));
						else
							sender.Root.Log.ErrorF(StringsScripting.Formatted_Unable_to_parse, "Date", (string)args[0].Value, typeof(DateTime).Name);
					}
					catch (ArgumentOutOfRangeException ex)
					{ sender.Root.Log.Error(ex.Message); }
				}
				else
					sender.Root.Log.ErrorF(StringsScripting.Formatted_Function_invalid_type, "Date", args[0].Value.GetType().Name, typeof(string).Name);
				return new Variable(new Date(DateTime.Now));
			}
			else
				sender.Root.Log.WarningF(StringsScripting.Formatted_Function_arguments_less_than_two, "Date");
			return new Variable(new Date(DateTime.Now));
		}
Beispiel #21
0
		private static Variable time(Context sender, Variable[] args)
		{
			if (args.Length == 0)
				return new Variable(new TimeFrame(TimeSpan.Zero));
			if (args.Length == 1)
			{
				if (!args[0].IsSet)
					sender.Root.Log.ErrorF(StringsScripting.Formatted_Function_argument_unset, "Time", "");
				else if (args[0].Value is string)
				{
					TimeSpan result;
					if (TimeSpan.TryParse((string)args[0].Value, out result))
						return new Variable(new TimeFrame(result));
					else
						sender.Root.Log.ErrorF(StringsScripting.Formatted_Unable_to_parse, "Time", (string)args[0].Value, typeof(TimeSpan).Name);
				}
				else
					sender.Root.Log.ErrorF(StringsScripting.Formatted_Function_invalid_type, "Time", args[0].Value.GetType().Name, typeof(string).Name);
				return new Variable(new TimeFrame(TimeSpan.Zero));
			}
			else
				sender.Root.Log.WarningF(StringsScripting.Formatted_Function_arguments_less_than_two, "Time");
			return new Variable(new TimeFrame(TimeSpan.Zero));
		}