//var function functionCall ({function})() a=b public static JsExpression ParseProgram(List <Token> list) { JsExpression program = new JsExpression("", null); current = program; index = 0; for (; index < list.Count; index++) { var item = list[index]; switch (item.type) { case TokenType.VAR: current = ParseVar(list); program.child.Add(current); break; case TokenType.FUNCTION: current = ParseFunction(list); program.child.Add(current); break; case TokenType.OpenParenthese: current = ParseLambdaCall(list); program.child.Add(current); break; case TokenType.IDENTIFY: switch (list[index + 1].type) { case TokenType.BIND: //= current = ParseAssign(list); break; case TokenType.SemiColon: //identifier current = ParseIdentify(list); index++; //match ; break; case TokenType.POINT: //call method or get field or set field or add new field { bool needMatchSemiColon = false; if (LookAhead(list, index, 3, TokenType.OpenParenthese) || LookAhead(list, index, 3, TokenType.SemiColon)) //if method call { needMatchSemiColon = true; } current = ParsePointExpression(list); // method call and get field need match ; // now only check method call // field get should not appear if (needMatchSemiColon) { index++; //match ; } } break; case TokenType.EQ: case TokenType.UNEQ: case TokenType.LT: case TokenType.GE: case TokenType.LE: case TokenType.GT: case TokenType.AND: case TokenType.OR: current = ParseBool(list); index++; //match ; break; default: //func call current = ParseFunctionCall(list); index++; //match ; break; } program.child.Add(current); break; case TokenType.NUMBER: // num | Math Exp | Bool Exp if (isMathOperation(list[index + 1])) { current = ParseRelation(list); } else if (isBoolOperation(list[index + 1])) { current = ParseBool(list); } else { current = new JsExpression(list[index].name, program); } index++; //match ; program.child.Add(current); break; case TokenType.STRING: current = new JsExpression(item.name, current); index++; //match ; program.child.Add(current); break; default: exceptions.Add(new Exception(current.value + " is an unknow expression")); break; } current = program; } return(program); }
//expList 内所有表达式都需要; //有的内部已经match了; //funcCall,PointExp没有match public static JsExpression ParseExpList(List <Token> list) { JsExpression expList = new JsExpression("{", current); current = expList; index++; while (list[index].type != TokenType.CloseBrace) { var item = list[index]; switch (item.type) { case TokenType.VAR: // already matched ; expList.child.Add(ParseVar(list)); break; case TokenType.FUNCTION: // already matched ; expList.child.Add(ParseFunction(list)); break; case TokenType.OpenParenthese: current = ParseLambdaCall(list); expList.child.Add(current); current = expList; index++; // match ; break; case TokenType.IDENTIFY: switch (list[index + 1].type) { case TokenType.BIND: //= // already matched ; expList.child.Add(ParseAssign(list)); break; case TokenType.POINT: //a.b()| a.b=1 |a.b { bool isMethodCall = false; if (LookAhead(list, index, 3, TokenType.OpenParenthese)) //if method call { isMethodCall = true; } expList.child.Add(ParsePointExpression(list)); // method call and get field need match ; // now only check method call // field get should not appear if (isMethodCall) { index++; //match ; } } break; default: //func call expList.child.Add(ParseFunctionCall(list)); index++; //match ; break; } break; case TokenType.IF: // no need to macth ; expList.child.Add(ParseIf(list)); break; case TokenType.WHILE: // no need to macth ; expList.child.Add(ParseWhile(list)); break; case TokenType.RETURN: // already matched ; expList.child.Add(ParseReturn(list)); break; default: exceptions.Add(new Exception("undefine indentifier")); break; } index++;//match } } current = expList.parent; return(expList); }
//a=num|function|(|indentify|new identify public static JsExpression ParseAssign(List <Token> list) { JsExpression assignExp = new JsExpression("=", current); current = assignExp; assignExp.child.Add(ParseIdentify(list)); index++; (list[index].type == TokenType.BIND).OrThrows("expected '='"); index++; switch (list[index].type) { case TokenType.NUMBER: assignExp.child.Add(GetSingleOrMathExpressionItem(list)); break; case TokenType.IDENTIFY: //var|function call|a.b|bool switch (list[index + 1].type) { case TokenType.OpenParenthese: //function call assignExp.child.Add(ParseFunctionCall(list)); break; case TokenType.SemiColon: //num or var assignExp.child.Add(new JsExpression(list[index].name, current)); break; case TokenType.POINT: //PointExp assignExp.child.Add(ParsePointExpression(list)); break; case TokenType.ADD: // Math Exp case TokenType.SUB: case TokenType.MUL: case TokenType.DIV: assignExp.child.Add(ParseRelation(list)); break; case TokenType.AND: case TokenType.OR: case TokenType.EQ: case TokenType.UNEQ: case TokenType.LT: case TokenType.GE: case TokenType.LE: case TokenType.GT: //Bool Exp assignExp.child.Add(ParseBool(list)); break; } break; case TokenType.FUNCTION: assignExp.child.Add(ParseFunction(list)); break; case TokenType.OpenParenthese: index++; //pass ( ;annoymous function assignExp.child.Add(ParseFunction(list)); break; case TokenType.NEW: assignExp.child.Add(ParseNewExpression(list)); break; default: assignExp.child.Add(new JsExpression(list[index].name, assignExp)); break; } index++;//match ; (list[index].type == TokenType.SemiColon).OrThrows("expected a semicolon"); current = assignExp.parent; return(assignExp); }
public JsFunction(string[] args, JsExpression body, Env env) { this.args = args; this.body = body; this.env = env; }