Skip to content

Commit

Permalink
(#182) Parser: update the approach to newline recognition
Browse files Browse the repository at this point in the history
For #182, we want to distinguish a single newline versus several newlines in a PowerShell file.

This change allows that.
  • Loading branch information
ForNeVeR committed May 22, 2024
1 parent 17b9133 commit 4abc8be
Show file tree
Hide file tree
Showing 7 changed files with 27 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ class PowerShellFoldingBuilder : CustomFoldingBuilder(), DumbAware {

fun PsiElement.getNextSiblingNonWhiteSpace(): PsiElement? {
var next = this.nextSibling
while (next != null && (next is PsiWhiteSpace || next.node.elementType == NLS)) {
while (next != null && (next is PsiWhiteSpace || next.node.elementType == NEWLINE)) {
next = next.nextSibling
}
return next
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ internal fun isSwitchStatementContext(node: ASTNode): Boolean {

//internal fun isFirstInChainedCall(node: ASTNode): Boolean {
// if (node.treeParent?.elementType !== PowerShellTypes.INVOCATION_EXPRESSION) return false
// return findSiblingSkipping(node, arrayOf(PowerShellTypes.NLS, TokenType.WHITE_SPACE, PowerShellTypes.DOT, PowerShellTypes.COLON2), false)?.elementType !== PowerShellTypes.INVOCATION_EXPRESSION
// return findSiblingSkipping(node, arrayOf(PowerShellTypes.NEWLINE, TokenType.WHITE_SPACE, PowerShellTypes.DOT, PowerShellTypes.COLON2), false)?.elementType !== PowerShellTypes.INVOCATION_EXPRESSION
//}

internal fun isSubExpressionContext(node: ASTNode): Boolean {
Expand Down Expand Up @@ -231,16 +231,16 @@ internal fun isParenthesizedExpressionContext(node: ASTNode): Boolean {
return node.treeParent?.elementType === PowerShellTypes.PARENTHESIZED_EXPRESSION
}

internal fun isFollowedByAttribute(childNode: ASTNode) = findSiblingSkipping(childNode, arrayOf(PowerShellTypes.NLS, TokenType.WHITE_SPACE), false)?.elementType === PowerShellTypes.ATTRIBUTE
internal fun isFollowedByAttribute(childNode: ASTNode) = findSiblingSkipping(childNode, arrayOf(PowerShellTypes.NEWLINE, TokenType.WHITE_SPACE), false)?.elementType === PowerShellTypes.ATTRIBUTE

internal fun isRhsBinaryExpressionContext(node: ASTNode): Boolean {
if (!isBinaryExpressionContext(node)) return false
val type = findSiblingSkipping(node, arrayOf(PowerShellTypes.NLS, TokenType.WHITE_SPACE), false)?.elementType
val type = findSiblingSkipping(node, arrayOf(PowerShellTypes.NEWLINE, TokenType.WHITE_SPACE), false)?.elementType
return node.psi is PowerShellExpression && PowerShellTokenTypeSets.OPERATORS.contains(type)
}

internal fun isFirstNodeInForParameter(node: ASTNode): Boolean {
val prevIEType = findSiblingSkipping(node, arrayOf(PowerShellTypes.NLS, TokenType.WHITE_SPACE), false)?.elementType
val prevIEType = findSiblingSkipping(node, arrayOf(PowerShellTypes.NEWLINE, TokenType.WHITE_SPACE), false)?.elementType
return node.treeParent.elementType === PowerShellTypes.FOR_CLAUSE && (prevIEType === PowerShellTypes.SEMI || prevIEType === PowerShellTypes.LP)
}

Expand All @@ -258,12 +258,12 @@ internal fun isArrayElement(node: ASTNode): Boolean {

internal fun isInvocationExpressionQualifier(node: ASTNode): Boolean {
if (node.treeParent?.elementType !== PowerShellTypes.INVOCATION_EXPRESSION) return false
val prevElement = findSiblingSkipping(node, arrayOf(PowerShellTypes.NLS, TokenType.WHITE_SPACE), false)?.elementType
val prevElement = findSiblingSkipping(node, arrayOf(PowerShellTypes.NEWLINE, TokenType.WHITE_SPACE), false)?.elementType
return (prevElement === PowerShellTypes.DOT || prevElement === PowerShellTypes.COLON2) && (node.elementType === PowerShellTypes.REFERENCE_IDENTIFIER || node.psi is PowerShellExpression)
}

internal fun isFirstNodeInParameter(node: ASTNode, checkFirstParameter: Boolean = false): Boolean {
val prevSibling = findSiblingSkipping(node, arrayOf(PowerShellTypes.NLS, TokenType.WHITE_SPACE), false)
val prevSibling = findSiblingSkipping(node, arrayOf(PowerShellTypes.NEWLINE, TokenType.WHITE_SPACE), false)
return prevSibling != null && (prevSibling.elementType === PowerShellTypes.COMMA || (checkFirstParameter && prevSibling.elementType === PowerShellTypes.LP))
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ open class PowerShellBlockImpl(node: ASTNode, wrap: Wrap?, alignment: Alignment?
val type = child.elementType
if (type === INVOCATION_EXPRESSION) {
collectNodes(nodes, child)
} else if (type !== NLS) {
} else if (type !== NEWLINE) {
nodes.add(child)
}
}
Expand Down Expand Up @@ -225,7 +225,7 @@ open class PowerShellBlockImpl(node: ASTNode, wrap: Wrap?, alignment: Alignment?
}

private fun createWrap(childNode: ASTNode): Wrap {
if ((isFunctionParameter(childNode) || isBlockParameter(childNode)) && findSiblingSkipping(childNode, arrayOf(NLS, WHITE_SPACE), false)?.elementType != LP) {
if ((isFunctionParameter(childNode) || isBlockParameter(childNode)) && findSiblingSkipping(childNode, arrayOf(NEWLINE, WHITE_SPACE), false)?.elementType != LP) {
val firstNode = isFirstNodeInParameter(childNode, true)
val wrapValue = if (isFunctionParameter(childNode)) myCommonSettings.METHOD_PARAMETERS_WRAP else myPSSettings.BLOCK_PARAMETER_CLAUSE_WRAP
val paramWrap = Wrap.createWrap(WrappingUtil.getWrapType(wrapValue), firstNode)
Expand All @@ -246,7 +246,7 @@ open class PowerShellBlockImpl(node: ASTNode, wrap: Wrap?, alignment: Alignment?
return paramWrap
}

if (isCallArgument(childNode) && findSiblingSkipping(childNode, arrayOf(NLS, WHITE_SPACE), false)?.elementType != LP) {
if (isCallArgument(childNode) && findSiblingSkipping(childNode, arrayOf(NEWLINE, WHITE_SPACE), false)?.elementType != LP) {
return Wrap.createWrap(WrappingUtil.getWrapType(myCommonSettings.CALL_PARAMETERS_WRAP), isFirstNodeInParameter(childNode, true))
}

Expand Down Expand Up @@ -373,7 +373,7 @@ class PowerShellSpacingProcessor(private val myCommonSettings: CommonCodeStyleSe

if (LCURLY === type1 || RCURLY === type2) {
val braceNode = if (LCURLY === type1) node1 else node2
val blockBody = findSiblingSkipping(braceNode, arrayOf(NLS, WHITE_SPACE), braceNode === node1)
val blockBody = findSiblingSkipping(braceNode, arrayOf(NEWLINE, WHITE_SPACE), braceNode === node1)
val blockBodyToken = blockBody?.elementType
if (blockBodyToken === IDENTIFIER || blockBodyToken === SIMPLE_ID) return null

Expand Down Expand Up @@ -403,7 +403,7 @@ class PowerShellSpacingProcessor(private val myCommonSettings: CommonCodeStyleSe

if (LP === type1) {
if (isArgumentListContext(node1)) {
val treeNext = findSiblingSkipping(node1, arrayOf(NLS, WHITE_SPACE))
val treeNext = findSiblingSkipping(node1, arrayOf(NEWLINE, WHITE_SPACE))
val lfAfterLparen = myCommonSettings.CALL_PARAMETERS_WRAP != DO_NOT_WRAP && myCommonSettings.CALL_PARAMETERS_LPAREN_ON_NEXT_LINE
if (treeNext?.elementType === RP) {
val lfAfterRparen = myCommonSettings.CALL_PARAMETERS_WRAP != DO_NOT_WRAP && myCommonSettings.CALL_PARAMETERS_RPAREN_ON_NEXT_LINE
Expand All @@ -413,7 +413,7 @@ class PowerShellSpacingProcessor(private val myCommonSettings: CommonCodeStyleSe
return createSpacing(myCommonSettings.SPACE_WITHIN_METHOD_CALL_PARENTHESES, lfAfterLparen)
}
if (isParameterClauseContext(node1) || isBlockParameterClauseContext(node1)) {
val treeNext = findSiblingSkipping(node1, arrayOf(NLS, WHITE_SPACE))
val treeNext = findSiblingSkipping(node1, arrayOf(NEWLINE, WHITE_SPACE))
val methodParam = isParameterClauseContext(node1)
val wrapValue = if (methodParam) myCommonSettings.METHOD_PARAMETERS_WRAP else myPowerShellSettings.BLOCK_PARAMETER_CLAUSE_WRAP
val lParenNextLine = if (methodParam) myCommonSettings.METHOD_PARAMETERS_LPAREN_ON_NEXT_LINE else myPowerShellSettings.BLOCK_PARAMETERS_LPAREN_ON_NEXT_LINE
Expand Down Expand Up @@ -447,14 +447,14 @@ class PowerShellSpacingProcessor(private val myCommonSettings: CommonCodeStyleSe
}
if (RP === type2) {
if (isArgumentListContext(node2)) {
val treePrev = findSiblingSkipping(node2, arrayOf(NLS, WHITE_SPACE), false)
val treePrev = findSiblingSkipping(node2, arrayOf(NEWLINE, WHITE_SPACE), false)
val lfAfterRparen = myCommonSettings.CALL_PARAMETERS_WRAP != DO_NOT_WRAP && myCommonSettings.CALL_PARAMETERS_RPAREN_ON_NEXT_LINE
if (treePrev?.elementType === LP) return createSpacing(myCommonSettings.SPACE_WITHIN_EMPTY_METHOD_CALL_PARENTHESES, lfAfterRparen)

return createSpacing(myCommonSettings.SPACE_WITHIN_METHOD_CALL_PARENTHESES, lfAfterRparen)
}
if (isParameterClauseContext(node2) || isBlockParameterClauseContext(node1)) {
val treePrev = findSiblingSkipping(node2, arrayOf(NLS, WHITE_SPACE), false)
val treePrev = findSiblingSkipping(node2, arrayOf(NEWLINE, WHITE_SPACE), false)
val methodParam = isParameterClauseContext(node2)
val wrapValue = if (methodParam) myCommonSettings.METHOD_PARAMETERS_WRAP else myPowerShellSettings.BLOCK_PARAMETER_CLAUSE_WRAP
val rParenNextLine = if (methodParam) myCommonSettings.METHOD_PARAMETERS_RPAREN_ON_NEXT_LINE else myPowerShellSettings.BLOCK_PARAMETERS_RPAREN_ON_NEXT_LINE
Expand Down Expand Up @@ -641,7 +641,7 @@ class PowerShellSpacingProcessor(private val myCommonSettings: CommonCodeStyleSe

if (type2 == SEMI) return simpleSpacing(myCommonSettings.SPACE_BEFORE_SEMICOLON)

if ((PowerShellTokenTypeSets.KEYWORDS.contains(type1) && !isIdentifier(node1.treeParent)/*|| HANDLER_PARAMETER_LABEL === type1*/) && NLS !== type2) {
if ((PowerShellTokenTypeSets.KEYWORDS.contains(type1) && !isIdentifier(node1.treeParent)/*|| HANDLER_PARAMETER_LABEL === type1*/) && NEWLINE !== type2) {
return Spacing.createSpacing(1, 1, 0, true, 0)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ internal fun findSiblingSkipping(node: ASTNode, toSkip: Array<IElementType>, for
}

internal fun findSiblingSkippingWS(node: ASTNode, forward: Boolean = true): ASTNode? {
return findSiblingSkipping(node, arrayOf(PowerShellTypes.NLS, TokenType.WHITE_SPACE), forward)
return findSiblingSkipping(node, arrayOf(PowerShellTypes.NEWLINE, TokenType.WHITE_SPACE), forward)
}

fun isTargetVariableContext(node: ASTNode): Boolean {
Expand All @@ -29,4 +29,4 @@ fun isFunctionDeclarationContext(node: ASTNode): Boolean {

fun isPathExpressionContext(node: ASTNode): Boolean {
return node.treeParent.elementType == PATH_EXPRESSION
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ private fun isWhiteSpace(node: ASTNode): Boolean {
}

fun ASTNode.isWhiteSpaceOrNls(): Boolean {
return isWhiteSpace(this) || elementType === PowerShellTypes.NLS || elementType === PowerShellTypes.LF
return isWhiteSpace(this) || elementType === PowerShellTypes.NEWLINE || elementType === PowerShellTypes.LF
}

val PowerShellAssignmentExpression.targetVariables: List<PowerShellTargetVariableExpression>
Expand Down
12 changes: 5 additions & 7 deletions src/main/resources/PowerShell.bnf
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,8 @@
OP_BNOT='-bnot'
EXCL_MARK='!'

// NewLines and spaces //
NLS ='regexp:[\ \t\f]*(\r|\n|\r\n)((\r|\n|\r\n)|([\ \t\f])*)*'
LF = 'regexp:(\r|\n|\r\n)+'

// A single newline
NEWLINE = 'regexp:(\r|\n|\r\n)'

LP='('
RP=')'
Expand Down Expand Up @@ -381,7 +379,7 @@ cast_expression ::= type_literal_expression unary_expression

//private attributed_expression ::= type_literal variable

left pipeline_tail ::= ( nls? PIPE nls? command_call_expression )+
left pipeline_tail ::= ( NEWLINE? PIPE nls? command_call_expression )+
{elementType=pipeline}

command_call_expression ::= command_invocation_operator ( (command_module command_name_expr command_element* ) | command_name_expr command_element* ) | command_name_expression command_element*
Expand Down Expand Up @@ -793,9 +791,9 @@ if_statement ::= 'if' nls? LP nls? pipeline nls? RP nls? statement_block (nls? e
elseif_clause ::= 'elseif' nls? LP nls? pipeline nls? RP nls? statement_block {pin=1}
else_clause ::= 'else' nls? statement_block {pin=1}

private sep ::= SEMI | NLS | new_line_char | comment //COMMENT //hide psi
private sep ::= SEMI | (NEWLINE space*) | new_line_char | comment //COMMENT //hide psi
private statement_end ::= sep | RCURLY | RP | <<eof>>//ex: parethnisized_expression $AllNodes.Where{$_.Role -eq "WebServer"}
private nls ::= (comment? NLS comment?)+ //NLS
private nls ::= (comment? NEWLINE space* comment?)+
private new_line_char ::= LF

comment ::= !is_id requires_comment | !is_id SINGLE_LINE_COMMENT | DELIMITED_COMMENT
Expand Down
7 changes: 3 additions & 4 deletions src/main/resources/_PowerShellLexer.flex
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,6 @@ OP_BOR={DASH}[bB]{OR}
EXCL_MARK="!"

NL=(\r|\n|\r\n)
NLS={WHITE_SPACE}*{NL}({NL}|{WHITE_SPACE}*)*
WS_OR_NL={WHITE_SPACE}|{NL}
CH_DQ=(\"|||)
CH_SQ=(\'||||)
Expand Down Expand Up @@ -302,12 +301,12 @@ BRACED_VAR_START={DS}{LCURLY}
<VERBATIM_ARGUMENT> {
{VERBATIM_ARG_INPUT} { return VERBATIM_ARG_INPUT; }
"|" { popState(); return PIPE; }
{NLS} { popState(); return NLS; }
{NL} { popState(); return NEWLINE; }
}
<FUNCTION_ID> {
{SIMPLE_ID} { popState(); return SIMPLE_ID; }
{WHITE_SPACE} { return WHITE_SPACE; }
{NLS} { return NLS; }
{NL} { return NEWLINE; }
{GENERIC_ID_PART_TOKENS} { popState(); return GENERIC_ID_PART; }
[^] { popState(); yypushback(yylength()); }
}
Expand Down Expand Up @@ -420,7 +419,7 @@ BRACED_VAR_START={DS}{LCURLY}
{OP_OR}/[^a-zA-Z]+{PARAMETER_CHAR}* { return OP_OR; }
{OP_XOR}/[^a-zA-Z]+{PARAMETER_CHAR}* { return OP_XOR; }
{EXCL_MARK} { return EXCL_MARK; }
{NLS} { return NLS; }
{NL} { return NEWLINE; }
{CH_DQ} { pushState(STRING); return DQ_OPEN; }
{VERBATIM_STRING} { return VERBATIM_STRING; }
{EXPANDABLE_HERE_STRING_START} { pushState(HERE_STRING); return EXPANDABLE_HERE_STRING_START; }
Expand Down

0 comments on commit 4abc8be

Please sign in to comment.