public ScriptEngine() { currentLexer = null; scopes = new List <ScriptVar>(); callStack = new Stack <ScriptVarLink>(); Root = (new ScriptVar(null, ScriptVar.Flags.Object)).Ref(); objectClass = (new ScriptVar(null, ScriptVar.Flags.Object)).Ref(); stringClass = (new ScriptVar(null, ScriptVar.Flags.Object)).Ref(); arrayClass = (new ScriptVar(null, ScriptVar.Flags.Object)).Ref(); Root.AddChild("Object", objectClass); Root.AddChild("String", stringClass); Root.AddChild("Array", arrayClass); }
public ScriptEngine(bool loadProviders = true) { _currentLexer = null; _scopes = new Stack <ScriptVar>(); _callStack = new Stack <string>(); Root = (new ScriptVar(null, ScriptVar.Flags.Object)).Ref(); _stringClass = (new ScriptVar(null, ScriptVar.Flags.Object)).Ref(); _objectClass = (new ScriptVar(null, ScriptVar.Flags.Object)).Ref(); _arrayClass = (new ScriptVar(null, ScriptVar.Flags.Object)).Ref(); Root.AddChild("String", _stringClass); Root.AddChild("Object", _objectClass); Root.AddChild("Array", _arrayClass); if (loadProviders) { LoadAllFunctionProviders(); } }
public void AddObject(String[] ns, String objectName, ScriptVar val) { ScriptVar baseVar = Root; if (ns != null) { int x = 0; for (; x < ns.Length; x++) { ScriptVarLink link = baseVar.FindChild(ns[x]); if (link == null) { link = baseVar.AddChild(ns[x], new ScriptVar(null, ScriptVar.Flags.Object)); } baseVar = link.Var; } } baseVar.AddChild(objectName, val); }
public void AddMethod(String funcProto, ScriptCallbackCB callback, Object userdata) { ScriptLex oldLex = _currentLexer; using (_currentLexer = new ScriptLex(funcProto)) { ScriptVar baseVar = Root; _currentLexer.Match(ScriptLex.LexTypes.RFunction); String funcName = _currentLexer.TokenString; _currentLexer.Match(ScriptLex.LexTypes.Id); while (_currentLexer.TokenType == (ScriptLex.LexTypes) '.') { _currentLexer.Match((ScriptLex.LexTypes) '.'); ScriptVarLink link = baseVar.FindChild(funcName); if (link == null) { link = baseVar.AddChild(funcName, new ScriptVar(null, ScriptVar.Flags.Object)); } baseVar = link.Var; funcName = _currentLexer.TokenString; _currentLexer.Match(ScriptLex.LexTypes.Id); } ScriptVar funcVar = new ScriptVar(null, ScriptVar.Flags.Function | ScriptVar.Flags.Native); funcVar.SetCallback(callback, userdata); ParseFunctionArguments(funcVar); baseVar.AddChild(funcName, funcVar); } _currentLexer = oldLex; }
public void AddMethod(String[] ns, String funcName, String[] args, ScriptCallbackCB callback, Object userdata) { String fName = funcName; ScriptVar baseVar = Root; if (ns != null) { int x = 0; for (; x < ns.Length; x++) { ScriptVarLink link = baseVar.FindChild(ns[x]); if (link == null) { link = baseVar.AddChild(ns[x], new ScriptVar(null, ScriptVar.Flags.Object)); } baseVar = link.Var; } } ScriptVar funcVar = new ScriptVar(null, ScriptVar.Flags.Function | ScriptVar.Flags.Native); funcVar.SetCallback(callback, userdata); //do we have any arguments to create? if (args != null) { foreach (string arg in args) { funcVar.AddChildNoDup(arg, null); } } baseVar.AddChild(fName, funcVar); }
public ScriptVar DeepCopy() { ScriptVar newVar = new ScriptVar(); newVar.CopySimpleData(this); ScriptVarLink link = FirstChild; while (link != null) { ScriptVar copied = link.Name != PrototypeClassName?link.Var.DeepCopy() : link.Var; newVar.AddChild(link.Name, copied); link = link.Next; } return(newVar); }
private ScriptVarLink FunctionCall(ref bool execute, ScriptVarLink function, ScriptVar parent) { if (execute) { if (!function.Var.IsFunction) { throw new ScriptException(String.Format("{0} is not a function", function.Name)); } currentLexer.Match((ScriptLex.LexTypes) '('); var functionRoot = new ScriptVar(null, ScriptVar.Flags.Function); if (parent != null) { functionRoot.AddChildNoDup("this", parent); } var v = function.Var.FirstChild; while (v != null) { var value = Base(ref execute); if (execute) { if (value.Var.IsBasic) { //pass by val functionRoot.AddChild(v.Name, value.Var.DeepCopy()); } else { //pass by ref functionRoot.AddChild(v.Name, value.Var); } } if (currentLexer.TokenType != (ScriptLex.LexTypes) ')') { currentLexer.Match((ScriptLex.LexTypes) ','); } v = v.Next; } currentLexer.Match((ScriptLex.LexTypes) ')'); var returnVarLink = functionRoot.AddChild(ScriptVar.ReturnVarName, null); scopes.PushBack(functionRoot); //callStack.PushBack(string.Format("{0} from line {1}", function.Name, currentLexer.LineNumber)); callStack.Push(function); if (function.Var.IsNative) { var func = function.Var.GetCallback(); func?.Invoke(functionRoot, function.Var.GetCallbackUserData()); } else { var oldLex = currentLexer; var newLex = new ScriptLex(function.Var.String); currentLexer = newLex; try { Block(ref execute); execute = true; } catch { throw; } finally { currentLexer = oldLex; } } callStack.Pop(); scopes.PopBack(); var returnVar = new ScriptVarLink(returnVarLink.Var, null); functionRoot.RemoveLink(returnVarLink); return(returnVar); } else { //not executing the function, just parsing it out currentLexer.Match((ScriptLex.LexTypes) '('); while (currentLexer.TokenType != (ScriptLex.LexTypes) ')') { Base(ref execute); if (currentLexer.TokenType != (ScriptLex.LexTypes) ')') { currentLexer.Match((ScriptLex.LexTypes) ','); } } currentLexer.Match((ScriptLex.LexTypes) ')'); if (currentLexer.TokenType == (ScriptLex.LexTypes) '{') //WTF? { Block(ref execute); } return(function); } }
private ScriptVarLink FunctionCall(ref bool execute, ScriptVarLink function, ScriptVar parent) { if (execute) { if (!function.Var.IsFunction) { throw new ScriptException(String.Format("{0} is not a function", function.Name)); } _currentLexer.Match((ScriptLex.LexTypes) '('); ScriptVar functionRoot = new ScriptVar(null, ScriptVar.Flags.Function); if (parent != null) { functionRoot.AddChildNoDup("this", parent); } ScriptVarLink v = function.Var.FirstChild; while (v != null) { ScriptVarLink value = Base(ref execute); if (value.Var.IsBasic) { //pass by val functionRoot.AddChild(v.Name, value.Var.DeepCopy()); } else { //pass by ref functionRoot.AddChild(v.Name, value.Var); } if (_currentLexer.TokenType != (ScriptLex.LexTypes) ')') { _currentLexer.Match((ScriptLex.LexTypes) ','); } v = v.Next; } _currentLexer.Match((ScriptLex.LexTypes) ')'); ScriptVarLink returnVarLink = functionRoot.AddChild(ScriptVar.ReturnVarName, null); _scopes.Push(functionRoot); _callStack.Push(String.Format("{0} from line {1}", function.Name, _currentLexer.LineNumber)); if (function.Var.IsNative) { ScriptCallbackCB func = function.Var.GetCallback(); if (func != null) { func(functionRoot, function.Var.GetCallbackUserData(), parent); } } else { ScriptException ex = null; ScriptLex oldLex = _currentLexer; ScriptLex newLex = new ScriptLex(function.Var.GetString()); _currentLexer = newLex; try { Block(ref execute); execute = true; } catch (ScriptException e) { ex = e; } _currentLexer = oldLex; if (ex != null) { throw ex; } } _callStack.Pop(); _scopes.Pop(); ScriptVarLink returnVar = new ScriptVarLink(returnVarLink.Var, null); functionRoot.RemoveLink(returnVarLink); return(returnVar); } //not executing the function, just parsing it out _currentLexer.Match((ScriptLex.LexTypes) '('); while (_currentLexer.TokenType != (ScriptLex.LexTypes) ')') { Base(ref execute); if (_currentLexer.TokenType != (ScriptLex.LexTypes) ')') { _currentLexer.Match((ScriptLex.LexTypes) ','); } } _currentLexer.Match((ScriptLex.LexTypes) ')'); if (_currentLexer.TokenType == (ScriptLex.LexTypes) '{') //WTF? { Block(ref execute); } return(function); }
private void Statement(ref bool execute) { if (currentLexer.TokenType == (ScriptLex.LexTypes) '{') { //code block Block(ref execute); } else if (currentLexer.TokenType == (ScriptLex.LexTypes) ';') { //allow for multiple semi colon such as ;;; currentLexer.Match((ScriptLex.LexTypes) ';'); } else if (currentLexer.TokenType == ScriptLex.LexTypes.RVar || currentLexer.TokenType == ScriptLex.LexTypes.RConst) { //creating variables //TODO: make this less shit var readOnly = currentLexer.TokenType == ScriptLex.LexTypes.RConst; currentLexer.Match(currentLexer.TokenType); while (currentLexer.TokenType != (ScriptLex.LexTypes) ';') { ScriptVarLink a = null; if (execute) { a = scopes.Back().FindChildOrCreate(currentLexer.TokenString, ScriptVar.Flags.Undefined, readOnly); } currentLexer.Match(ScriptLex.LexTypes.Id); //get through the dots while (currentLexer.TokenType == (ScriptLex.LexTypes) '.') { currentLexer.Match((ScriptLex.LexTypes) '.'); if (execute) { var aLast = a; if (aLast != null) { a = aLast.Var.FindChildOrCreate(currentLexer.TokenString); } } currentLexer.Match(ScriptLex.LexTypes.Id); } //initialiser if (currentLexer.TokenType == (ScriptLex.LexTypes) '=') { currentLexer.Match((ScriptLex.LexTypes) '='); var varLink = Base(ref execute); if (execute) { if (a != null) { a.ReplaceWith(varLink); } } } if (currentLexer.TokenType != (ScriptLex.LexTypes) ';') { currentLexer.Match((ScriptLex.LexTypes) ','); } } currentLexer.Match((ScriptLex.LexTypes) ';'); } else if (currentLexer.TokenType == ScriptLex.LexTypes.RIf) { //if condition currentLexer.Match(ScriptLex.LexTypes.RIf); currentLexer.Match((ScriptLex.LexTypes) '('); var varLink = Base(ref execute); currentLexer.Match((ScriptLex.LexTypes) ')'); bool condition = execute && varLink.Var.Bool; bool noExecute = false; if (condition) { Statement(ref execute); } else { Statement(ref noExecute); } if (currentLexer.TokenType == ScriptLex.LexTypes.RElse) { //else part of an if currentLexer.Match(ScriptLex.LexTypes.RElse); if (condition) { Statement(ref noExecute); } else { Statement(ref execute); } } } else if (currentLexer.TokenType == ScriptLex.LexTypes.RWhile) { //while loop currentLexer.Match(ScriptLex.LexTypes.RWhile); currentLexer.Match((ScriptLex.LexTypes) '('); var whileConditionStart = currentLexer.TokenStart; var noExecute = false; var condition = Base(ref execute); var loopCondition = execute && condition.Var.Bool; var whileCond = currentLexer.GetSubLex(whileConditionStart); currentLexer.Match((ScriptLex.LexTypes) ')'); var whileBodyStart = currentLexer.TokenStart; if (loopCondition) { Statement(ref execute); } else { Statement(ref noExecute); } var whileBody = currentLexer.GetSubLex(whileBodyStart); var oldLex = currentLexer; //TODO: possible maximum itteration limit? while (loopCondition) { whileCond.Reset(); currentLexer = whileCond; condition = Base(ref execute); loopCondition = execute && condition.Var.Bool; if (loopCondition) { whileBody.Reset(); currentLexer = whileBody; Statement(ref execute); } } currentLexer = oldLex; } else if (currentLexer.TokenType == ScriptLex.LexTypes.RFor) { //for loop currentLexer.Match(ScriptLex.LexTypes.RFor); currentLexer.Match((ScriptLex.LexTypes) '('); Statement(ref execute); //init var forConditionStart = currentLexer.TokenStart; var condition = Base(ref execute); var noExecute = false; var loopCondition = execute && condition.Var.Bool; var forCondition = currentLexer.GetSubLex(forConditionStart); currentLexer.Match((ScriptLex.LexTypes) ';'); var forIterStart = currentLexer.TokenStart; Base(ref noExecute); var forIter = currentLexer.GetSubLex(forIterStart); currentLexer.Match((ScriptLex.LexTypes) ')'); var forBodyStart = currentLexer.TokenStart; if (loopCondition) { Statement(ref execute); } else { Statement(ref noExecute); } var forBody = currentLexer.GetSubLex(forBodyStart); var oldLex = currentLexer; if (loopCondition) { forIter.Reset(); currentLexer = forIter; Base(ref execute); } //TODO: limit number of iterations? while (execute && loopCondition) { forCondition.Reset(); currentLexer = forCondition; condition = Base(ref execute); loopCondition = condition.Var.Bool; if (execute && loopCondition) { forBody.Reset(); currentLexer = forBody; Statement(ref execute); } if (execute && loopCondition) { forIter.Reset(); currentLexer = forIter; Base(ref execute); } } currentLexer = oldLex; } else if (currentLexer.TokenType == ScriptLex.LexTypes.RReturn) { currentLexer.Match(ScriptLex.LexTypes.RReturn); ScriptVarLink res = null; if (currentLexer.TokenType != (ScriptLex.LexTypes) ';') { res = Base(ref execute); } if (execute) { var resultVar = scopes.Back().FindChild(ScriptVar.ReturnVarName); if (resultVar != null) { resultVar.ReplaceWith(res); } else { //return statement outside of function??? System.Diagnostics.Trace.TraceWarning("Return statement outside of a function, what is going on?"); } execute = false; } currentLexer.Match((ScriptLex.LexTypes) ';'); } else if (currentLexer.TokenType == ScriptLex.LexTypes.RFunction) { //function var funcVar = ParseFunctionDefinition(); if (execute) { if (funcVar.Name == string.Empty) { //functions must have a name at statement level } else { var v = scopes.Back(); v.AddChildNoDup(funcVar.Name, funcVar.Var); } } } else if (currentLexer.TokenType == ScriptLex.LexTypes.RTry) { var tryBlock = ParseDefinition(ScriptLex.LexTypes.RTry); ScriptVarLink catchBlock = null, finallyBlock = null; var originalLexer = currentLexer; if (currentLexer.TokenType == ScriptLex.LexTypes.RCatch) { catchBlock = ParseDefinition(ScriptLex.LexTypes.RCatch); } if (currentLexer.TokenType == ScriptLex.LexTypes.RFinally) { finallyBlock = ParseDefinition(ScriptLex.LexTypes.RFinally); } try { var oldLex = currentLexer; var newLex = new ScriptLex(tryBlock.Var.String); currentLexer = newLex; Block(ref execute); execute = true; currentLexer = oldLex; } catch (JITException ex) { if (catchBlock != null) { var catchScope = new ScriptVar(null, ScriptVar.Flags.Object); var v = catchBlock?.Var?.FirstChild; if (v != null) { catchScope.AddChild(v.Name, ex.VarObj); } var oldLex = currentLexer; var newLex = new ScriptLex(catchBlock.Var.String); currentLexer = newLex; scopes.PushBack(catchScope); Block(ref execute); scopes.PopBack(); execute = true; currentLexer = oldLex; } else { throw new ScriptException(ex.Message, ex); } } finally { if (finallyBlock != null) { var oldLex = currentLexer; var newLex = new ScriptLex(finallyBlock.Var.String); currentLexer = newLex; Block(ref execute); execute = true; currentLexer = oldLex; } } currentLexer = originalLexer; } else if (currentLexer.TokenType == ScriptLex.LexTypes.RThrow) { currentLexer.Match(ScriptLex.LexTypes.RThrow); ScriptVar message = new ScriptVar(); if (currentLexer.TokenType == (ScriptLex.LexTypes) ';') { currentLexer.Match((ScriptLex.LexTypes) ';'); } else { var res = Base(ref execute); message = res.Var; } throw new JITException(message); } else { //execute a basic statement Base(ref execute); currentLexer.Match((ScriptLex.LexTypes) ';'); } }
private ScriptVarLink Factor(ref bool execute) { if (currentLexer.TokenType == (ScriptLex.LexTypes) '(') { currentLexer.Match((ScriptLex.LexTypes) '('); var a = Base(ref execute); currentLexer.Match((ScriptLex.LexTypes) ')'); return(a); } if (currentLexer.TokenType == ScriptLex.LexTypes.RTrue) { currentLexer.Match(ScriptLex.LexTypes.RTrue); return(new ScriptVarLink(new ScriptVar(1), null)); } if (currentLexer.TokenType == ScriptLex.LexTypes.RFalse) { currentLexer.Match(ScriptLex.LexTypes.RFalse); return(new ScriptVarLink(new ScriptVar(0), null)); } if (currentLexer.TokenType == ScriptLex.LexTypes.RNull) { currentLexer.Match(ScriptLex.LexTypes.RNull); return(new ScriptVarLink(new ScriptVar(null, ScriptVar.Flags.Null), null)); } if (currentLexer.TokenType == ScriptLex.LexTypes.RUndefined) { currentLexer.Match(ScriptLex.LexTypes.RUndefined); return(new ScriptVarLink(new ScriptVar(null, ScriptVar.Flags.Undefined), null)); } if (currentLexer.TokenType == ScriptLex.LexTypes.Id) { var a = execute ? FindInScopes(currentLexer.TokenString) : new ScriptVarLink(new ScriptVar(), null); ScriptVar parent = null; if (execute && a == null) { a = new ScriptVarLink(new ScriptVar(), currentLexer.TokenString); } currentLexer.Match(ScriptLex.LexTypes.Id); while (currentLexer.TokenType == (ScriptLex.LexTypes) '(' || currentLexer.TokenType == (ScriptLex.LexTypes) '.' || currentLexer.TokenType == (ScriptLex.LexTypes) '[') { if (currentLexer.TokenType == (ScriptLex.LexTypes) '(') // function call { a = FunctionCall(ref execute, a, parent); } else if (currentLexer.TokenType == (ScriptLex.LexTypes) '.') // child access { currentLexer.Match((ScriptLex.LexTypes) '.'); if (execute) { var name = currentLexer.TokenString; var child = a.Var.FindChild(name); if (child == null) { child = FindInParentClasses(a.Var, name); } if (child == null) { if (a.Var.IsArray && name == "length") { var length = a.Var.GetArrayLength(); child = new ScriptVarLink(new ScriptVar(length), null); } else if (a.Var.IsString && name == "length") { var length = a.Var.String.Length; child = new ScriptVarLink(new ScriptVar(length), null); } else { child = a.Var.AddChild(name, null); } } parent = a.Var; a = child; } currentLexer.Match(ScriptLex.LexTypes.Id); } else if (currentLexer.TokenType == (ScriptLex.LexTypes) '[') // array access { currentLexer.Match((ScriptLex.LexTypes) '['); var index = Base(ref execute); currentLexer.Match((ScriptLex.LexTypes) ']'); if (execute) { var child = a.Var.FindChildOrCreate(index.Var.String); parent = a.Var; a = child; } } else { throw new ScriptException("WTF?"); } } return(a); } if (currentLexer.TokenType == ScriptLex.LexTypes.Int || currentLexer.TokenType == ScriptLex.LexTypes.Float) { var a = new ScriptVar(currentLexer.TokenString, currentLexer.TokenType == ScriptLex.LexTypes.Int ? ScriptVar.Flags.Integer : ScriptVar.Flags.Double); currentLexer.Match(currentLexer.TokenType); return(new ScriptVarLink(a, null)); } if (currentLexer.TokenType == ScriptLex.LexTypes.Str) { var a = new ScriptVar(currentLexer.TokenString, ScriptVar.Flags.String); currentLexer.Match(currentLexer.TokenType); return(new ScriptVarLink(a, null)); } if (currentLexer.TokenType == (ScriptLex.LexTypes) '{') { var contents = new ScriptVar(null, ScriptVar.Flags.Object); //looking for JSON like objects currentLexer.Match((ScriptLex.LexTypes) '{'); while (currentLexer.TokenType != (ScriptLex.LexTypes) '}') { var id = currentLexer.TokenString; if (currentLexer.TokenType == ScriptLex.LexTypes.Str) { currentLexer.Match(ScriptLex.LexTypes.Str); } else { currentLexer.Match(ScriptLex.LexTypes.Id); } currentLexer.Match((ScriptLex.LexTypes) ':'); if (execute) { var a = Base(ref execute); contents.AddChild(id, a.Var); } if (currentLexer.TokenType != (ScriptLex.LexTypes) '}') { currentLexer.Match((ScriptLex.LexTypes) ','); } } currentLexer.Match((ScriptLex.LexTypes) '}'); return(new ScriptVarLink(contents, null)); } if (currentLexer.TokenType == (ScriptLex.LexTypes) '[') { int idx = 0; var contents = new ScriptVar(null, ScriptVar.Flags.Array); //looking for JSON like arrays currentLexer.Match((ScriptLex.LexTypes) '['); while (currentLexer.TokenType != (ScriptLex.LexTypes) ']') { if (execute) { var id = string.Format("{0}", idx); var a = Base(ref execute); contents.AddChild(id, a.Var); } if (currentLexer.TokenType != (ScriptLex.LexTypes) ']') { currentLexer.Match((ScriptLex.LexTypes) ','); } idx++; } currentLexer.Match((ScriptLex.LexTypes) ']'); return(new ScriptVarLink(contents, null)); } if (currentLexer.TokenType == ScriptLex.LexTypes.RFunction) { var funcVar = ParseFunctionDefinition(); if (funcVar.Name != string.Empty) { System.Diagnostics.Trace.TraceWarning("Functions not defined at statement level are not supposed to have a name"); } return(funcVar); } if (currentLexer.TokenType == ScriptLex.LexTypes.RNew) // new { currentLexer.Match(ScriptLex.LexTypes.RNew); var className = currentLexer.TokenString; if (execute) { var classOrFuncObject = FindInScopes(className); if (classOrFuncObject == null) { System.Diagnostics.Trace.TraceWarning("{0} is not a valid class name", className); return(new ScriptVarLink(new ScriptVar(), null)); } currentLexer.Match(ScriptLex.LexTypes.Id); var obj = new ScriptVar(null, ScriptVar.Flags.Object); var objLink = new ScriptVarLink(obj, null); if (classOrFuncObject.Var.IsFunction) { FunctionCall(ref execute, classOrFuncObject, obj); } else { obj.AddChild(ScriptVar.PrototypeClassName, classOrFuncObject.Var); if (currentLexer.TokenType == (ScriptLex.LexTypes) '(') { currentLexer.Match((ScriptLex.LexTypes) '('); currentLexer.Match((ScriptLex.LexTypes) ')'); } } return(objLink); } else { currentLexer.Match(ScriptLex.LexTypes.Id); if (currentLexer.TokenType == (ScriptLex.LexTypes) '(') { currentLexer.Match((ScriptLex.LexTypes) '('); currentLexer.Match((ScriptLex.LexTypes) ')'); } } } if (currentLexer.TokenType == ScriptLex.LexTypes.RegExp) { var a = new ScriptVar(currentLexer.TokenString, ScriptVar.Flags.Regexp); currentLexer.Match(currentLexer.TokenType); return(new ScriptVarLink(a, null)); } currentLexer.Match(ScriptLex.LexTypes.Eof); return(null); }
private ScriptVarLink Factor(ref bool execute) { if (_currentLexer.TokenType == (ScriptLex.LexTypes) '(') { _currentLexer.Match((ScriptLex.LexTypes) '('); ScriptVarLink a = Base(ref execute); _currentLexer.Match((ScriptLex.LexTypes) ')'); return(a); } if (_currentLexer.TokenType == ScriptLex.LexTypes.RTrue) { _currentLexer.Match(ScriptLex.LexTypes.RTrue); return(new ScriptVarLink(new ScriptVar(1), null)); } if (_currentLexer.TokenType == ScriptLex.LexTypes.RFalse) { _currentLexer.Match(ScriptLex.LexTypes.RTrue); return(new ScriptVarLink(new ScriptVar(0), null)); } if (_currentLexer.TokenType == ScriptLex.LexTypes.RNull) { _currentLexer.Match(ScriptLex.LexTypes.RUndefined); return(new ScriptVarLink(new ScriptVar(null, ScriptVar.Flags.Null), null)); } if (_currentLexer.TokenType == ScriptLex.LexTypes.RUndefined) { _currentLexer.Match(ScriptLex.LexTypes.RUndefined); return(new ScriptVarLink(new ScriptVar(null, ScriptVar.Flags.Undefined), null)); } if (_currentLexer.TokenType == ScriptLex.LexTypes.Id) { ScriptVarLink a = execute ? FindInScopes(_currentLexer.TokenString) : new ScriptVarLink(new ScriptVar(), null); ScriptVar parent = null; if (execute && a == null) { a = new ScriptVarLink(new ScriptVar(), _currentLexer.TokenString); } _currentLexer.Match(ScriptLex.LexTypes.Id); while (_currentLexer.TokenType == (ScriptLex.LexTypes) '(' || _currentLexer.TokenType == (ScriptLex.LexTypes) '.' || _currentLexer.TokenType == (ScriptLex.LexTypes) '[') { if (_currentLexer.TokenType == (ScriptLex.LexTypes) '(') // function call { a = FunctionCall(ref execute, a, parent); } else if (_currentLexer.TokenType == (ScriptLex.LexTypes) '.') // child access { _currentLexer.Match((ScriptLex.LexTypes) '.'); if (execute) { if (!a.Var.IsObject) { throw new ScriptException("Trying to call object member on non object type"); } String name = _currentLexer.TokenString; ScriptVarLink child = a.Var.FindChild(name); if (child == null) { child = FindInParentClasses(a.Var, name); } if (child == null) { if (a.Var.IsArray && name == "length") { Int32 length = a.Var.GetArrayLength(); child = new ScriptVarLink(new ScriptVar(length), null); } else if (a.Var.IsString && name == "length") { Int32 length = a.Var.GetString().Length; child = new ScriptVarLink(new ScriptVar(length), null); } else { child = a.Var.AddChild(name, null); } } parent = a.Var; a = child; } _currentLexer.Match(ScriptLex.LexTypes.Id); } else if (_currentLexer.TokenType == (ScriptLex.LexTypes) '[') // array access { _currentLexer.Match((ScriptLex.LexTypes) '['); ScriptVarLink index = Base(ref execute); _currentLexer.Match((ScriptLex.LexTypes) ']'); if (execute) { ScriptVarLink child = a.Var.FindChildOrCreate(index.Var.GetString()); parent = a.Var; a = child; } } else { throw new ScriptException("WTF?"); } } return(a); } if (_currentLexer.TokenType == ScriptLex.LexTypes.Int || _currentLexer.TokenType == ScriptLex.LexTypes.Float) { ScriptVar a = new ScriptVar(_currentLexer.TokenString, _currentLexer.TokenType == ScriptLex.LexTypes.Int ? ScriptVar.Flags.Integer : ScriptVar.Flags.Double); _currentLexer.Match(_currentLexer.TokenType); return(new ScriptVarLink(a, null)); } if (_currentLexer.TokenType == ScriptLex.LexTypes.Str) { ScriptVar a = new ScriptVar(_currentLexer.TokenString, ScriptVar.Flags.String); _currentLexer.Match(_currentLexer.TokenType); return(new ScriptVarLink(a, null)); } if (_currentLexer.TokenType == (ScriptLex.LexTypes) '{') { ScriptVar contents = new ScriptVar(null, ScriptVar.Flags.Object); //looking for JSON like objects _currentLexer.Match((ScriptLex.LexTypes) '{'); while (_currentLexer.TokenType != (ScriptLex.LexTypes) '}') { String id = _currentLexer.TokenString; if (_currentLexer.TokenType == ScriptLex.LexTypes.Str) { _currentLexer.Match(ScriptLex.LexTypes.Str); } else { _currentLexer.Match(ScriptLex.LexTypes.Id); } _currentLexer.Match((ScriptLex.LexTypes) ':'); if (execute) { ScriptVarLink a = Base(ref execute); contents.AddChild(id, a.Var); } if (_currentLexer.TokenType != (ScriptLex.LexTypes) '}') { _currentLexer.Match((ScriptLex.LexTypes) ','); } } _currentLexer.Match((ScriptLex.LexTypes) '}'); return(new ScriptVarLink(contents, null)); } if (_currentLexer.TokenType == (ScriptLex.LexTypes) '[') { Int32 idx = 0; ScriptVar contents = new ScriptVar(null, ScriptVar.Flags.Array); //looking for JSON like arrays _currentLexer.Match((ScriptLex.LexTypes) '['); while (_currentLexer.TokenType != (ScriptLex.LexTypes) ']') { if (execute) { String id = String.Format("{0}", idx); ScriptVarLink a = Base(ref execute); contents.AddChild(id, a.Var); } if (_currentLexer.TokenType != (ScriptLex.LexTypes) ']') { _currentLexer.Match((ScriptLex.LexTypes) ','); } idx++; } _currentLexer.Match((ScriptLex.LexTypes) ']'); return(new ScriptVarLink(contents, null)); } if (_currentLexer.TokenType == ScriptLex.LexTypes.RFunction) { ScriptVarLink funcVar = ParseFunctionDefinition(); if (funcVar.Name != String.Empty) { System.Diagnostics.Trace.TraceWarning("Functions not defined at statement level are not supposed to have a name"); } return(funcVar); } if (_currentLexer.TokenType == ScriptLex.LexTypes.RNew) // new { _currentLexer.Match(ScriptLex.LexTypes.RNew); String className = _currentLexer.TokenString; if (execute) { ScriptVarLink classOrFuncObject = FindInScopes(className); if (classOrFuncObject == null) { System.Diagnostics.Trace.TraceWarning("{0} is not a valid class name", className); return(new ScriptVarLink(new ScriptVar(), null)); } _currentLexer.Match(ScriptLex.LexTypes.Id); ScriptVar obj = new ScriptVar(null, ScriptVar.Flags.Object); ScriptVarLink objLink = new ScriptVarLink(obj, null); if (classOrFuncObject.Var.IsFunction) { FunctionCall(ref execute, classOrFuncObject, obj); } else { //creating new instance of a class if (classOrFuncObject.Var.ClassType != null) { obj.ClassInstance = Activator.CreateInstance(classOrFuncObject.Var.ClassType); } obj.AddChild(ScriptVar.PrototypeClassName, classOrFuncObject.Var); if (_currentLexer.TokenType == (ScriptLex.LexTypes) '(') { _currentLexer.Match((ScriptLex.LexTypes) '('); _currentLexer.Match((ScriptLex.LexTypes) ')'); } } return(objLink); } _currentLexer.Match(ScriptLex.LexTypes.Id); if (_currentLexer.TokenType == (ScriptLex.LexTypes) '(') { _currentLexer.Match((ScriptLex.LexTypes) '('); _currentLexer.Match((ScriptLex.LexTypes) ')'); } } _currentLexer.Match(ScriptLex.LexTypes.Eof); return(null); }