From 4c496c56a6bc51c5922a5ed19b6e0ec9b1b00de6 Mon Sep 17 00:00:00 2001 From: underscorediscovery Date: Wed, 10 Jun 2020 10:13:29 -0700 Subject: [PATCH] allow a newline before dot usage, for chained/fluent interfaces --- src/vm/wren_compiler.c | 11 +++ test/language/chained_newline.wren | 114 +++++++++++++++++++++++++++++ 2 files changed, 125 insertions(+) create mode 100644 test/language/chained_newline.wren diff --git a/src/vm/wren_compiler.c b/src/vm/wren_compiler.c index abd4ea183..856ce0f04 100644 --- a/src/vm/wren_compiler.c +++ b/src/vm/wren_compiler.c @@ -1169,6 +1169,12 @@ static void consumeLine(Compiler* compiler, const char* errorMessage) ignoreNewlines(compiler); } +static void allowLineBeforeDot(Compiler* compiler) { + if (peek(compiler) == TOKEN_LINE && peekNext(compiler) == TOKEN_DOT) { + nextToken(compiler->parser); + } +} + // Variables and scopes -------------------------------------------------------- // Emits one single-byte argument. Returns its index. @@ -1956,6 +1962,7 @@ static void namedCall(Compiler* compiler, bool canAssign, Code instruction) else { methodCall(compiler, instruction, &signature); + allowLineBeforeDot(compiler); } } @@ -2152,6 +2159,8 @@ static void field(Compiler* compiler, bool canAssign) loadThis(compiler); emitByteArg(compiler, isLoad ? CODE_LOAD_FIELD : CODE_STORE_FIELD, field); } + + allowLineBeforeDot(compiler); } // Compiles a read or assignment to [variable]. @@ -2183,6 +2192,8 @@ static void bareName(Compiler* compiler, bool canAssign, Variable variable) // Emit the load instruction. loadVariable(compiler, variable); + + allowLineBeforeDot(compiler); } static void staticField(Compiler* compiler, bool canAssign) diff --git a/test/language/chained_newline.wren b/test/language/chained_newline.wren new file mode 100644 index 000000000..72dcbae1b --- /dev/null +++ b/test/language/chained_newline.wren @@ -0,0 +1,114 @@ +class Test { + construct new() {} + test0() { + System.print("test0") + return this + } + test1() { + System.print("test1") + return this + } + test2() { + System.print("test2") + return this + } +} + +class Tester { + construct new() { + + var test = _test = Test.new() + + //test local access + + test. + test0(). // expect: test0 + test1(). // expect: test1 + test2() // expect: test2 + + test + .test0() // expect: test0 + .test1() // expect: test1 + .test2() // expect: test2 + + test + .test0() // expect: test0 + .test1(). // expect: test1 + test2() // expect: test2 + + //test field access + + _test. + test0(). // expect: test0 + test1(). // expect: test1 + test2() // expect: test2 + + _test + .test0() // expect: test0 + .test1() // expect: test1 + .test2() // expect: test2 + + _test + .test0(). // expect: test0 + test1(). // expect: test1 + test2() // expect: test2 + + } + + getter { _test } + method() { _test } + +} //Tester + +//access via methods/getter + +var external = Tester.new() + +external.getter. + test0(). // expect: test0 + test1(). // expect: test1 + test2() // expect: test2 + +external.getter + .test0() // expect: test0 + .test1() // expect: test1 + .test2() // expect: test2 + +external.getter. + test0() // expect: test0 + .test1() // expect: test1 + .test2() // expect: test2 + +external.method(). + test0(). // expect: test0 + test1(). // expect: test1 + test2() // expect: test2 + +external.method() + .test0() // expect: test0 + .test1() // expect: test1 + .test2() // expect: test2 + +external.method(). + test0() // expect: test0 + .test1(). // expect: test1 + test2() // expect: test2 + +//regular access in module scope + +var other = Test.new() + +other. + test0(). // expect: test0 + test1(). // expect: test1 + test2() // expect: test2 + +other + .test0() // expect: test0 + .test1() // expect: test1 + .test2() // expect: test2 + +other + .test0(). // expect: test0 + test1() // expect: test1 + .test2() // expect: test2