private bool ParseListExpressionStep(ref LightList <ASTNode> retn) { while (true) { int commaIndex = tokenStream.FindNextIndexAtSameLevel(ExpressionTokenType.Comma); if (commaIndex != -1) { ExpressionParser parser = CreateUndelimitedSubParser(commaIndex); tokenStream.Advance(); bool valid = parser.ParseListExpressionStep(ref retn); parser.Release(); if (!valid) { ReleaseList(retn); return(false); } } else { ASTNode node = ParseLoop(); if (node == null) { return(false); } retn.Add(node); return(true); } } }
private bool ParseTypeOfExpression(ref ASTNode retn) { if (tokenStream.Current != ExpressionTokenType.TypeOf || tokenStream.Next != ExpressionTokenType.ParenOpen) { return(false); } tokenStream.Advance(); int advance = tokenStream.FindMatchingIndex(ExpressionTokenType.ParenOpen, ExpressionTokenType.ParenClose); if (advance == -1) { Abort(); return(false); } tokenStream.Save(); ExpressionParser subParser = CreateSubParser(advance); TypeLookup typeLookup = new TypeLookup(); bool valid = subParser.ParseTypePath(ref typeLookup); subParser.Release(); if (!valid) { Abort(); // hard fail since typeof token has no other paths to go tokenStream.Restore(); return(false); } retn = ASTNode.TypeOfNode(typeLookup); return(true); }
private bool ParseTypePathGenerics(ref TypeLookup retn) { if (tokenStream.Current != ExpressionTokenType.LessThan) { return(false); } int advance = tokenStream.FindMatchingIndex(ExpressionTokenType.LessThan, ExpressionTokenType.GreaterThan); if (advance == -1) { // Abort(); return(false); } tokenStream.Save(); ExpressionParser subParser = CreateSubParser(advance); bool valid = subParser.ParseTypePathGenericStep(ref retn); subParser.Release(); if (!valid) { Abort(); } //tokenStream.Advance(); return(true); }
private bool ParseParenExpression(ref ASTNode retn) { if (tokenStream.Current != ExpressionTokenType.ParenOpen) { return(false); } int advance = tokenStream.FindMatchingIndex(ExpressionTokenType.ParenOpen, ExpressionTokenType.ParenClose); if (advance == -1) { throw new Exception("Unmatched paren"); // todo just abort } ExpressionParser subParser = CreateSubParser(advance); retn = subParser.ParseLoop(); if (retn.IsCompound) { retn = ASTNode.ParenNode(retn); } ASTNode access = null; if (ParseParenAccessExpression(ref access)) { ParenNode parenNode = (ParenNode)retn; parenNode.accessExpression = (MemberAccessExpressionNode)access; } subParser.Release(); return(true); }
public static ASTNode Parse(TokenStream tokenStream) { ExpressionParser parser = new ExpressionParser(tokenStream); ASTNode retn = parser.ParseLoop(); parser.Release(); return(retn); }
public static bool ParseSignature(TokenStream tokenStream, StructList <LambdaArgument> signature) { ExpressionParser parser = new ExpressionParser(tokenStream); bool retn = parser.ParseLambdaSignature(ref signature); parser.Release(); if (!retn) { signature.Clear(); } return(retn); }
public static bool TryParseTypeName(string typeName, out TypeLookup typeLookup) { StructList <ExpressionToken> list = StructList <ExpressionToken> .Get(); ExpressionTokenizer.Tokenize(typeName, list); ExpressionParser parser = new ExpressionParser(new TokenStream(list)); typeLookup = default; bool valid = parser.ParseTypePath(ref typeLookup); parser.Release(); list.Release(); return(valid); }
private bool ParseAttribute(ref AttributeNode node) { if (tokenStream.Current != ExpressionTokenType.ArrayAccessOpen) { return(false); } tokenStream.Save(); tokenStream.Advance(); TypeLookup typeLookup = default; ExpressionParser parser = new ExpressionParser(tokenStream); if (!parser.ParseTypePath(ref typeLookup)) { goto fail; } tokenStream.Set(parser.GetTokenPosition()); parser.Release(false); if (tokenStream.Current == ExpressionTokenType.ArrayAccessClose) { tokenStream.Advance(); node = new AttributeNode() { typeLookup = typeLookup }; return(true); } fail: { typeLookup.Release(); parser.Release(false); return(false); } }
private bool ParseListExpression(ref LightList <ASTNode> retn, ExpressionTokenType openExpressionToken, ExpressionTokenType closeExpressionToken) { if (tokenStream.Current != openExpressionToken) { return(false); } int range = tokenStream.FindMatchingIndex(openExpressionToken, closeExpressionToken); tokenStream.Save(); if (range == 1) { tokenStream.Advance(2); retn = LightList <ASTNode> .Get(); return(true); } if (retn != null) { LightList <ASTNode> .Release(ref retn); } retn = LightList <ASTNode> .Get(); //todo find next comma at same level (meaning not inside [ or ( or < ExpressionParser parser = CreateSubParser(range); bool valid = parser.ParseListExpressionStep(ref retn); parser.Release(); if (!valid) { tokenStream.Restore(); ReleaseList(retn); return(false); } return(true); }
// (int)something private bool ParseDirectCastExpression(ref ASTNode retn) { if (tokenStream.Current != ExpressionTokenType.ParenOpen) { return(false); } ASTNode expression = null; int advance = tokenStream.FindMatchingIndex(ExpressionTokenType.ParenOpen, ExpressionTokenType.ParenClose); if (advance == -1) { Abort(); return(false); } tokenStream.Save(); ExpressionParser subParser = CreateSubParser(advance); TypeLookup typeLookup = new TypeLookup(); bool valid = subParser.ParseTypePath(ref typeLookup); subParser.Release(); if (!valid) { tokenStream.Restore(); return(false); } if (!ParseExpression(ref expression)) { typeLookup.Release(); tokenStream.Restore(); tokenStream.Restore(); return(false); } retn = ASTNode.DirectCastNode(typeLookup, expression); return(true); }
// something.someValue // something[i] // something(*).x(*).y private bool ParseAccessExpression(ref ASTNode retn) { if (tokenStream.Current != ExpressionTokenType.Identifier) { return(false); } string identifier = tokenStream.Current.value; tokenStream.Save(); LightList <ASTNode> parts = LightList <ASTNode> .Get(); tokenStream.Advance(); while (tokenStream.HasMoreTokens) { if (tokenStream.Current == ExpressionTokenType.Dot || tokenStream.Current == ExpressionTokenType.Elvis) { if (tokenStream.Next != ExpressionTokenType.Identifier) { break; } tokenStream.Advance(); parts.Add(ASTNode.DotAccessNode(tokenStream.Current.value, tokenStream.Previous == ExpressionTokenType.Elvis)); tokenStream.Advance(); if (tokenStream.HasMoreTokens) { continue; } } else if (tokenStream.Current == ExpressionTokenType.ArrayAccessOpen || tokenStream.Current == ExpressionTokenType.QuestionMark && tokenStream.NextTokenIs(ExpressionTokenType.ArrayAccessOpen)) { bool isElvis = false; if (tokenStream.Current == ExpressionTokenType.QuestionMark) { isElvis = true; tokenStream.Advance(); } int advance = tokenStream.FindMatchingIndex(ExpressionTokenType.ArrayAccessOpen, ExpressionTokenType.ArrayAccessClose); if (advance == -1) { Abort("Unmatched array bracket"); } ExpressionParser subParser = CreateSubParser(advance); parts.Add(ASTNode.IndexExpressionNode(subParser.ParseLoop(), isElvis)); subParser.Release(); if (tokenStream.HasMoreTokens) { continue; } } else if (tokenStream.Current == ExpressionTokenType.ParenOpen) { LightList <ASTNode> parameters = null; if (!ParseListExpression(ref parameters, ExpressionTokenType.ParenOpen, ExpressionTokenType.ParenClose)) { Abort(); } parts.Add(ASTNode.InvokeNode(parameters)); if (tokenStream.HasMoreTokens) { continue; } } else if (tokenStream.Current == ExpressionTokenType.LessThan) { // shortcut the << operator since we can't have a << in a generic type node. List<<string>> is invalid for example if (tokenStream.HasMoreTokens && tokenStream.Next == ExpressionTokenType.LessThan) { tokenStream.Restore(); LightList <ASTNode> .Release(ref parts); return(false); } TypeLookup typePath = new TypeLookup(); if (!(ParseTypePathGenerics(ref typePath))) { tokenStream.Restore(); LightList <ASTNode> .Release(ref parts); return(false); } parts.Add(ASTNode.GenericTypePath(typePath)); if (tokenStream.HasMoreTokens) { continue; } } if (parts.Count == 0) { tokenStream.Restore(); LightList <ASTNode> .Release(ref parts); return(false); } retn = ASTNode.MemberAccessExpressionNode(identifier, parts).WithLocation(tokenStream.Peek()); return(true); } ReleaseList(parts); tokenStream.Restore(); return(false); }
private ASTNode ParseLoop() { while (tokenStream.HasMoreTokens) { ASTNode operand = default; if (ParseExpression(ref operand)) { if (tokenStream.Current == ExpressionTokenType.Increment) { tokenStream.Advance(); expressionStack.Push(ASTNode.UnaryExpressionNode(ASTNodeType.UnaryPostIncrement, operand)); } else if (tokenStream.Current == ExpressionTokenType.Decrement) { tokenStream.Advance(); expressionStack.Push(ASTNode.UnaryExpressionNode(ASTNodeType.UnaryPostDecrement, operand)); } else { expressionStack.Push(operand); } continue; } if (expressionStack.Count == 0) { Abort(); } if (tokenStream.Current == ExpressionTokenType.QuestionMark && !tokenStream.NextTokenIs(ExpressionTokenType.QuestionMark)) { while (operatorStack.Count != 0) { OperatorNode opNode = operatorStack.Pop(); opNode.right = expressionStack.Pop(); opNode.left = expressionStack.Pop(); expressionStack.Push(opNode); } OperatorNode condition = ASTNode.OperatorNode(OperatorType.TernaryCondition); OperatorNode selection = ASTNode.OperatorNode(OperatorType.TernarySelection); condition.WithLocation(tokenStream.Previous); tokenStream.Advance(); int idx = tokenStream.FindMatchingTernaryColon(); if (idx != -1) { TokenStream stream = tokenStream.AdvanceAndReturnSubStream(idx); // parse the left side of the : operator ExpressionParser parser = new ExpressionParser(stream); ASTNode leftNode = parser.ParseLoop(); parser.Release(); tokenStream.Advance(); // step over colon ExpressionParser parserRight = new ExpressionParser(tokenStream); ASTNode rightNode = parserRight.ParseLoop(); tokenStream.Set(parserRight.tokenStream.CurrentIndex); parserRight.Release(false); selection.left = leftNode; selection.right = rightNode; condition.left = expressionStack.Pop(); condition.right = selection; expressionStack.Push(condition); } else { // read to end use implicit default value for left hand side ExpressionParser parserLeft = new ExpressionParser(tokenStream); ASTNode leftNode = parserLeft.ParseLoop(); tokenStream.Set(parserLeft.tokenStream.CurrentIndex); parserLeft.Release(false); selection.left = leftNode; selection.right = ASTNode.DefaultLiteralNode("default"); condition.left = expressionStack.Pop(); condition.right = selection; expressionStack.Push(condition); } continue; } OperatorNode op; if (!ParseOperatorExpression(out op)) { Abort(); break; } while (operatorStack.Count != 0 && op.priority <= operatorStack.Peek().priority) { OperatorNode opNode = operatorStack.Pop(); opNode.right = expressionStack.Pop(); opNode.left = expressionStack.Pop(); expressionStack.Push(opNode); } operatorStack.Push(op); } while (operatorStack.Count != 0) { OperatorNode opNode = operatorStack.Pop(); opNode.right = expressionStack.Pop(); opNode.left = expressionStack.Pop(); expressionStack.Push(opNode); } if (expressionStack.Count != 1) { Abort(); } return(expressionStack.Pop()); }
private bool ParseDeclaration(ref ASTNode node) { AttributeNode attrNode = null; LightList <AttributeNode> attributes = LightList <AttributeNode> .Get(); while (ParseAttribute(ref attrNode)) { attributes.Add(attrNode); if (tokenStream.Current != ExpressionTokenType.ArrayAccessOpen) { break; } } if (attributes.size == 0) { LightList <AttributeNode> .Release(ref attributes); } if (tokenStream.Current != ExpressionTokenType.Identifier) { return(false); } // modifiers? -> returnType -> name -> signature -> openBrace * closeBrace tokenStream.Save(); bool isStatic = false; if (tokenStream.Current == "static") { isStatic = true; tokenStream.Advance(); } ExpressionParser parser = new ExpressionParser(tokenStream); StructList <LambdaArgument> signature = null; TypeLookup typeLookup = default; if (!parser.ParseTypePath(ref typeLookup)) { goto fail; } tokenStream.Set(parser.GetTokenPosition()); parser.Release(false); if (tokenStream.Current != ExpressionTokenType.Identifier) { goto fail; } string name = tokenStream.Current.value; tokenStream.Advance(); // if semi colon then we have a field! if (tokenStream.Current == ExpressionTokenType.SemiColon) { tokenStream.Advance(); node = new FieldNode() { name = name, isStatic = isStatic, attributes = attributes, typeLookup = typeLookup }; return(true); } if (tokenStream.Current != ExpressionTokenType.ParenOpen) { goto fail; } signature = StructList <LambdaArgument> .Get(); if (tokenStream.NextTokenIs(ExpressionTokenType.ParenClose)) { tokenStream.Advance(2); } else { int matchingIndex = tokenStream.FindMatchingIndex(ExpressionTokenType.ParenOpen, ExpressionTokenType.ParenClose); if (matchingIndex == -1) { goto fail; } TokenStream subStream = tokenStream.AdvanceAndReturnSubStream(matchingIndex); subStream.Advance(); tokenStream.Advance(); if (!ExpressionParser.ParseSignature(subStream, signature)) { goto fail; } for (int i = 0; i < signature.size; i++) { if (signature.array[i].type == null) { throw new ParseException($"When defining a method you must specify a type for all arguments. Found identifier {signature.array[i].identifier} but no type was given."); } } } if (tokenStream.Current != ExpressionTokenType.ExpressionOpen) { goto fail; } BlockNode block = ParseBlock(); node = new MethodNode() { body = block, returnTypeLookup = typeLookup, attributes = attributes, name = name, isStatic = isStatic, signatureList = signature != null?signature.ToArray() : s_EmptySignature }; StructList <LambdaArgument> .Release(ref signature); parser.Release(false); return(true); fail: { tokenStream.Restore(); parser.Release(false); typeLookup.Release(); signature?.Release(); return(false); } }
private bool ParseLocalVariableDeclaration(ref ASTNode node) { ExpressionParser parser = default; TypeLookup typeLookup = default; if (tokenStream.Current == ExpressionTokenType.Var) { if (!tokenStream.NextTokenIs(ExpressionTokenType.Identifier)) { return(false); } tokenStream.Advance(); } else if (tokenStream.Current == ExpressionTokenType.Identifier) { tokenStream.Save(); parser = new ExpressionParser(tokenStream); if (!parser.ParseTypePath(ref typeLookup)) { goto fail; } tokenStream.Set(parser.GetTokenPosition()); parser.Release(false); } else { goto fail; } if (tokenStream.Current != ExpressionTokenType.Identifier) { goto fail; } string name = tokenStream.Current.value; tokenStream.Advance(); if (tokenStream.Current == ExpressionTokenType.SemiColon) { tokenStream.Advance(); node = new LocalVariableNode() { name = name, typeLookup = typeLookup // will be default for var }; return(true); } if (tokenStream.Current == ExpressionTokenType.Assign) { // todo -- would fail on this: var x = new F(() => { return x; }); tokenStream.Advance(); ASTNode expression = null; if (!ParseTerminatedExpression(ref expression)) { goto fail; } node = new LocalVariableNode() { name = name, value = expression, typeLookup = typeLookup // will be default for var }; return(true); } fail: { parser.Release(false); typeLookup.Release(); tokenStream.Restore(); return(false); } }