public static Dictionary <string, string> Read(TextReader reader, string filenameHint = null) { var properties = new Dictionary <string, string>(StringComparer.Ordinal); var yaml = new YamlLexer(reader, filenameHint); while (true) { var t = yaml.ReadNext(); if (t.Kind == YamlTokenKind.EndOfFile) { break; } if (t.Kind != YamlTokenKind.Property) { // $$$ error t = YamlToken.NewError(t.Span, "Only properties are supported in this context"); } if (t.Kind == YamlTokenKind.Error) { // ToString will include source span and message. throw new InvalidOperationException(t.ToString()); } properties[t.Property] = t.Value; } return(properties); }
// Parse the control definition line. Something like: // Screen1 as Screen // Label1 As Label.Variant private TypedNameNode ParseControlDef(YamlToken token) { string line = token.Property; if (!TryParseControlDefCore(line, out var controlName, out var templateName, out var variantName)) { _errorContainer.ParseError(token.Span, "Can't parse control definition"); throw new DocumentException(); } return(new TypedNameNode { Identifier = controlName, Kind = new TypeNode { TypeName = templateName, OptionalVariant = variantName } }); }
private ArgMetadataBlockNode ParseArgMetadataBlock(YamlToken p) { var argNode = new ArgMetadataBlockNode() { Identifier = p.Property }; while (true) { p = _yaml.ReadNext(); switch (p.Kind) { case YamlTokenKind.EndObj: return(argNode); case YamlTokenKind.Property: if (p.Property == nameof(ArgMetadataBlockNode.Default)) { argNode.Default = new ExpressionNode() { Expression = p.Value } } ; else { _errorContainer.ParseError(p.Span, $"Unexpected key in function definition: {p}"); throw new DocumentException(); } break; case YamlTokenKind.Error: _errorContainer.ParseError(p.Span, p.Value); return(null); default: _errorContainer.ParseError(p.Span, $"Unexpected yaml token: {p}"); throw new DocumentException(); } } }
// Name ( Parameter-Name As Data-type [ , Parameter-Name As Data-type ... ] ) : (ThisProperty or Parameter-Name) : Metadata-Name : Metadata-Value ... ... // Currently iterating on what fields are present in the property metadata blocks // Right now, only Default is permitted private FunctionNode ParseFunctionDef(YamlToken p) { // Validation here mirrors validation in PA-Client var paramRegex = new Regex(@"^([\p{L}\p{Nd}\p{Mn}\p{Mc}\p{Pc}\p{Cf}]+?)\s+As\s+([\p{L}\p{Nd}\p{Mn}\p{Mc}\p{Pc}\p{Cf}]+)"); var funcNameRegex = new Regex(@"^([\p{L}\p{Nd}\p{Mn}\p{Mc}\p{Pc}\p{Cf}]+?)\("); var line = p.Property; var m = funcNameRegex.Match(line); if (!m.Success) { _errorContainer.ParseError(p.Span, $"Can't parse Function definition"); throw new DocumentException(); } var funcName = m.Groups[1].Value; var functionNode = new FunctionNode() { Identifier = funcName }; line = line.Substring(m.Length); m = paramRegex.Match(line); while (m.Success) { string argName = CharacterUtils.UnEscapeName(m.Groups[1].Value, _errorContainer); string kindName = CharacterUtils.UnEscapeName(m.Groups[2].Value, _errorContainer); functionNode.Args.Add(new TypedNameNode { Identifier = argName, Kind = new TypeNode { TypeName = kindName } }); line = line.Substring(m.Length).TrimStart(',', ' '); m = paramRegex.Match(line); } if (line != ")") { _errorContainer.ParseError(p.Span, $"Missing closing ')' in function definition"); throw new DocumentException(); } while (true) { p = _yaml.ReadNext(); switch (p.Kind) { case YamlTokenKind.EndObj: return(functionNode); // Expecting N+1 child objs where one is ThisProperty and the others N are the args case YamlTokenKind.StartObj: functionNode.Metadata.Add(ParseArgMetadataBlock(p)); break; case YamlTokenKind.Error: _errorContainer.ParseError(p.Span, p.Value); return(null); default: _errorContainer.ParseError(p.Span, $"Unexpected yaml token: {p}"); throw new DocumentException(); } } }
private BlockNode ParseNestedControl(YamlToken p) { if (p.Kind != YamlTokenKind.StartObj) { _errorContainer.ParseError(p.Span, $"Unexpected token {p}"); throw new DocumentException(); } var controlDef = ParseControlDef(p); var block = new BlockNode { Name = controlDef }; while (true) { p = _yaml.ReadNext(); switch (p.Kind) { case YamlTokenKind.EndObj: return(block); case YamlTokenKind.Property: block.Properties.Add(new PropertyNode { Identifier = CharacterUtils.UnEscapeName(p.Property, _errorContainer), Expression = new ExpressionNode { Expression = p.Value } }); break; // StartObj can either be a Control or Function def case YamlTokenKind.StartObj: if (IsControlStart(p.Property)) { var childNode = ParseNestedControl(p); if (_errorContainer.HasErrors) { return(null); } block.Children.Add(childNode); } else { var functionNode = ParseFunctionDef(p); if (_errorContainer.HasErrors) { return(null); } block.Functions.Add(functionNode); } break; case YamlTokenKind.Error: _errorContainer.ParseError(p.Span, p.Value); return(null); default: _errorContainer.ParseError(p.Span, $"Unexpected yaml token: {p}"); throw new DocumentException(); } } }