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

Delegate tree building to the parser #128

Merged
merged 14 commits into from
Jun 1, 2017

Conversation

little-bobby-tables
Copy link
Contributor

Removing the intermediate representation reduces the complexity of the parser and makes it easier to perform line-independent transforms (handling if-else, for instance).

I had to add trailing whitespace removal to the preprocessor because I couldn't handle certain edge cases like "blank lines after if-else" (test/rendering_test.ex) without severely complicating the grammar.

@doomspork
Copy link
Member

Thank you @little-bobby-tables! @Rakoth and/or myself will take a peek at this and let you know if we have any feedback 😁

Copy link
Member

@Rakoth Rakoth left a comment

Choose a reason for hiding this comment

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

This is a great work done, @little-bobby-tables ! I left some comments, there are two about parser grammar, which we could open as separate issues, if you think it is not in scope of this changes.

"/" -> {[], true}
"" -> {[], false}
[] -> {[], false}
(%EExNode{} = eex) -> {[eex], false}
Copy link
Member

Choose a reason for hiding this comment

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

We could use content variable here and in next match:

%EExNode{} -> {[content], false}

body = cond do
tag.closed -> "<" <> tag_head <> "/>"
name in @void_elements -> "<" <> tag_head <> ">"
:otherwise -> "<" <> tag_head <> ">"
Copy link
Member

Choose a reason for hiding this comment

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

matter of taste, but I would prefer line-break after -> in this case

|> Enum.map(fn branch -> render_branch(branch) end)
|> Enum.join(lines_sep)
def compile([]), do: ""
def compile([h | tree]) do
Copy link
Member

Choose a reason for hiding this comment

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

guard will do better here compile(tags) when is_list(tags)


% NOTE: Leading whitespace is handled separately for comments and verbatim text
tag <- comment / verbatim_text / space? tag_item / blank:(space? &eol);
tags <- (tag crlf*)+;
Copy link
Member

Choose a reason for hiding this comment

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

Should we order rules as they appear in grammar, from top to bottom for easier reading?


tag_item <- (embedded_engine / inline_html / code / html_tag);
inline_html <- &'<' text_content nested_tags?;
Copy link
Member

Choose a reason for hiding this comment

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

Am I missing something, or html with nested children should always have a closing inline html part, so the following examples should raise a parsing error.

<img />
  | test
<div>
  | test
</div>
  | test 1

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Slim does not check for the closing tag. It's an interesting idea — it could be handled similar to if-else — but I think it is out of scope of this PR, yes.

code <- inline:('=' '='? tag_spaces? / '-') space? code:code_lines;
code_lines <- code_line / code_line_with_brake crlf (indent code_lines dedent / code_lines);
simple_tag <- tag:tag_shortcut spaces:tag_spaces space?
content:attributes_with_content children:nested_tags?;
Copy link
Member

@Rakoth Rakoth May 27, 2017

Choose a reason for hiding this comment

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

There are some invalid test cases, currently supported by accident. In ruby-slim tag with inline content could not have nested children tags, (if there are nested lines, they treated as inline content continuation). In some cases it as already not handled by slime, so I think it is time to fix this behaviour, or at least have a parsing error for this case.
For example:

div test
  test

in slim renders to

<div>test
test</div>

@Rakoth
Copy link
Member

Rakoth commented May 27, 2017

There is also some problem with code continuation lines:

= Enum.join([1,
  2])

p test

raises a parser error about unexpected dedent on line 3

@little-bobby-tables
Copy link
Contributor Author

@Rakoth, I think I've addressed the issues you've brought up. I couldn't pinpoint exactly why the code continuation rule was failing; I believe it was due to some other rule that used to consume dedents past it, but I'm not sure. Either way, since the preprocessor already skips indentation for lines broken by a backslash, I've just added commas to the regular expression there and that seemed to solve it.

I also haven't replied to your comment about grammar reordering. I don't feel strongly about it, it's probably better to do it outside of this changeset.

@doomspork: the PR now includes a breaking change concerning the behavior of nodes with inline content. What used to be rendered as nested tags:

h1 Secret:
  = word

is now rendered as text, so as to fit this example from the Slim documentation:

p No items found. Please add some inventory.
  Thank you!

WDYT?

Copy link
Member

@Rakoth Rakoth left a comment

Choose a reason for hiding this comment

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

👍 LGTM

@Rakoth
Copy link
Member

Rakoth commented Jun 1, 2017

@doomspork I think we good to merge this PR, any objections?

@doomspork
Copy link
Member

No sir @Rakoth! This looks good to me.

Thank you again @little-bobby-tables, this is great!

@doomspork doomspork merged commit 64d6d9c into slime-lang:master Jun 1, 2017
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.

3 participants