Skip to content

Commit

Permalink
Add support for multi-line elixir statements (#96)
Browse files Browse the repository at this point in the history
  • Loading branch information
bfad authored and doomspork committed Apr 12, 2016
1 parent 285ac45 commit 311cf0f
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 7 deletions.
45 changes: 38 additions & 7 deletions lib/slime/parser.ex
Original file line number Diff line number Diff line change
Expand Up @@ -20,22 +20,28 @@ defmodule Slime.Parser do
r = ~r/(^|\G)(?:\\.|[^#]|#(?!\{)|(?<pn>#\{(?:[^"}]++|"(?:\\.|[^"#]|#(?!\{)|(?&pn))*")*\}))*?\K"/u
@quote_outside_interpolation_regex r
@verbatim_text_regex ~r/^(\s*)([#{@content}#{@preserved}])\s?/
@eex_line_regex ~r/^(\s*)(-|=|==)\s*(.*?)$/

@merge_attrs %{class: " "}

def parse_lines(lines, acc \\ [])

def parse_lines([], result), do: Enum.reverse(result)
def parse_lines([head | tail], result) do
case parse_verbatim_text(head, tail) do
{text, rest} ->
parse_lines(rest, [text | result])
parsed_result =
parse_verbatim_text(head, tail) ||
parse_eex_lines(head, tail) ||
parse_line(head)

case parsed_result do
nil ->
case parse_line(head) do
nil -> parse_lines(tail, result)
line -> parse_lines(tail, [line | result])
end
parse_lines(tail, result)

{text, rest} when is_list(rest) ->
parse_lines(rest, [text | result])

text ->
parse_lines(tail, [text | result])
end
end

Expand Down Expand Up @@ -242,6 +248,31 @@ defmodule Slime.Parser do
{text_lines, rest}
end

defp parse_eex_lines(head, tail) do
{indent, head} = strip_line(head)

case Regex.run(@eex_line_regex, head, capture: :all_but_first) do
nil ->
nil

[_, delim, content] ->
{content, rest} = slurp_eex_lines("", [content | tail])
inline? = @smart == String.first delim

{{indent, {:eex, content: content, inline: inline?}}, rest}
end
end

defp slurp_eex_lines(content, [head | tail]) do
content = content <> head

if String.last(head) in [",", "\\"] do
slurp_eex_lines(content <> "\n", tail)
else
{content, tail}
end
end

defp parse_wrapped_attributes(line, delim) do
[attrs, rem] = line
|> String.strip
Expand Down
52 changes: 52 additions & 0 deletions test/parser/multiline_elixir_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
defmodule ParserMultilineElixirTest do
use ExUnit.Case
alias Slime.Parser

test "= allows multi-line elixir expressions ending with backslash" do
lines = [
"= very_long_method_name \\",
" another_expression \\",
" Final_expression"
]
parsed = Parser.parse_lines(lines)
content = lines |> Enum.join("\n") |> String.lstrip(?=) |> String.lstrip

assert parsed == [{0, {:eex, [content: content, inline: true]}}]
end

test "= allows multi-line elixir method arguments" do
lines = [
"=method_name param1,",
" param2,",
" param3"
]
parsed = Parser.parse_lines(lines)
content = lines |> Enum.join("\n") |> String.lstrip(?=) |> String.lstrip

assert parsed == [{0, {:eex, [content: content, inline: true]}}]
end

test "- allows multi-line elixir expressions ending with backslash" do
lines = [
"- very_long_method_name \\",
" another_expression \\",
" Final_expression"
]
parsed = Parser.parse_lines(lines)
content = lines |> Enum.join("\n") |> String.lstrip(?-) |> String.lstrip

assert parsed == [{0, {:eex, [content: content, inline: false]}}]
end

test "- allows multi-line elixir method arguments" do
lines = [
"-method_name param1,",
" param2,",
" param3"
]
parsed = Parser.parse_lines(lines)
content = lines |> Enum.join("\n") |> String.lstrip(?-) |> String.lstrip

assert parsed == [{0, {:eex, [content: content, inline: false]}}]
end
end

0 comments on commit 311cf0f

Please sign in to comment.