private void ParseArgument(MapLexer lexer, MapParserContext context, MappedDataExpression expression) { // We should have an identifier... // TODO - literals var ident = CompoundIdentifier.Parse(lexer); // The identifier is either an attribute or a model... if (ident.HasPrefix) { expression.Arguments.Add(new MappedDataArgument(context.Resolve(ident))); } else { // A model...look it up and add it... var modelId = ident.Parts.First(); var model = context.Models.FirstOrDefault(x => x.Id == modelId); if (model == null) { throw new ParserException(ident, $"Model '{modelId}' not found."); } expression.Arguments.Add(new MappedDataArgument(model)); } }
private void ParseIgnore(MapParserContext context, MapLexer lexer) { lexer.Consume(TokenKind.Keyword, "ignore"); lexer.Consume(TokenKind.LeftCurly); while (lexer.Token.Kind == TokenKind.Identifier || lexer.Token.Kind == TokenKind.Keyword) { var ignoredId = CompoundIdentifier.Parse(lexer); var ignoredAttribute = context.Resolve(ignoredId); context.MapList.AddIgnored(ignoredAttribute); lexer.Consume(TokenKind.Semicolon); } lexer.Consume(TokenKind.RightCurly); }
public MappedDataExpression Parse(MapLexer lexer, MapParserContext context) { var expression = new MappedDataExpression(); // Regardless, we should always start with an identifier. This means that functions // are not keywords. lexer.VerifyToken(TokenKind.Identifier); // If the identifier is a function name, parse a function call... if (functions.Contains(lexer.Token.Text)) { ParseFunctionCall(lexer, context, expression); } else { // We don't have a function call, it must be an identifier. Parse it... var ident = CompoundIdentifier.Parse(lexer); var resolved = context.Resolve(ident); expression.Arguments.Add(new MappedDataArgument(resolved)); } return(expression); }
private void ParseStatement(MapParserContext context, MapLexer lexer) { // Constructs: // examples ... // ignore ... // with ... // { statements } if (lexer.Token.Kind == TokenKind.Keyword) { if (lexer.Token.Text == "with") { ParseWith(context, lexer); return; } else if (lexer.Token.Text == "name") { ParseName(context, lexer); return; } else if (lexer.Token.Text == "examples") { ParseExamples(context, lexer); return; } else if (lexer.Token.Text == "ignore") { ParseIgnore(context, lexer); return; } else { throw new ParserException($"Unexpected keyword '{lexer.Token.Text}'.", lexer.Token); } } else if (lexer.Token.Kind == TokenKind.LeftCurly) { lexer.Consume(TokenKind.LeftCurly); while (lexer.Token.Kind != TokenKind.RightCurly) { ParseStatement(context, lexer); } lexer.Consume(TokenKind.RightCurly); return; } // Constructs: // ident = model(ident); // ident:ident = ident:ident; var lhs = CompoundIdentifier.Parse(lexer); lexer.Consume(TokenKind.Equals); var rhs = expressionParser.Parse(lexer, context); // A little special handling for the model function if (rhs.FunctionName == "model") { var model = rhs.Arguments.First().Model; if (model == null) { throw new ParserException("The 'model' function requires a model argument."); } context.AddModelAlias(lhs.Parts.First(), model); lexer.Consume(TokenKind.Semicolon); } else { var target = context.Resolve(lhs); var mapCount = context.MapList.Maps.Where(x => x.TargetAttribute.Equals(target)).Count(); var mapping = new ExpressiveMapping(IdNames.Substring(mapCount, 1), target, rhs); context.MapList.Maps.Add(mapping); if (lexer.Token.Kind == TokenKind.LeftCurly) { ParseMappingExtras(context, lexer, mapping); } else { lexer.Consume(TokenKind.Semicolon); } } }