Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#nullable enable

using Microsoft.CodeAnalysis.Text;
using System;
using System.Collections.Generic;
using System.Text;

namespace Microsoft.DotNet.Interactive.Http.Parsing;
internal class HttpEscapedCharacterSequenceNode : HttpSyntaxNode
{
public HttpEscapedCharacterSequenceNode(SourceText sourceText, HttpSyntaxTree syntaxTree) : base(sourceText, syntaxTree)
{
}

public string NonEscapedText => Text.TrimStart('\\');

}
Original file line number Diff line number Diff line change
Expand Up @@ -138,13 +138,19 @@ private static void AddCommentsIfAny(
if (node is null)
{
if (CurrentToken is
{ Kind: TokenKind.Word } or
{ Kind: TokenKind.Punctuation } and ({ Text: "/" } or { Text: "'" } or { Text: "\"" }))
{ Kind: TokenKind.Word } or
{ Kind: TokenKind.Punctuation } and ({ Text: "/" } or { Text: "'" } or { Text: "\"" }))
{
node = new HttpVariableValueNode(_sourceText, _syntaxTree);

ParseLeadingWhitespaceAndComments(node);
}
else if (IsStartOfEscapedCharacterSequence())
{
node = new HttpVariableValueNode(_sourceText, _syntaxTree);
var escapedSequence = ParseEscapedCharacterSequence();
node.Add(escapedSequence);
}
else if (IsAtStartOfEmbeddedExpression())
{
node = new HttpVariableValueNode(_sourceText, _syntaxTree);
Expand All @@ -164,6 +170,10 @@ private static void AddCommentsIfAny(
{
node.Add(ParseEmbeddedExpression());
}
else if (IsStartOfEscapedCharacterSequence())
{
node.Add(ParseEscapedCharacterSequence());
}
else
{
ConsumeCurrentTokenInto(node);
Expand Down Expand Up @@ -541,6 +551,13 @@ private bool IsAtStartOfEmbeddedExpression() =>
CurrentToken is { Text: "{" } &&
CurrentTokenPlus(1) is { Text: "{" };

private bool IsStartOfEscapedCharacterSequence() =>
CurrentToken is { Kind: TokenKind.Punctuation } and { Text: "\\" } &&
(CurrentTokenPlus(1) is { Kind: TokenKind.Punctuation } and { Text: "{" } &&
CurrentTokenPlus(2) is { Kind: TokenKind.Punctuation } and { Text: "{" }) ||
(CurrentTokenPlus(1) is { Kind: TokenKind.Punctuation } and { Text: "}" } &&
CurrentTokenPlus(2) is { Kind: TokenKind.Punctuation } and { Text: "}" });

private HttpEmbeddedExpressionNode ParseEmbeddedExpression()
{
var node = new HttpEmbeddedExpressionNode(_sourceText, _syntaxTree);
Expand Down Expand Up @@ -889,6 +906,17 @@ private HttpCommentStartNode ParseCommentStart()
return node;
}

private HttpEscapedCharacterSequenceNode ParseEscapedCharacterSequence()
{
var node = new HttpEscapedCharacterSequenceNode(_sourceText, _syntaxTree);

ConsumeCurrentTokenInto(node); // parse the first \
ConsumeCurrentTokenInto(node); // parse the first { or }
ConsumeCurrentTokenInto(node); // parse the second { or }

return ParseTrailingWhitespace(node);
}

private bool IsComment()
{
if (MoreTokens() && !IsRequestSeparator())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using System.Collections.Generic;
using System.Linq;
using Microsoft.DotNet.Interactive.Parsing;
using System.Text;

namespace Microsoft.DotNet.Interactive.Http.Parsing;

Expand Down Expand Up @@ -53,51 +54,71 @@ public void Add(HttpRequestSeparatorNode separatorNode)
if (node.ValueNode is not null && node.DeclarationNode is not null)
{
var embeddedExpressionNodes = node.ValueNode.ChildNodes.OfType<HttpEmbeddedExpressionNode>();
if (!embeddedExpressionNodes.Any())
var potentialEscapedCharacters = node.ValueNode.ChildNodes.OfType<HttpEscapedCharacterSequenceNode>();
if (potentialEscapedCharacters.Any())
{
foundVariableValues[node.DeclarationNode.VariableName] = node.ValueNode.Text;
declaredVariables[node.DeclarationNode.VariableName] = new DeclaredVariable(node.DeclarationNode.VariableName, node.ValueNode.Text, HttpBindingResult<string>.Success(Text));
}
else
{
var value = node.ValueNode.TryGetValue(node =>
StringBuilder sb = new StringBuilder();
foreach (var child in node.ValueNode.ChildNodesAndTokens)
{
if (foundVariableValues.TryGetValue(node.Text, out string? stringValue))
if (child is HttpEscapedCharacterSequenceNode sequenceNode)
{
return node.CreateBindingSuccess(stringValue);
}
else if (bind != null)
{
return bind(node);
sb.Append(sequenceNode.NonEscapedText);
}
else
{
return DynamicExpressionUtilities.ResolveExpressionBinding(node, node.Text);
sb.Append(child.Text);
}
}

var value = sb.ToString();
foundVariableValues[node.DeclarationNode.VariableName] = value;
declaredVariables[node.DeclarationNode.VariableName] = new DeclaredVariable(node.DeclarationNode.VariableName, value, HttpBindingResult<string>.Success(Text));
}
else if (!embeddedExpressionNodes.Any())
{
foundVariableValues[node.DeclarationNode.VariableName] = node.ValueNode.Text;
declaredVariables[node.DeclarationNode.VariableName] = new DeclaredVariable(node.DeclarationNode.VariableName, node.ValueNode.Text, HttpBindingResult<string>.Success(Text));
}
else
{
var value = node.ValueNode.TryGetValue(node =>
{
if (foundVariableValues.TryGetValue(node.Text, out string? stringValue))
{
return node.CreateBindingSuccess(stringValue);
}
else if (bind != null)
{
return bind(node);
}
else
{
return DynamicExpressionUtilities.ResolveExpressionBinding(node, node.Text);
}

});
});

if (value?.Value != null)
if (value?.Value != null)
{
declaredVariables[node.DeclarationNode.VariableName] = new DeclaredVariable(node.DeclarationNode.VariableName, value.Value, value);
}
else
{
if(diagnostics is null)
{
declaredVariables[node.DeclarationNode.VariableName] = new DeclaredVariable(node.DeclarationNode.VariableName, value.Value, value);
}
else
diagnostics = value?.Diagnostics;
}
else
{
if(diagnostics is null)
{
diagnostics = value?.Diagnostics;
}
else
if (value is not null)
{
if (value is not null)
{
diagnostics.AddRange(value.Diagnostics);
}

}
diagnostics.AddRange(value.Diagnostics);
}

}
}
}
}
}

return (declaredVariables, diagnostics);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,7 @@ internal HttpVariableValueNode(SourceText sourceText, HttpSyntaxTree syntaxTree)

public void Add(HttpEmbeddedExpressionNode node) => AddInternal(node);

public void Add(HttpEscapedCharacterSequenceNode node) => AddInternal(node);

public HttpBindingResult<string> TryGetValue(HttpBindingDelegate bind) => this.BindByInterpolation(bind);
}
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,35 @@ public void single_quotes_in_variable_values_are_supported()

}

[Fact]
public void double_braces_escaping_single_braces_are_supported()
{
var result = Parse(
"""

@text=\{{text\}}
"""
);

var variables = result.SyntaxTree.RootNode.TryGetDeclaredVariables().declaredVariables;
variables.Should().Contain(n => n.Key == "text").Which.Value.Should().BeOfType<DeclaredVariable>().Which.Value.Should().Be("{{text}}");
}

[Fact]
public void triple_escaped_curly_braces_in_variable_values_are_supported()
{
var result = Parse(
"""

@text=\{{{text\}}}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the escaping only intended to work on the RHS of variable assignment? Do we support literal values inside embedded expression within the body of requests for instance, and can those literal values contain {{ sequences that may need to be escaped?

(Sorry drawing a blank on how the embedded expressions are supposed to work within body and whether they only support references to other variables etc. :) If literal values are not supported within embedded expressions and only other variable references are supported there in, then feel free to ignore...)

"""
);

var variables = result.SyntaxTree.RootNode.TryGetDeclaredVariables().declaredVariables;
variables.Should().Contain(n => n.Key == "text").Which.Value.Should().BeOfType<DeclaredVariable>().Which.Value.Should().Be("{{{text}}}");

}

[Fact]
public void double_quotes_in_variable_values_are_supported()
{
Expand Down