Enable tests and fix destructuring/prop setter parsing
This commit is contained in:
parent
824a58bbc5
commit
be337144eb
@ -1981,6 +1981,39 @@ class Compiler(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private suspend fun parseDestructuringPattern(): List<ListEntry> {
|
||||||
|
// it should be called after Token.Type.LBRACKET is consumed
|
||||||
|
val entries = mutableListOf<ListEntry>()
|
||||||
|
while (true) {
|
||||||
|
val t = cc.next()
|
||||||
|
when (t.type) {
|
||||||
|
Token.Type.COMMA -> {
|
||||||
|
// allow trailing/extra commas
|
||||||
|
}
|
||||||
|
Token.Type.RBRACKET -> return entries
|
||||||
|
Token.Type.LBRACKET -> {
|
||||||
|
val nested = parseDestructuringPattern()
|
||||||
|
entries += ListEntry.Element(ListLiteralRef(nested))
|
||||||
|
}
|
||||||
|
Token.Type.ELLIPSIS -> {
|
||||||
|
val id = cc.requireToken(Token.Type.ID, "Expected identifier after ...")
|
||||||
|
val ref = LocalVarRef(id.value, id.pos)
|
||||||
|
entries += ListEntry.Spread(ref)
|
||||||
|
}
|
||||||
|
Token.Type.ID -> {
|
||||||
|
val ref = LocalVarRef(t.value, t.pos)
|
||||||
|
if (cc.peekNextNonWhitespace().type == Token.Type.ELLIPSIS) {
|
||||||
|
cc.next()
|
||||||
|
entries += ListEntry.Spread(ref)
|
||||||
|
} else {
|
||||||
|
entries += ListEntry.Element(ref)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> throw ScriptError(t.pos, "invalid destructuring pattern: expected identifier")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun parseScopeOperator(operand: ObjRef?): ObjRef {
|
private fun parseScopeOperator(operand: ObjRef?): ObjRef {
|
||||||
// implement global scope maybe?
|
// implement global scope maybe?
|
||||||
if (operand == null) throw ScriptError(cc.next().pos, "Expecting expression before ::")
|
if (operand == null) throw ScriptError(cc.next().pos, "Expecting expression before ::")
|
||||||
@ -4406,6 +4439,55 @@ class Compiler(
|
|||||||
return parseBlockWithPredeclared(emptyList(), skipLeadingBrace)
|
return parseBlockWithPredeclared(emptyList(), skipLeadingBrace)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private suspend fun parseExpressionWithPredeclared(
|
||||||
|
predeclared: List<Pair<String, Boolean>>
|
||||||
|
): Statement {
|
||||||
|
val startPos = cc.currentPos()
|
||||||
|
resolutionSink?.enterScope(ScopeKind.BLOCK, startPos, null)
|
||||||
|
val exprSlotPlan = SlotPlan(mutableMapOf(), 0, nextScopeId++)
|
||||||
|
for ((name, isMutable) in predeclared) {
|
||||||
|
declareSlotNameIn(exprSlotPlan, name, isMutable, isDelegated = false)
|
||||||
|
resolutionSink?.declareSymbol(name, SymbolKind.LOCAL, isMutable, startPos, isOverride = false)
|
||||||
|
}
|
||||||
|
slotPlanStack.add(exprSlotPlan)
|
||||||
|
val capturePlan = CapturePlan(exprSlotPlan)
|
||||||
|
capturePlanStack.add(capturePlan)
|
||||||
|
val expr = try {
|
||||||
|
parseExpression() ?: throw ScriptError(cc.current().pos, "Expected expression")
|
||||||
|
} finally {
|
||||||
|
capturePlanStack.removeLast()
|
||||||
|
slotPlanStack.removeLast()
|
||||||
|
}
|
||||||
|
resolutionSink?.exitScope(cc.currentPos())
|
||||||
|
return expr
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun parseExpressionBlockWithPredeclared(
|
||||||
|
predeclared: List<Pair<String, Boolean>>
|
||||||
|
): Statement {
|
||||||
|
val startPos = cc.currentPos()
|
||||||
|
resolutionSink?.enterScope(ScopeKind.BLOCK, startPos, null)
|
||||||
|
val blockSlotPlan = SlotPlan(mutableMapOf(), 0, nextScopeId++)
|
||||||
|
for ((name, isMutable) in predeclared) {
|
||||||
|
declareSlotNameIn(blockSlotPlan, name, isMutable, isDelegated = false)
|
||||||
|
resolutionSink?.declareSymbol(name, SymbolKind.LOCAL, isMutable, startPos, isOverride = false)
|
||||||
|
}
|
||||||
|
slotPlanStack.add(blockSlotPlan)
|
||||||
|
val capturePlan = CapturePlan(blockSlotPlan)
|
||||||
|
capturePlanStack.add(capturePlan)
|
||||||
|
val expr = try {
|
||||||
|
parseExpression() ?: throw ScriptError(cc.current().pos, "Expected expression")
|
||||||
|
} finally {
|
||||||
|
capturePlanStack.removeLast()
|
||||||
|
slotPlanStack.removeLast()
|
||||||
|
}
|
||||||
|
val planSnapshot = slotPlanIndices(blockSlotPlan)
|
||||||
|
val block = Script(startPos, listOf(expr))
|
||||||
|
val stmt = BlockStatement(block, planSnapshot, capturePlan.captures.toList(), startPos)
|
||||||
|
resolutionSink?.exitScope(cc.currentPos())
|
||||||
|
return stmt
|
||||||
|
}
|
||||||
|
|
||||||
private fun resolveInitializerObjClass(initializer: Statement?): ObjClass? {
|
private fun resolveInitializerObjClass(initializer: Statement?): ObjClass? {
|
||||||
if (initializer is BytecodeStatement) {
|
if (initializer is BytecodeStatement) {
|
||||||
val fn = initializer.bytecodeFunction()
|
val fn = initializer.bytecodeFunction()
|
||||||
@ -4647,7 +4729,7 @@ class Compiler(
|
|||||||
// Destructuring
|
// Destructuring
|
||||||
if (isStatic) throw ScriptError(start, "static destructuring is not supported")
|
if (isStatic) throw ScriptError(start, "static destructuring is not supported")
|
||||||
|
|
||||||
val entries = parseArrayLiteral()
|
val entries = parseDestructuringPattern()
|
||||||
val pattern = ListLiteralRef(entries)
|
val pattern = ListLiteralRef(entries)
|
||||||
|
|
||||||
// Register all names in the pattern
|
// Register all names in the pattern
|
||||||
@ -5043,14 +5125,20 @@ class Compiler(
|
|||||||
implicitThisTypeName = extTypeName
|
implicitThisTypeName = extTypeName
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
parseBlock()
|
parseBlockWithPredeclared(listOf(setArgName to true))
|
||||||
}
|
}
|
||||||
object : Statement() {
|
object : Statement() {
|
||||||
override val pos: Pos = body.pos
|
override val pos: Pos = body.pos
|
||||||
override suspend fun execute(scope: Scope): Obj {
|
override suspend fun execute(scope: Scope): Obj {
|
||||||
val value = scope.args.list.firstOrNull() ?: ObjNull
|
val value = scope.args.list.firstOrNull() ?: ObjNull
|
||||||
scope.addItem(setArgName, true, value, recordType = ObjRecord.Type.Argument)
|
scope.addItem(setArgName, true, value, recordType = ObjRecord.Type.Argument)
|
||||||
return body.execute(scope)
|
val prev = scope.skipScopeCreation
|
||||||
|
scope.skipScopeCreation = true
|
||||||
|
return try {
|
||||||
|
body.execute(scope)
|
||||||
|
} finally {
|
||||||
|
scope.skipScopeCreation = prev
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (cc.peekNextNonWhitespace().type == Token.Type.ASSIGN) {
|
} else if (cc.peekNextNonWhitespace().type == Token.Type.ASSIGN) {
|
||||||
@ -5063,8 +5151,7 @@ class Compiler(
|
|||||||
implicitThisTypeName = extTypeName
|
implicitThisTypeName = extTypeName
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
parseExpression()
|
parseExpressionBlockWithPredeclared(listOf(setArgName to true))
|
||||||
?: throw ScriptError(cc.current().pos, "Expected setter expression")
|
|
||||||
}
|
}
|
||||||
val st = expr
|
val st = expr
|
||||||
object : Statement() {
|
object : Statement() {
|
||||||
@ -5072,7 +5159,13 @@ class Compiler(
|
|||||||
override suspend fun execute(scope: Scope): Obj {
|
override suspend fun execute(scope: Scope): Obj {
|
||||||
val value = scope.args.list.firstOrNull() ?: ObjNull
|
val value = scope.args.list.firstOrNull() ?: ObjNull
|
||||||
scope.addItem(setArgName, true, value, recordType = ObjRecord.Type.Argument)
|
scope.addItem(setArgName, true, value, recordType = ObjRecord.Type.Argument)
|
||||||
return st.execute(scope)
|
val prev = scope.skipScopeCreation
|
||||||
|
scope.skipScopeCreation = true
|
||||||
|
return try {
|
||||||
|
st.execute(scope)
|
||||||
|
} finally {
|
||||||
|
scope.skipScopeCreation = prev
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -5100,14 +5193,20 @@ class Compiler(
|
|||||||
implicitThisTypeName = extTypeName
|
implicitThisTypeName = extTypeName
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
parseBlock()
|
parseBlockWithPredeclared(listOf(setArg.value to true))
|
||||||
}
|
}
|
||||||
object : Statement() {
|
object : Statement() {
|
||||||
override val pos: Pos = body.pos
|
override val pos: Pos = body.pos
|
||||||
override suspend fun execute(scope: Scope): Obj {
|
override suspend fun execute(scope: Scope): Obj {
|
||||||
val value = scope.args.list.firstOrNull() ?: ObjNull
|
val value = scope.args.list.firstOrNull() ?: ObjNull
|
||||||
scope.addItem(setArg.value, true, value, recordType = ObjRecord.Type.Argument)
|
scope.addItem(setArg.value, true, value, recordType = ObjRecord.Type.Argument)
|
||||||
return body.execute(scope)
|
val prev = scope.skipScopeCreation
|
||||||
|
scope.skipScopeCreation = true
|
||||||
|
return try {
|
||||||
|
body.execute(scope)
|
||||||
|
} finally {
|
||||||
|
scope.skipScopeCreation = prev
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (cc.peekNextNonWhitespace().type == Token.Type.ASSIGN) {
|
} else if (cc.peekNextNonWhitespace().type == Token.Type.ASSIGN) {
|
||||||
@ -5120,17 +5219,20 @@ class Compiler(
|
|||||||
implicitThisTypeName = extTypeName
|
implicitThisTypeName = extTypeName
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
parseExpression() ?: throw ScriptError(
|
parseExpressionBlockWithPredeclared(listOf(setArg.value to true))
|
||||||
cc.current().pos,
|
|
||||||
"Expected setter expression"
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
object : Statement() {
|
object : Statement() {
|
||||||
override val pos: Pos = st.pos
|
override val pos: Pos = st.pos
|
||||||
override suspend fun execute(scope: Scope): Obj {
|
override suspend fun execute(scope: Scope): Obj {
|
||||||
val value = scope.args.list.firstOrNull() ?: ObjNull
|
val value = scope.args.list.firstOrNull() ?: ObjNull
|
||||||
scope.addItem(setArg.value, true, value, recordType = ObjRecord.Type.Argument)
|
scope.addItem(setArg.value, true, value, recordType = ObjRecord.Type.Argument)
|
||||||
return st.execute(scope)
|
val prev = scope.skipScopeCreation
|
||||||
|
scope.skipScopeCreation = true
|
||||||
|
return try {
|
||||||
|
st.execute(scope)
|
||||||
|
} finally {
|
||||||
|
scope.skipScopeCreation = prev
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -926,7 +926,6 @@ class ScriptTest {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Ignore("incremental enable")
|
|
||||||
@Test
|
@Test
|
||||||
fun bookTest0() = runTest {
|
fun bookTest0() = runTest {
|
||||||
assertEquals(
|
assertEquals(
|
||||||
@ -1041,7 +1040,6 @@ class ScriptTest {
|
|||||||
// assertEquals( "4", c.eval("x+0").toString())
|
// assertEquals( "4", c.eval("x+0").toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
@Ignore("incremental enable")
|
|
||||||
@Test
|
@Test
|
||||||
fun bookTest2() = runTest {
|
fun bookTest2() = runTest {
|
||||||
val src = """
|
val src = """
|
||||||
@ -4609,7 +4607,6 @@ class ScriptTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Ignore("incremental enable: destructuring assignments not implemented in bytecode compiler")
|
|
||||||
@Test
|
@Test
|
||||||
fun testDestructuringAssignment() = runTest {
|
fun testDestructuringAssignment() = runTest {
|
||||||
eval(
|
eval(
|
||||||
|
|||||||
@ -6,7 +6,6 @@ import kotlin.test.Test
|
|||||||
|
|
||||||
class PropsTest {
|
class PropsTest {
|
||||||
|
|
||||||
@Ignore("Setter parameter binding (value) not wired in compile-time resolution yet")
|
|
||||||
@Test
|
@Test
|
||||||
fun propsProposal() = runTest {
|
fun propsProposal() = runTest {
|
||||||
eval("""
|
eval("""
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user