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();
        }
Example #5
0
        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;
            }
        }