Skip to content

Commit

Permalink
Upgrade apex-parser version to 4.0.0 (#52)
Browse files Browse the repository at this point in the history
This upgrades apex-parser to the new version and adjust to the grammar changes (trigger block)

https://github.com/apex-dev-tools/apex-parser/releases/tag/v4.0.0

This upgrade also contains a fix for typeof needed in pmd/pmd#4922 .
  • Loading branch information
adangel committed Apr 16, 2024
1 parent beb9e62 commit 9b981b1
Show file tree
Hide file tree
Showing 6 changed files with 79 additions and 14 deletions.
2 changes: 1 addition & 1 deletion WORKSPACE
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ maven_install(
"com.google.guava:guava:31.1-jre",
"com.google.flogger:flogger-system-backend:0.7.4",
"junit:junit:4.13.2",
"io.github.apex-dev-tools:apex-parser:3.6.0",
"io.github.apex-dev-tools:apex-parser:4.0.0",
"com.google.truth:truth:1.1.3",
"com.google.code.gson:gson:2.9.0",
"org.jetbrains.kotlin:kotlin-reflect:1.7.0",
Expand Down
6 changes: 3 additions & 3 deletions src/main/java/com/google/summit/SummitAST.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ package com.google.summit
import com.google.common.flogger.FluentLogger
import com.google.summit.ast.CompilationUnit
import com.google.summit.translation.Translate
import com.nawforce.apexparser.ApexLexer
import com.nawforce.apexparser.ApexParser
import com.nawforce.apexparser.CaseInsensitiveInputStream
import io.github.apexdevtools.apexparser.ApexLexer
import io.github.apexdevtools.apexparser.ApexParser
import io.github.apexdevtools.apexparser.CaseInsensitiveInputStream
import java.nio.file.Files
import java.nio.file.Path
import org.antlr.v4.runtime.BaseErrorListener
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,14 @@ import com.google.summit.ast.statement.CompoundStatement
* @param id the unqualified name of the trigger
* @param target the SObject type to watch
* @param cases a list of operations to watch
* @param body the code to execute
* @param body the declarations and/or code to execute
* @param loc the location in the source file
*/
class TriggerDeclaration(
id: Identifier,
val target: Identifier,
val cases: List<TriggerCase>,
val body: CompoundStatement,
val body: List<Node>,
loc: SourceLocation
) : TypeDeclaration(id, loc) {

Expand All @@ -50,5 +50,5 @@ class TriggerDeclaration(
TRIGGER_AFTER_UNDELETE,
}

override fun getChildren(): List<Node> = modifiers + listOfNotNull(id, target, body)
override fun getChildren(): List<Node> = modifiers + listOfNotNull(id, target) + body
}
47 changes: 43 additions & 4 deletions src/main/java/com/google/summit/translation/Translate.kt
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,8 @@ import com.google.summit.ast.statement.ThrowStatement
import com.google.summit.ast.statement.TryStatement
import com.google.summit.ast.statement.VariableDeclarationStatement
import com.google.summit.ast.statement.WhileLoopStatement
import com.nawforce.apexparser.ApexParser
import com.nawforce.apexparser.ApexParserBaseVisitor
import io.github.apexdevtools.apexparser.ApexParser
import io.github.apexdevtools.apexparser.ApexParserBaseVisitor
import kotlin.math.min
import org.antlr.v4.runtime.ParserRuleContext
import org.antlr.v4.runtime.TokenStream
Expand All @@ -97,7 +97,7 @@ import java.math.BigDecimal
* NOTE: This is a WIP, and only a subset of the Apex language is represented or translated.
*
* The translation is accomplished with a single-pass depth-first traversal of the parse tree, using
* the ANTLR-generated [com.nawforce.apexparser.ApexParserVisitor] interface. Each translated
* the ANTLR-generated [io.github.apexdevtools.apexparser.ApexParserVisitor] interface. Each translated
* grammar rule returns the corresponding AST object.
*
* @property file path (or other descriptor) that is being translated
Expand Down Expand Up @@ -169,7 +169,7 @@ class Translate(val file: String, private val tokens: TokenStream) : ApexParserB
id = visitId(ctx.id().get(0)),
target = visitId(ctx.id().get(1)),
cases = ctx.triggerCase().map { visitTriggerCase(it) },
body = visitBlock(ctx.block()),
body = visitTriggerBlock(ctx.triggerBlock()),
loc = loc
),
file,
Expand Down Expand Up @@ -788,6 +788,45 @@ class Translate(val file: String, private val tokens: TokenStream) : ApexParserB
toSourceLocation(ctx)
)

override fun visitTriggerBlock(ctx: ApexParser.TriggerBlockContext): List<Node> =
ctx.triggerBlockMember().mapNotNull { visitTriggerBlockMember(it) }

override fun visitTriggerBlockMember(ctx: ApexParser.TriggerBlockMemberContext): Node? {
matchExactlyOne(ruleBeingChecked = ctx, ctx.triggerMemberDeclaration(), ctx.statement())

return when {
ctx.triggerMemberDeclaration() != null -> {
val member = visitTriggerMemberDeclaration(ctx.triggerMemberDeclaration())
(member as HasModifiers).modifiers = ctx.modifier().map { visitModifier(it) }
member
}
ctx.statement() != null -> visitStatement(ctx.statement())
else -> throw TranslationException(ctx, "Unreachable case reached")
}
}

override fun visitTriggerMemberDeclaration(ctx: ApexParser.TriggerMemberDeclarationContext): Node {
matchExactlyOne(
ruleBeingChecked = ctx,
ctx.methodDeclaration(),
ctx.fieldDeclaration(),
ctx.interfaceDeclaration(),
ctx.classDeclaration(),
ctx.enumDeclaration(),
ctx.propertyDeclaration()
)

return when {
ctx.methodDeclaration() != null -> visitMethodDeclaration(ctx.methodDeclaration())
ctx.fieldDeclaration() != null -> visitFieldDeclaration(ctx.fieldDeclaration())
ctx.interfaceDeclaration() != null -> visitInterfaceDeclaration(ctx.interfaceDeclaration())
ctx.classDeclaration() != null -> visitClassDeclaration(ctx.classDeclaration())
ctx.enumDeclaration() != null -> visitEnumDeclaration(ctx.enumDeclaration())
ctx.propertyDeclaration() != null -> visitPropertyDeclaration(ctx.propertyDeclaration())
else -> throw TranslationException(ctx, "Unreachable case reached")
}
}

/** Translates the 'finallyBlock' grammar rule and returns an AST [CompoundStatement]. */
override fun visitFinallyBlock(ctx: ApexParser.FinallyBlockContext): CompoundStatement =
visitBlock(ctx.block())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ import com.google.summit.ast.Untranslated
import com.google.summit.ast.statement.Statement
import com.google.summit.ast.traversal.DfsWalker
import com.google.summit.translation.Translate
import com.nawforce.apexparser.ApexLexer
import com.nawforce.apexparser.ApexParser
import com.nawforce.apexparser.CaseInsensitiveInputStream
import io.github.apexdevtools.apexparser.ApexLexer
import io.github.apexdevtools.apexparser.ApexParser
import io.github.apexdevtools.apexparser.CaseInsensitiveInputStream
import org.antlr.v4.runtime.BaseErrorListener
import org.antlr.v4.runtime.CharStreams
import org.antlr.v4.runtime.CommonTokenStream
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ package com.google.summit.translation
import com.google.common.truth.Truth.assertThat
import com.google.common.truth.Truth.assertWithMessage
import com.google.summit.ast.declaration.EnumDeclaration
import com.google.summit.ast.declaration.MethodDeclaration
import com.google.summit.ast.declaration.TriggerDeclaration
import com.google.summit.ast.statement.Statement
import com.google.summit.testing.TranslateHelpers
import org.junit.Test
import org.junit.runner.RunWith
Expand Down Expand Up @@ -66,4 +68,28 @@ class CompilationUnitTest {
TriggerDeclaration.TriggerCase.TRIGGER_AFTER_DELETE
)
}

@Test
fun triggerWithStatement_translatesTo_expectedTree() {
val cu =
TranslateHelpers.parseAndTranslate(
"trigger MyTrigger on MyObject(before update, after delete) { System.debug(''); }"
)

val triggerDecl = cu.typeDeclaration as TriggerDeclaration
val statement = triggerDecl.body.first() as Statement
assertThat(triggerDecl.body).containsExactly(statement)
}

@Test
fun triggerWithDeclaration_translatesTo_expectedTree() {
val cu =
TranslateHelpers.parseAndTranslate(
"trigger MyTrigger on MyObject(before update, after delete) { public void func() {} }"
)

val triggerDecl = cu.typeDeclaration as TriggerDeclaration
val methodDeclaration = triggerDecl.body.first() as MethodDeclaration
assertThat(triggerDecl.body).containsExactly(methodDeclaration)
}
}

0 comments on commit 9b981b1

Please sign in to comment.