/// <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. }
protected void CheckArgumentCount(int expected, int received) { if (expected != received) { throw DmlSyntaxError.BadArgumentCount(Name, expected, received); } }
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"); } }
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"); } }
/// <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; } }
/// <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)); }
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); } }
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"); } }
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"); } }
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)); }
/// <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); }
/// <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); } }
public DmlSyntaxError(int line, DmlSyntaxError inner) : base( String.Format("An error occurred on line {0}.\n{1}", line, inner.Message) ) { }
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"); } }
/// <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)); }
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())); }
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; }
public DmlSyntaxError(int line, DmlSyntaxError inner) : base(String.Format("An error occurred on line {0}.\n{1}", line, inner.Message)) { }