Skip to content

Commit

Permalink
Interconnect Symbol Resolution and Type Calculation
Browse files Browse the repository at this point in the history
  • Loading branch information
ftomassetti committed Sep 20, 2024
1 parent d649072 commit 841e10f
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 65 deletions.
8 changes: 2 additions & 6 deletions src/main/kotlin/com/strumenta/entity/parser/ast/EntityAst.kt
Original file line number Diff line number Diff line change
Expand Up @@ -97,15 +97,11 @@ enum class Operator {
}

data class InvocationExpression(
var operation: OperationReference,
var context: Expression,
var operation: ReferenceByName<Operation>,
var arguments: MutableList<Expression> = mutableListOf(),
) : Expression()

data class OperationReference(
var context: Expression? = null,
var operation: ReferenceByName<Operation>,
) : Node()

data class ReferenceExpression(
var context: Expression? = null,
var target: ReferenceByName<Symbol>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,11 +112,8 @@ class EntityParseTreeToAstTransformer(issues: MutableList<Issue> = mutableListOf
// invocation expression
this.registerNodeFactory(AntlrEntityParser.Invocation_expressionContext::class) { ctx ->
InvocationExpression(
operation =
OperationReference(
context = translateOptional(ctx.context),
operation = ReferenceByName(name = ctx.target.text),
),
context = translateCasted(ctx.context),
operation = ReferenceByName(name = ctx.target.text),
arguments = translateList(ctx.argument_list().arguments),
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import com.strumenta.entity.parser.ast.IntegerLiteralExpression
import com.strumenta.entity.parser.ast.InvocationExpression
import com.strumenta.entity.parser.ast.Module
import com.strumenta.entity.parser.ast.Operation
import com.strumenta.entity.parser.ast.OperationReference
import com.strumenta.entity.parser.ast.Operator
import com.strumenta.entity.parser.ast.OperatorExpression
import com.strumenta.entity.parser.ast.ReferenceExpression
Expand All @@ -23,17 +22,18 @@ import com.strumenta.entity.parser.runtime.StringType
import com.strumenta.entity.parser.runtime.builtinTypes
import com.strumenta.kolasu.model.Node
import com.strumenta.kolasu.model.PossiblyNamed
import com.strumenta.kolasu.model.ReferenceByName
import com.strumenta.kolasu.model.previousSamePropertySibling
import com.strumenta.kolasu.semantics.scope.description.ScopeDescription
import com.strumenta.kolasu.semantics.scope.description.ScopeDescriptionApi
import com.strumenta.kolasu.semantics.scope.provider.declarative.DeclarativeScopeProvider
import com.strumenta.kolasu.semantics.scope.provider.declarative.scopeFor
import com.strumenta.kolasu.semantics.semantics
import com.strumenta.kolasu.semantics.symbol.resolver.SymbolResolver
import com.strumenta.kolasu.traversing.findAncestorOfType
import com.strumenta.kolasu.traversing.walkDescendants
import com.strumenta.kolasu.validation.Issue
import com.strumenta.kolasu.validation.IssueSeverity
import kotlin.reflect.KProperty1

interface ModuleFinder {
fun findModule(moduleName: String): Module?
Expand All @@ -52,7 +52,8 @@ interface TypeCalculator {

fun setTypeIfNeeded(node: Node): Type? {
if (node.type == null) {
node.type = calculateType(node)
val calculatedType = calculateType(node)
node.type = calculatedType
}
return node.type
}
Expand Down Expand Up @@ -109,10 +110,6 @@ fun symbolResolver(
}
},
)
// scopeFor(Symbol::type) {
// // all entities from current, imported and standard module
// symbolResolver.scopeFrom(it.findAncestorOfType(Module::class.java))
// },
dsp.addRule(
scopeFor(Operation::type) {
parent(moduleLevelTypes(it.node))
Expand All @@ -125,12 +122,24 @@ fun symbolResolver(
)
dsp.addRule(
scopeFor(ReferenceExpression::target) {
parent(entityLevelValues(it.node))
if (it.node.context == null) {
parent(entityLevelValues(it.node))
} else {
TODO()
}
},
)
dsp.addRule(
scopeFor(OperationReference::operation) {
parent(entityLevelOperations(it.node))
scopeFor(InvocationExpression::operation) {
sr.resolve(it.node.context)
val type =
typeCalculator.getType(it.node.context)
?: throw IllegalStateException(
"Cannot resolve operation as the type of the context is unknown. " +
"Context: ${it.node.context}",
)
val entity = type as? Entity ?: throw IllegalStateException("We cannot only invoke operations on entities")
define(entity.operations)
},
)
dsp.addRule(
Expand Down Expand Up @@ -164,12 +173,32 @@ internal fun MutableList<Issue>.addIncompatibleTypesError(operatorExpression: Op
)
}

object EntityTypeCalculator : TypeCalculator {
class EntityTypeCalculator : TypeCalculator {
var sr: SymbolResolver? = null

fun getTypeOfReference(
refHolder: Node,
ref: KProperty1<Node, ReferenceByName<PossiblyNamed>?>,
): Type? {
val refValue = ref.getValue(refHolder, ref) ?: return null
if (!refValue.resolved) {
sr?.resolve(refHolder, ref)
}
return if (refValue.resolved) {
getType(refValue.referred!! as Node)
} else {
null
}
}

override fun calculateType(node: Node): Type? {
return when (node) {
is OperatorExpression -> {
val leftType = getType(node.left)
val rightType = getType(node.right)
if (leftType == null || rightType == null) {
return null
}
when (node.operator) {
Operator.ADDITION -> {
when (val operandTypes = Pair(leftType, rightType)) {
Expand All @@ -178,6 +207,12 @@ object EntityTypeCalculator : TypeCalculator {
else -> TODO("$operandTypes for expression $node")
}
}
Operator.MULTIPLICATION -> {
when (val operandTypes = Pair(leftType, rightType)) {
Pair(IntegerType, IntegerType) -> IntegerType
else -> TODO("$operandTypes for expression $node")
}
}
else -> TODO(node.operator.toString())
}
}
Expand Down Expand Up @@ -208,8 +243,8 @@ object EntityTypeCalculator : TypeCalculator {
IntegerType
}
is InvocationExpression -> {
if (node.operation.operation.resolved) {
getType(node.operation.operation.referred!!)
if (node.operation.resolved) {
getType(node.operation.referred!!)
} else {
null
}
Expand Down Expand Up @@ -239,8 +274,10 @@ object EntityTypeCalculator : TypeCalculator {

fun Module.semanticEnrichment(moduleFinder: ModuleFinder): List<Issue> {
val issues = mutableListOf<Issue>()
val typeCalculator = EntityTypeCalculator
symbolResolver(moduleFinder, typeCalculator).resolve(this, entireTree = true)
val typeCalculator = EntityTypeCalculator()
val sr = symbolResolver(moduleFinder, typeCalculator)
typeCalculator.sr = sr
sr.resolve(this, entireTree = true)
this.walkDescendants(Expression::class).forEach { expression ->
typeCalculator.setTypeIfNeeded(expression)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,51 @@ import com.strumenta.entity.parser.EntityParser
import com.strumenta.entity.parser.ast.ConstructorExpression
import com.strumenta.entity.parser.ast.Feature
import com.strumenta.entity.parser.ast.Import
import com.strumenta.entity.parser.ast.InvocationExpression
import com.strumenta.entity.parser.ast.Module
import com.strumenta.entity.parser.ast.Operation
import com.strumenta.entity.parser.ast.OperationReference
import com.strumenta.entity.parser.ast.ReferenceExpression
import com.strumenta.entity.parser.ast.Variable
import com.strumenta.kolasu.model.Expression
import com.strumenta.kolasu.model.KReferenceByName
import com.strumenta.kolasu.model.Node
import com.strumenta.kolasu.model.ReferenceByName
import com.strumenta.kolasu.model.kReferenceByNameProperties
import com.strumenta.kolasu.testing.assertReferencesNotResolved
import com.strumenta.kolasu.testing.assertReferencesResolved
import com.strumenta.kolasu.traversing.walkChildren
import com.strumenta.kolasu.traversing.walkDescendants
import org.junit.Test
import kotlin.test.assertTrue
import kotlin.test.fail

class EntitySemanticsTest {
private val parser: EntityParser = EntityParser()

@Test
fun resolveInvocations() {
val simpleModuleFinder = SimpleModuleFinder()
val animalsModule =
parser.parse(
"""
module animals
entity Dog {
move(): Integer {
return 2
}
}
entity FastDog {
move(): Integer {
return new Dog().move() * 2
}
}
""".trimIndent(),
).root!! as Module
simpleModuleFinder.registerModule(animalsModule)
animalsModule.semanticEnrichment(simpleModuleFinder)
animalsModule.assertReferencesResolved(forProperty = InvocationExpression::operation)
}

@Test
fun testSymbolResolution() {
val simpleModuleFinder = SimpleModuleFinder()
Expand Down Expand Up @@ -53,15 +78,13 @@ class EntitySemanticsTest {
""".trimIndent(),
).root!! as Module
simpleModuleFinder.registerModule(personModule)
personModule.semanticEnrichment(simpleModuleFinder)
try {
personModule.semanticEnrichment(simpleModuleFinder)
fail()
} catch (e: IllegalStateException) {
// Expected
}

// address module is currently not included in the workspace
// hence symbol resolution fails to resolve references to its symbols
personModule.assertReferencesNotResolved(forProperty = Import::module)
personModule.assertReferencesResolved(forProperty = Operation::type)
personModule.assertReferencesResolved(forProperty = ConstructorExpression::entity)
personModule.assertReferencesNotResolved(forProperty = Variable::type)
personModule.assertSomeReferencesNotResolved(forProperty = Feature::type)
val addressModule =
parser.parse(
"""
Expand Down Expand Up @@ -93,7 +116,7 @@ class EntitySemanticsTest {
addressModule.assertReferencesResolved(forProperty = ConstructorExpression::entity)
personModule.assertReferencesResolved(forProperty = Import::module)
personModule.assertReferencesResolved(forProperty = Feature::type)
personModule.assertReferencesResolved(forProperty = OperationReference::operation)
personModule.assertReferencesResolved(forProperty = InvocationExpression::operation)
}

@Test
Expand Down
38 changes: 11 additions & 27 deletions src/test/resources/metamodel.json
Original file line number Diff line number Diff line change
Expand Up @@ -208,12 +208,21 @@
} ]
}, {
"eClass" : "http://www.eclipse.org/emf/2002/Ecore#//EClass",
"name" : "OperationReference",
"name" : "InvocationExpression",
"eSuperTypes" : [ {
"eClass" : "http://www.eclipse.org/emf/2002/Ecore#//EClass",
"$ref" : "https://strumenta.com/starlasu/v2#//ASTNode"
"$ref" : "//Expression"
} ],
"eStructuralFeatures" : [ {
"eClass" : "http://www.eclipse.org/emf/2002/Ecore#//EReference",
"name" : "arguments",
"upperBound" : -1,
"eType" : {
"eClass" : "http://www.eclipse.org/emf/2002/Ecore#//EClass",
"$ref" : "//Expression"
},
"containment" : true
}, {
"eClass" : "http://www.eclipse.org/emf/2002/Ecore#//EReference",
"name" : "context",
"eType" : {
Expand All @@ -238,31 +247,6 @@
},
"containment" : true
} ]
}, {
"eClass" : "http://www.eclipse.org/emf/2002/Ecore#//EClass",
"name" : "InvocationExpression",
"eSuperTypes" : [ {
"eClass" : "http://www.eclipse.org/emf/2002/Ecore#//EClass",
"$ref" : "//Expression"
} ],
"eStructuralFeatures" : [ {
"eClass" : "http://www.eclipse.org/emf/2002/Ecore#//EReference",
"name" : "arguments",
"upperBound" : -1,
"eType" : {
"eClass" : "http://www.eclipse.org/emf/2002/Ecore#//EClass",
"$ref" : "//Expression"
},
"containment" : true
}, {
"eClass" : "http://www.eclipse.org/emf/2002/Ecore#//EReference",
"name" : "operation",
"eType" : {
"eClass" : "http://www.eclipse.org/emf/2002/Ecore#//EClass",
"$ref" : "//OperationReference"
},
"containment" : true
} ]
}, {
"eClass" : "http://www.eclipse.org/emf/2002/Ecore#//EClass",
"name" : "ConstructorExpression",
Expand Down

0 comments on commit 841e10f

Please sign in to comment.