
var TokenType={None:0,Word:1,Number:2,String:3,Symbol:4};var ComparisonOperator={Equal:0,NotEqual:1,LessThan:2,GreaterThan:3,LessThanOrEqual:4,GreaterThanOrEqual:5};var apiFunctions=new Array();apiFunctions['sin']=function(arguments){return Math.sin(arguments[0]);};apiFunctions['cos']=function(arguments){return Math.cos(arguments[0]);};apiFunctions['tan']=function(arguments){return Math.tan(arguments[0]);};apiFunctions['abs']=function(arguments){return Math.abs(arguments[0]);};apiFunctions['acos']=function(arguments){return Math.acos(arguments[0]);};apiFunctions['asin']=function(arguments){return Math.asin(arguments[0]);};apiFunctions['atan']=function(arguments){return Math.atan(arguments[0]);};apiFunctions['ceil']=function(arguments){return Math.ceil(arguments[0]);};apiFunctions['pi']=function(arguments){return Math.PI;};apiFunctions['floor']=function(arguments){return Math.floor(arguments[0]);};apiFunctions['exp']=function(arguments){return Math.exp(arguments[0]);};apiFunctions['log']=function(arguments){return Math.log(arguments[0]);};apiFunctions['sqrt']=function(arguments){return Math.sqrt(arguments[0]);};apiFunctions['min']=function(arguments){return Math.min(arguments[0],arguments[1]);};apiFunctions['max']=function(arguments){return Math.max(arguments[0],arguments[1]);};apiFunctions['pow']=function(arguments){return Math.pow(arguments[0],arguments[1]);};apiFunctions['random']=function(arguments){return Math.random();};apiFunctions['round']=function(arguments){return Math.round(arguments[0]);};apiFunctions['alert']=function(arguments){alert(arguments[0]);};apiFunctions['split']=function(arguments){return(""+arguments[1]).split(arguments[0]);};apiFunctions['trim']=function(arguments){return(""+arguments[0]).replace(/^\s\s*/,"").replace(/\s\s*$/,"");};apiFunctions['lowercase']=function(arguments){return(""+arguments[0]).toLowerCase();};apiFunctions['uppercase']=function(arguments){return(""+arguments[0]).toUpperCase();};apiFunctions['find']=function(arguments){return(""+arguments[0]).indexOf(arguments[1],arguments[2]);};apiFunctions['substr']=function(arguments){if(arguments[2]==null||arguments[2]==undefined)return(""+arguments[0]).substr(arguments[1]);return(""+arguments[0]).substr(arguments[1],arguments[2]);};apiFunctions['len']=function(arguments){return(""+arguments[0]).length;};apiFunctions['count']=function(arguments){return arguments[0].length;};apiFunctions['replace']=function(arguments){return arguments[0].replace(arguments[1],arguments[2]);};apiFunctions['escape']=function(arguments){return escape(""+arguments[0]).replace(/\+/g,'%2B');};apiFunctions['unescape']=function(arguments){return unescape(""+arguments[0]);};function debug(line){document.getElementById('debugArea').innerHTML+=line+"<BR>";}
function StringReader(source){this.pos=0;this.source=source;this.EOF=(this.pos>=this.source.length);this.row=0;this.col=0;this.Read=function(){if(this.pos>=this.source.length){this.EOF=true;return null;}
this.pos++;this.EOF=false;try
{var c=this.source.charAt(this.pos-1);if(c=='\n'){this.row++;this.col=0;}
else
this.col++;return c;}
catch(ex){throw("Invalid pos: "+this.pos);}}
this.PeekNext=function(){if(this.pos>=this.source.length)return null;try
{return this.source.charAt(this.pos);}
catch(ex){throw("Invalid pos: "+this.pos);}}}
function IsWhiteSpace(c){return(" \t\n\r".indexOf(c)!=-1);}
function IsLetter(c){return("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_1234567890".indexOf(c)!=-1);}
function IsDigit(c){return("1234567890.".indexOf(c)!=-1);}
function Parser(source){this.tokenizer=new Tokenizer(source);this.currentToken=null;this.ReadNextToken=function(){this.currentToken=this.tokenizer.ReadNextToken();}
this.CodePosition=function(){return"Row: "+(this.tokenizer.source.row+1)+"\nCol: "+(this.tokenizer.source.col+1);}
this.SkipExpected=function(type,content){if(this.currentToken==null)throw("Syntax error: unexpected end of script.\n"+this.CodePosition());if(!(this.currentToken.type==type&&this.currentToken.content==content))throw("Syntax error: expected '"+content+"' and found '"+this.currentToken.content+"'.\n"+this.CodePosition());this.ReadNextToken();}
this.ReadNextStatement=function(){while(true){if(this.currentToken==null)return null;if(!(this.currentToken.type==TokenType.Symbol&&this.currentToken.content==";"))break;this.ReadNextToken();}
if(this.currentToken.type==TokenType.Symbol&&this.currentToken.content=="{")return this.ParseBlock();if(this.currentToken.type!=TokenType.Word)throw("Syntax error: a statement must start with a word or be a code block.\n"+this.CodePosition());if(this.currentToken.type==TokenType.Word)switch(this.currentToken.content){case"function":return this.ParseFunctionDefinitionStatement();case"return":return this.ParseReturnStatement();case"if":return this.ParseIf();case"else":throw("Syntax error: unexpected else statement.\n"+this.CodePosition());case"while":return this.ParseWhileStatement(false);case"do":return this.ParseWhileStatement(true);case"for":return this.ParseForStatement();case"switch":return this.ParseSwitchStatement();case"break":this.ReadNextToken();return new BreakStatement();default:return this.ParseAssignmentOrFunctionCallStatement();}}
this.ParseSwitchStatement=function(){this.ReadNextToken();this.SkipExpected(TokenType.Symbol,"(");var toCheck=this.ParseExpression();this.SkipExpected(TokenType.Symbol,")");this.SkipExpected(TokenType.Symbol,"{");var cases=new Array();while(true){if(this.currentToken!=null&&this.currentToken.type==TokenType.Word&&(this.currentToken.content=="case"||this.currentToken.content=="default")){var anchor=null;if(this.currentToken.content=="case"){this.ReadNextToken();anchor=this.ParseExpression();}
else
this.ReadNextToken();this.SkipExpected(TokenType.Symbol,":");var block=new Array();while(this.currentToken!=null&&!(this.currentToken.type==TokenType.Word&&(this.currentToken.content=="break"||this.currentToken.content=="case"||this.currentToken.content=="default"))){if(this.currentToken.type==TokenType.Symbol&&this.currentToken.content==";"){this.ReadNextToken();continue;}
if(this.currentToken.type==TokenType.Symbol&&this.currentToken.content=="}")break;block[block.length]=this.ReadNextStatement();}
if(this.currentToken.type==TokenType.Word&&this.currentToken.content=="break")block[block.length]=this.ReadNextStatement();cases[cases.length]=new CaseStatement(anchor,new BlockStatement(block));}
else if(this.currentToken!=null&&this.currentToken.type==TokenType.Symbol&&this.currentToken.content==";"){this.ReadNextToken();}
else if(this.currentToken!=null&&this.currentToken.type==TokenType.Symbol&&this.currentToken.content=="}"){this.ReadNextToken();break;}
else
{throw("Syntax error: was expecting a case or default statement and found '"+this.currentToken.content+"'.\n"+this.CodePosition());}}
return new SwitchStatement(toCheck,cases);}
this.ParseWhileStatement=function(reversed){this.ReadNextToken();if(!reversed){this.SkipExpected(TokenType.Symbol,"(");var condition=this.ParseExpression();this.SkipExpected(TokenType.Symbol,")");}
var loopBlock=this.ReadNextStatement();if(reversed){this.SkipExpected(TokenType.Word,"while");this.SkipExpected(TokenType.Symbol,"(");var condition=this.ParseExpression();this.SkipExpected(TokenType.Symbol,")");}
return new ForStatement(new Array(),condition,new Array(),loopBlock,reversed);}
this.ParseForStatement=function(){this.ReadNextToken();this.SkipExpected(TokenType.Symbol,"(");var assignements=new Array();if(!(this.currentToken.type==TokenType.Symbol&&this.currentToken.content==";"))while(true){if(this.currentToken==null)throw("Syntax error: unexpected end of script.\n"+this.CodePosition());var a=this.ParseAssignmentOrFunctionCallStatement();if(!Assignement.prototype.isPrototypeOf(a))throw("Syntax error: expected an assigement.\n"+this.CodePosition());assignements[assignements.length]=a;if(this.currentToken==null)throw("Syntax error: unexpected end of script.\n"+this.CodePosition());if(this.currentToken.type==TokenType.Symbol&&this.currentToken.content==";")break;if(!(this.currentToken.type==TokenType.Symbol&&this.currentToken.content==","))throw("Syntax error: wrong for loop initialisation.\n"+this.CodePosition());this.ReadNextToken();}
this.SkipExpected(TokenType.Symbol,";");var condition=this.ParseExpression();this.SkipExpected(TokenType.Symbol,";");var increments=new Array();if(!(this.currentToken.type==TokenType.Symbol&&this.currentToken.content==")"))while(true){increments[increments.length]=this.ParseAssignmentOrFunctionCallStatement();if(this.currentToken==null)throw("Syntax error: unexpected end of script.\n"+this.CodePosition());if(this.currentToken.type==TokenType.Symbol&&this.currentToken.content==")")break;if(!(this.currentToken.type==TokenType.Symbol&&this.currentToken.content==","))throw("Syntax error: wrong for loop initialisation.\n"+this.CodePosition());this.ReadNextToken();}
this.SkipExpected(TokenType.Symbol,")");var loopBlock=this.ReadNextStatement();return new ForStatement(assignements,condition,increments,loopBlock,false);}
this.ParseReturnStatement=function(){this.ReadNextToken();return new ReturnStatement(this.ParseExpression());}
this.ParseFunctionDefinitionStatement=function(){this.ReadNextToken();var funcName=this.currentToken.content;this.ReadNextToken();var arguments=new Array();this.SkipExpected(TokenType.Symbol,"(");while(!(this.currentToken.type==TokenType.Symbol&&this.currentToken.content==")")){arguments[arguments.length]=this.currentToken.content;this.ReadNextToken();if(this.currentToken.type==TokenType.Symbol&&this.currentToken.content==","){this.ReadNextToken();}
else if(this.currentToken.type==TokenType.Symbol&&this.currentToken.content==")"){}
else
{throw("Syntax error: expected ',' or ')'.\n"+this.CodePosition());}}
this.ReadNextToken();var block=this.ParseBlock();return new FunctionStatement(funcName,arguments,block);}
this.ParseBlock=function(){var block=new Array();this.ReadNextToken();while(this.currentToken!=null&&!(this.currentToken.type==TokenType.Symbol&&this.currentToken.content=="}")){if(this.currentToken.type==TokenType.Symbol&&this.currentToken.content==";"){this.ReadNextToken();continue;}
block[block.length]=this.ReadNextStatement();}
this.ReadNextToken();return new BlockStatement(block);}
this.ParseIf=function(){this.ReadNextToken();var condition=this.ParseExpression();if(this.currentToken==null)throw("Syntax error: unexpected end of script.\n"+this.CodePosition());var trueBlock=this.ReadNextStatement();var falseBlock=null;if(this.currentToken!=null&&this.currentToken.type==TokenType.Word&&this.currentToken.content=="else"){this.ReadNextToken();falseBlock=this.ReadNextStatement();}
return new IfStatement(condition,trueBlock,falseBlock);}
this.ParseAssignmentOrFunctionCallStatement=function(){var token=this.currentToken;var position=null;this.ReadNextToken();if(this.currentToken==null)throw("Syntax error: unexpected end of script.\n"+this.CodePosition());if(this.currentToken.type==TokenType.Symbol&&this.currentToken.content=="["){this.ReadNextToken();position=this.ParseExpression();this.SkipExpected(TokenType.Symbol,"]");}
if(this.currentToken.type==TokenType.Symbol&&this.currentToken.content=="=")return this.ParseAssignment(new Variable(token.content,position));else if(this.currentToken.type==TokenType.Symbol&&this.currentToken.content=="++"){this.ReadNextToken();return new Assignement(new Variable(token.content,position),new Addition(new Variable(token.content,position),new NumberConstant(1)));}
else if(this.currentToken.type==TokenType.Symbol&&this.currentToken.content=="+="){this.ReadNextToken();return new Assignement(new Variable(token.content,position),new Addition(new Variable(token.content,position),this.ParseExpression()));}
else if(this.currentToken.type==TokenType.Symbol&&this.currentToken.content=="--"){this.ReadNextToken();return new Assignement(new Variable(token.content,position),new Substraction(new Variable(token.content,position),new NumberConstant(1)));}
else if(this.currentToken.type==TokenType.Symbol&&this.currentToken.content=="-="){this.ReadNextToken();return new Assignement(new Variable(token.content,position),new Substraction(new Variable(token.content,position),this.ParseExpression()));}
else if(this.currentToken.type==TokenType.Symbol&&this.currentToken.content=="*="){this.ReadNextToken();return new Assignement(new Variable(token.content,position),new Multiplication(new Variable(token.content,position),this.ParseExpression()));}
else if(this.currentToken.type==TokenType.Symbol&&this.currentToken.content=="/="){this.ReadNextToken();return new Assignement(new Variable(token.content,position),new Division(new Variable(token.content,position),this.ParseExpression()));}
else if(this.currentToken.type==TokenType.Symbol&&this.currentToken.content=="(")return this.ParseFunctionCall(token.content);throw("Syntax error: expected a statement found '"+this.currentToken.content+"'.\n"+this.CodePosition());}
this.ParseAssignment=function(variable){this.ReadNextToken();return new Assignement(variable,this.ParseExpression());}
this.ParseExpression=function(){return this.ParseAndExpression();}
this.ParseAndExpression=function(){var node=this.ParseOrExpression();while(this.currentToken!=null&&this.currentToken.type==TokenType.Symbol&&this.currentToken.content=="&&"){this.ReadNextToken();node=new AndExpression(node,this.ParseOrExpression());}
return node;}
this.ParseOrExpression=function(){var node=this.ParseComparison();while(this.currentToken!=null&&this.currentToken.type==TokenType.Symbol&&this.currentToken.content=="||"){this.ReadNextToken();node=new OrExpression(node,this.ParseComparison());}
return node;}
this.ParseComparison=function(){var node=this.ParseAdditiveExpression();var oper=null;if(this.currentToken==null||this.currentToken.type!=TokenType.Symbol)return node;switch(this.currentToken.content){case"==":oper=ComparisonOperator.Equal;break;case"<>":case"!=":oper=ComparisonOperator.NotEqual;break;case"<":oper=ComparisonOperator.LessThan;break;case">":oper=ComparisonOperator.GreaterThan;break;case"<=":oper=ComparisonOperator.LessThanOrEqual;break;case">=":oper=ComparisonOperator.GreaterThanOrEqual;break;default:return node;}
this.ReadNextToken();return new Comparison(oper,node,this.ParseAdditiveExpression());}
this.ParseAdditiveExpression=function(){var node=this.ParseMultiplicativeExpression();while(this.currentToken!=null){if(this.currentToken.type==TokenType.Symbol&&this.currentToken.content=="+"){this.ReadNextToken();node=new Addition(node,this.ParseMultiplicativeExpression());}
else if(this.currentToken.type==TokenType.Symbol&&this.currentToken.content=="-"){this.ReadNextToken();node=new Substraction(node,this.ParseMultiplicativeExpression());}
else
break;}
return node;}
this.ParseMultiplicativeExpression=function(){var node=this.ParseUnaryExpression();while(this.currentToken!=null){if(this.currentToken.type==TokenType.Symbol&&this.currentToken.content=="*"){this.ReadNextToken();node=new Multiplication(node,this.ParseUnaryExpression());}
else if(this.currentToken.type==TokenType.Symbol&&this.currentToken.content=="/"){this.ReadNextToken();node=new Division(node,this.ParseUnaryExpression());}
else
break;}
return node;}
this.ParseUnaryExpression=function(){if(this.currentToken==null)throw("Syntax error: unexpected end of script.\n"+this.CodePosition());else if(this.currentToken.type==TokenType.Symbol&&this.currentToken.content=="-"){this.ReadNextToken();return new Negation(this.ParseBaseExpression());}
else if(this.currentToken.type==TokenType.Symbol&&this.currentToken.content=="!"){this.ReadNextToken();return new Not(this.ParseBaseExpression());}
else if(this.currentToken.type==TokenType.Symbol&&this.currentToken.content=="+"){this.ReadNextToken();}
else if(this.currentToken.type==TokenType.Symbol&&this.currentToken.content=="++"){this.ReadNextToken();var value=this.currentToken.content;this.ReadNextToken();var position=null;if(this.currentToken.type==TokenType.Symbol&&this.currentToken.content=="["){this.ReadNextToken();position=this.ParseExpression();this.SkipExpected(TokenType.Symbol,"]");}
return new Assignement(new Variable(value,position),new Addition(new Variable(value,position),new NumberConstant(1)));}
else if(this.currentToken.type==TokenType.Symbol&&this.currentToken.content=="--"){this.ReadNextToken();var value=this.currentToken.content;this.ReadNextToken();var position=null;if(this.currentToken.type==TokenType.Symbol&&this.currentToken.content=="["){this.ReadNextToken();position=this.ParseExpression();this.SkipExpected(TokenType.Symbol,"]");}
return new Assignement(new Variable(value,position),new Substraction(new Variable(value,position),new NumberConstant(1)));}
return this.ParseBaseExpression();}
this.ParseBaseExpression=function(){if(this.currentToken==null)throw("Syntax error: unexpected end of script.\n"+this.CodePosition());switch(this.currentToken.type){case TokenType.String:return this.ParseStringConstant();case TokenType.Number:return this.ParseNumberConstant();case TokenType.Word:return this.ParseVariableOrFunctionCall();case TokenType.Symbol:if(this.currentToken.content=="(")return this.ParseGroupExpression();throw("Syntax error: expected an expression found '"+this.currentToken.content+"'.\n"+this.CodePosition());default:throw("Syntax error: unknown token type.\n"+this.CodePosition());}}
this.ParseGroupExpression=function(){this.ReadNextToken();if(this.currentToken==null)throw("Syntax error: unexpected end of script.\n"+this.CodePosition());var expression=this.ParseExpression();this.SkipExpected(TokenType.Symbol,")");return expression;}
this.ParseStringConstant=function(){var value=this.currentToken.content;this.ReadNextToken();return new StringConstant(value);}
this.ParseNumberConstant=function(){var value=this.currentToken.content;this.ReadNextToken();return new NumberConstant(value);}
this.ParseVariableOrFunctionCall=function(){var value=this.currentToken.content;this.ReadNextToken();if(this.currentToken!=null&&this.currentToken.type==TokenType.Symbol&&this.currentToken.content=="(")return this.ParseFunctionCall(value);var position=null;if(this.currentToken.type==TokenType.Symbol&&this.currentToken.content=="["){this.ReadNextToken();position=this.ParseExpression();this.SkipExpected(TokenType.Symbol,"]");}
if(this.currentToken!=null&&this.currentToken.type==TokenType.Symbol&&this.currentToken.content=="++"){this.ReadNextToken();return new Assignement(new Variable(value,position),new Addition(new Variable(value,position),new NumberConstant(1)));}
else if(this.currentToken!=null&&this.currentToken.type==TokenType.Symbol&&this.currentToken.content=="--"){this.ReadNextToken();return new Assignement(new Variable(value,position),new Substraction(new Variable(value,position),new NumberConstant(1)));}
return new Variable(value,position);}
this.ParseFunctionCall=function(name){this.ReadNextToken();if(this.currentToken==null)throw("Syntax error: unexpected end of script.\n"+this.CodePosition());var arguments=new Array();while(!(this.currentToken.type==TokenType.Symbol&&this.currentToken.content==")")){arguments[arguments.length]=this.ParseExpression();if(this.currentToken.type==TokenType.Symbol&&this.currentToken.content==","){this.ReadNextToken();}
else if(this.currentToken.type==TokenType.Symbol&&this.currentToken.content==")"){}
else
{throw("Syntax error: expected ',' or ')'.\n"+this.CodePosition());}}
this.ReadNextToken();return new FunctionCall(name,arguments);}
this.ReadNextToken();}
function Token(type,content){this.type=type;this.content=content;}
function Tokenizer(source){this.source=new StringReader(source);this.currentChar=this.source.Read();this.buffer="";this.ReadNextChar=function(){this.currentChar=this.source.Read();}
this.StoreAndRead=function(){this.buffer+=this.currentChar;this.ReadNextChar();}
this.GetBuffer=function(){var res=this.buffer;this.buffer="";return res;}
this.SkipWhitespace=function(){while(!this.source.EOF&&IsWhiteSpace(this.currentChar))this.ReadNextChar();}
this.ReadNextToken=function(){this.SkipWhitespace();if(this.source.EOF){return null;}
while(true){if(this.currentChar=="/"&&this.source.PeekNext()=="/"){while(this.currentChar!="\n"&&this.currentChar!="\r")this.ReadNextChar();this.SkipWhitespace();}
else if(this.currentChar=="/"&&this.source.PeekNext()=="*"){this.ReadNextChar();this.ReadNextChar();while(!(this.currentChar=="*"&&this.source.PeekNext()=="/")){this.ReadNextChar();}
this.ReadNextChar();this.ReadNextChar();this.SkipWhitespace();}
else
break;}
if(IsDigit(this.currentChar))return this.ReadNumber();else if(IsLetter(this.currentChar))return this.ReadWord();else if(this.currentChar=='\"')return this.ReadString();return this.ReadSymbol();}
this.ReadWord=function(){do
{this.StoreAndRead();}while(!this.source.EOF&&IsLetter(this.currentChar));return new Token(TokenType.Word,this.GetBuffer());}
this.ReadNumber=function(){do
{this.StoreAndRead();}while(!this.source.EOF&&IsDigit(this.currentChar));return new Token(TokenType.Number,parseFloat(this.GetBuffer()));}
this.ReadString=function(){this.ReadNextChar();while(!this.source.EOF&&this.currentChar!='"'){this.StoreAndRead();}
this.ReadNextChar();return new Token(TokenType.String,this.GetBuffer());}
this.ReadSymbol=function(){switch(this.currentChar){case'+':this.StoreAndRead();if(this.currentChar=='='||this.currentChar=='+')this.StoreAndRead();return new Token(TokenType.Symbol,this.GetBuffer());case'-':this.StoreAndRead();if(this.currentChar=='='||this.currentChar=='-')this.StoreAndRead();return new Token(TokenType.Symbol,this.GetBuffer());case'*':case'/':this.StoreAndRead();if(this.currentChar=='=')this.StoreAndRead();return new Token(TokenType.Symbol,this.GetBuffer());case';':case':':case'(':case')':case'{':case'}':case',':case'[':case']':this.StoreAndRead();return new Token(TokenType.Symbol,this.GetBuffer());case'!':case'=':case'>':this.StoreAndRead();if(this.currentChar=='=')this.StoreAndRead();return new Token(TokenType.Symbol,this.GetBuffer());case'<':this.StoreAndRead();if(this.currentChar=='>'||this.currentChar=='=')this.StoreAndRead();return new Token(TokenType.Symbol,this.GetBuffer());case'&':this.StoreAndRead();if(this.currentChar=='&')this.StoreAndRead();return new Token(TokenType.Symbol,this.GetBuffer());case'|':this.StoreAndRead();if(this.currentChar=='|')this.StoreAndRead();return new Token(TokenType.Symbol,this.GetBuffer());default:throw"Invalid Char";}}}
function VariableObject(name,position,value){this.name=name;this.value=new Array();this.value[position]=value;}
function IfStatement(condition,trueBlock,falseBlock){this.condition=condition;this.trueBlock=trueBlock;this.falseBlock=falseBlock;this.Run=function(variables,functions){if(this.condition.Run(variables,functions)==true)return this.trueBlock.Run(variables,functions);else if(this.falseBlock!=null)return this.falseBlock.Run(variables,functions);}}
function Variable(name,position){this.name=name;this.position=position;this.Run=function(variables,functions){if(this.name=="null")return null;var index=0;if(this.position!=null)index=this.position.Run(variables,functions);for(var i=0;i<variables.length;i++){if(variables[i].name==this.name){if(this.position==null&&variables[i].value.length>1)return variables[i].value;return variables[i].value[index];}}
return null;}}
function NumberConstant(value){this.value=value;this.Run=function(variables,functions){return this.value;}}
function FunctionCall(name,arguments){this.name=name;this.arguments=arguments;this.Run=function(variables,functions){var values=new Array();for(var i=0;i<this.arguments.length;i++)values[i]=this.arguments[i].Run(variables,functions);if(apiFunctions[this.name]!=null&&apiFunctions[this.name]!=undefined)return apiFunctions[this.name](values);else if(functions[this.name]!=null&&functions[this.name]!=undefined)return functions[this.name].Evaluate(values,functions);else
throw("Runtime: call to an undefined function '"+this.name+"'");}}
function Assignement(variable,value){this.variable=variable;this.value=value;this.Run=function(variables,functions){var index=0;if(variable.position!=null)index=variable.position.Run(variables,functions);var res=this.value.Run(variables,functions);for(var i=0;i<variables.length;i++){if(variables[i].name==this.variable.name){if(res.constructor.toString().indexOf("Array")==-1)variables[i].value[index]=res;else
variables[i].value=res;return res;}}
if(res.constructor.toString().indexOf("Array")==-1){variables[variables.length]=new VariableObject(this.variable.name,index,res);}
else
{variables[variables.length]=new VariableObject(this.variable.name,index,null);variables[variables.length-1].value=res;}
return res;}}
function AndExpression(conditionA,conditionB){this.conditionA=conditionA;this.conditionB=conditionB;this.Run=function(variables,functions){return this.conditionA.Run(variables,functions)&&this.conditionB.Run(variables,functions);}}
function OrExpression(conditionA,conditionB){this.conditionA=conditionA;this.conditionB=conditionB;this.Run=function(variables,functions){return this.conditionA.Run(variables,functions)||this.conditionB.Run(variables,functions);}}
function Comparison(operator,valueA,valueB){this.operator=operator;this.valueA=valueA;this.valueB=valueB;this.Run=function(variables,functions){var a=this.valueA.Run(variables,functions);var b=this.valueB.Run(variables,functions);switch(this.operator){case ComparisonOperator.Equal:return(a==b);case ComparisonOperator.GreaterThan:return(a>b);case ComparisonOperator.LessThan:return(a<b);case ComparisonOperator.GreaterThanOrEqual:return(a>=b);case ComparisonOperator.LessThanOrEqual:return(a<=b);case ComparisonOperator.NotEqual:return(a!=b);default:throw("Runtime: unkown operator.");}
return false;}}
function Addition(valueA,valueB){this.valueA=valueA;this.valueB=valueB;this.Run=function(variables,functions){var a=this.valueA.Run(variables,functions);var b=this.valueB.Run(variables,functions);return a+b;}}
function Substraction(valueA,valueB){this.valueA=valueA;this.valueB=valueB;this.Run=function(variables,functions){var a=this.valueA.Run(variables,functions);var b=this.valueB.Run(variables,functions);return a-b;}}
function Multiplication(valueA,valueB){this.valueA=valueA;this.valueB=valueB;this.Run=function(variables,functions){var a=this.valueA.Run(variables,functions);var b=this.valueB.Run(variables,functions);return a*b;}}
function Division(valueA,valueB){this.valueA=valueA;this.valueB=valueB;this.Run=function(variables,functions){var a=this.valueA.Run(variables,functions);var b=this.valueB.Run(variables,functions);return a/b;}}
function Negation(valueA){this.valueA=valueA;this.Run=function(variables,functions){var a=this.valueA.Run(variables,functions);return-a;}}
function NotExpression(valueA){this.valueA=valueA;this.Run=function(variables,functions){var a=this.valueA.Run(variables,functions);return!a;}}
function StringConstant(valueA){this.valueA=valueA;this.Run=function(variables,functions){return this.valueA;}}
function NumberConstant(valueA){this.valueA=valueA;this.Run=function(variables,functions){return this.valueA;}}
var needReturn=false;function BlockStatement(block){this.block=block;this.Run=function(variables,functions){needReturn=false;for(var i=0;i<this.block.length;i++){var res=this.block[i].Run(variables,functions);if(needReturn)return res;if(needToBreak)return null;}
return null;}}
function ReturnStatement(value){this.value=value;this.Run=function(variables,functions){needReturn=true;var res=this.value.Run(variables,functions);return res;}}
function FunctionStatement(name,arguments,block){this.name=name;this.arguments=arguments;this.block=block;this.Run=function(variables,functions){functions[this.name]=this;}
this.Evaluate=function(values,functions){var variables=new Array();for(var i=0;i<this.arguments.length;i++){variables[i]=new VariableObject(this.arguments[i],0,values[i]);if(values[i].constructor.toString().indexOf("Array")!=-1)variables[i].value=values[i];}
var res=block.Run(variables,functions);needReturn=false;return res;}}
var needToBreak=false;function ForStatement(assignements,condition,increments,loopBlock,reversed){this.assignements=assignements;this.condition=condition;this.increments=increments;this.loopBlock=loopBlock;this.reversed=reversed;this.Run=function(variables,functions){for(var i=0;i<this.assignements.length;i++)this.assignements[i].Run(variables,functions);needToBreak=false;if(this.reversed){do
{this.loopBlock.Run(variables,functions);if(needToBreak)break;for(var i=0;i<this.increments.length;i++)this.increments[i].Run(variables,functions);}while(this.condition.Run(variables,functions));}
else
{while(this.condition.Run(variables,functions)){this.loopBlock.Run(variables,functions);if(needToBreak)break;for(var i=0;i<this.increments.length;i++)this.increments[i].Run(variables,functions);}}
needToBreak=false;}}
function BreakStatement(){this.Run=function(variables,functions){needToBreak=true;}}
function CaseStatement(anchor,block){this.anchor=anchor;this.block=block;}
function SwitchStatement(tocheck,cases){this.tocheck=tocheck;this.cases=cases;this.Run=function(variables,functions){var value=this.tocheck.Run(variables,functions);var runCase=false;var gotCase=false;needToBreak=false;for(var i=0;i<cases.length;i++){if(cases[i].anchor==null&&(gotCase==false||runCase==true)){gotCase=true;runCase=true;}
else if(cases[i].anchor.Run(variables,functions)==value){runCase=true;gotCase=true;}
if(runCase){cases[i].block.Run(variables,functions);if(needToBreak)break;}}
needToBreak=false;}}
function WsScript(){this.statements=new Array();this.functions=new Array();this.variables=new Array();this.Parse=function(source){this.statements=new Array();var script=new Parser(source);var statement=script.ReadNextStatement();while(statement!=null){this.statements[this.statements.length]=statement;statement=script.ReadNextStatement();}
this.variables=new Array();this.functions=new Array();for(var i=0;i<this.statements.length;i++){if(!FunctionStatement.prototype.isPrototypeOf(this.statements[i]))continue;this.statements[i].Run(this.variables,this.functions);}}
this.ExecuteGlobal=function(){for(var i=0;i<this.statements.length;i++){if(FunctionStatement.prototype.isPrototypeOf(this.statements[i]))continue;this.statements[i].Run(this.variables,this.functions);}}
this.FunctionDefined=function(name){return(this.functions[name]!=null&&this.functions[name]!=undefined)}
this.ExecuteFunction=function(name,args){return this.functions[name].Evaluate(args,this.functions);}}