Skip to content

Commit

Permalink
Add more tests
Browse files Browse the repository at this point in the history
  • Loading branch information
honvex-cool committed Jan 27, 2025
1 parent d8d4b74 commit 1c385c5
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 4 deletions.
2 changes: 2 additions & 0 deletions src/test/kotlin/cacophony/TestAstUtils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,8 @@ fun variableWrite(variableUse: VariableUse, value: Expression) =

fun primVar(name: String = "") = Variable.PrimitiveVariable(name)

fun funVar() = Variable.FunctionVariable(primVar(), primVar())

fun allocation(value: Expression) = Allocation(mockRange(), value)

fun dereference(value: Expression) = Dereference(mockRange(), value)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
package cacophony.semantic.analysis

import cacophony.*
import cacophony.controlflow.Variable
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test

class ClosureAnalysisKtTest {
@Test
fun `lambda expressions are correctly separated into static functions and closures`() {
fun `simple functional expressions are correctly separated into static functions and closures`() {
/*
* let f = [x: Int] -> Int => x; # f is a static function
* let g = ([x: Int] -> Int => x); # g is a closure
Expand All @@ -17,16 +16,17 @@ class ClosureAnalysisKtTest {
val fArgUse = variableUse("x")
val staticLambda = lambda(listOf(fArg), intType(), fArgUse)
val fDef = functionDefinition("f", staticLambda)
val fVar = Variable.FunctionVariable(primVar(), primVar())
val fVar = funVar()

val gArg = intArg("x")
val gArgVar = primVar()
val gArgUse = variableUse("x")
val dynamicLambda = lambda(listOf(gArg), intType(), gArgUse)
val gDef = variableDeclaration("g", block(dynamicLambda))
val gVar = Variable.FunctionVariable(primVar(), primVar())
val gVar = funVar()

val ast = block(fDef, gDef)

val variablesMap =
VariablesMap(
mapOf(fArgUse to fArgVar, gArgUse to gArgVar),
Expand All @@ -38,4 +38,60 @@ class ClosureAnalysisKtTest {
assertThat(result.closures).containsExactlyInAnyOrder(dynamicLambda)
assertThat(result.staticFunctions).containsExactlyInAnyOrder(staticLambda)
}

@Test
fun `escaping static functions are promoted to closures`() {
/*
* let f = [] -> [] -> Int => (
* let x = 42;
* let g = [] -> Int => x;
* g
* );
* # g has escaped
*/
val xDef = variableDeclaration("x", lit(42))
val xVar = primVar()
val xUse = variableUse("x")

val gLambda = lambda(emptyList(), intType(), xUse)
val gDef = functionDefinition("g", gLambda)
val gVar = funVar()
val gUse = variableUse("g")

val fBody = block(xDef, gDef, gUse)
val fLambda = lambda(emptyList(), functionalType(emptyList(), intType()), fBody)
val fDef = functionDefinition("f", fLambda)
val fVar = funVar()

val ast = block(fDef)

val variablesMap =
VariablesMap(
mapOf(xUse to xVar, gUse to gVar),
mapOf(xDef to xVar, gDef to gVar, fDef to fVar),
)
val escaping = setOf(xVar, gVar)

val result = analyzeClosures(ast, variablesMap, escaping)

assertThat(result.closures).containsExactlyInAnyOrder(gLambda)
assertThat(result.staticFunctions).containsExactlyInAnyOrder(fLambda)
}

@Test
fun `standalone lambda expressions are identified as closures`() {
// ([x: Int] -> Int => x + 1)[1];
val xDef = intArg("x")
val xUse = variableUse("x")
val xVar = primVar()

val lambda = lambda(listOf(xDef), intType(), xUse add lit(1))
val ast = block(call(lambda, lit(1)))
val variablesMap = VariablesMap(mapOf(xUse to xVar), mapOf(xDef to xVar))

val result = analyzeClosures(ast, variablesMap, emptySet())

assertThat(result.closures).containsExactlyInAnyOrder(lambda)
assertThat(result.staticFunctions).isEmpty()
}
}

0 comments on commit 1c385c5

Please sign in to comment.