private static AstNode ParseClass (TokenStream stream) { stream.Expect (TokenClass.Keyword, "class"); string name = stream.Expect (TokenClass.Identifier).Value; List<string> baseClass = new List<string> (); if (stream.Accept (TokenClass.Colon)) { do { baseClass.Add (ParseClassName (stream)); } while (stream.Accept (TokenClass.Comma)); } ClassDeclaration clazz = new ClassDeclaration (stream.Location, name, baseClass); stream.Expect (TokenClass.OpenBrace); while (!stream.Match (TokenClass.CloseBrace)) { if (stream.Match (TokenClass.Keyword, "func") || stream.Match (TokenClass.Operator, "@")) { FunctionDeclaration func = ParseFunction (stream, false, clazz) as FunctionDeclaration; if (func.Name == name) { clazz.Constructor = func; } else { clazz.Add (func); } } else { clazz.Add (ParseStatement (stream)); } } stream.Expect (TokenClass.CloseBrace); return clazz; }
public static AstNode ParseAdditive(TokenStream stream) { AstNode expr = ParseMultiplicative (stream); while (stream.Match (TokenClass.Operator)) { switch (stream.Current.Value) { case "+": stream.Accept (TokenClass.Operator); expr = new BinaryExpression (stream.Location, BinaryOperation.Add, expr, ParseMultiplicative (stream)); continue; case "-": stream.Accept (TokenClass.Operator); expr = new BinaryExpression (stream.Location, BinaryOperation.Sub, expr, ParseMultiplicative (stream)); continue; default: break; } break; } return expr; }
private static AstNode ParseBlock(TokenStream stream) { CodeBlock ret = new CodeBlock (stream.Location); stream.Expect (TokenClass.OpenBrace); while (!stream.Match (TokenClass.CloseBrace)) { ret.Add (ParseStatement (stream)); } stream.Expect (TokenClass.CloseBrace); return ret; }
public static AstNode ParseMulDivMod(TokenStream stream) { AstNode expr = ParseUnary (stream); while (stream.Match (TokenClass.Operator)) { switch (stream.Current.Value) { case "*": stream.Accept (TokenClass.Operator); expr = new BinaryExpression (stream.Location, BinaryOperation.Mul, expr, ParseUnary (stream)); continue; case "/": stream.Accept (TokenClass.Operator); expr = new BinaryExpression (stream.Location, BinaryOperation.Div, expr, ParseUnary (stream)); continue; case "%": stream.Accept (TokenClass.Operator); expr = new BinaryExpression (stream.Location, BinaryOperation.Mod, expr, ParseUnary (stream)); continue; default: break; } break; } return expr; }
private static string ParseModuleName(TokenStream stream) { Token initIdent = stream.Expect (TokenClass.Identifier); if (stream.Match (TokenClass.Operator, ".")) { StringBuilder accum = new StringBuilder (); accum.Append (initIdent.Value); while (stream.Accept (TokenClass.Operator, ".")) { Token ident = stream.Expect (TokenClass.Identifier); accum.Append (Path.DirectorySeparatorChar); accum.Append (ident.Value); } return accum.ToString (); } else { return initIdent.Value; } }
private static AstNode ParseInterface(TokenStream stream) { stream.Expect (TokenClass.Keyword, "interface"); string name = stream.Expect (TokenClass.Identifier).Value; InterfaceDeclaration contract = new InterfaceDeclaration (stream.Location, name); stream.Expect (TokenClass.OpenBrace); while (!stream.Match (TokenClass.CloseBrace)) { if (stream.Match (TokenClass.Keyword, "func")) { FunctionDeclaration func = ParseFunction (stream, true) as FunctionDeclaration; contract.Add (func); } else { stream.ErrorLog.AddError (ErrorType.ParserError, stream.Location, "Interface may only contain function prototypes!"); } while (stream.Accept (TokenClass.SemiColon)); } stream.Expect (TokenClass.CloseBrace); return contract; }
private static AstNode ParseGiven(TokenStream stream) { GivenStatement switchStmt = new GivenStatement (stream.Location); stream.Expect (TokenClass.Keyword, "given"); stream.Expect (TokenClass.OpenParan); switchStmt.Add (ParseExpression (stream)); stream.Expect (TokenClass.CloseParan); stream.Expect (TokenClass.OpenBrace); AstNode defaultBlock = new AstRoot (stream.Location); AstRoot caseStatements = new AstRoot (stream.Location); while (!stream.EndOfStream && !stream.Match (TokenClass.CloseBrace)) { caseStatements.Add (ParseWhen (stream)); if (stream.Accept (TokenClass.Keyword, "default")) { defaultBlock = ParseStatement (stream); } } switchStmt.Add (caseStatements); switchStmt.Add (defaultBlock); stream.Expect (TokenClass.CloseBrace); return switchStmt; }
private static AstNode ParseEnum(TokenStream stream) { stream.Expect (TokenClass.Keyword, "enum"); string name = stream.Expect (TokenClass.Identifier).Value; EnumDeclaration decl = new EnumDeclaration (stream.Location, name); stream.Expect (TokenClass.OpenBrace); int defaultVal = -1; while (!stream.Match (TokenClass.CloseBrace)) { string ident = stream.Expect (TokenClass.Identifier).Value; if (stream.Accept (TokenClass.Operator, "=")) { string val = stream.Expect (TokenClass.IntLiteral).Value; int numVal = 0; if (val != "") { numVal = Int32.Parse (val); } decl.Items [ident] = numVal; } else { decl.Items [ident] = defaultVal--; } if (!stream.Accept (TokenClass.Comma)) { break; } } stream.Expect (TokenClass.CloseBrace); return decl; }
private static UseStatement ParseUse(TokenStream stream) { stream.Expect (TokenClass.Keyword, "use"); bool relative = stream.Accept (TokenClass.Operator, "."); string ident = ""; if (!stream.Match (TokenClass.Operator, "*")) ident = ParseModuleName (stream); if (stream.Match (TokenClass.Keyword, "from") || stream.Match (TokenClass.Comma) || stream.Match (TokenClass.Operator, "*")) { List<string> items = new List<string> (); bool wildcard = false; if (!stream.Accept (TokenClass.Operator, "*")) { items.Add (ident); stream.Accept (TokenClass.Comma); while (!stream.Match (TokenClass.Keyword, "from")) { Token item = stream.Expect (TokenClass.Identifier); items.Add (item.Value); if (!stream.Accept (TokenClass.Comma)) { break; } } } else { wildcard = true; } stream.Expect (TokenClass.Keyword, "from"); relative = stream.Accept (TokenClass.Operator, "."); string module = ParseModuleName (stream); return new UseStatement (stream.Location, module, items, wildcard, relative); } return new UseStatement (stream.Location, ident, relative); }
private static ArgumentList ParseTypeList(TokenStream stream) { ArgumentList argList = new ArgumentList (stream.Location); while (!stream.Match (TokenClass.CloseParan)) { argList.Add (ParseExpression (stream)); if (!stream.Accept (TokenClass.Comma)) { break; } } return argList; }
private static AstNode ParseTuple(AstNode firstVal, TokenStream stream) { TupleExpression tuple = new TupleExpression (stream.Location); tuple.Add (firstVal); while (!stream.Match (TokenClass.CloseParan)) { tuple.Add (ParseExpression (stream)); if (!stream.Accept (TokenClass.Comma)) { break; } } stream.Expect (TokenClass.CloseParan); return tuple; }
private static AstNode ParseStatement(TokenStream stream) { if (stream.Match (TokenClass.Keyword)) { switch (stream.Current.Value) { case "class": return ParseClass (stream); case "enum": return ParseEnum (stream); case "interface": return ParseInterface (stream); case "func": return ParseFunction (stream); case "if": return ParseIf (stream); case "given": return ParseGiven (stream); case "for": return ParseFor (stream); case "foreach": return ParseForeach (stream); case "with": return ParseWith (stream); case "while": return ParseWhile (stream); case "do": return ParseDoWhile (stream); case "use": return ParseUse (stream); case "return": return ParseReturn (stream); case "raise": return ParseRaise (stream); case "yield": return ParseYield (stream); case "try": return ParseTryExcept (stream); case "break": stream.Accept (TokenClass.Keyword); return new BreakStatement (stream.Location); case "continue": stream.Accept (TokenClass.Keyword); return new ContinueStatement (stream.Location); case "super": stream.ErrorLog.AddError (ErrorType.ParserError, stream.Location, "super () constructor must be called first!"); return ParseSuperCall (stream, new ClassDeclaration (stream.Location, "", null)); } } if (stream.Match (TokenClass.OpenBrace)) { return ParseBlock (stream); } else if (stream.Accept (TokenClass.SemiColon)) { return new Statement (stream.Location); } else if (stream.Match (TokenClass.Operator, "@")) { return ParseFunction (stream); } else { AstNode node = ParseExpression (stream); if (node == null) { stream.MakeError (); } return new Expression (stream.Location, node); } }
private static AstNode ParseRange(TokenStream stream) { AstNode expr = ParseBoolOr (stream); while (stream.Match (TokenClass.Operator)) { switch (stream.Current.Value) { case "...": stream.Accept (TokenClass.Operator); expr = new BinaryExpression (stream.Location, BinaryOperation.ClosedRange, expr, ParseBoolOr (stream)); continue; case "..": stream.Accept (TokenClass.Operator); expr = new BinaryExpression (stream.Location, BinaryOperation.HalfRange, expr, ParseBoolOr (stream)); continue; default: break; } break; } return expr; }
public static AstNode ParseBitshift(TokenStream stream) { AstNode expr = ParseAdditive (stream); while (stream.Match (TokenClass.Operator)) { switch (stream.Current.Value) { case "<<": stream.Accept (TokenClass.Operator); expr = new BinaryExpression (stream.Location, BinaryOperation.LeftShift, expr, ParseAdditive (stream)); continue; case ">>": stream.Accept (TokenClass.Operator); expr = new BinaryExpression (stream.Location, BinaryOperation.RightShift, expr, ParseAdditive (stream)); continue; default: break; } break; } return expr; }
private static AstNode ParseBoolOr(TokenStream stream) { AstNode expr = ParseBoolAnd (stream); while (stream.Match (TokenClass.Operator)) { switch (stream.Current.Value) { case "||": stream.Accept (TokenClass.Operator); expr = new BinaryExpression (stream.Location, BinaryOperation.BoolOr, expr, ParseBoolAnd (stream)); continue; case "??": stream.Accept (TokenClass.Operator); expr = new BinaryExpression (stream.Location, BinaryOperation.NullCoalescing, expr, ParseBoolAnd (stream)); continue; default: break; } break; } return expr; }
private static string ParseClassName(TokenStream stream) { StringBuilder ret = new StringBuilder (); do { string attr = stream.Expect (TokenClass.Identifier).Value; ret.Append (attr); if (stream.Match (TokenClass.Operator, ".")) ret.Append ('.'); } while (stream.Accept (TokenClass.Operator, ".")); return ret.ToString (); }
public static AstNode ParseCallSubscriptAccess(TokenStream stream, AstNode lvalue) { if (stream.Match (TokenClass.OpenParan)) { return ParseCallSubscriptAccess (stream, new CallExpression (stream.Location, lvalue, ParseArgumentList (stream))); } else if (stream.Match (TokenClass.OpenBracket)) { return ParseCallSubscriptAccess (stream, ParseIndexer (lvalue, stream)); } else if (stream.Match (TokenClass.Operator, ".")) { return ParseCallSubscriptAccess (stream, ParseGet (lvalue, stream)); } return lvalue; }
private static List<string> ParseFuncParameters(TokenStream stream, out bool isInstanceMethod, out bool isVariadic, out bool hasKeywordArgs) { isVariadic = false; hasKeywordArgs = false; isInstanceMethod = false; List<string> ret = new List<string> (); stream.Expect (TokenClass.OpenParan); if (stream.Accept (TokenClass.Keyword, "self")) { isInstanceMethod = true; if (!stream.Accept (TokenClass.Comma)) { stream.Expect (TokenClass.CloseParan); return ret; } } while (!stream.Match (TokenClass.CloseParan)) { if (!hasKeywordArgs && stream.Accept (TokenClass.Operator, "*")) { if (stream.Accept (TokenClass.Operator, "*")) { hasKeywordArgs = true; Token ident = stream.Expect (TokenClass.Identifier); ret.Add (ident.Value); } else { isVariadic = true; Token ident = stream.Expect (TokenClass.Identifier); ret.Add (ident.Value); } } else { if (hasKeywordArgs) { stream.ErrorLog.AddError (ErrorType.ParserError, stream.Location, "Argument after keyword arguments!"); } if (isVariadic) { stream.ErrorLog.AddError (ErrorType.ParserError, stream.Location, "Argument after params keyword!"); } Token param = stream.Expect (TokenClass.Identifier); ret.Add (param.Value); } if (!stream.Accept (TokenClass.Comma)) { break; } } stream.Expect (TokenClass.CloseParan); return ret; }
public static AstNode ParseEquals(TokenStream stream) { AstNode expr = ParseRelationalOp (stream); while (stream.Match (TokenClass.Operator)) { switch (stream.Current.Value) { case "==": stream.Accept (TokenClass.Operator); expr = new BinaryExpression (stream.Location, BinaryOperation.Equals, expr, ParseRelationalOp (stream)); continue; case "!=": stream.Accept (TokenClass.Operator); expr = new BinaryExpression (stream.Location, BinaryOperation.NotEquals, expr, ParseRelationalOp (stream)); continue; default: break; } break; } return expr; }
private static AstNode ParseFunction(TokenStream stream, bool prototype = false, ClassDeclaration cdecl = null) { if (stream.Accept (TokenClass.Operator, "@")) { /* * Function decorators in the form of * @myDecorator * func foo () { * } * are merely syntatic sugar for * func foo () { * } * foo = myDecorator (foo) */ AstNode expr = ParseExpression (stream); // Decorator expression /* This is the original function which is to be decorated */ FunctionDeclaration idecl = ParseFunction (stream, prototype, cdecl) as FunctionDeclaration; /* We must construct an arglist which will be passed to the decorator */ ArgumentList args = new ArgumentList (stream.Location); args.Add (new NameExpression (stream.Location, idecl.Name)); /* * Since two values can not be returned, we must return a single node containing both * the function declaration and call to the decorator */ AstRoot nodes = new AstRoot (stream.Location); nodes.Add (idecl); nodes.Add (new Expression (stream.Location, new BinaryExpression (stream.Location, BinaryOperation.Assign, new NameExpression (stream.Location, idecl.Name), new CallExpression (stream.Location, expr, args)))); return nodes; } stream.Expect (TokenClass.Keyword, "func"); bool isInstanceMethod; bool isVariadic; bool hasKeywordArgs; Token ident = stream.Expect (TokenClass.Identifier); List<string> parameters = ParseFuncParameters (stream, out isInstanceMethod, out isVariadic, out hasKeywordArgs); FunctionDeclaration decl = new FunctionDeclaration (stream.Location, ident != null ? ident.Value : "", isInstanceMethod, isVariadic, hasKeywordArgs, parameters); if (!prototype) { if (stream.Accept (TokenClass.Operator, "=>")) { decl.Add (new ReturnStatement (stream.Location, ParseExpression (stream))); } else { stream.Expect (TokenClass.OpenBrace); CodeBlock scope = new CodeBlock (stream.Location); if (stream.Match (TokenClass.Keyword, "super")) { scope.Add (ParseSuperCall (stream, cdecl)); } while (!stream.Match (TokenClass.CloseBrace)) { scope.Add (ParseStatement (stream)); } decl.Add (scope); stream.Expect (TokenClass.CloseBrace); } } return decl; }
public static AstNode ParseRelationalOp(TokenStream stream) { AstNode expr = ParseBitshift (stream); while (stream.Match (TokenClass.Operator)) { switch (stream.Current.Value) { case ">": stream.Accept (TokenClass.Operator); expr = new BinaryExpression (stream.Location, BinaryOperation.GreaterThan, expr, ParseBitshift (stream)); continue; case "<": stream.Accept (TokenClass.Operator); expr = new BinaryExpression (stream.Location, BinaryOperation.LessThan, expr, ParseBitshift (stream)); continue; case ">=": stream.Accept (TokenClass.Operator); expr = new BinaryExpression (stream.Location, BinaryOperation.GreaterThanOrEqu, expr, ParseBitshift (stream)); continue; case "<=": stream.Accept (TokenClass.Operator); expr = new BinaryExpression (stream.Location, BinaryOperation.LessThanOrEqu, expr, ParseBitshift (stream)); continue; case "is": stream.Accept (TokenClass.Operator); expr = new BinaryExpression (stream.Location, BinaryOperation.InstanceOf, expr, ParseBitshift (stream)); continue; case "isnot": stream.Accept (TokenClass.Operator); expr = new BinaryExpression (stream.Location, BinaryOperation.NotInstanceOf, expr, ParseBitshift (stream)); continue; case "as": stream.Accept (TokenClass.Operator); expr = new BinaryExpression (stream.Location, BinaryOperation.DynamicCast, expr, ParseBitshift (stream)); continue; default: break; } break; } return expr; }
private static AstNode ParseHash(TokenStream stream) { stream.Expect (TokenClass.OpenBrace); HashExpression ret = new HashExpression (stream.Location); while (!stream.Match (TokenClass.CloseBrace)) { ret.Add (ParseExpression (stream)); stream.Expect (TokenClass.Colon); ret.Add (ParseExpression (stream)); if (!stream.Accept (TokenClass.Comma)) { break; } } stream.Expect (TokenClass.CloseBrace); return ret; }
public static AstNode ParseUnary(TokenStream stream) { if (stream.Match (TokenClass.Operator)) { switch (stream.Current.Value) { case "-": stream.Accept (TokenClass.Operator); return new UnaryExpression (stream.Location, UnaryOperation.Negate, ParseUnary ( stream)); case "~": stream.Accept (TokenClass.Operator); return new UnaryExpression (stream.Location, UnaryOperation.Not, ParseUnary ( stream)); case "!": stream.Accept (TokenClass.Operator); return new UnaryExpression (stream.Location, UnaryOperation.BoolNot, ParseUnary ( stream)); } } return ParseCallSubscriptAccess (stream); }
private static AstNode ParseList(TokenStream stream) { stream.Expect (TokenClass.OpenBracket); ListExpression ret = new ListExpression (stream.Location); while (!stream.Match (TokenClass.CloseBracket)) { AstNode expr = ParseExpression (stream); if (stream.Accept (TokenClass.Keyword, "for")) { string ident = stream.Expect (TokenClass.Identifier).Value; stream.Expect (TokenClass.Keyword, "in"); AstNode iterator = ParseExpression (stream); AstNode predicate = null; if (stream.Accept (TokenClass.Keyword, "when")) { predicate = ParseExpression (stream); } stream.Expect (TokenClass.CloseBracket); return new ListCompExpression (expr.Location, expr, ident, iterator, predicate); } ret.Add (expr); if (!stream.Accept (TokenClass.Comma)) { break; } } stream.Expect (TokenClass.CloseBracket); return ret; }
private static AstNode ParseArgumentList(TokenStream stream) { ArgumentList argList = new ArgumentList (stream.Location); stream.Expect (TokenClass.OpenParan); KeywordArgumentList kwargs = null; while (!stream.Match (TokenClass.CloseParan)) { if (stream.Accept (TokenClass.Operator, "*")) { argList.Packed = true; argList.Add (ParseExpression (stream)); break; } AstNode arg = ParseExpression (stream); if (stream.Accept (TokenClass.Colon)) { if (kwargs == null) { kwargs = new KeywordArgumentList (arg.Location); } NameExpression ident = arg as NameExpression; AstNode val = ParseExpression (stream); if (ident == null) { stream.ErrorLog.AddError (ErrorType.ParserError, arg.Location, "Keyword must be a valid identifier"); } else { kwargs.Add (ident.Value, val); } } else argList.Add (arg); if (!stream.Accept (TokenClass.Comma)) { break; } } if (kwargs != null) { argList.Add (kwargs); } stream.Expect (TokenClass.CloseParan); return argList; }
private static AstNode ParsePatternOr(TokenStream stream) { AstNode expr = ParsePatternAnd (stream); while (stream.Match (TokenClass.Operator, "|")) { stream.Accept (TokenClass.Operator); expr = new BinaryExpression (stream.Location, BinaryOperation.Or, expr, ParsePatternAnd (stream)); } return expr; }
private static AstNode ParseAssign(TokenStream stream) { AstNode expr = ParseTernaryIfElse (stream); while (stream.Match (TokenClass.Operator)) { switch (stream.Current.Value) { case "=": stream.Accept (TokenClass.Operator); expr = new BinaryExpression (stream.Location, BinaryOperation.Assign, expr, ParseTernaryIfElse (stream)); continue; case "+=": stream.Accept (TokenClass.Operator); expr = new BinaryExpression (stream.Location, BinaryOperation.Assign, expr, new BinaryExpression (stream.Location, BinaryOperation.Add, expr, ParseTernaryIfElse (stream))); continue; case "-=": stream.Accept (TokenClass.Operator); expr = new BinaryExpression (stream.Location, BinaryOperation.Assign, expr, new BinaryExpression (stream.Location, BinaryOperation.Sub, expr, ParseTernaryIfElse (stream))); continue; case "*=": stream.Accept (TokenClass.Operator); expr = new BinaryExpression (stream.Location, BinaryOperation.Assign, expr, new BinaryExpression (stream.Location, BinaryOperation.Mul, expr, ParseTernaryIfElse (stream))); continue; case "/=": stream.Accept (TokenClass.Operator); expr = new BinaryExpression (stream.Location, BinaryOperation.Assign, expr, new BinaryExpression (stream.Location, BinaryOperation.Div, expr, ParseTernaryIfElse (stream))); continue; case "%=": stream.Accept (TokenClass.Operator); expr = new BinaryExpression (stream.Location, BinaryOperation.Assign, expr, new BinaryExpression (stream.Location, BinaryOperation.Mod, expr, ParseTernaryIfElse (stream))); continue; case "^=": stream.Accept (TokenClass.Operator); expr = new BinaryExpression (stream.Location, BinaryOperation.Assign, expr, new BinaryExpression (stream.Location, BinaryOperation.Xor, expr, ParseTernaryIfElse (stream))); continue; case "&=": stream.Accept (TokenClass.Operator); expr = new BinaryExpression (stream.Location, BinaryOperation.Assign, expr, new BinaryExpression (stream.Location, BinaryOperation.And, expr, ParseTernaryIfElse (stream))); continue; case "|=": stream.Accept (TokenClass.Operator); expr = new BinaryExpression (stream.Location, BinaryOperation.Assign, expr, new BinaryExpression (stream.Location, BinaryOperation.Or, expr, ParseTernaryIfElse (stream))); continue; case "<<=": stream.Accept (TokenClass.Operator); expr = new BinaryExpression (stream.Location, BinaryOperation.Assign, expr, new BinaryExpression (stream.Location, BinaryOperation.LeftShift, expr, ParseTernaryIfElse (stream))); continue; case ">>=": stream.Accept (TokenClass.Operator); expr = new BinaryExpression (stream.Location, BinaryOperation.Assign, expr, new BinaryExpression (stream.Location, BinaryOperation.RightShift, expr, ParseTernaryIfElse (stream))); continue; default: break; } break; } return expr; }