Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix ASTNode#to_s to use escape sequence correctly #5842

Conversation

makenowjust
Copy link
Contributor

ASTNode#to_s against StringInterpolation, RegexLiteral, and Call of backtick operator is buggy, it is missing to use escape sequence.

For example pp "#{1}\0" cannot be compiled by current compiler:

$ cat foo.cr
pp "#{1}\0"
$ crystal run foo.cr
Error in foo.cr:1: macro didn't expand to a valid program, it expanded to:

================================================================================
--------------------------------------------------------------------------------
   1.
   2.
   3.     __temp_20 = "#{"\"\#{1}\u0000\""} # => "
   4.     ::print __temp_20
   5.     __temp_21 = "#{1}"
   6.     PrettyPrint.format(__temp_21, STDOUT, width: 80 - __temp_20.size, indent: __temp_20.size)
   7.     ::puts
   8.     __temp_21
   9.
--------------------------------------------------------------------------------
Syntax error in expanded macro: pp:5: unterminated string literal

    __temp_21 = "#{1}"
                     ^

================================================================================

pp "#{1}\0"
^~

Because ASTNode#to_s against "#{1}\0" yields "#{1} and real null character.

Thank you.

@straight-shoota
Copy link
Member

Wouldn't it be better to implement the escape logic from #5841 in a class method so it can be reused here?

@makenowjust
Copy link
Contributor Author

makenowjust commented Mar 20, 2018

@straight-shoota Good idea. I'll fix this PR after #5841 is merged.

@makenowjust makenowjust force-pushed the fix/crystal/to-s-for-string-like-literal-escape branch from e4a7fd6 to 0fb38bd Compare March 21, 2018 04:21
@makenowjust
Copy link
Contributor Author

Updated. Escape logic is only in Regex class method now.

@@ -499,9 +499,9 @@ module Crystal
@str << '`'
case exp
when StringLiteral
@str << exp.value.inspect[1..-2]
@str << exp.value.inspect_unquoted.gsub('`', "\\`")
Copy link
Member

Choose a reason for hiding this comment

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

inspect_unquoted will escape \" which is not wrong but also not needed here. Not sure if this should be changed in this PR as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes. backtick operator must need escaping backtick and null character. However, it also accepts all string escape sequences, so I use inspect_unquoted.

@@ -968,9 +968,9 @@ module Crystal
@str << "/"
case exp = node.value
when StringLiteral
@str << exp.value.gsub('/', "\\/")
@str << escape_regex exp.value
Copy link
Member

Choose a reason for hiding this comment

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

Regex.append_source(exp.value, @str)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes.

when StringInterpolation
visit_interpolation exp, &.gsub('/', "\\/")
visit_interpolation(exp) { |s| escape_regex s }
end
Copy link
Member

Choose a reason for hiding this comment

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

ditto

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think no ditto here.

when StringInterpolation
visit_interpolation exp, &.gsub('/', "\\/")
visit_interpolation(exp) { |s| escape_regex s }
Copy link
Member

Choose a reason for hiding this comment

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

Why not use Regex.append_source directly? visit_interpolation simply appends to @str. You can do that in the block as well and don't need the string builder. Just make sure the block returns nil or empty string.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You are trick star!! Yeah!

makenowjust added a commit to makenowjust/crystal that referenced this pull request Mar 21, 2018
Copy link
Member

@straight-shoota straight-shoota left a comment

Choose a reason for hiding this comment

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

Great work!

@RX14 RX14 modified the milestone: Next Mar 21, 2018
@RX14 RX14 requested a review from asterite March 21, 2018 13:47
@sdogruyol
Copy link
Member

@makenowjust this need a rebase 👍

ASTNode#to_s against StringInterpolation, RegexLiteral, and Call of
backtick operator is buggy, it is missing to use escape sequence.

For example `pp "#{1}\0"` cannot be compiled by current compiler.
@makenowjust makenowjust force-pushed the fix/crystal/to-s-for-string-like-literal-escape branch from 3f1f6f1 to 9282181 Compare April 14, 2018 13:51
@sdogruyol sdogruyol merged commit 9f589a0 into crystal-lang:master Apr 19, 2018
@sdogruyol sdogruyol added this to the Next milestone Apr 19, 2018
@makenowjust makenowjust deleted the fix/crystal/to-s-for-string-like-literal-escape branch April 21, 2018 00:31
@makenowjust
Copy link
Contributor Author

@sdogruyol Thank you.

chris-huxtable pushed a commit to chris-huxtable/crystal that referenced this pull request Jun 6, 2018
* Fix ASTNode#to_s to use escape sequence correctly

ASTNode#to_s against StringInterpolation, RegexLiteral, and Call of
backtick operator is buggy, it is missing to use escape sequence.

For example `pp "#{1}\0"` cannot be compiled by current compiler.

* Regex: make append_source as class method for RegexLiteral#to_s

* Use Regex.append_source directly

* Remove escape_regex and use Regex.append_source directly for all

crystal-lang#5842 (comment)

It is super tricky way.
But @straight-shoota said, so it is right way also.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants