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(); } } }
// 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(); } } }
internal static bool TryParseIdent(string source, out string parsed, out int length) { length = 0; parsed = null; if (source.Length == 0) { return(false); } var i = 0; var result = new StringBuilder(); var hasDelimiterStart = CharacterUtils.IsIdentDelimiter(source[i]); var hasDelimiterEnd = false; if (!hasDelimiterStart) { // Simple identifier. while (i < source.Length && CharacterUtils.IsSimpleIdentCh(source[i])) { result.Append(source[i]); ++i; } parsed = result.ToString(); length = i; return(true); } // Delimited identifier. ++i; // Accept any characters up to the next unescaped identifier delimiter. for (; ;) { if (i >= source.Length) { break; } if (CharacterUtils.IsIdentDelimiter(source[i])) { if (i + 1 < source.Length && CharacterUtils.IsIdentDelimiter(source[i + 1])) { // Escaped delimiter. result.Append(source[i]); i += 2; } else { // End of the identifier. hasDelimiterEnd = true; ++i; break; } } else { result.Append(source[i]); ++i; } } if (hasDelimiterStart == hasDelimiterEnd && result.Length > 0) { length = i; parsed = result.ToString(); return(true); } return(false); }