diff --git a/cfml.parsing/src/main/java/cfml/parsing/cfmentat/tag/CFMLStartTag.java b/cfml.parsing/src/main/java/cfml/parsing/cfmentat/tag/CFMLStartTag.java index 7ab72e8..9c838f7 100644 --- a/cfml.parsing/src/main/java/cfml/parsing/cfmentat/tag/CFMLStartTag.java +++ b/cfml.parsing/src/main/java/cfml/parsing/cfmentat/tag/CFMLStartTag.java @@ -69,6 +69,8 @@ protected int getEnd(final Source source, final int pos) { if (!isInQuotes && !isInApos) { if (x > 2 && text.subSequence(x - 3, x).equals("---")) { // do nothing, this is a comment + } else if (isArrowOperator(text, x)) { + // do nothing, this '>' is the tail of => or -> inside an expression } else { return x + 1; } @@ -95,6 +97,25 @@ protected int getEnd(final Source source, final int pos) { return endStartTagEnd; } + /** + * True when the '>' at pos is the second character of an arrow operator, as in + * <cfset f = (x) => x + 1>. Without this the tag ends inside the operator + * and the expression is silently truncated to f = (x) =. + * + * A '-' is only an arrow when it does not follow another '-', so the decrement in + * <cfset a = i--> still ends the tag. + */ + private static boolean isArrowOperator(final ParseText text, final int pos) { + if (pos < 1) { + return false; + } + final char previous = text.charAt(pos - 1); + if (previous == '=') { + return true; + } + return previous == '-' && (pos < 2 || text.charAt(pos - 2) != '-'); + } + protected ArrayList getAttributes(String inData) { ArrayList attributes = new ArrayList(); Matcher matcher; diff --git a/cfml.parsing/src/test/resources/tag/tests/parsing/cfset_lambda_44.cfm b/cfml.parsing/src/test/resources/tag/tests/parsing/cfset_lambda_44.cfm new file mode 100644 index 0000000..786f3dd --- /dev/null +++ b/cfml.parsing/src/test/resources/tag/tests/parsing/cfset_lambda_44.cfm @@ -0,0 +1,8 @@ +prefix + t.b()> + t.b()> + x + y> + target.toString() )> + + + diff --git a/cfml.parsing/src/test/resources/tag/tests/parsing/cfset_lambda_44.expected.txt b/cfml.parsing/src/test/resources/tag/tests/parsing/cfset_lambda_44.expected.txt new file mode 100644 index 0000000..55c6c74 --- /dev/null +++ b/cfml.parsing/src/test/resources/tag/tests/parsing/cfset_lambda_44.expected.txt @@ -0,0 +1,279 @@ +START:cfoutput + =========TAG================= + prefix +END:cfoutput +START:cfset + =========TAG================= + t.b()> + TAG + ==========Tokens============== + IDENTIFIER + '=' <=> + IDENTIFIER + '=>' <=>> + IDENTIFIER + '.' <.> + IDENTIFIER + '(' <(> + ')' <)> + ===========Tree================ + (expression + (assignmentExpression + (startExpression + (baseExpression (unaryExpression (memberExpression (identifier closure)))) + ) + = + (startExpression + (baseExpression + (lambdaDeclaration + (identifier t) + => + (startExpression + (baseExpression + (unaryExpression + (memberExpression + (identifier t) + . + (qualifiedFunctionCall (identifier b) ( argumentList )) + ) + ) + ) + ) + ) + ) + ) + ) + + ) + ===========Expression=============== + closure = (t) => t.b() + ================================== +END:cfset +START:cfset + =========TAG================= + t.b()> + TAG + ==========Tokens============== + IDENTIFIER + '=' <=> + IDENTIFIER + '->' <->> + IDENTIFIER + '.' <.> + IDENTIFIER + '(' <(> + ')' <)> + ===========Tree================ + (expression + (assignmentExpression + (startExpression + (baseExpression (unaryExpression (memberExpression (identifier lambda)))) + ) + = + (startExpression + (baseExpression + (lambdaDeclaration + (identifier t) + -> + (startExpression + (baseExpression + (unaryExpression + (memberExpression + (identifier t) + . + (qualifiedFunctionCall (identifier b) ( argumentList )) + ) + ) + ) + ) + ) + ) + ) + ) + + ) + ===========Expression=============== + lambda = (t) -> t.b() + ================================== +END:cfset +START:cfset + =========TAG================= + x + y> + TAG + ==========Tokens============== + IDENTIFIER + '=' <=> + '(' <(> + IDENTIFIER + ',' <,> + IDENTIFIER + ')' <)> + '=>' <=>> + IDENTIFIER + '+' <+> + IDENTIFIER + ===========Tree================ + (expression + (assignmentExpression + (startExpression + (baseExpression + (unaryExpression (memberExpression (identifier parenthesised))) + ) + ) + = + (startExpression + (baseExpression + (lambdaDeclaration + ( + (parameterList (parameter (identifier x)) , (parameter (identifier y))) + ) + => + (startExpression + (baseExpression + (baseExpression (unaryExpression (memberExpression (identifier x)))) + + + (baseExpression (unaryExpression (memberExpression (identifier y)))) + ) + ) + ) + ) + ) + ) + + ) + ===========Expression=============== + parenthesised = (x, y) => x + y + ================================== +END:cfset +START:cfset + =========TAG================= + target.toString() )> + TAG + ==========Tokens============== + IDENTIFIER + '=' <=> + IDENTIFIER + '(' <(> + ')' <)> + '.' <.> + IDENTIFIER + '(' <(> + IDENTIFIER + '->' <->> + IDENTIFIER + '.' <.> + IDENTIFIER + '(' <(> + ')' <)> + ')' <)> + ===========Tree================ + (expression + (assignmentExpression + (startExpression + (baseExpression (unaryExpression (memberExpression (identifier nested)))) + ) + = + (startExpression + (baseExpression + (unaryExpression + (memberExpression + (functionCall (identifier getURLs) ( argumentList )) + . + (qualifiedFunctionCall + (identifier map) + ( + (argumentList + (argument + (lambdaDeclaration + (identifier target) + -> + (startExpression + (baseExpression + (unaryExpression + (memberExpression + (identifier target) + . + (qualifiedFunctionCall (identifier toString) ( argumentList )) + ) + ) + ) + ) + ) + ) + ) + ) + ) + ) + ) + ) + ) + ) + + ) + ===========Expression=============== + nested = getURLs().map((target) -> target.toString()) + ================================== +END:cfset +START:!--- + =========TAG================= + +END:!--- +START:cfset + =========TAG================= + + TAG + ==========Tokens============== + IDENTIFIER + '=' <=> + IDENTIFIER + '--' <--> + ===========Tree================ + (expression + (assignmentExpression + (startExpression + (baseExpression (unaryExpression (memberExpression (identifier countdown)))) + ) + = + (startExpression + (baseExpression + (unaryExpression (unaryExpression (memberExpression (identifier i))) --) + ) + ) + ) + + ) + ===========Expression=============== + countdown = i-- + ================================== +END:cfset +START:cfset + =========TAG================= + + TAG + ==========Tokens============== + IDENTIFIER + '=' <=> + IDENTIFIER + GT + INTEGER_LITERAL <1> + ===========Tree================ + (expression + (assignmentExpression + (startExpression + (baseExpression (unaryExpression (memberExpression (identifier comparison)))) + ) + = + (startExpression + (baseExpression + (baseExpression (unaryExpression (memberExpression (identifier total)))) + (compareExpressionOperator gt) + (baseExpression (unaryExpression (primaryExpression (literalExpression 1)))) + ) + ) + ) + + ) + ===========Expression=============== + comparison = total gt 1 + ================================== +END:cfset