forked from leanprover/lean4
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: string gaps for continuing string literals across multiple lines (
leanprover#2821) Implements "gaps" in string literals. These are escape sequences of the form `"\" newline whitespace+` that have the interpretation of an empty string. For example, ``` "this is \ a string" ``` is equivalent to `"this is a string"`. These are modeled after string continuations in [Rust](https://doc.rust-lang.org/beta/reference/tokens.html#string-literals). Implements RFC leanprover#2838
- Loading branch information
Showing
9 changed files
with
257 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
import Lean.Parser.Extension | ||
import Lean.Elab.Term | ||
|
||
/-! | ||
# Testing string gaps in string literals | ||
String gaps are described in RFC #2838 | ||
-/ | ||
|
||
/-! | ||
A string gap with no trailing space. | ||
-/ | ||
#eval "a\ | ||
b" | ||
|
||
/-! | ||
A string gap with trailing space before the `b`, which is consumed. | ||
-/ | ||
#eval "a\ | ||
b" | ||
|
||
/-! | ||
A string gap with space before the gap, which is not consumed. | ||
-/ | ||
#eval "a \ | ||
b" | ||
|
||
/-! | ||
Multiple string gaps in a row. | ||
-/ | ||
#eval "a \ | ||
\ | ||
\ | ||
b" | ||
|
||
/-! | ||
Two tests from the RFC. | ||
-/ | ||
#eval "this is \ | ||
a string" | ||
#eval "this is \ | ||
a string" | ||
|
||
/-! | ||
Two examples of how spaces are accounted for in string gaps. `\x20` is a way to force a leading space. | ||
-/ | ||
#eval "there are three spaces between the brackets < \ | ||
>" | ||
#eval "there are three spaces between the brackets <\ | ||
\x20 >" | ||
|
||
/-! | ||
Using `\n` to terminate a string gap, which is a technique suggested by Mario for using string gaps to write | ||
multiline literals in an indented context. | ||
-/ | ||
#eval "this is\ | ||
\n a string with two space indent" | ||
|
||
/-! | ||
Similar tests but for interpolated strings. | ||
-/ | ||
#eval s!"a\ | ||
b" | ||
#eval s!"a\ | ||
b" | ||
#eval s!"a\ | ||
b" | ||
|
||
/-! | ||
The `{` terminates the string gap. | ||
-/ | ||
#eval s!"a\ | ||
{"b"}\ | ||
" | ||
|
||
open Lean | ||
|
||
/-! | ||
## Testing whitespace handling with specific line terminators | ||
-/ | ||
|
||
/-! | ||
Standard string gap, with LF | ||
-/ | ||
#eval show MetaM String from do | ||
let stx ← ofExcept <| Parser.runParserCategory (← getEnv) `term "\"a\\\n b\"" | ||
let some s := stx.isStrLit? | failure | ||
return s | ||
|
||
/-! | ||
Standard string gap, with CRLF | ||
-/ | ||
#eval show MetaM String from do | ||
let stx ← ofExcept <| Parser.runParserCategory (← getEnv) `term "\"a\\\r\n b\"" | ||
let some s := stx.isStrLit? | failure | ||
return s | ||
|
||
/-! | ||
Isolated CR, which is an error | ||
-/ | ||
#eval show MetaM String from do | ||
let stx ← ofExcept <| Parser.runParserCategory (← getEnv) `term "\"a\\\r b\"" | ||
let some s := stx.isStrLit? | failure | ||
return s | ||
|
||
/-! | ||
Not a string gap since there's no end-of-line. | ||
-/ | ||
#eval show MetaM String from do | ||
let stx ← ofExcept <| Parser.runParserCategory (← getEnv) `term "\"a\\ b\"" | ||
let some s := stx.isStrLit? | failure | ||
return s | ||
|
||
/-! | ||
## Scala-style stripMargin | ||
This is a test that string gaps could be paired with a new string elaboration syntax | ||
for indented multiline string literals. | ||
-/ | ||
|
||
def String.dedent (s : String) : Option String := | ||
let parts := s.split (· == '\n') |>.map String.trimLeft | ||
match parts with | ||
| [] => "" | ||
| [p] => p | ||
| p₀ :: parts => | ||
if !parts.all (·.startsWith "|") then | ||
none | ||
else | ||
p₀ ++ "\n" ++ String.intercalate "\n" (parts.map fun p => p.drop 1) | ||
|
||
elab "d!" s:str : term => do | ||
let some s := s.raw.isStrLit? | Lean.Elab.throwIllFormedSyntax | ||
let some s := String.dedent s | Lean.Elab.throwIllFormedSyntax | ||
pure $ Lean.mkStrLit s | ||
|
||
#eval d!"this is \ | ||
line 1 | ||
| line 2, indented | ||
|line 3" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
"ab" | ||
"ab" | ||
"a b" | ||
"a b" | ||
"this is a string" | ||
"this is a string" | ||
"there are three spaces between the brackets < >" | ||
"there are three spaces between the brackets < >" | ||
"this is\n a string with two space indent" | ||
"ab" | ||
"ab" | ||
"ab" | ||
"ab" | ||
"ab" | ||
"ab" | ||
|
||
string_gaps.lean:101:0-104:10: error: <input>:1:4: expecting newline after carriage return | ||
|
||
string_gaps.lean:109:0-112:10: error: <input>:1:3: invalid escape sequence | ||
"this is line 1\n line 2, indented\nline 3" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
/-! | ||
# String gaps error test | ||
A string gap shouldn't have more than one trailing newline according to RFC #2838 | ||
-/ | ||
|
||
#eval "a\ | ||
b" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
string_gaps_err_newline.lean:8:0: error: unexpected additional newline in string gap |