public ForEachStatement( IExecutable declarationStatement, IValue loopVariable, IValueGetter containerExpression, IExecutable loopBody, KeywordToken keywordToken) { if (!typeof(IEnumerable).IsAssignableFrom(containerExpression.GetValueType())) { throw new ScriptParsingException( source: keywordToken, message: $"Collection of ForEach statement is not an Enumerable collection: {containerExpression.GetValueType().Name}"); } if (!loopVariable.GetValueType().AssignableFromType(containerExpression.GetValueType().GetGenericArguments()[0])) { throw new ScriptParsingException( source: keywordToken, message: $"Collection items of type " + $"({containerExpression.GetValueType().GetGenericArguments()[0].Name}) " + $"not assignable to declared item type: {loopVariable.GetValueType().Name}"); } this.loopVariable = loopVariable; this.declarationStatement = declarationStatement; this.containerExpression = containerExpression; this.loopBody = loopBody; }
public void ValidateFlowControlKeyword(KeywordToken controlKeyword) { if (!ControlKeywordValid()) { throw new ScriptParsingException( source: controlKeyword, message: $"Unable to use control keyword {controlKeyword.keyword} here. No Loop present in parent contexts."); } }
public void ValidateReturn(KeywordToken returnKeyword, Type returnType) { if (!GetReturnType().AssignableFromType(returnType)) { throw new ScriptParsingException( source: returnKeyword, message: $"Unable to return value. Expected type {GetReturnType().Name}, received type {returnType.Name}."); } }
public ReturnStatement( KeywordToken keywordToken, IValueGetter returnValue, CompilationContext context) { this.returnValue = returnValue; context.ValidateReturn( returnKeyword: keywordToken, returnType: returnValue?.GetValueType() ?? typeof(void)); returnType = context.GetReturnType(); }
public WhileStatement( IValueGetter continueExpression, IExecutable loopBody, KeywordToken keywordToken) { if (continueExpression.GetValueType() != typeof(bool)) { throw new ScriptParsingException( source: keywordToken, message: $"ContinueExpression of {keywordToken} statement is not a boolean value: type {continueExpression.GetValueType().Name}"); } this.continueExpression = continueExpression; this.loopBody = loopBody; }
public ControlStatement( KeywordToken keywordToken, CompilationContext context) { keyword = keywordToken.keyword; context.ValidateFlowControlKeyword(keywordToken); switch (keyword) { case Keyword.Continue: case Keyword.Break: //Acceptable break; default: throw new ArgumentException($"Unexpected Keyword: {keyword}"); } }
public static Type ReadType(this IEnumerator <Token> tokens) { KeywordToken typeToken = tokens.GetTokenAndAdvance <KeywordToken>(); if (!typeToken.keyword.IsTypeKeyword()) { throw new ScriptParsingException( source: typeToken, message: $"Expected a Type keyword, but instead found: {typeToken.keyword}"); } if (typeToken.keyword.IsGenericType()) { return(typeToken.keyword.GetValueType().MakeGenericType(tokens.ReadTypeArguments())); } return(typeToken.keyword.GetValueType()); }
private static IExecutable ParseKeywordStatement( KeywordToken kwToken, IEnumerator <Token> tokens, CompilationContext context) { //Valid operations: // Continue, Break // Return (With or Without return value) // Declaration (With or Without assignment, with or without global) // If ( Condition ) // While ( Condition ) // For ( A; B; C ) bool constDeclaration = false; switch (kwToken.keyword) { case Keyword.If: { tokens.CautiousAdvance(); tokens.AssertAndSkip(Separator.OpenParen); IValueGetter ifTest = Expression.ParseNextGetterExpression(tokens, context); tokens.AssertAndSkip(Separator.CloseParen); IExecutable trueStatement = ParseNextStatement(tokens, context); IExecutable falseStatement = null; if (trueStatement == null) { throw new ScriptParsingException( source: kwToken, message: $"No statement returned for If block: {kwToken}"); } //Check the next token for Else or Else IF if (tokens.TestAndConditionallySkip(Keyword.Else)) { falseStatement = ParseNextStatement(tokens, context); } else if (tokens.TestWithoutSkipping(Keyword.ElseIf)) { KeywordToken replacementIf = new KeywordToken( source: tokens.Current, keyword: Keyword.If); falseStatement = ParseKeywordStatement( kwToken: replacementIf, tokens: tokens, context: context); } return(new IfStatement( condition: ifTest, trueBlock: trueStatement, falseBlock: falseStatement, keywordToken: kwToken)); } case Keyword.While: { tokens.CautiousAdvance(); //New context is used for loop context = context.CreateChildScope(true); tokens.AssertAndSkip(Separator.OpenParen); IValueGetter conditionTest = Expression.ParseNextGetterExpression(tokens, context); tokens.AssertAndSkip(Separator.CloseParen); IExecutable loopBody = ParseNextStatement(tokens, context); return(new WhileStatement( continueExpression: conditionTest, loopBody: loopBody, keywordToken: kwToken)); } case Keyword.For: { tokens.CautiousAdvance(); //New context is used for loop context = context.CreateChildScope(true); //Open Paren tokens.AssertAndSkip(Separator.OpenParen); //Initialization IExecutable initializationStatement = ParseNextStatement(tokens, context); //Semicolon already skipped by statement parsing //Continue Expression IValueGetter continueExpression = Expression.ParseNextGetterExpression(tokens, context); //Semicolon tokens.AssertAndSkip(Separator.Semicolon); //Increment IExecutable incrementStatement = ParseForIncrementer(tokens, context); //Close Paren tokens.AssertAndSkip(Separator.CloseParen); IExecutable loopBody = ParseNextStatement(tokens, context); return(new ForStatement( initializationStatement: initializationStatement, continueExpression: continueExpression, incrementStatement: incrementStatement, loopBody: loopBody, keywordToken: kwToken)); } case Keyword.ForEach: { tokens.CautiousAdvance(); //New context is used for loop context = context.CreateChildScope(true); //Open Paren tokens.AssertAndSkip(Separator.OpenParen); //Item Declaration Type itemType = tokens.GetTokenAndAdvance <KeywordToken>().keyword.GetValueType(); IdentifierToken identifierToken = tokens.GetTokenAndAdvance <IdentifierToken>(); IExecutable declaration = new DeclarationOperation( identifierToken: identifierToken, valueType: itemType, context: context); IValue loopVariable = new IdentifierExpression( identifierToken: identifierToken, context: context); tokens.AssertAndSkip(Keyword.In); //Container IValueGetter containerExpression = Expression.ParseNextGetterExpression(tokens, context); //Close Paren tokens.AssertAndSkip(Separator.CloseParen); IExecutable loopBody = ParseNextStatement(tokens, context); return(new ForEachStatement( declarationStatement: declaration, loopVariable: loopVariable, containerExpression: containerExpression, loopBody: loopBody, keywordToken: kwToken)); } case Keyword.Continue: case Keyword.Break: { tokens.CautiousAdvance(); tokens.AssertAndSkip(Separator.Semicolon, false); return(new ControlStatement(kwToken, context)); } case Keyword.Return: { tokens.CautiousAdvance(); IExecutable returnStatement = new ReturnStatement( keywordToken: kwToken, returnValue: Expression.ParseNextGetterExpression(tokens, context), context: context); tokens.AssertAndSkip(Separator.Semicolon, false); return(returnStatement); } case Keyword.Extern: case Keyword.Global: throw new ScriptParsingException( source: kwToken, message: $"{kwToken.keyword} variable declarations invalid in local context. Put them outside classes and methods."); case Keyword.Const: constDeclaration = true; tokens.CautiousAdvance(); goto case Keyword.Bool; case Keyword.Bool: case Keyword.Double: case Keyword.Integer: case Keyword.String: case Keyword.List: case Keyword.Queue: case Keyword.Stack: case Keyword.DepletableBag: case Keyword.DepletableList: case Keyword.RingBuffer: case Keyword.Dictionary: case Keyword.HashSet: case Keyword.Random: case Keyword.DataFile: { Type valueType = tokens.ReadType(); IdentifierToken identToken = tokens.GetTokenAndAdvance <IdentifierToken>(); if (tokens.TestAndConditionallySkip(Separator.Semicolon, false)) { if (constDeclaration) { throw new ScriptParsingException( source: kwToken, message: $"const variable declared without a value. What is the point?"); } return(new DeclarationOperation( identifierToken: identToken, valueType: valueType, context: context)); } else if (tokens.TestAndConditionallySkip(Operator.Assignment)) { IValueGetter initializerExpression = Expression.ParseNextGetterExpression(tokens, context); tokens.AssertAndSkip(Separator.Semicolon, false); return(DeclarationAssignmentOperation.CreateDelcaration( identifierToken: identToken, valueType: valueType, initializer: initializerExpression, isConstant: constDeclaration, context: context)); } throw new ScriptParsingException( source: identToken, message: $"Invalid variable declaration: {kwToken} {identToken} {tokens.Current}"); } case Keyword.System: case Keyword.User: case Keyword.Debug: case Keyword.Math: { IExecutable identifierStatement = Expression.ParseNextExecutableExpression(tokens, context); tokens.AssertAndSkip(Separator.Semicolon, false); return(identifierStatement); } case Keyword.ElseIf: case Keyword.Else: throw new ScriptParsingException( source: kwToken, message: $"Unpaired {kwToken.keyword} token: {kwToken}"); default: throw new ScriptParsingException( source: kwToken, message: $"A Statement cannot begin with this keyword: {kwToken}"); } }
private static void HandleNextKeyword( KeywordToken keywordToken, List <ParsingUnit> units, IEnumerator <Token> tokens, CompilationContext context) { switch (keywordToken.keyword) { case Keyword.New: { tokens.CautiousAdvance(); Type newObjectType = tokens.ReadType(); IValueGetter[] args = ParseArguments(tokens, context); if (tokens.TestWithoutSkipping(Separator.OpenCurlyBoi)) { Type itemType = newObjectType.GetInitializerItemType(); if (itemType == null) { throw new ScriptParsingException( source: keywordToken, message: $"Initializer Lists only function on collections. " + $"Did you enter the wrong type, or possibly omit a semicolon at the end of the expression?"); } //Initializer Syntax IValueGetter[] items = ParseItems(tokens, itemType, context); units.Add(new ParsedValuedUnit( value: new ConstructInitializedCollectionExpression( objectType: newObjectType, args: args, items: items, source: keywordToken), firstToken: keywordToken)); } else { units.Add(new ParsedValuedUnit( value: new ConstructObjectExpression( objectType: newObjectType, args: args), firstToken: keywordToken)); } } break; case Keyword.System: case Keyword.User: case Keyword.Math: case Keyword.Debug: { tokens.CautiousAdvance(); tokens.AssertAndSkip(Operator.MemberAccess); IdentifierToken identifierToken = tokens.GetTokenAndAdvance <IdentifierToken>(); if (tokens.TestWithoutSkipping(Operator.IsLessThan)) { //Generic Method Type[] internalTypes = tokens.ReadTypeArguments(); units.Add(new ParsedValuedUnit( value: MemberManagement.HandleStaticGenericMethodExpression( keywordToken: keywordToken, args: ParseArguments(tokens, context), identifier: identifierToken.identifier, genericTypes: internalTypes), firstToken: keywordToken)); } else if (tokens.TestWithoutSkipping(Separator.OpenParen)) { //Method units.Add(new ParsedValuedUnit( value: MemberManagement.HandleStaticMethodExpression( keywordToken: keywordToken, args: ParseArguments(tokens, context), identifier: identifierToken.identifier), firstToken: keywordToken)); } else { //Member units.Add(new ParsedValuedUnit( value: MemberManagement.HandleStaticMemberExpression( keywordToken: keywordToken, identifier: identifierToken.identifier), firstToken: keywordToken)); } } break; default: units.Add(new TokenUnit(tokens.Current)); tokens.CautiousAdvance(); break; } }