fix #9 block argument {} call without ()
This commit is contained in:
parent
20c81dbf2e
commit
2a93e6f7da
@ -67,7 +67,7 @@ Functions defined inside a class body are methods, and unless declared
|
|||||||
// private called from inside public: OK
|
// private called from inside public: OK
|
||||||
assertEquals( 5, p.length() )
|
assertEquals( 5, p.length() )
|
||||||
// but us not available directly
|
// but us not available directly
|
||||||
assertThrows() { p.d2() }
|
assertThrows { p.d2() }
|
||||||
void
|
void
|
||||||
>>> void
|
>>> void
|
||||||
|
|
||||||
@ -126,7 +126,7 @@ Private fields are visible only _inside the class instance_:
|
|||||||
assert( c.isEnough() )
|
assert( c.isEnough() )
|
||||||
|
|
||||||
// but the count is not available outside:
|
// but the count is not available outside:
|
||||||
assertThrows() { c.count }
|
assertThrows { c.count }
|
||||||
void
|
void
|
||||||
>>> void
|
>>> void
|
||||||
|
|
||||||
@ -137,7 +137,7 @@ set at construction but not available outside the class:
|
|||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
val c = SecretCounter(10)
|
val c = SecretCounter(10)
|
||||||
assertThrows() { c.count }
|
assertThrows { c.count }
|
||||||
void
|
void
|
||||||
>>> void
|
>>> void
|
||||||
|
|
||||||
|
@ -11,7 +11,8 @@ class Compiler(
|
|||||||
class Settings
|
class Settings
|
||||||
|
|
||||||
fun compile(source: Source): Script {
|
fun compile(source: Source): Script {
|
||||||
return parseScript(source.startPos,
|
return parseScript(
|
||||||
|
source.startPos,
|
||||||
CompilerContext(parseLyng(source))
|
CompilerContext(parseLyng(source))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -38,7 +39,7 @@ class Compiler(
|
|||||||
}
|
}
|
||||||
|
|
||||||
Token.Type.PRIVATE, Token.Type.PROTECTED -> {
|
Token.Type.PRIVATE, Token.Type.PROTECTED -> {
|
||||||
if(cc.nextIdValue() in setOf("var", "val", "class", "fun", "fn")) {
|
if (cc.nextIdValue() in setOf("var", "val", "class", "fun", "fn")) {
|
||||||
continue
|
continue
|
||||||
} else
|
} else
|
||||||
throw ScriptError(t.pos, "unexpected keyword ${t.value}")
|
throw ScriptError(t.pos, "unexpected keyword ${t.value}")
|
||||||
@ -132,21 +133,49 @@ class Compiler(
|
|||||||
var isCall = false
|
var isCall = false
|
||||||
val next = cc.next()
|
val next = cc.next()
|
||||||
if (next.type == Token.Type.ID) {
|
if (next.type == Token.Type.ID) {
|
||||||
cc.ifNextIs(Token.Type.LPAREN) {
|
// could be () call or obj.method {} call
|
||||||
// instance method call
|
val nt = cc.current()
|
||||||
val args = parseArgs(cc)
|
when (nt.type) {
|
||||||
isCall = true
|
Token.Type.LPAREN -> {
|
||||||
operand = Accessor { context ->
|
cc.next()
|
||||||
context.pos = next.pos
|
// instance method call
|
||||||
val v = left.getter(context).value
|
val args = parseArgs(cc)
|
||||||
ObjRecord(
|
isCall = true
|
||||||
v.invokeInstanceMethod(
|
operand = Accessor { context ->
|
||||||
context,
|
context.pos = next.pos
|
||||||
next.value,
|
val v = left.getter(context).value
|
||||||
args.toArguments(context)
|
ObjRecord(
|
||||||
), isMutable = false
|
v.invokeInstanceMethod(
|
||||||
)
|
context,
|
||||||
|
next.value,
|
||||||
|
args.toArguments(context)
|
||||||
|
), isMutable = false
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Token.Type.LBRACE -> {
|
||||||
|
// single lambda arg, like assertTrows { ... }
|
||||||
|
cc.next()
|
||||||
|
isCall = true
|
||||||
|
val lambda =
|
||||||
|
parseExpression(cc) ?: throw ScriptError(t.pos, "expected valid lambda here")
|
||||||
|
println(cc.current())
|
||||||
|
cc.skipTokenOfType(Token.Type.RBRACE)
|
||||||
|
operand = Accessor { context ->
|
||||||
|
context.pos = next.pos
|
||||||
|
val v = left.getter(context).value
|
||||||
|
ObjRecord(
|
||||||
|
v.invokeInstanceMethod(
|
||||||
|
context,
|
||||||
|
next.value,
|
||||||
|
Arguments(listOf(Arguments.Info(lambda, t.pos)))
|
||||||
|
), isMutable = false
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!isCall) {
|
if (!isCall) {
|
||||||
@ -169,6 +198,7 @@ class Compiler(
|
|||||||
operand = parseFunctionCall(
|
operand = parseFunctionCall(
|
||||||
cc,
|
cc,
|
||||||
left,
|
left,
|
||||||
|
false,
|
||||||
)
|
)
|
||||||
} ?: run {
|
} ?: run {
|
||||||
// Expression in parentheses
|
// Expression in parentheses
|
||||||
@ -314,9 +344,10 @@ class Compiler(
|
|||||||
}
|
}
|
||||||
|
|
||||||
Token.Type.LBRACE -> {
|
Token.Type.LBRACE -> {
|
||||||
if (operand != null) {
|
operand = operand?.let { left ->
|
||||||
throw ScriptError(t.pos, "syntax error: lambda expression not allowed here")
|
cc.previous()
|
||||||
} else operand = parseLambdaExpression(cc)
|
parseFunctionCall(cc, left, blockArgument = true)
|
||||||
|
} ?: parseLambdaExpression(cc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -410,6 +441,7 @@ class Compiler(
|
|||||||
|
|
||||||
enum class AccessType(val isMutable: Boolean) {
|
enum class AccessType(val isMutable: Boolean) {
|
||||||
Val(false), Var(true),
|
Val(false), Var(true),
|
||||||
|
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
Initialization(false)
|
Initialization(false)
|
||||||
}
|
}
|
||||||
@ -441,9 +473,10 @@ class Compiler(
|
|||||||
cc.restorePos(startPos); return null
|
cc.restorePos(startPos); return null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Token.Type.ID -> {
|
Token.Type.ID -> {
|
||||||
// visibility
|
// visibility
|
||||||
val visibility = if( isClassDeclaration )
|
val visibility = if (isClassDeclaration)
|
||||||
cc.getVisibility(Visibility.Public)
|
cc.getVisibility(Visibility.Public)
|
||||||
else Visibility.Public
|
else Visibility.Public
|
||||||
// val/var?
|
// val/var?
|
||||||
@ -530,6 +563,7 @@ class Compiler(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun parseArgs(cc: CompilerContext): List<ParsedArgument> {
|
private fun parseArgs(cc: CompilerContext): List<ParsedArgument> {
|
||||||
|
|
||||||
val args = mutableListOf<ParsedArgument>()
|
val args = mutableListOf<ParsedArgument>()
|
||||||
do {
|
do {
|
||||||
val t = cc.next()
|
val t = cc.next()
|
||||||
@ -570,9 +604,17 @@ class Compiler(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun parseFunctionCall(cc: CompilerContext, left: Accessor): Accessor {
|
private fun parseFunctionCall(cc: CompilerContext, left: Accessor, blockArgument: Boolean): Accessor {
|
||||||
// insofar, functions always return lvalue
|
// insofar, functions always return lvalue
|
||||||
val args = parseArgs(cc)
|
val args = if (blockArgument) {
|
||||||
|
val blockArg = ParsedArgument(
|
||||||
|
parseExpression(cc)
|
||||||
|
?: throw ScriptError(cc.currentPos(), "lambda body expected"), cc.currentPos()
|
||||||
|
)
|
||||||
|
listOf(blockArg)
|
||||||
|
} else {
|
||||||
|
parseArgs(cc)
|
||||||
|
}
|
||||||
|
|
||||||
return Accessor { context ->
|
return Accessor { context ->
|
||||||
val v = left.getter(context)
|
val v = left.getter(context)
|
||||||
@ -724,12 +766,13 @@ class Compiler(
|
|||||||
constructorArgsDeclaration?.assignToContext(this)
|
constructorArgsDeclaration?.assignToContext(this)
|
||||||
bodyInit?.execute(this)
|
bodyInit?.execute(this)
|
||||||
// export public
|
// export public
|
||||||
for( (name,record) in objects ) {
|
for ((name, record) in objects) {
|
||||||
when(record.visibility) {
|
when (record.visibility) {
|
||||||
Visibility.Public -> {
|
Visibility.Public -> {
|
||||||
thisObj.publicFields += name
|
thisObj.publicFields += name
|
||||||
thisObj.protectedFields += name
|
thisObj.protectedFields += name
|
||||||
}
|
}
|
||||||
|
|
||||||
Visibility.Protected ->
|
Visibility.Protected ->
|
||||||
thisObj.protectedFields += name
|
thisObj.protectedFields += name
|
||||||
|
|
||||||
@ -1133,9 +1176,10 @@ class Compiler(
|
|||||||
|
|
||||||
private fun parseVarDeclaration(kind: String, mutable: Boolean, tokens: CompilerContext): Statement {
|
private fun parseVarDeclaration(kind: String, mutable: Boolean, tokens: CompilerContext): Statement {
|
||||||
// we are just after var/val, visibility if exists is 2 steps behind
|
// we are just after var/val, visibility if exists is 2 steps behind
|
||||||
val visibility = when( tokens.atOffset(-2)?.type ) {
|
val visibility = when (tokens.atOffset(-2)?.type) {
|
||||||
Token.Type.PRIVATE ->
|
Token.Type.PRIVATE ->
|
||||||
Visibility.Private
|
Visibility.Private
|
||||||
|
|
||||||
Token.Type.PROTECTED -> Visibility.Protected
|
Token.Type.PROTECTED -> Visibility.Protected
|
||||||
else -> Visibility.Public
|
else -> Visibility.Public
|
||||||
}
|
}
|
||||||
|
@ -1461,7 +1461,30 @@ class ScriptTest {
|
|||||||
class Point(private var x,y)
|
class Point(private var x,y)
|
||||||
val p = Point(1,2)
|
val p = Point(1,2)
|
||||||
p.y = 101
|
p.y = 101
|
||||||
assertThrows() { p.x = 10 }
|
assertThrows { p.x = 10 }
|
||||||
""")
|
""")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testLBraceMethodCall() = runTest {
|
||||||
|
eval("""
|
||||||
|
class Foo() {
|
||||||
|
fun cond(block) {
|
||||||
|
block()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val f = Foo()
|
||||||
|
assertEquals( 1, f.cond { 1 } )
|
||||||
|
""".trimIndent())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testLBraceFnCall() = runTest {
|
||||||
|
eval("""
|
||||||
|
fun cond(block) {
|
||||||
|
block()
|
||||||
|
}
|
||||||
|
assertEquals( 1, cond { 1 } )
|
||||||
|
""".trimIndent())
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user