Skip to content

Commit

Permalink
Relax whitespace requirement around operators. (#706)
Browse files Browse the repository at this point in the history
  • Loading branch information
gdotdesign authored Nov 18, 2024
1 parent 68aebac commit 7278b7a
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 22 deletions.
12 changes: 12 additions & 0 deletions spec/examples/pipe
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,15 @@ component Main {
""
}
}
-------------------------------------------------------------------------------
component Main {
fun test (value : String) {
value
}

fun render : Html {
"test" |> test

<div/>
}
}
1 change: 0 additions & 1 deletion src/parser/top_level.cr
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,6 @@ module Mint
component ||
constant ||
property ||
operator ||
provider ||
function ||
comment ||
Expand Down
65 changes: 44 additions & 21 deletions src/parsers/operator.cr
Original file line number Diff line number Diff line change
Expand Up @@ -26,40 +26,63 @@ module Mint
"!" => 16,
}

# Parses an operator.
#
# All operators must follow a whitespace because we don't have an end of
# line token, so the expression can leak through to the next entity, for
# example:
#
# const NAME = "Joe"
#
# /* This is a comment. */
# fun greet (name : String = NAME) { ... }
#
# In this case the start token of the comment (/*) can be interpreted as an
# operation (/) and the whitespace prevents that.
def operator : String?
parse do
parse do |start_position|
whitespace

saved_position =
position

operator =
OPERATORS.keys.find { |item| word! item }
OPERATORS.keys.find { |item| word? item }

next unless operator
next if operator != "|>" && !whitespace?

case operator
when "<"
# If we are in a different line then left side then it's probably
# not a operation:
#
# Left side
# |---|
# <div>
# <div>
# |
# Potential operator
#
next if start_position.line < position.line

# If the right side parses as a base expression:
#
# Left side Right side
# |---| |---|
# <div> <div>
# |
# Potential operator
#
next if parse { whitespace; base_expression }

# This prevents the this to parse as a regexp literal:
#
# Start tag Variable Potential operator
# |---| |-------| |
# <div> variable </div>
# |
# Regexp literal start
#
next if next_char == '/'
when "/"
# It's probably a comment (`// comment`, `/* comment */`)
next if next_char.in?('*', '/')
end

word! operator

case operator
when "or"
# This is not an operation but part of a statements
# "or return" section.
next if parse do
whitespace
keyword! "return"
end
# `or return` section.
next if parse { whitespace; keyword! "return" }

ast.keywords << {from: saved_position, to: saved_position + operator.size}
else
Expand Down

0 comments on commit 7278b7a

Please sign in to comment.