Initial project's source code check-in.
This commit is contained in:
commit
b03b0b373f
4573 changed files with 981205 additions and 0 deletions
712
WebsitePanel/Sources/WebsitePanel.Templates/Parser.cs
Normal file
712
WebsitePanel/Sources/WebsitePanel.Templates/Parser.cs
Normal file
|
@ -0,0 +1,712 @@
|
|||
// Copyright (c) 2011, Outercurve Foundation.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// - Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
//
|
||||
// - Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// - Neither the name of the Outercurve Foundation nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from this
|
||||
// software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Globalization;
|
||||
using System.Diagnostics;
|
||||
|
||||
using WebsitePanel.Templates.AST;
|
||||
|
||||
namespace WebsitePanel.Templates
|
||||
{
|
||||
internal class Parser
|
||||
{
|
||||
Lexer lexer;
|
||||
Token current;
|
||||
List<Statement> statements;
|
||||
|
||||
public Parser(Lexer lexer)
|
||||
{
|
||||
this.lexer = lexer;
|
||||
this.statements = new List<Statement>();
|
||||
}
|
||||
|
||||
Token Consume()
|
||||
{
|
||||
Token old = current;
|
||||
current = lexer.Next();
|
||||
return old;
|
||||
}
|
||||
|
||||
Token Consume(TokenType type)
|
||||
{
|
||||
Token old = current;
|
||||
current = lexer.Next();
|
||||
|
||||
if (old.TokenType != type)
|
||||
throw new ParserException("Unexpected token: " + current.TokenType.ToString() + ". Was expecting: " + type,
|
||||
current.Line, current.Column);
|
||||
|
||||
return old;
|
||||
}
|
||||
|
||||
Token Current
|
||||
{
|
||||
get { return current; }
|
||||
}
|
||||
|
||||
public List<Statement> Parse()
|
||||
{
|
||||
statements.Clear();
|
||||
|
||||
Consume();
|
||||
|
||||
while (true)
|
||||
{
|
||||
Statement stm = ParseStatement();
|
||||
if (stm == null)
|
||||
break;
|
||||
else
|
||||
statements.Add(stm);
|
||||
}
|
||||
|
||||
foreach (Statement stm in statements)
|
||||
Debug.Write(stm);
|
||||
|
||||
return statements;
|
||||
}
|
||||
|
||||
|
||||
private Statement ParseStatement()
|
||||
{
|
||||
switch (Current.TokenType)
|
||||
{
|
||||
case TokenType.EOF:
|
||||
return null;
|
||||
case TokenType.Print:
|
||||
return ParsePrintStatement();
|
||||
case TokenType.Set:
|
||||
return ParseSetStatement();
|
||||
case TokenType.If:
|
||||
return ParseIfStatement();
|
||||
case TokenType.Foreach:
|
||||
return ParseForeachStatement();
|
||||
case TokenType.For:
|
||||
return ParseForStatement();
|
||||
case TokenType.Template:
|
||||
return ParseTemplateStatement();
|
||||
case TokenType.OpenTag:
|
||||
return ParseCallTemplateStatement();
|
||||
case TokenType.Text:
|
||||
TextStatement text = new TextStatement(Current.Data, Current.Line, Current.Column);
|
||||
Consume();
|
||||
return text;
|
||||
default:
|
||||
throw new ParserException("Invalid token: " + Current.TokenType.ToString(), Current.Line, Current.Column);
|
||||
}
|
||||
}
|
||||
|
||||
private Statement ParsePrintStatement()
|
||||
{
|
||||
Consume(TokenType.Print);
|
||||
PrintStatement stm = new PrintStatement(current.Line, current.Column);
|
||||
stm.PrintExpression = ParseExpression();
|
||||
return stm;
|
||||
}
|
||||
|
||||
private Statement ParseSetStatement()
|
||||
{
|
||||
// parse statement declaration
|
||||
SetStatement stm = new SetStatement(current.Line, current.Column);
|
||||
Consume(TokenType.Set);
|
||||
|
||||
// parse tag attributes
|
||||
do
|
||||
{
|
||||
if (Current.TokenType != TokenType.Attribute)
|
||||
throw new ParserException("Expected tag attribute", stm.Line, stm.Column);
|
||||
|
||||
string attrName = Current.Data;
|
||||
Consume(TokenType.Attribute);
|
||||
Consume(TokenType.Assign);
|
||||
|
||||
// look for "test" attribute
|
||||
if (attrName == "name")
|
||||
{
|
||||
stm.Name = Current.Data;
|
||||
Consume(TokenType.String);
|
||||
}
|
||||
else if (attrName == "value")
|
||||
{
|
||||
stm.ValueExpression = ParseExpression();
|
||||
}
|
||||
}
|
||||
while (Current.TokenType == TokenType.Attribute);
|
||||
|
||||
// check statement
|
||||
if (stm.Name == null)
|
||||
throw new ParserException("\"name\" attribute was not specified", stm.Line, stm.Column);
|
||||
if (stm.ValueExpression == null)
|
||||
throw new ParserException("\"value\" attribute was not specified", stm.Line, stm.Column);
|
||||
|
||||
// it must be an "empty" tag
|
||||
Consume(TokenType.EmptyTag);
|
||||
|
||||
return stm;
|
||||
}
|
||||
|
||||
private Statement ParseIfStatement()
|
||||
{
|
||||
// parse statement declaration
|
||||
IfStatement stm = new IfStatement(current.Line, current.Column);
|
||||
Consume(TokenType.If);
|
||||
|
||||
if(Current.TokenType != TokenType.Attribute)
|
||||
throw new ParserException("Expected tag attribute", stm.Line, stm.Column);
|
||||
|
||||
// look for "test" attribute
|
||||
if (Current.Data == "test")
|
||||
{
|
||||
Consume(TokenType.Attribute);
|
||||
Consume(TokenType.Assign);
|
||||
stm.Condition = ParseExpression();
|
||||
}
|
||||
|
||||
// check statement
|
||||
if (stm.Condition == null)
|
||||
throw new ParserException("\"test\" attribute was not specified", stm.Line, stm.Column);
|
||||
|
||||
bool falseBlock = false;
|
||||
|
||||
// parse body
|
||||
while (true)
|
||||
{
|
||||
if (Current.TokenType == TokenType.EndIf)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if (Current.TokenType == TokenType.Else)
|
||||
{
|
||||
Consume(); // else
|
||||
falseBlock = true;
|
||||
continue;
|
||||
}
|
||||
else if (Current.TokenType == TokenType.ElseIf)
|
||||
{
|
||||
stm.ElseIfStatements.Add(ParseElseIfStatement());
|
||||
}
|
||||
else
|
||||
{
|
||||
// parse statement
|
||||
Statement blockStm = ParseStatement();
|
||||
if (blockStm == null)
|
||||
throw new ParserException("Expected closing </ad:if> tag", stm.Line, stm.Column);
|
||||
|
||||
if (falseBlock)
|
||||
stm.FalseStatements.Add(blockStm);
|
||||
else
|
||||
stm.TrueStatements.Add(blockStm);
|
||||
}
|
||||
}
|
||||
|
||||
Consume(TokenType.EndIf);
|
||||
|
||||
return stm;
|
||||
}
|
||||
|
||||
private ElseIfStatement ParseElseIfStatement()
|
||||
{
|
||||
// parse statement declaration
|
||||
ElseIfStatement stm = new ElseIfStatement(current.Line, current.Column);
|
||||
Consume(TokenType.ElseIf);
|
||||
|
||||
if (Current.TokenType != TokenType.Attribute)
|
||||
throw new ParserException("Expected tag attribute", stm.Line, stm.Column);
|
||||
|
||||
// look for "test" attribute
|
||||
if (Current.Data == "test")
|
||||
{
|
||||
Consume(TokenType.Attribute);
|
||||
Consume(TokenType.Assign);
|
||||
stm.Condition = ParseExpression();
|
||||
}
|
||||
|
||||
// check statement
|
||||
if (stm.Condition == null)
|
||||
throw new ParserException("\"test\" attribute was not specified", stm.Line, stm.Column);
|
||||
|
||||
// parse body
|
||||
while (true)
|
||||
{
|
||||
if (Current.TokenType == TokenType.ElseIf
|
||||
|| Current.TokenType == TokenType.Else
|
||||
|| Current.TokenType == TokenType.EndIf)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
Statement blockStm = ParseStatement();
|
||||
if (blockStm == null)
|
||||
throw new ParserException("Expected <ad:elseif>, <ad:else> or </ad:if> tags", stm.Line, stm.Column);
|
||||
|
||||
// parse statement
|
||||
stm.TrueStatements.Add(blockStm);
|
||||
}
|
||||
}
|
||||
|
||||
return stm;
|
||||
}
|
||||
|
||||
private Statement ParseForeachStatement()
|
||||
{
|
||||
// parse statement declaration
|
||||
ForeachStatement stm = new ForeachStatement(current.Line, current.Column);
|
||||
Consume(TokenType.Foreach);
|
||||
|
||||
// parse tag attributes
|
||||
do
|
||||
{
|
||||
if (Current.TokenType != TokenType.Attribute)
|
||||
throw new ParserException("Expected tag attribute", stm.Line, stm.Column);
|
||||
|
||||
string attrName = Current.Data;
|
||||
Consume(TokenType.Attribute);
|
||||
Consume(TokenType.Assign);
|
||||
|
||||
// look for "test" attribute
|
||||
if (attrName == "collection")
|
||||
{
|
||||
stm.Collection = ParseExpression();
|
||||
}
|
||||
else if (attrName == "var")
|
||||
{
|
||||
stm.ElementIdentifier = Current.Data;
|
||||
Consume(TokenType.String);
|
||||
}
|
||||
else if (attrName == "index")
|
||||
{
|
||||
stm.IndexIdentifier = Current.Data;
|
||||
Consume(TokenType.String);
|
||||
}
|
||||
}
|
||||
while (Current.TokenType == TokenType.Attribute);
|
||||
|
||||
// check statement
|
||||
if (stm.Collection == null)
|
||||
throw new ParserException("\"collection\" attribute was not specified", stm.Line, stm.Column);
|
||||
if (stm.ElementIdentifier == null)
|
||||
throw new ParserException("\"var\" attribute was not specified", stm.Line, stm.Column);
|
||||
|
||||
// parse body
|
||||
while (true)
|
||||
{
|
||||
if (Current.TokenType == TokenType.EndForeach)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
Statement blockStm = ParseStatement();
|
||||
if (blockStm == null)
|
||||
throw new ParserException("Expected {/foreach} statement", stm.Line, stm.Column);
|
||||
|
||||
// parse statement
|
||||
stm.Statements.Add(blockStm);
|
||||
}
|
||||
}
|
||||
|
||||
Consume(TokenType.EndForeach);
|
||||
|
||||
return stm;
|
||||
}
|
||||
|
||||
private Statement ParseForStatement()
|
||||
{
|
||||
// parse statement declaration
|
||||
ForStatement stm = new ForStatement(current.Line, current.Column);
|
||||
Consume(TokenType.For);
|
||||
|
||||
// parse tag attributes
|
||||
do
|
||||
{
|
||||
if (Current.TokenType != TokenType.Attribute)
|
||||
throw new ParserException("Expected tag attribute", stm.Line, stm.Column);
|
||||
|
||||
string attrName = Current.Data;
|
||||
Consume(TokenType.Attribute);
|
||||
Consume(TokenType.Assign);
|
||||
|
||||
// look for "test" attribute
|
||||
if (attrName == "from")
|
||||
{
|
||||
stm.StartIndex = ParseExpression();
|
||||
}
|
||||
else if (attrName == "to")
|
||||
{
|
||||
stm.EndIndex = ParseExpression();
|
||||
}
|
||||
else if (attrName == "index")
|
||||
{
|
||||
stm.IndexIdentifier = Current.Data;
|
||||
Consume(TokenType.String);
|
||||
}
|
||||
}
|
||||
while (Current.TokenType == TokenType.Attribute);
|
||||
|
||||
// check statement
|
||||
if (stm.StartIndex == null)
|
||||
throw new ParserException("\"from\" attribute was not specified", stm.Line, stm.Column);
|
||||
if (stm.EndIndex == null)
|
||||
throw new ParserException("\"to\" attribute was not specified", stm.Line, stm.Column);
|
||||
if (stm.IndexIdentifier == null)
|
||||
throw new ParserException("\"index\" attribute was not specified", stm.Line, stm.Column);
|
||||
|
||||
// parse body
|
||||
while (true)
|
||||
{
|
||||
if (Current.TokenType == TokenType.EndFor)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
Statement blockStm = ParseStatement();
|
||||
if (blockStm == null)
|
||||
throw new ParserException("Expected </ad:for> tag", stm.Line, stm.Column);
|
||||
|
||||
// parse statement
|
||||
stm.Statements.Add(blockStm);
|
||||
}
|
||||
}
|
||||
|
||||
Consume(TokenType.EndFor);
|
||||
|
||||
return stm;
|
||||
}
|
||||
|
||||
private Statement ParseTemplateStatement()
|
||||
{
|
||||
// parse statement declaration
|
||||
TemplateStatement stm = new TemplateStatement(current.Line, current.Column);
|
||||
Consume(TokenType.Template);
|
||||
|
||||
// parse tag attributes
|
||||
do
|
||||
{
|
||||
if (Current.TokenType != TokenType.Attribute)
|
||||
throw new ParserException("Expected tag attribute", stm.Line, stm.Column);
|
||||
|
||||
string attrName = Current.Data;
|
||||
Consume(TokenType.Attribute);
|
||||
Consume(TokenType.Assign);
|
||||
|
||||
// look for "test" attribute
|
||||
if (attrName == "name")
|
||||
{
|
||||
stm.Name = Current.Data;
|
||||
Consume(TokenType.String);
|
||||
}
|
||||
}
|
||||
while (Current.TokenType == TokenType.Attribute);
|
||||
|
||||
// check statement
|
||||
if (stm.Name == null)
|
||||
throw new ParserException("\"name\" attribute was not specified", stm.Line, stm.Column);
|
||||
|
||||
// parse body
|
||||
while (true)
|
||||
{
|
||||
if (Current.TokenType == TokenType.EndTemplate)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
Statement blockStm = ParseStatement();
|
||||
if (blockStm == null)
|
||||
throw new ParserException("Expected {/template} tag", stm.Line, stm.Column);
|
||||
|
||||
// parse statement
|
||||
stm.Statements.Add(blockStm);
|
||||
}
|
||||
}
|
||||
|
||||
Consume(TokenType.EndTemplate);
|
||||
|
||||
return stm;
|
||||
}
|
||||
|
||||
private Statement ParseCallTemplateStatement()
|
||||
{
|
||||
// parse statement declaration
|
||||
CallTemplateStatement stm = new CallTemplateStatement(current.Line, current.Column);
|
||||
stm.TemplateName = Current.Data;
|
||||
Consume(TokenType.OpenTag);
|
||||
|
||||
// parse tag attributes
|
||||
do
|
||||
{
|
||||
if (Current.TokenType != TokenType.Attribute)
|
||||
throw new ParserException("Expected tag attribute", stm.Line, stm.Column);
|
||||
|
||||
string attrName = Current.Data;
|
||||
Consume(TokenType.Attribute);
|
||||
Consume(TokenType.Assign);
|
||||
|
||||
// save parameter
|
||||
stm.Parameters.Add(attrName, ParseExpression());
|
||||
}
|
||||
while (Current.TokenType == TokenType.Attribute);
|
||||
|
||||
// parse body
|
||||
while (true)
|
||||
{
|
||||
if (Current.TokenType == TokenType.EmptyTag)
|
||||
{
|
||||
// />
|
||||
Consume(TokenType.EmptyTag);
|
||||
break;
|
||||
}
|
||||
else if (Current.TokenType == TokenType.CloseTag
|
||||
&& Current.Data == stm.TemplateName)
|
||||
{
|
||||
Consume(TokenType.CloseTag);
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
Statement blockStm = ParseStatement();
|
||||
if (blockStm == null)
|
||||
throw new ParserException("Expected closing tag", stm.Line, stm.Column);
|
||||
|
||||
// parse statement
|
||||
stm.Statements.Add(blockStm);
|
||||
}
|
||||
}
|
||||
return stm;
|
||||
}
|
||||
|
||||
private Expression ParseExpression()
|
||||
{
|
||||
return ParseLogicalExpression();
|
||||
}
|
||||
|
||||
private Expression ParseLogicalExpression()
|
||||
{
|
||||
Expression lhs = ParseRelationalExpression();
|
||||
return ParseLogicalExpressionRest(lhs);
|
||||
}
|
||||
|
||||
private Expression ParseLogicalExpressionRest(Expression lhs)
|
||||
{
|
||||
if (Current.TokenType == TokenType.And || Current.TokenType == TokenType.Or)
|
||||
{
|
||||
Consume(); // &&, ||
|
||||
Expression rhs = ParseRelationalExpression();
|
||||
BinaryExpression lhsChild = new BinaryExpression(lhs.Line, lhs.Column, lhs, TokenType.And, rhs);
|
||||
return ParseLogicalExpressionRest(lhsChild);
|
||||
}
|
||||
else
|
||||
{
|
||||
return lhs;
|
||||
}
|
||||
}
|
||||
|
||||
private Expression ParseRelationalExpression()
|
||||
{
|
||||
Expression lhs = ParseAdditiveExpression();
|
||||
|
||||
if (Current.TokenType == TokenType.Less
|
||||
|| Current.TokenType == TokenType.LessOrEqual
|
||||
|| Current.TokenType == TokenType.Greater
|
||||
|| Current.TokenType == TokenType.GreaterOrEqual
|
||||
|| Current.TokenType == TokenType.Equal
|
||||
|| Current.TokenType == TokenType.NotEqual)
|
||||
{
|
||||
Token tok = Consume(); // <, >, <=, >=, ==, !=
|
||||
Expression rhs = ParseRelationalExpression(); // recursion
|
||||
return new BinaryExpression(lhs.Line, lhs.Column, lhs, tok.TokenType, rhs);
|
||||
}
|
||||
|
||||
return lhs;
|
||||
}
|
||||
|
||||
private Expression ParseAdditiveExpression()
|
||||
{
|
||||
Expression lhs = ParseMultiplyExpression();
|
||||
return ParseAdditiveExpressionRest(lhs);
|
||||
}
|
||||
|
||||
private Expression ParseAdditiveExpressionRest(Expression lhs)
|
||||
{
|
||||
if (Current.TokenType == TokenType.Plus
|
||||
|| Current.TokenType == TokenType.Minus)
|
||||
{
|
||||
Token tok = Consume(); // +, -
|
||||
Expression rhs = ParseMultiplyExpression();
|
||||
BinaryExpression lhsChild = new BinaryExpression(lhs.Line, lhs.Column, lhs, tok.TokenType, rhs);
|
||||
return ParseAdditiveExpressionRest(lhsChild);
|
||||
}
|
||||
else
|
||||
{
|
||||
return lhs;
|
||||
}
|
||||
}
|
||||
|
||||
private Expression ParseMultiplyExpression()
|
||||
{
|
||||
Expression lhs = ParseUnaryExpression();
|
||||
return ParseMultiplyExpressionRest(lhs);
|
||||
}
|
||||
|
||||
private Expression ParseMultiplyExpressionRest(Expression lhs)
|
||||
{
|
||||
if (Current.TokenType == TokenType.Mult
|
||||
|| Current.TokenType == TokenType.Div
|
||||
|| Current.TokenType == TokenType.Mod)
|
||||
{
|
||||
Token tok = Consume(); // *, /, %
|
||||
Expression rhs = ParseUnaryExpression();
|
||||
BinaryExpression lhsChild = new BinaryExpression(lhs.Line, lhs.Column, lhs, tok.TokenType, rhs);
|
||||
return ParseMultiplyExpressionRest(lhsChild);
|
||||
}
|
||||
|
||||
return lhs;
|
||||
}
|
||||
|
||||
private Expression ParseUnaryExpression()
|
||||
{
|
||||
if (Current.TokenType == TokenType.Minus ||
|
||||
Current.TokenType == TokenType.Not)
|
||||
{
|
||||
Token tok = Consume(); // -, !
|
||||
Expression rhs = ParseUnaryExpression();
|
||||
UnaryExpression exp = new UnaryExpression(Current.Line, Current.Column, tok.TokenType, rhs);
|
||||
return exp;
|
||||
}
|
||||
|
||||
return ParsePrimaryExpression();
|
||||
}
|
||||
|
||||
private Expression ParsePrimaryExpression()
|
||||
{
|
||||
if (Current.TokenType == TokenType.String)
|
||||
{
|
||||
LiteralExpression literal = new LiteralExpression(Current.Line, Current.Column, Current.Data);
|
||||
Consume();
|
||||
return literal;
|
||||
}
|
||||
else if (Current.TokenType == TokenType.Null)
|
||||
{
|
||||
LiteralExpression literal = new LiteralExpression(Current.Line, Current.Column, null);
|
||||
Consume();
|
||||
return literal;
|
||||
}
|
||||
else if (Current.TokenType == TokenType.True)
|
||||
{
|
||||
LiteralExpression literal = new LiteralExpression(Current.Line, Current.Column, true);
|
||||
Consume();
|
||||
return literal;
|
||||
}
|
||||
else if (Current.TokenType == TokenType.False)
|
||||
{
|
||||
LiteralExpression literal = new LiteralExpression(Current.Line, Current.Column, false);
|
||||
Consume();
|
||||
return literal;
|
||||
}
|
||||
else if (Current.TokenType == TokenType.Integer)
|
||||
{
|
||||
LiteralExpression literal = new LiteralExpression(Current.Line, Current.Column, Int32.Parse(Current.Data));
|
||||
Consume();
|
||||
return literal;
|
||||
}
|
||||
else if (Current.TokenType == TokenType.Decimal)
|
||||
{
|
||||
LiteralExpression literal = new LiteralExpression(Current.Line, Current.Column,
|
||||
Decimal.Parse(Current.Data, NumberFormatInfo.InvariantInfo));
|
||||
Consume();
|
||||
return literal;
|
||||
}
|
||||
else if (Current.TokenType == TokenType.Identifier)
|
||||
{
|
||||
IdentifierExpression id = new IdentifierExpression(Current.Line, Current.Column);
|
||||
while (Current.TokenType == TokenType.Identifier)
|
||||
{
|
||||
id.Parts.Add(ParseIdentifierPart());
|
||||
|
||||
if (Current.TokenType != TokenType.Dot)
|
||||
break;
|
||||
else
|
||||
{
|
||||
Consume(); // .
|
||||
if(Current.TokenType != TokenType.Identifier)
|
||||
throw new ParserException("Wrong usage of period. Identifier was expected.", Current.Line, Current.Column);
|
||||
}
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
else if (Current.TokenType == TokenType.LParen)
|
||||
{
|
||||
Consume(); // eat (
|
||||
Expression exp = ParseExpression();
|
||||
Consume(TokenType.RParen); // eat )
|
||||
|
||||
return exp;
|
||||
}
|
||||
else
|
||||
throw new ParserException("Invalid token in expression: " + Current.TokenType + ". Was expecting identifier, string or number", Current.Line, Current.Column);
|
||||
}
|
||||
|
||||
private IdentifierPart ParseIdentifierPart()
|
||||
{
|
||||
IdentifierPart part = new IdentifierPart(Current.Data, Current.Line, Current.Column);
|
||||
Consume(); // consume identifier
|
||||
|
||||
// check for indexer
|
||||
if (Current.TokenType == TokenType.LBracket)
|
||||
{
|
||||
Consume(); // [
|
||||
part.Index = ParseExpression();
|
||||
Consume(TokenType.RBracket); // ]
|
||||
}
|
||||
// check for method call
|
||||
else if (Current.TokenType == TokenType.LParen)
|
||||
{
|
||||
Consume(); // (
|
||||
part.IsMethod = true;
|
||||
|
||||
// parse parameters
|
||||
while (Current.TokenType != TokenType.RParen)
|
||||
{
|
||||
part.MethodParameters.Add(ParseExpression());
|
||||
if (Current.TokenType == TokenType.RParen)
|
||||
break; // )
|
||||
|
||||
Consume(TokenType.Comma); // ,
|
||||
}
|
||||
Consume(TokenType.RParen); // )
|
||||
}
|
||||
|
||||
return part;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue