Пример #1
0
        /// <summary>
        /// Parse the next token.
        /// </summary>
        protected void ParseNext()
        {
            if (DmlTokens.IsMatch(CurrentToken, DmlTokens.NEWLINE))
            {
                Advance(notNull: false);
            }
            else if (skipNext > 0)
            {
                skipNext--;
                Advance(notNull: false);
            }
            // Just kill the parsing if either of the above calls to Advance
            // caused the current token to push past the end.
            if (CurrentToken == null)
            {
                return;
            }

            if (expecting.Count > 0)
            {
                string nextExpecting = expecting.Pop();
                if (!DmlTokens.IsMatch(CurrentToken, nextExpecting))
                {
                    throw DmlSyntaxError.UnexpectedToken(nextExpecting);
                }
            }

            ProcessNext();

            Advance(notNull: false, strict: false);
            // By setting `notNull` to `false`, we allow `current` to be set to `null`,
            // which is what causes `Done` to return `true` causing the while loop to
            // end.
        }
Пример #2
0
 protected void CheckArgumentCount(int expected, int received)
 {
     if (expected != received)
     {
         throw DmlSyntaxError.BadArgumentCount(Name, expected, received);
     }
 }
Пример #3
0
 protected override void ProcessNext()
 {
     if (DmlTokens.IsMatch(CurrentToken, DmlTokens.KW_ASSIGN))
     {
         ProcessAssignment(NamespaceType.BulletUpdate);
     }
     else if (DmlTokens.IsMatch(CurrentToken, DmlTokens.KW_RANGE))
     {
         ProcessRange();
     }
     else if (DmlTokens.IsMatch(CurrentToken, DmlTokens.KW_CHILDREN))
     {
         throw new NotImplementedException("This hasn't been implemented yet, sorry!");
     }
     else if (DmlTokens.IsTimeCommand(CurrentToken))
     {
         ProcessTimeCommand();
     }
     else if (DmlTokens.IsName(CurrentToken) || DmlTokens.IsBuiltin(CurrentToken))
     {
         ProcessExpression(GetUntil(DmlTokens.EOL));
     }
     else if (DmlTokens.IsBehaviour(CurrentToken))
     {
         ProcessBehaviour();
     }
     else
     {
         throw DmlSyntaxError.InvalidTokenForContext(CurrentToken, "bullet update");
     }
 }
Пример #4
0
 protected override void ProcessNext()
 {
     if (DmlTokens.IsTimeCommand(CurrentToken))
     {
         ProcessTimeCommand();
     }
     else if (DmlTokens.IsMatch(CurrentToken, DmlTokens.KW_ASSIGN))
     {
         ProcessAssignment(NamespaceType.Timeline);
     }
     else if (DmlTokens.IsMatch(CurrentToken, DmlTokens.KW_RANGE))
     {
         ProcessRange();
     }
     else if (DmlTokens.IsMatch(CurrentToken, "Spawn"))
     {
         if (!inTimeStamp)
         {
             throw DmlSyntaxError.InvalidSpawnPlacement();
         }
         ProcessBehaviour();
     }
     else
     {
         throw DmlSyntaxError.InvalidTokenForContext(CurrentToken, "timeline");
     }
 }
Пример #5
0
        /// <summary>
        /// Advance the parser by the given number of steps.
        ///
        /// Note: This will also automatically ignore newline tokens (incrementing the newline counter)
        /// and will check for any expecting tokens.
        /// </summary>
        /// <param name="steps">The number of tokens forwards to advance.</param>
        /// <param name="notNull">
        ///     Whether or not to allow CurrentToken to advance
        ///     past the last token and become null.
        /// </param>
        /// <param name="strict">
        ///     Whether or not to throw an error if we could not
        ///     advance the desired number of steps. True by default.
        /// </param>
        /// <param name="exception">
        ///     The exception to throw if strict is true and we could
        ///     not advance the desired number of steps. Null by default.
        /// </param>
        public void Advance(int steps = 1, bool notNull = true, bool strict = true, Exception exception = null)
        {
            // If `notNull` is `true`, then we disallow the setting of `current` as `null`.
            while (0 < steps-- && HasNext(notNull))
            {
                current = current.Next;
                if (DmlTokens.IsMatch(CurrentToken, DmlTokens.NEWLINE) && HasNext(notNull))
                {
                    current = current.Next;
                    currentLine++;
                }
                if (expecting.Count > 0)
                {
                    string nextExpecting = expecting.Pop();
                    if (!DmlTokens.IsMatch(CurrentToken, nextExpecting))
                    {
                        throw DmlSyntaxError.UnexpectedToken(nextExpecting);
                    }
                }
            }

            // As with `Reverse`, the value of `steps` will be -1 unless we couldn't advance anymore.
            if (steps != -1 && strict)
            {
                if (exception == null)
                {
                    throw new ParserError("Cannot advance the desired amount of steps.");
                }
                throw exception;
            }
        }
Пример #6
0
        /// <summary>
        /// Parse a function call using the given loading instruction.
        /// </summary>
        /// <param name="load"></param>
        private void ParseFuncCall(Instruction load)
        {
            int parenthDepth = 1;

            DmlSyntaxError badCall = new DmlSyntaxError(
                "Invalid syntax; mismatched brackets for function call.");

            var subExpressions    = new List <List <string> >();
            var currentExpression = new List <string>();

            while (true)
            {
                Advance(exception: badCall);
                if (DmlTokens.IsMatch(CurrentToken, DmlTokens.LPAR))
                {
                    parenthDepth++;
                }
                else if (DmlTokens.IsMatch(CurrentToken, DmlTokens.RPAR))
                {
                    parenthDepth--;
                }
                else if (DmlTokens.IsMatch(CurrentToken, DmlTokens.COMMA) && parenthDepth == 1)
                {
                    subExpressions.Add(currentExpression);
                    currentExpression = new List <string>();
                    continue;
                }
                if (parenthDepth == 0)
                {
                    if (currentExpression.Count > 0)
                    {
                        subExpressions.Add(currentExpression);
                    }
                    break;
                }
                currentExpression.Add(CurrentToken);
            }

            ExpressionBuilder eb;

            foreach (var subExpression in subExpressions)
            {
                eb = new ExpressionBuilder(subExpression.ToArray(), currentLine);
                eb.Parse();

                foreach (Instruction instruction in (Instruction[])(eb.GetResult()))
                {
                    instructions.Add(instruction);
                }
            }

            instructions.Add(load);
            instructions.Add(new CallFunction(subExpressions.Count));
        }
Пример #7
0
        protected override void ProcessNext()
        {
            try
            {
                if (DmlTokens.IsMatch(CurrentToken, DmlTokens.KW_ASSIGN))
                {
                    ProcessAssignment(NamespaceType.Global);
                }
                else if (DmlTokens.IsMatch(CurrentToken, DmlTokens.KW_RANGE))
                {
                    ProcessRange();
                }
                else if (DmlTokens.IsMatch(CurrentToken, DmlTokens.UQNAME) ||
                         DmlTokens.IsBuiltin(CurrentToken))
                {
                    ProcessExpression(GetUntil(DmlTokens.EOL));
                }
                else if (DmlTokens.IsMatch(CurrentToken, DmlTokens.KW_BULLET))
                {
                    SetExpecting(DmlTokens.AT, DmlTokens.UQNAME, DmlTokens.LANGLE);
                    Advance(2, exception: DmlSyntaxError.BadBulletDeclaration());

                    string bulletName = CurrentToken;
                    Advance(exception: DmlSyntaxError.BadBulletDeclaration());

                    BulletBuilder bulletBuilder = new BulletBuilder(bulletName, GetNamespaceBlock(), currentLine);
                    bulletBuilder.Parse();

                    Bullets[bulletName] = (DmlBulletFactory)bulletBuilder.GetResult();
                }
                else if (DmlTokens.IsMatch(CurrentToken, DmlTokens.KW_TIMELINE))
                {
                    if (globalTimeline != null)
                    {
                        throw DmlSyntaxError.DuplicateTimeline();
                    }
                    SetExpecting(DmlTokens.LANGLE);
                    Advance(exception: DmlSyntaxError.BlockMissingDelimiters("Timeline"));

                    TimelineBuilder timelineBuilder = new TimelineBuilder(GetNamespaceBlock(), currentLine);
                    timelineBuilder.Parse();

                    globalTimeline = (DmlTimeline)timelineBuilder.GetResult();
                }
            }
            catch (DmlSyntaxError exception)
            {
                throw new DmlSyntaxError(currentLine, exception);
            }
        }
Пример #8
0
        protected override void ProcessNext()
        {
            // Check for an assignment statement.
            if (DmlTokens.IsMatch(CurrentToken, DmlTokens.KW_ASSIGN))
            {
                throw DmlSyntaxError.BadAssignmentNamespace();
            }
            else if (DmlTokens.IsMatch(CurrentToken, DmlTokens.KW_INIT))
            {
                if (Init != null)
                {
                    throw DmlSyntaxError.DuplicateNamespaceInBullet("Init");
                }
                SetExpecting(DmlTokens.LANGLE);
                Advance(exception: DmlSyntaxError.BlockMissingDelimiters("Init"));

                string[]          tokens      = GetNamespaceBlock();
                BulletInitBuilder initBuilder = new BulletInitBuilder(tokens, currentLine);
                initBuilder.Parse();

                var initBlock = (Instruction[])initBuilder.GetResult();
                Init = new CodeBlock(initBlock);
            }
            else if (DmlTokens.IsMatch(CurrentToken, DmlTokens.KW_UPDATE))
            {
                if (Update != null)
                {
                    throw DmlSyntaxError.DuplicateNamespaceInBullet("Update");
                }
                SetExpecting(DmlTokens.LANGLE);
                Advance(exception: DmlSyntaxError.BlockMissingDelimiters("Update"));

                string[]            tokens        = GetNamespaceBlock();
                BulletUpdateBuilder updateBuilder = new BulletUpdateBuilder(tokens, currentLine);
                updateBuilder.Parse();

                var updateBlock = (Instruction[])updateBuilder.GetResult();
                Update = new CodeBlock(updateBlock);
            }
            else
            {
                throw DmlSyntaxError.InvalidTokenForContext(CurrentToken, "bullet");
            }
        }
Пример #9
0
 protected override void ProcessNext()
 {
     if (DmlTokens.IsMatch(CurrentToken, DmlTokens.KW_ASSIGN))
     {
         ProcessAssignment(NamespaceType.BulletInit);
     }
     else if (DmlTokens.IsMatch(CurrentToken, DmlTokens.KW_RANGE))
     {
         ProcessRange();
     }
     else if (DmlTokens.IsName(CurrentToken) || DmlTokens.IsBuiltin(CurrentToken))
     {
         ProcessExpression(GetUntil(DmlTokens.EOL));
     }
     else
     {
         throw DmlSyntaxError.InvalidTokenForContext(CurrentToken, "bullet init");
     }
 }
Пример #10
0
        protected virtual void ProcessTimeCommand()
        {
            DmlSyntaxError badTimeCommand = DmlSyntaxError.BadTimeCommandSyntax();

            ProcessExpression(GetUntil(DmlTokens.LANGLE));

            string jumpName = String.Format("#{0:X6}", Globals.randGen.Next(0x1000000));

            Instructions.Add(new JumpIfFalse(jumpName));

            Advance(exception: badTimeCommand);

            int angleDepth = 0;

            while (!Done)
            {
                if (DmlTokens.IsMatch(CurrentToken, DmlTokens.LANGLE))
                {
                    angleDepth++;
                }
                else if (DmlTokens.IsMatch(CurrentToken, DmlTokens.RANGLE))
                {
                    if (angleDepth == 0)
                    {
                        break;
                    }
                    angleDepth--;
                }
                ParseNext();
            }
            if (angleDepth != 0) // We want it to break forcefully, otherwise there would be invalid syntax.
            {
                throw DmlSyntaxError.MismatchedNamespaceDelimiters();
            }

            Instructions.Add(new Label(jumpName));
        }
Пример #11
0
        /// <summary>
        /// Process a generic `Assign` statement.
        /// </summary>
        /// <param name="nsType"></param>
        protected void ProcessAssignment(NamespaceType nsType)
        {
            DmlSyntaxError badAssign = DmlSyntaxError.BadAssignmentStatement();

            Advance(exception: badAssign);

            Instruction assigner; // The instruction that performs the assignment.

            // Check for a global identifier.
            if (DmlTokens.IsMatch(CurrentToken, DmlTokens.AT))
            {
                Advance(exception: badAssign);
                if (DmlTokens.IsMatch(CurrentToken, DmlTokens.UQNAME))
                {
                    assigner = new AssignGlobal(CurrentToken);
                }
                else
                {
                    throw DmlSyntaxError.BadGlobalName(CurrentToken);
                }
            }
            // Check for an instance bound indentifier.
            else if (DmlTokens.IsMatch(CurrentToken, DmlTokens.DOLLAR))
            {
                switch (nsType)
                {
                case NamespaceType.BulletInit:
                case NamespaceType.BulletUpdate:
                    Advance(exception: badAssign);
                    if (DmlTokens.IsName(CurrentToken))
                    {
                        switch (CurrentToken)
                        {
                        // Assign directly to the bullet direction.
                        case DmlTokens.INTRINSIC_DIRECTION:
                            assigner = AssignIntrinsicBulletProperty.Direction;
                            break;

                        // Assign directly to the bullet speed.
                        case DmlTokens.INTRINSIC_SPEED:
                            assigner = AssignIntrinsicBulletProperty.Speed;
                            break;

                        // Assign directly to the bullet colour.
                        case DmlTokens.INTRINSIC_COLOUR:
                            assigner = AssignIntrinsicBulletProperty.Colour;
                            break;

                        case DmlTokens.INTRINSIC_SPRITE:
                            assigner = AssignIntrinsicBulletProperty.Sprite;
                            break;

                        default:
                            assigner = new AssignBulletBound(CurrentToken);
                            break;
                        }
                    }
                    else
                    {
                        throw DmlSyntaxError.BadVariableName(CurrentToken);
                    }
                    break;

                default:
                    throw DmlSyntaxError.BadAssignmentNamespace();
                }
            }
            // Check for an ordinary local name.
            else if (DmlTokens.IsMatch(CurrentToken, DmlTokens.UQNAME))
            {
                assigner = new AssignLocal(CurrentToken);
            }
            else
            {
                throw DmlSyntaxError.BadVariableName(CurrentToken);
            }

            // Read the expression.
            Advance(exception: badAssign);
            string[] expression_tokens = GetUntil(DmlTokens.EOL);
            ProcessExpression(expression_tokens);
            Instructions.Add(assigner);
        }
Пример #12
0
        /// <summary>
        /// Process a generic `Range` statement.
        /// </summary>
        /// <param name="nsType"></param>
        protected void ProcessRange()
        {
            DmlSyntaxError badRange = DmlSyntaxError.BadRangeStatement();

            Advance(exception: badRange);

            // Parse the loop variable.
            if (!DmlTokens.IsName(CurrentToken))
            {
                throw badRange;
            }

            string loopVariable = CurrentToken;

            Advance(exception: badRange);

            // Parse the range start.
            List <String> startTokens;

            try {
                startTokens = new List <String>(GetUntil(DmlTokens.ELLIPSES));
            } catch (ParserError) {
                throw badRange;
            }
            ExpressionBuilder startExpressionBuilder = new ExpressionBuilder(startTokens.ToArray(), currentLine);

            startExpressionBuilder.Parse();
            var startInstructions = (Instruction[])startExpressionBuilder.GetResult();

            Advance(exception: badRange);

            // Parse the range end and range step.
            List <String> endTokens;

            try {
                endTokens = new List <String>(GetUntil(DmlTokens.LANGLE));
            } catch (ParserError) {
                throw badRange;
            }

            // Check if the range operator is extended to include a step.
            int           stepIndex = endTokens.IndexOf(DmlTokens.TRANSOP);
            List <String> stepTokens;

            if (stepIndex == endTokens.Count - 1)
            {
                throw badRange;
            }
            else if (stepIndex != -1)
            {
                stepTokens = new List <string>(endTokens.Skip(stepIndex + 1));
                endTokens  = new List <string>(endTokens.Take(stepIndex));
            }
            else
            {
                // Default step size is 1.
                stepTokens = new List <String>()
                {
                    "1"
                }
            };

            ExpressionBuilder endExpressionBuilder  = new ExpressionBuilder(endTokens.ToArray(), currentLine);
            ExpressionBuilder stepExpressionBuilder = new ExpressionBuilder(stepTokens.ToArray(), currentLine);

            endExpressionBuilder.Parse();
            stepExpressionBuilder.Parse();

            var endInstructions  = (Instruction[])endExpressionBuilder.GetResult();
            var stepInstructions = (Instruction[])stepExpressionBuilder.GetResult();

            /*
             * if (DmlParser.IsSimpleConstant(startInstructions) &&
             *  DmlParser.IsSimpleConstant(endInstructions) &&
             *  DmlParser.IsSimpleConstant(stepInstructions)
             *  )
             * {
             *  double start, end, step;
             *  try
             *  {
             *      start = (double)(new CodeBlock(startInstructions).Evaluate(null, null).Value);
             *      end   = (double)(new CodeBlock(endInstructions).Evaluate(null, null).Value);
             *      step  = (double)(new CodeBlock(stepInstructions).Evaluate(null, null).Value);
             *      InlineRange(loopVariable, start, end, step);
             *  }
             *  catch (InvalidCastException)
             *  {
             *      // InlineRange can only handle double values.
             *      ComplexRange(loopVariable, startInstructions, endInstructions, stepInstructions);
             *  }
             * }
             * else
             */
            // FIXME:
            // So there's a problem with InlineRange. If there are jump statements inside the code within
            // the Range block, the labels and the jumps will get repeated, so all jumps lead to the same
            // spot, which leads to infinite recursion.

            // Not sure why but sometimes the current token is set to the left namespace delimiter,
            // and sometimes its set to the first token after the delimiter. It doesn't seem to be
            // dependent on the presense of the step operator \> either. For now this works.
            if (DmlTokens.IsMatch(CurrentToken, DmlTokens.LANGLE))
            {
                Advance();
            }
            ComplexRange(loopVariable, startInstructions, endInstructions, stepInstructions);
        }
    }
Пример #13
0
 public DmlSyntaxError(int line, DmlSyntaxError inner) : base(
         String.Format("An error occurred on line {0}.\n{1}", line, inner.Message)
         )
 {
 }
Пример #14
0
        protected override void ProcessNext()
        {
            if (DmlTokens.IsMatch(CurrentToken, DmlTokens.AT) ||
                DmlTokens.IsMatch(CurrentToken, DmlTokens.DOLLAR) ||
                DmlTokens.IsNonKeywordName(CurrentToken) ||
                DmlTokens.IsBuiltin(CurrentToken))
            {
                Instruction load;
                string      badName = "Invalid syntax; invalid name \"{0}\".";
                if (DmlTokens.IsMatch(CurrentToken, DmlTokens.AT))
                {
                    Advance(exception: new DmlSyntaxError("Invalid syntax: global identifier `@` must be followed by a name."));
                    if (!DmlTokens.IsName(CurrentToken))
                    {
                        throw new DmlSyntaxError(String.Format(badName, CurrentToken));
                    }
                    load = new LoadGlobal(CurrentToken);
                }
                else if (DmlTokens.IsMatch(CurrentToken, DmlTokens.DOLLAR))
                {
                    Advance(exception: new DmlSyntaxError("Invalid syntax: identifier `$` must be followed by a name."));
                    if (DmlTokens.IsName(CurrentToken))
                    {
                        switch (CurrentToken)
                        {
                        case DmlTokens.INTRINSIC_DIRECTION:
                            load = LoadIntrinsicBulletProperty.Direction;
                            break;

                        case DmlTokens.INTRINSIC_SPEED:
                            load = LoadIntrinsicBulletProperty.Speed;
                            break;

                        case DmlTokens.INTRINSIC_COLOUR:
                            load = LoadIntrinsicBulletProperty.Colour;
                            break;

                        case DmlTokens.INTRINSIC_ORIGIN:
                            load = LoadIntrinsicBulletProperty.Origin;
                            break;

                        case DmlTokens.INTRINSIC_POSITION:
                            load = LoadIntrinsicBulletProperty.Position;
                            break;

                        case DmlTokens.INTRINSIC_VELOCITY:
                            load = LoadIntrinsicBulletProperty.Velocity;
                            break;

                        case DmlTokens.INTRINSIC_TIME:
                            load = LoadIntrinsicBulletProperty.Time;
                            break;

                        default:
                            load = new LoadInstanceBound(CurrentToken);
                            break;
                        }
                    }
                    else
                    {
                        throw new DmlSyntaxError(String.Format(badName, CurrentToken));
                    }
                }
                else if (DmlTokens.IsName(CurrentToken))
                {
                    load = new LoadLocal(CurrentToken);
                }
                else
                {
                    load = new LoadConstant(BuiltinsDict.Builtins[CurrentToken]);
                }

                bool isCall = false;
                // Check if this is a function call.
                // We actually want to catch the ParserError thrown by Advance() in this case
                // because it's very possible the expression could end with a name.
                if (NextToken != null)
                {
                    Advance();
                    if (DmlTokens.IsMatch(CurrentToken, DmlTokens.LPAR))
                    {
                        isCall = true;
                        ParseFuncCall(load);
                    }
                    else
                    {
                        Reverse();
                    }
                }
                if (!isCall)
                {
                    instructions.Add(load);
                }
            }
            else if (DmlTokens.IsMatch(CurrentToken, DmlTokens.KW_TRUE))
            {
                instructions.Add(new LoadConstant(new DmlObject(DmlType.Bool, true)));
            }
            else if (DmlTokens.IsMatch(CurrentToken, DmlTokens.KW_FALSE))
            {
                instructions.Add(new LoadConstant(new DmlObject(DmlType.Bool, false)));
            }
            else if (DmlTokens.IsMatch(CurrentToken, DmlTokens.KW_NULL))
            {
                instructions.Add(new LoadConstant(new DmlObject(DmlType.Null, null)));
            }
            // Check for a left parenthesis.
            else if (DmlTokens.IsMatch(CurrentToken, DmlTokens.LPAR))
            {
                // We know this will never be the start of a function call because
                // that case would be caught by the above if block.
                operators.Push(CurrentToken);
            }
            // Check for a right parenthesis.
            else if (DmlTokens.IsMatch(CurrentToken, DmlTokens.RPAR))
            {
                // By the shunting-yard algorithm, we pop every operator until we find a left
                // parenthesis. If we don't find one, then there are mismatched parentheses.
                if (operators.Count == 0 || !operators.Contains(DmlTokens.LPAR))
                {
                    throw DmlSyntaxError.MismatchedParentheses();
                }
                string top;
                while (operators.Count > 0)
                {
                    top = operators.First();
                    if (DmlTokens.IsMatch(top, DmlTokens.LPAR))
                    {
                        operators.Pop();
                        break;
                    }
                    instructions.Add(OPERATOR_INSTRUCTIONS[operators.Pop()]);
                }
            }
            // Check if the next token is a valid mathematical operator.
            else if (IsOperator(CurrentToken))
            {
                if (operators.Count == 0)
                {
                    operators.Push(CurrentToken);
                }
                // If there are prior operators, pop them and add them to the instructions according to their
                // associativity and precedence.
                else
                {
                    string top;
                    while (operators.Count > 0)
                    {
                        top = operators.First();
                        if ((IsLeftAssociative(top) && OPERATOR_PRECEDENCE[top] >= OPERATOR_PRECEDENCE[CurrentToken]) ||
                            (IsRightAssociative(top) && OPERATOR_PRECEDENCE[top] > OPERATOR_PRECEDENCE[CurrentToken]))
                        {
                            instructions.Add(OPERATOR_INSTRUCTIONS[operators.Pop()]);
                        }
                        else
                        {
                            break;
                        }
                    }
                    operators.Push(CurrentToken);
                }
            }
            // Check for a number.
            else if (DmlTokens.IsNumber(CurrentToken))
            {
                instructions.Add(new LoadConstant(new DmlObject(DmlType.Number, Double.Parse(CurrentToken))));
            }
            // Check for True.
            else if (DmlTokens.IsMatch(CurrentToken, DmlTokens.KW_TRUE))
            {
                instructions.Add(new LoadConstant(new DmlObject(DmlType.Bool, true)));
            }
            // Check for False.
            else if (DmlTokens.IsMatch(CurrentToken, DmlTokens.KW_FALSE))
            {
                instructions.Add(new LoadConstant(new DmlObject(DmlType.Bool, false)));
            }
            // Check for Null.
            else if (DmlTokens.IsMatch(CurrentToken, DmlTokens.KW_NULL))
            {
                instructions.Add(new LoadConstant(new DmlObject(DmlType.Null, null)));
            }
            else if (DmlTokens.IsString(CurrentToken))
            {
                instructions.Add(new LoadConstant(new DmlObject(DmlType.String, CurrentToken)));
            }
            // Check for Lambda.
            else if (DmlTokens.IsMatch(CurrentToken, DmlTokens.KW_LAMBDA))
            {
                throw new NotImplementedException("This hasn't been implemented yet, sorry!");
            }
            else
            {
                throw DmlSyntaxError.InvalidTokenForContext(CurrentToken, "expression");
            }
        }
Пример #15
0
        /// <summary>
        /// Parse a function call using the given loading instruction.
        /// </summary>
        /// <param name="load"></param>
        private void ParseFuncCall(Instruction load)
        {
            int parenthDepth = 1;

            DmlSyntaxError badCall = new DmlSyntaxError(
                "Invalid syntax; mismatched brackets for function call.");

            var subExpressions = new List<List<string>>();
            var currentExpression = new List<string>();

            while (true)
            {
                Advance(exception: badCall);
                if (DmlTokens.IsMatch(CurrentToken, DmlTokens.LPAR))
                    parenthDepth++;
                else if (DmlTokens.IsMatch(CurrentToken, DmlTokens.RPAR))
                    parenthDepth--;
                else if (DmlTokens.IsMatch(CurrentToken, DmlTokens.COMMA) && parenthDepth == 1) 
                {
                    subExpressions.Add(currentExpression);
                    currentExpression = new List<string>();
                    continue;
                }
                if (parenthDepth == 0) 
                {
                    if (currentExpression.Count > 0)
                        subExpressions.Add(currentExpression);
                    break;
                }
                currentExpression.Add(CurrentToken);
            }

            ExpressionBuilder eb;
            foreach (var subExpression in subExpressions)
            {
                eb = new ExpressionBuilder(subExpression.ToArray(), currentLine);
                eb.Parse();

                foreach (Instruction instruction in (Instruction[])(eb.GetResult()))
                    instructions.Add(instruction);
            }

            instructions.Add(load);
            instructions.Add(new CallFunction(subExpressions.Count));
        }
Пример #16
0
        protected void ProcessBehaviour()
        {
            DmlSyntaxError badBehaviour = DmlSyntaxError.BadBehaviourSyntax();

            string behaviourName = CurrentToken;

            SetExpecting(DmlTokens.VBAR);
            Advance(2, exception: badBehaviour);

            if (DmlTokens.IsMatch(CurrentToken, DmlTokens.EOL))
            {
                // The behaviour is empty.
                Instructions.Add(BehavioursDict.InitializeBehaviour(behaviourName, new string[] { }));
                return;
            }

            var  paramExpressions = new List <List <string> >();
            var  parameters       = new List <string>();
            bool insideExpression = false;
            int  parenthDepth     = 0;

            while (!Done)
            {
                if (!insideExpression && DmlTokens.IsMatch(CurrentToken, DmlTokens.PERCENT))
                {
                    Advance(exception: badBehaviour);
                    if (!DmlTokens.IsNonKeywordName(CurrentToken))
                    {
                        throw DmlSyntaxError.BadVariableName(CurrentToken);
                    }
                    parameters.Add(CurrentToken);
                    paramExpressions.Add(new List <string>());
                    insideExpression = true;
                }
                else if (DmlTokens.IsMatch(CurrentToken, DmlTokens.COMMA) && parenthDepth == 0)
                {
                    insideExpression = false;
                    SetExpecting(DmlTokens.PERCENT);
                }
                else if (DmlTokens.IsMatch(CurrentToken, DmlTokens.EOL) && parenthDepth == 0)
                {
                    break;
                }
                else
                {
                    if (DmlTokens.IsLeftBracket(CurrentToken))
                    {
                        if (!insideExpression)
                        {
                            throw badBehaviour;
                        }
                        parenthDepth++;
                    }
                    else if (DmlTokens.IsRightBracket(CurrentToken))
                    {
                        if (!insideExpression)
                        {
                            throw badBehaviour;
                        }
                        parenthDepth--;
                    }
                    paramExpressions.Last().Add(CurrentToken);
                }
                Advance();
            }
            if (parenthDepth != 0) // We want it to break forcefully, otherwise there would be invalid syntax.
            {
                throw badBehaviour;
            }

            foreach (var expression in paramExpressions)
            {
                ProcessExpression(expression.ToArray());
            }
            Instructions.Add(BehavioursDict.InitializeBehaviour(behaviourName, parameters.ToArray()));
        }
Пример #17
0
        protected override void ProcessTimeCommand()
        {
            if (inTimeStamp)
            {
                throw DmlSyntaxError.BadTimeCommandPlacement();
            }
            inTimeStamp = true;

            DmlSyntaxError badTimeCommand = DmlSyntaxError.BadTimeCommandSyntax();
            double         time, start = -1, end = -1;
            string         timeCommand = CurrentToken;

            switch (timeCommand)
            {
            case "At":
            case "Before":
            case "After":
                SetExpecting(DmlTokens.LPAR, DmlTokens.NUMBER, DmlTokens.RPAR, DmlTokens.LANGLE);

                Advance(2, exception: badTimeCommand);
                time = Double.Parse(CurrentToken);

                Advance(2, exception: badTimeCommand);
                if (timeCommand == "At")
                {
                    currentTimestamp = new TimestampAt(time);
                }
                else if (timeCommand == "Before")
                {
                    currentTimestamp = new TimestampBefore(time);
                }
                else
                {
                    currentTimestamp = new TimestampAfter(time);
                }
                break;

            case "AtIntervals":
            case "DuringIntervals":
                SetExpecting(DmlTokens.LPAR, DmlTokens.NUMBER);

                Advance(2, exception: badTimeCommand);
                time = Double.Parse(CurrentToken);

                if (DmlTokens.IsMatch(NextToken, DmlTokens.COMMA))
                {
                    SetExpecting(DmlTokens.COMMA, DmlTokens.NUMBER);
                    Advance(2, exception: badTimeCommand);
                    start = Double.Parse(CurrentToken);

                    SetExpecting(DmlTokens.COMMA, DmlTokens.NUMBER);
                    Advance(2, exception: badTimeCommand);
                    end = Double.Parse(CurrentToken);
                }

                SetExpecting(DmlTokens.RPAR, DmlTokens.LANGLE);
                Advance(2, exception: badTimeCommand);

                if (timeCommand == "AtIntervals")
                {
                    if (start == -1)
                    {
                        currentTimestamp = new TimestampAtIntervals(time);
                    }
                    else
                    {
                        currentTimestamp = new TimestampAtIntervals(time, start, end);
                    }
                }
                else
                {
                    if (start == -1)
                    {
                        currentTimestamp = new TimestampDuringIntervals(time);
                    }
                    else
                    {
                        currentTimestamp = new TimestampDuringIntervals(time, start, end);
                    }
                }
                break;

            case "From":
                SetExpecting(
                    DmlTokens.LPAR, DmlTokens.NUMBER, DmlTokens.COMMA,
                    DmlTokens.NUMBER, DmlTokens.RPAR, DmlTokens.LANGLE
                    );
                Advance(2, exception: badTimeCommand);
                start = Double.Parse(CurrentToken);

                Advance(2, exception: badTimeCommand);
                end = Double.Parse(CurrentToken);

                Advance(2, exception: badTimeCommand);
                currentTimestamp = new TimestampFrom(start, end);
                break;
            }

            Advance(exception: badTimeCommand);
            int angleDepth = 0;

            while (!Done)
            {
                if (DmlTokens.IsMatch(CurrentToken, DmlTokens.LANGLE))
                {
                    angleDepth++;
                }
                else if (DmlTokens.IsMatch(CurrentToken, DmlTokens.RANGLE))
                {
                    if (angleDepth == 0)
                    {
                        break;
                    }
                    angleDepth--;
                }
                ParseNext();
            }

            currentTimestamp.SetCode(new CodeBlock(Instructions.ToArray()));
            Instructions = new List <Instruction>();
            timeline.AddTimestamp(currentTimestamp);
            inTimeStamp = false;
        }
Пример #18
0
 public DmlSyntaxError(int line, DmlSyntaxError inner)
     : base(String.Format("An error occurred on line {0}.\n{1}", line, inner.Message))
 {
 }