savi-lang / savi

A fast language for programmers who are passionate about their craft.
BSD 3-Clause "New" or "Revised" License
154 stars 12 forks source link

Indented Multi-line string literals #396

Closed mneumann closed 1 year ago

mneumann commented 1 year ago

Instead of:

:class A
  :fun b
    v = <<<Line 1
Line 2
Line 3
>>>

I am proposing adding something like Zig's multi-line strings:

:class A
  :fun b
    v =
    \\Line 1
    \\Line 2
    \\Line 3

which would be functionally equivalent to (minus the trailing newline):

:class A
  :fun b
    v = String.join([
      "Line 1"
      "Line 2"
      "Line 3"
      ], "\n")
jemc commented 1 year ago

@mneumann - This should work today:

:class A
  :fun b
    v = <<<
      Line 1
      Line 2
      Line 3
    >>>
jemc commented 1 year ago

To elaborate, it uses the indentation of the first lines content to determine the "base" indentation to subtract from future lines. So your example didn't work only because you had zero indentation prior to Line 1.

mneumann commented 1 year ago

great! that looks nice

mneumann commented 1 year ago

one more issue: Escape sequences. They seem to be not working. Is there another form of heredocs that expand escape sequences and allow string interpolation?

jemc commented 1 year ago

Right now, by design, <<</>>>-style strings do not allow any escape sequences. I originally designed this form for Pony-like docstrings before I had ::-style doc comments, and the intent there was that they are 100% literal in their content, apart from indentation. And these are still useful today for being able to paste arbitrary content from arbitrary languages (e.g. JSON content with strings that have escape codes, and to have those escape codes be interpreted by the JSON parser at run time instead of by the Savi parser at compile time).

Note that we also have the \-[line break] escape sequence in a "/"-style string, which removes the literal line break and any indentation that follows it. This makes possible a few different patterns:

:class A
  :fun b
    v = "\
      Line 1\
      Line 2\
      Line 3\
    " // equivalent to "Line 1Line 2Line 3"
:class A
  :fun b
    v = "\
      Line 1 \
      Line 2 \
      Line 3\
    " // equivalent to "Line 1 Line 2 Line 3"
:class A
  :fun b
    v = "\
      Line 1
\
      Line 2
\
      Line 3
\
    " // equivalent to "Line 1\nLine 2\nLine 3\n"
mneumann commented 1 year ago

so in case I want to have indentation with " and \, I could do:

:class A
  :fun b
    v = "\
      Line 1\n   \
         Indented Line 2\n\
      Line 3\
    " // equivalent to "Line 1\n   Line 2\nLine 3"

It's tricky that the actual indentation is on the previous line (before \), but what I like is that leading whitespace are not significant.