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
 | 
			
		||||
    assertEquals( 5, p.length() )
 | 
			
		||||
    // but us not available directly
 | 
			
		||||
    assertThrows() { p.d2() }
 | 
			
		||||
    assertThrows { p.d2() }
 | 
			
		||||
    void
 | 
			
		||||
    >>> void
 | 
			
		||||
 | 
			
		||||
@ -126,7 +126,7 @@ Private fields are visible only _inside the class instance_:
 | 
			
		||||
    assert( c.isEnough() )
 | 
			
		||||
 | 
			
		||||
    // but the count is not available outside:
 | 
			
		||||
    assertThrows() { c.count }
 | 
			
		||||
    assertThrows { c.count }
 | 
			
		||||
    void
 | 
			
		||||
    >>> void
 | 
			
		||||
 | 
			
		||||
@ -137,7 +137,7 @@ set at construction but not available outside the class:
 | 
			
		||||
        // ...
 | 
			
		||||
    }
 | 
			
		||||
    val c = SecretCounter(10)
 | 
			
		||||
    assertThrows() { c.count }
 | 
			
		||||
    assertThrows { c.count }
 | 
			
		||||
    void
 | 
			
		||||
    >>> void
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -11,7 +11,8 @@ class Compiler(
 | 
			
		||||
    class Settings
 | 
			
		||||
 | 
			
		||||
    fun compile(source: Source): Script {
 | 
			
		||||
        return parseScript(source.startPos,
 | 
			
		||||
        return parseScript(
 | 
			
		||||
            source.startPos,
 | 
			
		||||
            CompilerContext(parseLyng(source))
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
@ -38,7 +39,7 @@ class Compiler(
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                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
 | 
			
		||||
                    } else
 | 
			
		||||
                        throw ScriptError(t.pos, "unexpected keyword ${t.value}")
 | 
			
		||||
@ -132,21 +133,49 @@ class Compiler(
 | 
			
		||||
                        var isCall = false
 | 
			
		||||
                        val next = cc.next()
 | 
			
		||||
                        if (next.type == Token.Type.ID) {
 | 
			
		||||
                            cc.ifNextIs(Token.Type.LPAREN) {
 | 
			
		||||
                                // instance method call
 | 
			
		||||
                                val args = parseArgs(cc)
 | 
			
		||||
                                isCall = true
 | 
			
		||||
                                operand = Accessor { context ->
 | 
			
		||||
                                    context.pos = next.pos
 | 
			
		||||
                                    val v = left.getter(context).value
 | 
			
		||||
                                    ObjRecord(
 | 
			
		||||
                                        v.invokeInstanceMethod(
 | 
			
		||||
                                            context,
 | 
			
		||||
                                            next.value,
 | 
			
		||||
                                            args.toArguments(context)
 | 
			
		||||
                                        ), isMutable = false
 | 
			
		||||
                                    )
 | 
			
		||||
                            // could be () call or obj.method {} call
 | 
			
		||||
                            val nt = cc.current()
 | 
			
		||||
                            when (nt.type) {
 | 
			
		||||
                                Token.Type.LPAREN -> {
 | 
			
		||||
                                    cc.next()
 | 
			
		||||
                                    // instance method call
 | 
			
		||||
                                    val args = parseArgs(cc)
 | 
			
		||||
                                    isCall = true
 | 
			
		||||
                                    operand = Accessor { context ->
 | 
			
		||||
                                        context.pos = next.pos
 | 
			
		||||
                                        val v = left.getter(context).value
 | 
			
		||||
                                        ObjRecord(
 | 
			
		||||
                                            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) {
 | 
			
		||||
@ -169,6 +198,7 @@ class Compiler(
 | 
			
		||||
                        operand = parseFunctionCall(
 | 
			
		||||
                            cc,
 | 
			
		||||
                            left,
 | 
			
		||||
                            false,
 | 
			
		||||
                        )
 | 
			
		||||
                    } ?: run {
 | 
			
		||||
                        // Expression in parentheses
 | 
			
		||||
@ -314,9 +344,10 @@ class Compiler(
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                Token.Type.LBRACE -> {
 | 
			
		||||
                    if (operand != null) {
 | 
			
		||||
                        throw ScriptError(t.pos, "syntax error: lambda expression not allowed here")
 | 
			
		||||
                    } else operand = parseLambdaExpression(cc)
 | 
			
		||||
                    operand = operand?.let { left ->
 | 
			
		||||
                        cc.previous()
 | 
			
		||||
                        parseFunctionCall(cc, left, blockArgument = true)
 | 
			
		||||
                    } ?: parseLambdaExpression(cc)
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -410,6 +441,7 @@ class Compiler(
 | 
			
		||||
 | 
			
		||||
    enum class AccessType(val isMutable: Boolean) {
 | 
			
		||||
        Val(false), Var(true),
 | 
			
		||||
 | 
			
		||||
        @Suppress("unused")
 | 
			
		||||
        Initialization(false)
 | 
			
		||||
    }
 | 
			
		||||
@ -441,9 +473,10 @@ class Compiler(
 | 
			
		||||
                        cc.restorePos(startPos); return null
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                Token.Type.ID -> {
 | 
			
		||||
                    // visibility
 | 
			
		||||
                    val visibility = if( isClassDeclaration )
 | 
			
		||||
                    val visibility = if (isClassDeclaration)
 | 
			
		||||
                        cc.getVisibility(Visibility.Public)
 | 
			
		||||
                    else Visibility.Public
 | 
			
		||||
                    // val/var?
 | 
			
		||||
@ -530,6 +563,7 @@ class Compiler(
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun parseArgs(cc: CompilerContext): List<ParsedArgument> {
 | 
			
		||||
 | 
			
		||||
        val args = mutableListOf<ParsedArgument>()
 | 
			
		||||
        do {
 | 
			
		||||
            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
 | 
			
		||||
        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 ->
 | 
			
		||||
            val v = left.getter(context)
 | 
			
		||||
@ -724,12 +766,13 @@ class Compiler(
 | 
			
		||||
            constructorArgsDeclaration?.assignToContext(this)
 | 
			
		||||
            bodyInit?.execute(this)
 | 
			
		||||
            // export public
 | 
			
		||||
            for( (name,record) in objects ) {
 | 
			
		||||
                when(record.visibility) {
 | 
			
		||||
            for ((name, record) in objects) {
 | 
			
		||||
                when (record.visibility) {
 | 
			
		||||
                    Visibility.Public -> {
 | 
			
		||||
                        thisObj.publicFields += name
 | 
			
		||||
                        thisObj.protectedFields += name
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    Visibility.Protected ->
 | 
			
		||||
                        thisObj.protectedFields += name
 | 
			
		||||
 | 
			
		||||
@ -1133,9 +1176,10 @@ class Compiler(
 | 
			
		||||
 | 
			
		||||
    private fun parseVarDeclaration(kind: String, mutable: Boolean, tokens: CompilerContext): Statement {
 | 
			
		||||
        // 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 ->
 | 
			
		||||
                Visibility.Private
 | 
			
		||||
 | 
			
		||||
            Token.Type.PROTECTED -> Visibility.Protected
 | 
			
		||||
            else -> Visibility.Public
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -1461,7 +1461,30 @@ class ScriptTest {
 | 
			
		||||
            class Point(private var x,y)
 | 
			
		||||
            val p = Point(1,2)
 | 
			
		||||
            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