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; }
private static AstNode ParseReturn(TokenStream stream) { stream.Expect (TokenClass.Keyword, "return"); if (stream.Accept (TokenClass.SemiColon)) { return new ReturnStatement (stream.Location, new CodeBlock (stream.Location)); } else { return new ReturnStatement (stream.Location, ParseExpression (stream)); } }
private static AstNode ParseMatch(TokenStream stream) { MatchExpression expr = new MatchExpression (stream.Location); stream.Expect (TokenClass.Keyword, "match"); expr.Add (ParseExpression (stream)); stream.Expect (TokenClass.OpenBrace); while (stream.Accept (TokenClass.Keyword, "case")) { AstNode condition = null; AstNode pattern = ParsePattern (stream); if (stream.Accept (TokenClass.Keyword, "when")) { condition = ParseExpression (stream); } stream.Expect (TokenClass.Operator, "=>"); AstNode value = ParseExpression (stream); expr.Children.Add (new CaseExpression (pattern.Location, pattern, condition, value)); } stream.Expect (TokenClass.CloseBrace); return expr; }
private static AstNode ParseLambda(TokenStream stream) { stream.Expect (TokenClass.Keyword, "lambda"); bool isInstanceMethod; bool isVariadic; bool acceptsKwargs; List<string> parameters = ParseFuncParameters (stream, out isInstanceMethod, out isVariadic, out acceptsKwargs); LambdaExpression decl = new LambdaExpression (stream.Location, isInstanceMethod, isVariadic, acceptsKwargs, parameters); if (stream.Accept (TokenClass.Operator, "=>")) decl.Add (new ReturnStatement (stream.Location, ParseExpression (stream))); else decl.Add (ParseStatement (stream)); return decl; }
private static AstNode ParseIndexer(AstNode lvalue, TokenStream stream) { stream.Expect (TokenClass.OpenBracket); AstNode index = ParseExpression (stream); stream.Expect (TokenClass.CloseBracket); return new IndexerExpression (stream.Location, lvalue, index); }
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; }
private static AstNode ParseGet(AstNode lvalue, TokenStream stream) { stream.Expect (TokenClass.Operator, "."); Token ident = stream.Expect (TokenClass.Identifier); return new GetExpression (stream.Location, lvalue, ident.Value); }
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; }
private static AstNode ParseYield(TokenStream stream) { stream.Expect (TokenClass.Keyword, "yield"); return new YieldStatement (stream.Location, ParseExpression (stream)); }
private static AstNode ParseWith(TokenStream stream) { WithStatement ret = new WithStatement (stream.Location); stream.Expect (TokenClass.Keyword, "with"); stream.Expect (TokenClass.OpenParan); ret.Add (ParseExpression (stream)); stream.Expect (TokenClass.CloseParan); ret.Add (ParseStatement (stream)); return ret; }
private static AstNode ParseWhen(TokenStream stream) { WhenStatement caseStmt = new WhenStatement (stream.Location); stream.Expect (TokenClass.Keyword, "when"); AstNode value = ParseExpression (stream); AstNode body = ParseStatement (stream); AstNode lambda = new LambdaExpression (body.Location, false, false, false, new System.Collections.Generic.List<string> ()); lambda.Add (body); caseStmt.Add (value); caseStmt.Add (lambda); return caseStmt; }
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 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 ParseTryExcept(TokenStream stream) { TryExceptStatement retVal = null; stream.Expect (TokenClass.Keyword, "try"); AstNode tryBody = ParseStatement (stream); AstNode typeList = new ArgumentList (stream.Location); stream.Expect (TokenClass.Keyword, "except"); if (stream.Accept (TokenClass.OpenParan)) { Token ident = stream.Expect (TokenClass.Identifier); if (stream.Accept (TokenClass.Operator, "as")) { typeList = ParseTypeList (stream); } stream.Expect (TokenClass.CloseParan); retVal = new TryExceptStatement (stream.Location, ident.Value); } else { retVal = new TryExceptStatement (stream.Location, null); } retVal.Add (tryBody); retVal.Add (ParseStatement (stream)); retVal.Add (typeList); return retVal; }
private static AstNode ParseTernaryIfElse(TokenStream stream) { AstNode expr = ParsePipeline (stream); while (stream.Accept (TokenClass.Keyword, "when")) { AstNode condition = ParseExpression (stream); stream.Expect (TokenClass.Keyword, "else"); AstNode altValue = ParseTernaryIfElse (stream); expr = new TernaryExpression (expr.Location, condition, expr, altValue); } return expr; }
private static AstNode ParseFor(TokenStream stream) { ForStatement ret = new ForStatement (stream.Location); stream.Expect (TokenClass.Keyword, "for"); stream.Expect (TokenClass.OpenParan); ret.Add (new Expression (stream.Location, ParseExpression (stream))); stream.Expect (TokenClass.SemiColon); ret.Add (ParseExpression (stream)); stream.Expect (TokenClass.SemiColon); ret.Add (new Expression (stream.Location, ParseExpression (stream))); stream.Expect (TokenClass.CloseParan); ret.Add (ParseStatement (stream)); return ret; }
private static AstNode ParseForeach(TokenStream stream) { stream.Expect (TokenClass.Keyword, "foreach"); stream.Expect (TokenClass.OpenParan); Token identifier = stream.Expect (TokenClass.Identifier); stream.Expect (TokenClass.Keyword, "in"); AstNode expr = ParseExpression (stream); stream.Expect (TokenClass.CloseParan); AstNode body = ParseStatement (stream); return new ForeachStatement (stream.Location, identifier.Value, expr, body); }
public static SuperCallExpression ParseSuperCall(TokenStream stream, ClassDeclaration parent) { SuperCallExpression ret = new SuperCallExpression (stream.Location); stream.Expect (TokenClass.Keyword, "super"); ret.Parent = parent; ret.Add (ParseArgumentList (stream)); while (stream.Accept (TokenClass.SemiColon)) ; return ret; }
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 ParseTerm(TokenStream stream) { switch (stream.Current.Class) { case TokenClass.Identifier: return new NameExpression (stream.Location, stream.ReadToken ().Value); case TokenClass.IntLiteral: return new IntegerExpression (stream.Location, long.Parse ( stream.ReadToken ().Value)); case TokenClass.FloatLiteral: return new FloatExpression (stream.Location, double.Parse ( stream.ReadToken ().Value)); case TokenClass.InterpolatedStringLiteral: AstNode val = ParseString (stream.Location, stream.ReadToken ().Value); if (val == null) { stream.MakeError (); return new StringExpression (stream.Location, ""); } return val; case TokenClass.StringLiteral: return new StringExpression (stream.Location, stream.ReadToken ().Value); case TokenClass.OpenBracket: return ParseList (stream); case TokenClass.OpenBrace: return ParseHash (stream); case TokenClass.OpenParan: stream.ReadToken (); AstNode expr = ParseExpression (stream); if (stream.Accept (TokenClass.Comma)) { return ParseTuple (expr, stream); } stream.Expect (TokenClass.CloseParan); return expr; case TokenClass.Keyword: switch (stream.Current.Value) { case "self": stream.ReadToken (); return new SelfStatement (stream.Location); case "true": stream.ReadToken (); return new TrueExpression (stream.Location); case "false": stream.ReadToken (); return new FalseExpression (stream.Location); case "null": stream.ReadToken (); return new NullExpression (stream.Location); case "lambda": return ParseLambda (stream); case "match": return ParseMatch (stream); } break; } stream.MakeError (); return null; }
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 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 ParseIf(TokenStream stream) { IfStatement ifStmt = new IfStatement (stream.Location); stream.Expect (TokenClass.Keyword, "if"); stream.Expect (TokenClass.OpenParan); ifStmt.Add (ParseExpression (stream)); stream.Expect (TokenClass.CloseParan); ifStmt.Add (ParseStatement (stream)); if (stream.Accept (TokenClass.Keyword, "else")) { ifStmt.Add (ParseStatement (stream)); } else { ifStmt.Add (new CodeBlock (stream.Location)); } return ifStmt; }
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; }
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 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 (); }
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 ParseDoWhile(TokenStream stream) { DoStatement ret = new DoStatement (stream.Location); stream.Expect (TokenClass.Keyword, "do"); ret.Add (ParseStatement (stream)); stream.Expect (TokenClass.Keyword, "while"); stream.Expect (TokenClass.OpenParan); ret.Add (ParseExpression (stream)); stream.Expect (TokenClass.CloseParan); return ret; }
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 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; }