# A question about parsing (Markdown) string literals

**URL:** <https://discourse.julialang.org/t/a-question-about-parsing-markdown-string-literals/117442>\
**Category:** General Usage\
**Tags:** question, julia-markdown, internals\
**Created:** [July 24, 2024, 8:31pm UTC](https://discourse.julialang.org/t/a-question-about-parsing-markdown-string-literals/117442 "2024-07-24T20:31:57Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![mitiemannn](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mitiemannn/32/206115_2.png) [@mitiemannn](https://discourse.julialang.org/u/mitiemannn)\
**Post date:** [July 24, 2024, 8:31pm UTC](https://discourse.julialang.org/t/a-question-about-parsing-markdown-string-literals/117442/1 "2024-07-24T20:31:57Z")

</div>

Hi everyone,

I’ve tried to generate a `Markdown.MD` object from an computed string and observed something odd (MWE):

```julia
julia> using Markdown

julia> md"foo\
       bar"
  foo
  bar

julia> md"foo\\\nbar"
  foo\\nbar

julia> test = "foo\\\nbar"
"foo\\\nbar"

julia> @md_str "foo\\\nbar"
  foo
  bar

julia> Markdown.parse(test)
  foo
  bar

julia> @md_str test
ERROR: LoadError: MethodError: no method matching parse(::Symbol; flavor::Symbol)

Closest candidates are:
  parse(::AbstractString; flavor)
   @ Markdown C:\Users\mail\.julia\juliaup\julia-1.10.4+0.x64.w64.mingw32\share\julia\stdlib\v1.10\Markdown\src\Markdown.jl:31

```

Can anybody explain to me why the last call to the macro fails, but calling it on the string literal directly works?  
Also, would it make sense to declare `Markdown.parse` as part of the public API for similar use cases?  
I’ve stumbled across this while trying to get a line break when using

```julia
julia> using Markdown

julia> test = "foo\\\nbar"
"foo\\\nbar"

julia> md"$test"
"foo\\\nbar"

```

I understand that in some string literals having recursive parsing would be a bad choice (e.g., regular expressions), but I’m guessing in some cases, it might make sense to enable or disable it via an API. I couldn’t find a standardized way how this is handled, though.  
E.g., in [HypertextLiteral.jl](https://github.com/JuliaPluto/HypertextLiteral.jl) there is a difference between

```julia
htl"foobar"

```

and

```julia
@htl "foobar"

```

with the latter enabling recursive descent by default. Would something similar make sense for certain use cases in `Stdlib` as well?

Thanks,  
Michael

_Edit:_ Should this have been posted to [Internals & Design](https://discourse.julialang.org/c/dev/5)?

---

<div class="post-metadata">

**Author:** ![savq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/savq/32/22063_2.png) [@savq](https://discourse.julialang.org/u/savq)\
**Post date:** [July 25, 2024, 1:18am UTC](https://discourse.julialang.org/t/a-question-about-parsing-markdown-string-literals/117442/2 "2024-07-25T01:18:44Z")

</div>

> Can anybody explain to me why the last call to the macro fails, but calling it on the string literal directly works?

The macro call `@md_str test` fails because macros don’t take values, they operate at the syntax level. In this case, the macro only “sees” the symbol `test`, it cannot see that the value of `test` is `"foo\\\nbar"`.

> Also, would it make sense to declare `Markdown.parse` as part of the public API for similar use cases?

I don’t know. I do find it weird that the [Markdown docs](https://docs.julialang.org/en/v1/stdlib/Markdown/) explain Julia’s bespoke markdown dialect, but they don’t actually document anything about the API of the package. Like… there’s not even a reference to `@md_str` 🤨

I didn’t understand that last part tho. Do you have an example? I’m pretty sure HypertextLiteral was written so `@htl_str` behaved like `@htl`.

---

<div class="post-metadata">

**Author:** ![mitiemannn](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mitiemannn/32/206115_2.png) [@mitiemannn](https://discourse.julialang.org/u/mitiemannn)\
**Post date:** [July 25, 2024, 8:31am UTC](https://discourse.julialang.org/t/a-question-about-parsing-markdown-string-literals/117442/3 "2024-07-25T08:31:46Z")

</div>

> The macro call `@md_str test` fails because macros don’t take values, they operate at the syntax level. In this case, the macro only “sees” the symbol `test`, it cannot see that the value of `test` is `"foo\\\nbar"`.

Thanks, that makes sense.

> I don’t know. I do find it weird that the [Markdown docs](https://docs.julialang.org/en/v1/stdlib/Markdown/) explain Julia’s bespoke markdown dialect, but they don’t actually document anything about the API of the package. Like… there’s not even a reference to `@md_str` 🤨

This has been fixed in 1.11 by yours truly 🕶 If I can find the time, I’ll try to improve it further still, but no promises at this point.

> I didn’t understand that last part tho. Do you have an example? I’m pretty sure HypertextLiteral was written so `@htl_str` behaved like `@htl`.

No, and this is by design. `@htl` allows nesting, i.e., recursive calls (see [here](https://juliapluto.github.io/HypertextLiteral.jl/stable/notation/)). I guess I don’t need fully recursive parsing in `Markdown`, but it would be nice to control whether special characters are parsed or taken literal, i.e., the difference between

```julia
julia> using Markdown

julia> test = "foo\\\nbar"
"foo\\\nbar"

julia> md"$test"
"foo\\\nbar"

```

and

```julia
julia> md"$test"
  foo
  bar

```

Do you see what I mean?

---

<div class="post-metadata">

**Author:** ![savq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/savq/32/22063_2.png) [@savq](https://discourse.julialang.org/u/savq)\
**Post date:** [July 25, 2024, 4:57pm UTC](https://discourse.julialang.org/t/a-question-about-parsing-markdown-string-literals/117442/4 "2024-07-25T16:57:22Z")

</div>

Ahh, ok. I get it. I thought you were asking a completely different thing. Yeah, there’s a couple of differences between string literals and non-standard string literals.

### Non-standard string literals don’t parse escape sequences (with some exceptions)

```julia-repl
julia> function f(s)
          return (s, length(s))
      end;

julia> macro m_str(s)
          return (s, length(s))
      end;

julia> f("\n")
("\n", 1)

julia> m"\n" # not escaped
("\\n", 2)

julia> f("\"")
("\"", 1)

julia> m"\"" # double quotes are escaped
("\"", 1)

julia> julia> m"\\ \\"
("\\\\ \\", 4)

```

In the last example the first `\\` is not an escape sequence, but the second one is. Otherwise we wouldn’t have a way to represent a backslash at the end of the string.

### Non-standard string literals don’t interpolate. ever.

HypertextLiteral’s `@htl_str` appears to interpolate, but this is a hack. What the macro does is manually scan the string, find the `$`, split the string, try to parse the “interpolations” with `Meta.parse`, and concatenate the result.

This is also why it you cannot write nested strings. If you have `m"$("`, then that’s it. That’s the whole string! You cannot enable or disable this behavior. That would require modifying the julia parser at runtime.

The thing that made non-standard string literals click for me was seeing that [`@raw_str` is in fact a no-op.](https://github.com/JuliaLang/julia/blob/48d4fd48430af58502699fdf3504b90589df3852/base/strings/io.jl#L590)

* * *

Going back to your example, since `@md_str` interpolations are fake, we’d need to know what function they’re using to interpolate the values. Maybe it’s intentional that interpolations cannot break lines or maybe it’s a bug.

edit: Thanks for updating the docs!
