From 8d1af508f4173e4af6a4ea98584c1a86619f6a20 Mon Sep 17 00:00:00 2001
From: Li Jin <dragon-fly@qq.com>
Date: Sat, 18 Jan 2020 18:15:24 +0800
Subject: fix Moonscript issue 122, add support for ? operator.

---
 makefile                       |   2 +-
 spec/inputs/assign.moon        |   2 +-
 spec/inputs/class.moon         |  30 +--
 spec/inputs/comprehension.moon |  14 +-
 spec/inputs/cond.moon          |  12 +-
 spec/inputs/destructure.moon   |   2 +-
 spec/inputs/do.moon            |   2 +-
 spec/inputs/existential.moon   |   8 +
 spec/inputs/funcs.moon         |  30 +--
 spec/inputs/lists.moon         |   8 +-
 spec/inputs/literals.moon      |  62 ++---
 spec/inputs/local.moon         |   2 +-
 spec/inputs/loops.moon         |  12 +-
 spec/inputs/return.moon        |   8 +-
 spec/inputs/string.moon        |   2 +-
 spec/inputs/switch.moon        |  10 +-
 spec/inputs/syntax.moon        |  42 ++--
 spec/inputs/tables.moon        |   2 +-
 spec/inputs/using.moon         |   8 +-
 spec/inputs/whitespace.moon    |  22 +-
 spec/inputs/with.moon          |   4 +-
 src/MoonP/ast.hpp              |   6 +
 src/MoonP/moon_ast.cpp         |   1 +
 src/MoonP/moon_ast.h           |   5 +-
 src/MoonP/moon_compiler.cpp    | 508 +++++++++++++++++++++++++++++------------
 src/MoonP/moon_parser.cpp      |  15 +-
 src/moonc.cpp                  |  12 +-
 27 files changed, 523 insertions(+), 308 deletions(-)
 create mode 100644 spec/inputs/existential.moon

diff --git a/makefile b/makefile
index 5042b08..a3379a4 100644
--- a/makefile
+++ b/makefile
@@ -206,7 +206,7 @@ clean:
 .PHONY: test
 test: release
 	@echo "Compiling Moonscript codes..."
-	@./$(BIN_NAME) $(TEST_INPUT)/*.moon -a -s -t $(TEST_OUTPUT)
+	@./$(BIN_NAME) $(TEST_INPUT)/*.moon -l -t $(TEST_OUTPUT)
 
 # Main rule, checks the executable and symlinks to the output
 all: $(BIN_PATH)/$(BIN_NAME)
diff --git a/spec/inputs/assign.moon b/spec/inputs/assign.moon
index 1e5e7a6..3e66491 100644
--- a/spec/inputs/assign.moon
+++ b/spec/inputs/assign.moon
@@ -1,5 +1,5 @@
 
-->
+_ = ->
   joop = 2302
 
   (hi) ->
diff --git a/spec/inputs/class.moon b/spec/inputs/class.moon
index 9a98055..2290bc7 100644
--- a/spec/inputs/class.moon
+++ b/spec/inputs/class.moon
@@ -73,11 +73,11 @@ class CoolSuper
   hi: =>
     super(1,2,3,4) 1,2,3,4
     super.something 1,2,3,4
-    super.something(1,2,3,4).world
+    _ = super.something(1,2,3,4).world
     super\yeah"world".okay hi, hi, hi
-    something.super
-    super.super.super.super
-    super\hello
+    _ = something.super
+    _ = super.super.super.super
+    _ = super\hello
     nil
 
 
@@ -114,11 +114,11 @@ y = @@
 @ = 343
 @.hello 2,3,4
 
-hello[@].world
+_ = hello[@].world
 
 
 class Whacko
-  @hello
+  _ = @hello
   if something
     print "hello world"
 
@@ -132,20 +132,20 @@ print "hello"
 
 yyy = ->
   class Cool
-    nil
+    _ = nil
 
 
 --
 
 class a.b.c.D
-  nil
+  _ = nil
 
 
 class a.b["hello"]
-  nil
+  _ = nil
 
 class (-> require "moon")!.Something extends Hello.World
-  nil
+  _ = nil
 
 --
 
@@ -160,7 +160,7 @@ print (class WhatsUp).__name
 
 export ^
 class Something
-  nil
+  _ = nil
 
 
 --
@@ -197,17 +197,17 @@ class Whack extends Thing
 class Wowha extends Thing
   @butt: ->
     super!
-    super.hello
+    _ = super.hello
     super\hello!
-    super\hello
+    _ = super\hello
 
 
   @zone: cool {
     ->
       super!
-      super.hello
+      _ = super.hello
       super\hello!
-      super\hello
+      _ = super\hello
   }
 
 nil
diff --git a/spec/inputs/comprehension.moon b/spec/inputs/comprehension.moon
index 1609d79..f07cf89 100644
--- a/spec/inputs/comprehension.moon
+++ b/spec/inputs/comprehension.moon
@@ -11,11 +11,11 @@ copy  = {k,v for k,v in pairs x when k != "okay"}
 
 --
 
-{ unpack(x) for x in yes }
-{ unpack(x) for x in *yes }
+_ = { unpack(x) for x in yes }
+_ = { unpack(x) for x in *yes }
 
-{ xxxx for x in yes }
-{ unpack [a*i for i, a in ipairs x] for x in *{{1,2}, {3,4}} }
+_ = { xxxx for x in yes }
+_ = { unpack [a*i for i, a in ipairs x] for x in *{{1,2}, {3,4}} }
 
 
 --
@@ -28,7 +28,7 @@ bb = [y for thing in y for i=1,10]
 cc = [y for i=1,10 for thing in y]
 dd = [y for i=1,10 when cool for thing in y when x > 3 when c + 3]
 
-{"hello", "world" for i=1,10}
+_ = {"hello", "world" for i=1,10}
 
 --
 
@@ -44,8 +44,8 @@ ok(a,b,c) for {a,b,c} in things
 
 --
 
-[item for item in *items[1 + 2,3+4]]
-[item for item in *items[hello! * 4, 2 - thing[4]]]
+_ = [item for item in *items[1 + 2,3+4]]
+_ = [item for item in *items[hello! * 4, 2 - thing[4]]]
 
 
 
diff --git a/spec/inputs/cond.moon b/spec/inputs/cond.moon
index 18e42b9..e8b6283 100644
--- a/spec/inputs/cond.moon
+++ b/spec/inputs/cond.moon
@@ -1,25 +1,25 @@
 
 you_cool = false
 
-if cool
+_ = if cool
   if you_cool
     one
   else if eatdic
     yeah
   else
-    two
+    _ = two
     three
 else
   no
 
-if cool then no
-if cool then no else yes
+_ = if cool then no
+_ = if cool then no else yes
 
 if cool then wow cool else
   noso cool
 
 if working
-  if cool then if cool then okay else what else nah
+  _ = if cool then if cool then okay else what else nah
 
 
 if yeah then no day elseif cool me then okay ya else u way
@@ -70,7 +70,7 @@ hello = 5 + if something = 10
 
 z = false
 
-if false
+_ = if false
   one
 elseif x = true
   two
diff --git a/spec/inputs/destructure.moon b/spec/inputs/destructure.moon
index beb79d6..2509968 100644
--- a/spec/inputs/destructure.moon
+++ b/spec/inputs/destructure.moon
@@ -90,7 +90,7 @@ do
 do
   {a,b,c} = z
 
-(z) ->
+_ = (z) ->
   {a,b,c} = z
 
 do
diff --git a/spec/inputs/do.moon b/spec/inputs/do.moon
index 334e68f..21e2127 100644
--- a/spec/inputs/do.moon
+++ b/spec/inputs/do.moon
@@ -11,7 +11,7 @@ y = do
   things = "shhh"
   -> "hello: " .. things
 
--> if something then do "yeah"
+_ = -> if something then do "yeah"
 
 t = {
   y: do
diff --git a/spec/inputs/existential.moon b/spec/inputs/existential.moon
new file mode 100644
index 0000000..97e8de0
--- /dev/null
+++ b/spec/inputs/existential.moon
@@ -0,0 +1,8 @@
+if {:x} = a?.if?\then?(123)? @?\function 998
+	print x
+
+with abc?!\func?!
+	if \p? "abc"
+		return 123
+
+@?\func 998
diff --git a/spec/inputs/funcs.moon b/spec/inputs/funcs.moon
index 08a29b6..7a4d5d6 100644
--- a/spec/inputs/funcs.moon
+++ b/spec/inputs/funcs.moon
@@ -2,9 +2,9 @@
 
 x = -> print what
 
-->
+_ = ->
 
--> -> ->
+_ = -> -> ->
 
 go to the barn
 
@@ -27,29 +27,29 @@ x = (...) ->
 hello!
 hello.world!
 
-hello!.something
-what!["ofefe"]
+_ = hello!.something
+_ = what!["ofefe"]
 
 what! the! heck!
 
-(a,b,c,d,e) ->
+_ = (a,b,c,d,e) ->
 
-(a,a,a,a,a) ->
+_ = (a,a,a,a,a) ->
   print a
 
-(x=23023) ->
+_ = (x=23023) ->
 
-(x=(y=()->) ->) ->
+_ = (x=(y=()->) ->) ->
 
-(x = if something then yeah else no) ->
+_ = (x = if something then yeah else no) ->
 
 something = (hello=100, world=(x=[[yeah cool]])-> print "eat rice") ->
   print hello
 
-(x, y) =>
-(@x, @y) =>
-(x=1) =>
-(@x=1,y,@z="hello world") =>
+_ = (x, y) =>
+_ = (@x, @y) =>
+_ = (x=1) =>
+_ = (@x=1,y,@z="hello world") =>
 
 
 x -> return
@@ -57,7 +57,7 @@ y -> return 1
 z -> return 1, "hello", "world"
 k -> if yes then return else return
 
--> real_name if something
+_ = -> real_name if something
 
 --
 
@@ -97,7 +97,7 @@ f(
 
 x = (a,
   b) ->
-    print "what"
+   print "what"
 
 
 y = (a="hi",
diff --git a/spec/inputs/lists.moon b/spec/inputs/lists.moon
index c119185..e377d5e 100644
--- a/spec/inputs/lists.moon
+++ b/spec/inputs/lists.moon
@@ -3,14 +3,14 @@ hi = [x*2 for _, x in ipairs{1,2,3,4}]
 
 items = {1,2,3,4,5,6}
 
-[z for z in ipairs items when z > 4]
+_ = [z for z in ipairs items when z > 4]
 
 rad = [{a} for a in ipairs {
    1,2,3,4,5,6,
 } when good_number a]
 
 
-[z for z in items for j in list when z > 4]
+_ = [z for z in items for j in list when z > 4]
 
 require "util"
 
@@ -32,7 +32,7 @@ print x,y for x in ipairs{1,2,4} for y in ipairs{1,2,3} when x != 2
 
 print "hello", x for x in items
 
-[x for x in x]
+_ = [x for x in x]
 x = [x for x in x]
 
 print x,y for x in ipairs{1,2,4} for y in ipairs{1,2,3} when x != 2
@@ -67,6 +67,6 @@ normal = (hello) ->
 test = x 1,2,3,4,5
 print thing for thing in *test
 
--> a = b for row in *rows
+_ = -> a = b for row in *rows
 
 
diff --git a/spec/inputs/literals.moon b/spec/inputs/literals.moon
index c3a24a6..d4b0326 100644
--- a/spec/inputs/literals.moon
+++ b/spec/inputs/literals.moon
@@ -1,46 +1,46 @@
 
+_ = {
+	121
+	121.2323
+	121.2323e-1
+	121.2323e13434
+	2323E34
+	0x12323
 
-121
-121.2323
-121.2323e-1
-121.2323e13434
-2323E34
-0x12323
+	0xfF2323
+	0xabcdef
+	0xABCDEF
 
-0xfF2323
-0xabcdef
-0xABCDEF
+	.2323
+	.2323e-1
+	.2323e13434
 
-.2323
-.2323e-1
-.2323e13434
 
+	1LL
+	1ULL
+	9332LL
+	9332
+	0x2aLL
+	0x2aULL
 
-1LL
-1ULL
-9332LL
-9332
-0x2aLL
-0x2aULL
+	[[ hello world ]]
 
-[[ hello world ]]
+	[=[ hello world ]=]
+	[====[ hello world ]====]
 
-[=[ hello world ]=]
-[====[ hello world ]====]
+	"another world"
 
-"another world"
+	'what world'
 
-'what world'
 
+	"
+	hello world
+	"
 
-"
-hello world
-"
-
-'yeah
-what is going on
-here is something cool'
-
+	'yeah
+	what is going on
+	here is something cool'
 
+}
 nil
 
diff --git a/spec/inputs/local.moon b/spec/inputs/local.moon
index fec78b1..f14f575 100644
--- a/spec/inputs/local.moon
+++ b/spec/inputs/local.moon
@@ -89,6 +89,6 @@ do
 do
   local *
   -- this generates a nil value in the body
-  for a in *{} do a
+  for a in *{} do _ = a
 
 g = 2323 -- test if anything leaked
diff --git a/spec/inputs/loops.moon b/spec/inputs/loops.moon
index a704e56..130570e 100644
--- a/spec/inputs/loops.moon
+++ b/spec/inputs/loops.moon
@@ -33,7 +33,7 @@ for x in y, z, k
 
 x = ->
   for x in y
-    y
+    _ = y
 
 hello = {1,2,3,4,5}
 
@@ -43,7 +43,7 @@ x = for y in *hello
 
 x = ->
   for x in *hello
-    y
+    _ = y
 
 t = for i=10,20 do i * 2
 
@@ -52,11 +52,11 @@ y = for j = 3,30, 8
   hmm += 1
   j * hmm
 
-->
+_ = ->
   for k=10,40
-    "okay"
+    _ = "okay"
 
-->
+_ = ->
   return for k=10,40
     "okay"
 
@@ -68,7 +68,7 @@ while 5 + 5
 
 while also do
   i work too
-  "okay"
+  _ = "okay"
 
 i = 0
 x = while i < 10
diff --git a/spec/inputs/return.moon b/spec/inputs/return.moon
index 61d3dca..98c3104 100644
--- a/spec/inputs/return.moon
+++ b/spec/inputs/return.moon
@@ -1,7 +1,7 @@
 -- testing `return` propagation
 
--> x for x in *things
--> [x for x in *things]
+_ = -> _ = x for x in *things
+_ = -> [x for x in *things]
 
 
 -- doesn't make sense on purpose
@@ -14,7 +14,7 @@ do
 do
   return {x,y for x,y in *things}
 
-->
+_ = ->
   if a
     if a
       a
@@ -49,7 +49,7 @@ do
     else
       b
 
--> a\b
+_ = -> a\b
 do a\b
 
 
diff --git a/spec/inputs/string.moon b/spec/inputs/string.moon
index 897056a..5d8f772 100644
--- a/spec/inputs/string.moon
+++ b/spec/inputs/string.moon
@@ -52,7 +52,7 @@ c = 'hello #{hello}'
 
 --
 
-"hello"
+_ = "hello"
 "hello"\format 1
 "hello"\format(1,2,3)
 "hello"\format(1,2,3) 1,2,3
diff --git a/spec/inputs/switch.moon b/spec/inputs/switch.moon
index 3bc179b..a028f98 100644
--- a/spec/inputs/switch.moon
+++ b/spec/inputs/switch.moon
@@ -15,7 +15,7 @@ switch value
   when "cool"
     print "hello world"
   when "yeah"
-    [[FFFF]] + [[MMMM]]
+    _ = [[FFFF]] + [[MMMM]]
   when 2323 + 32434
     print "okay"
   else
@@ -33,9 +33,9 @@ out = switch value
 with something
   switch \value!
     when .okay
-      "world"
+      _ = "world"
     else
-      "yesh"
+      _ = "yesh"
 
 fix this
 call_func switch something
@@ -46,7 +46,7 @@ call_func switch something
 
 switch hi
   when hello or world
-    greene
+    _ = greene
 
 --
 
@@ -54,7 +54,7 @@ switch hi
   when "one", "two"
     print "cool"
   when "dad"
-    no
+    _ = no
 
 switch hi
   when 3+1, hello!, (-> 4)!
diff --git a/spec/inputs/syntax.moon b/spec/inputs/syntax.moon
index 854f629..351b22c 100644
--- a/spec/inputs/syntax.moon
+++ b/spec/inputs/syntax.moon
@@ -27,7 +27,7 @@ what(the)[3243] world, yeck heck
 
 hairy[hands][are](gross) okay okay[world]
 
-(get[something] + 5)[years]
+_ = (get[something] + 5)[years]
 
 i,x  = 200, 300
 
@@ -37,27 +37,27 @@ yeah = ((1+5)*3)/2 + i % 100
 
 whoa = (1+2) * (3+4) * (4+5)
 
-->
+_ = ->
   if something
     return 1,2,4
 
   print "hello"
 
-->
+_ = ->
   if hello
     "heloo", "world"
   else
     no, way
 
 
--> 1,2,34
+_ = -> 1,2,34
 
 return 5 + () -> 4 + 2
 
 return 5 + (() -> 4) + 2
 
 print 5 + () ->
-	34
+	_ = 34
 	good nads
 
 
@@ -66,19 +66,19 @@ something 'else', "ya"
 something'else'
 something"else"
 
-something[[hey]] * 2
-something[======[hey]======] * 2
+_ = something[[hey]] * 2
+_ = something[======[hey]======] * 2
 
 
-something'else', 2
-something"else", 2
-something[[else]], 2
+_ = something'else', 2
+_ = something"else", 2
+_ = something[[else]], 2
 
 something 'else', 2
 something "else", 2
 something [[else]], 2
 
-here(we)"go"[12123]
+_ = here(we)"go"[12123]
 
 -- this runs
 something =
@@ -120,9 +120,9 @@ print "hello" for i=1,10
 
 print "nutjob"
 
-if hello then 343
+if hello then _ = 343
 
-print "what" if cool else whack
+print "what" if cool else whack!
 
 arg = {...}
 
@@ -139,7 +139,7 @@ y = #"hello"
 
 x = #{#{},#{1},#{1,2}}
 
-hello, world
+_ = hello, world
 
 something\hello(what) a,b
 something\hello what
@@ -163,7 +163,7 @@ a["hello#{tostring ff}"] += 10
 a[four].x += 10
 
 x = 0
-(if ntype(v) == "fndef" then x += 1) for v in *values
+_ = (if ntype(v) == "fndef" then x += 1) for v in *values
 
 
 hello =
@@ -176,10 +176,10 @@ hello =
 
 div class: "cool"
 
-5 + what wack
+_ = 5 + what wack
 what whack + 5
 
-5 - what wack
+_ = 5 - what wack
 what whack - 5
 
 x = hello - world - something
@@ -189,16 +189,16 @@ x = hello - world - something
   print something)!
 
 if something
-  03589
+  _ = 03589
 
 -- okay what about this
 
 else
-  3434
+  _ = 3434
 
 
 if something
-  yeah
+  _ = yeah
 
 
 elseif "ymmm"
@@ -207,7 +207,7 @@ elseif "ymmm"
 
 else
 
-  okay
+  _ = okay
 
 
 -- test names containing keywords
diff --git a/spec/inputs/tables.moon b/spec/inputs/tables.moon
index 2bf66d7..10bccde 100644
--- a/spec/inputs/tables.moon
+++ b/spec/inputs/tables.moon
@@ -138,7 +138,7 @@ thing what:
 thing what:
   "great", no:
     "more"
-okay: 123 -- a anon table
+_ = okay: 123 -- a anon table
 
 
 -- 
diff --git a/spec/inputs/using.moon b/spec/inputs/using.moon
index 55a16a7..e407983 100644
--- a/spec/inputs/using.moon
+++ b/spec/inputs/using.moon
@@ -2,18 +2,18 @@
 hello = "hello"
 world = "world"
 
-(using nil) ->
+_ = (using nil) ->
   hello = 3223
 
-(a using nil) ->
+_ = (a using nil) ->
   hello = 3223
   a = 323
 
-(a,b,c using a,b,c) ->
+_ = (a,b,c using a,b,c) ->
   a,b,c = 1,2,3
   world = 12321
 
-(a,e,f using a,b,c, hello) ->
+_ = (a,e,f using a,b,c, hello) ->
   a,b,c = 1,2,3
   hello = 12321
   world = "yeah"
diff --git a/spec/inputs/whitespace.moon b/spec/inputs/whitespace.moon
index 4a2ff1f..e505b1b 100644
--- a/spec/inputs/whitespace.moon
+++ b/spec/inputs/whitespace.moon
@@ -1,42 +1,42 @@
 
-{
+_ = {
   1, 2
 }
 
-{ 1, 2
+_ = { 1, 2
 }
 
-{ 1, 2 }
+_ = { 1, 2 }
 
-{1,2}
+_ = {1,2}
 
-{
+_ = {
 1,2
 
 }
 
-{ something 1,2,
+_ = { something 1,2,
     4,5,6,
   3,4,5
 }
 
-{
+_ = {
   a 1,2,3,
   4,5,6
   1,2,3
 }
 
 
-{
+_ = {
   b 1,2,3,
     4,5,6
   1,2,3,
     1,2,3
 }
 
-{ 1,2,3 }
+_ = { 1,2,3 }
 
-{ c 1,2,3,
+_ = { c 1,2,3,
 }
 
 
@@ -58,7 +58,7 @@ hello 1,2,3,
   9,9
 
 
-{
+_ = {
   hello 1,2,
   3,4,
   5, 6
diff --git a/spec/inputs/with.moon b/spec/inputs/with.moon
index ae3c8c0..f543356 100644
--- a/spec/inputs/with.moon
+++ b/spec/inputs/with.moon
@@ -37,7 +37,7 @@ do
 
 do
   with foo
-    \prop"something".hello
+    _ = \prop"something".hello
     .prop\send(one)
     .prop\send one
 
@@ -107,7 +107,7 @@ do
       print .c
 
 do
-  ->
+  _ = ->
     with hi
       return .a, .b
 
diff --git a/src/MoonP/ast.hpp b/src/MoonP/ast.hpp
index f2ef76c..0b5ffca 100644
--- a/src/MoonP/ast.hpp
+++ b/src/MoonP/ast.hpp
@@ -392,6 +392,12 @@ public:
 		node->release();
 	}
 
+	void pop_back() {
+		auto node = m_objects.back();
+		m_objects.pop_back();
+		node->release();
+	}
+
 	 const node_container& objects() const {
         return m_objects;
     }
diff --git a/src/MoonP/moon_ast.cpp b/src/MoonP/moon_ast.cpp
index 0ccd0ed..f3fe31e 100644
--- a/src/MoonP/moon_ast.cpp
+++ b/src/MoonP/moon_ast.cpp
@@ -79,6 +79,7 @@ AST_IMPL(ColonChainItem)
 AST_IMPL(default_value)
 AST_IMPL(Slice)
 AST_IMPL(Invoke)
+AST_IMPL(existential_op)
 AST_IMPL(TableLit)
 AST_IMPL(TableBlock)
 AST_IMPL(class_member_list)
diff --git a/src/MoonP/moon_ast.h b/src/MoonP/moon_ast.h
index a614465..8b80af3 100644
--- a/src/MoonP/moon_ast.h
+++ b/src/MoonP/moon_ast.h
@@ -407,11 +407,14 @@ AST_NODE(Invoke, "Invoke"_id)
 	AST_MEMBER(Invoke, &sep, &args)
 AST_END(Invoke)
 
+AST_LEAF(existential_op, "existential_op"_id)
+AST_END(existential_op)
+
 class InvokeArgs_t;
 
 AST_NODE(ChainValue, "ChainValue"_id)
 	ast_ptr<true, Seperator_t> sep;
-	ast_sel_list<true, Callable_t, Invoke_t, DotChainItem_t, ColonChainItem_t, Slice_t, Exp_t, String_t, InvokeArgs_t> items;
+	ast_sel_list<true, Callable_t, Invoke_t, DotChainItem_t, ColonChainItem_t, Slice_t, Exp_t, String_t, InvokeArgs_t, existential_op_t> items;
 	AST_MEMBER(ChainValue, &sep, &items)
 AST_END(ChainValue)
 
diff --git a/src/MoonP/moon_compiler.cpp b/src/MoonP/moon_compiler.cpp
index d30f413..9164f6a 100644
--- a/src/MoonP/moon_compiler.cpp
+++ b/src/MoonP/moon_compiler.cpp
@@ -15,6 +15,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
 #include <memory>
 #include <sstream>
 #include <string_view>
+#include <iostream>
 using namespace std::string_view_literals;
 #include "MoonP/parser.hpp"
 #include "MoonP/moon_ast.h"
@@ -426,6 +427,35 @@ private:
 		return ast_is<InvokeArgs_t, Invoke_t>(chainValue->items.back());
 	}
 
+	bool isSpecialChainValue(ChainValue_t* chainValue) {
+		if (ast_is<ColonChainItem_t>(chainValue->items.back())) {
+			return true;
+		}
+		for (auto item : chainValue->items.objects()) {
+			if (auto colonChain = ast_cast<ColonChainItem_t>(item)) {
+				if (ast_is<LuaKeyword_t>(colonChain->name)) {
+					return true;
+				}
+			} else if (ast_is<existential_op_t>(item) && item != chainValue->items.back()) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+	std::string singleVariableFrom(ChainValue_t* chainValue) {
+		BLOCK_START
+		BREAK_IF(!chainValue);
+		BREAK_IF(chainValue->items.size() != 1);
+		auto callable = ast_cast<Callable_t>(chainValue->items.front());
+		BREAK_IF(!callable || !(callable->item.is<Variable_t>() || callable->getByPath<SelfName_t,self_t>()));
+		str_list tmp;
+		transformCallable(callable, tmp);
+		return tmp.back();
+		BLOCK_END
+		return Empty;
+	}
+
 	std::string singleVariableFrom(ast_node* expList) {
 		if (!ast_is<Exp_t, ExpList_t>(expList)) return Empty;
 		BLOCK_START
@@ -435,7 +465,7 @@ private:
 		BREAK_IF(!chainValue);
 		BREAK_IF(chainValue->items.size() != 1);
 		auto callable = ast_cast<Callable_t>(chainValue->items.front());
-		BREAK_IF(!callable || !callable->item.is<Variable_t>());
+		BREAK_IF(!callable || !(callable->item.is<Variable_t>() || callable->getByPath<SelfName_t,self_t>()));
 		str_list tmp;
 		transformCallable(callable, tmp);
 		return tmp.back();
@@ -443,22 +473,6 @@ private:
 		return Empty;
 	}
 
-	bool isColonChain(ChainValue_t* chainValue) {
-		return ast_is<ColonChainItem_t>(chainValue->items.back());
-	}
-
-	bool hasKeywordColonChainItem(ChainValue_t* chainValue) {
-		const auto& chainList = chainValue->items.objects();
-		for (auto it = chainList.begin(); it != chainList.end(); ++it) {
-			if (auto colonItem = ast_cast<ColonChainItem_t>(*it)) {
-				if (colonItem->name.is<LuaKeyword_t>()) {
-					return true;
-				}
-			}
-		}
-		return false;
-	}
-
 	bool isAssignable(const node_container& chainItems) {
 		if (chainItems.size() == 1) {
 			 auto firstItem = chainItems.back();
@@ -539,7 +553,7 @@ private:
 		}
 		auto line = _converter.to_bytes(std::wstring(begin, end));
 		int oldCol = loc->m_begin.m_col;
-		int col = loc->m_begin.m_col - 1;
+		int col = std::max(0, oldCol - 1);
 		auto it = begin;
 		for (int i = 0; i < oldCol; ++i) {
 			if (*it > ASCII) {
@@ -558,7 +572,7 @@ private:
 		auto x = statement;
 		if (statement->appendix) {
 			if (auto assignment = assignmentFrom(statement)) {
-				auto preDefine = getPredefine(transformAssignDefs(assignment->expList));
+				auto preDefine = getPredefine(assignment);
 				if (!preDefine.empty()) out.push_back(preDefine + nll(statement));
 			}
 			auto appendix = statement->appendix.get();
@@ -790,7 +804,7 @@ private:
 	}
 
 	std::string getDestrucureDefine(ExpListAssign_t* assignment) {
-		auto info = extractDestructureInfo(assignment);
+		auto info = extractDestructureInfo(assignment, true);
 		if (!info.first.empty()) {
 			for (const auto& destruct : info.first) {
 				str_list defs;
@@ -909,11 +923,10 @@ private:
 			}
 			case "With"_id: {
 				auto withNode = static_cast<With_t*>(value);
-				str_list temp;
 				auto expList = assignment->expList.get();
 				std::string preDefine = getPredefine(assignment);
-				transformWith(withNode, temp, expList);
-				out.push_back(preDefine + temp.back());
+				transformWith(withNode, out, expList);
+				out.back() = preDefine + out.back();
 				return;
 			}
 			case "Do"_id: {
@@ -940,50 +953,42 @@ private:
 				return;
 			}
 			case "For"_id: {
-				str_list temp;
 				auto expList = assignment->expList.get();
 				std::string preDefine = getPredefine(assignment);
-				transformForInPlace(static_cast<For_t*>(value), temp, expList);
-				out.push_back(preDefine + temp.back());
+				transformForInPlace(static_cast<For_t*>(value), out, expList);
+				out.back() = preDefine + out.back();
 				return;
 			}
 			case "ForEach"_id: {
-				str_list temp;
 				auto expList = assignment->expList.get();
 				std::string preDefine = getPredefine(assignment);
-				transformForEachInPlace(static_cast<ForEach_t*>(value), temp, expList);
-				out.push_back(preDefine + temp.back());
+				transformForEachInPlace(static_cast<ForEach_t*>(value), out, expList);
+				out.back() = preDefine + out.back();
 				return;
 			}
 			case "ClassDecl"_id: {
-				str_list temp;
 				auto expList = assignment->expList.get();
 				std::string preDefine = getPredefine(assignment);
-				transformClassDecl(static_cast<ClassDecl_t*>(value), temp, ExpUsage::Assignment, expList);
-				out.push_back(preDefine + temp.back());
+				transformClassDecl(static_cast<ClassDecl_t*>(value), out, ExpUsage::Assignment, expList);
+				out.back() = preDefine + out.back();
 				return;
 			}
 			case "While"_id: {
-				str_list temp;
 				auto expList = assignment->expList.get();
 				std::string preDefine = getPredefine(assignment);
-				transformWhileInPlace(static_cast<While_t*>(value), temp, expList);
-				out.push_back(preDefine + temp.back());
+				transformWhileInPlace(static_cast<While_t*>(value), out, expList);
+				out.back() = preDefine + out.back();
 				return;
 			}
 		}
 		auto exp = ast_cast<Exp_t>(value);
 		BREAK_IF(!exp);
 		if (auto chainValue = exp->value->item.as<ChainValue_t>()) {
-			if (isColonChain(chainValue)) {
-				auto assignable = assignment->expList.get();
-				std::string preDefine = getPredefine(transformAssignDefs(assignable));
-				transformColonChain(chainValue, out, ExpUsage::Assignment, assignable);
-				auto nl = preDefine.empty() ? Empty : nll(chainValue);
-				if (!preDefine.empty()) out.back() = preDefine + nl + out.back();
-				return;
-			} else if (hasKeywordColonChainItem(chainValue)) {
-				transformChainValue(chainValue, out, ExpUsage::Assignment, assignment->expList);
+			if (isSpecialChainValue(chainValue)) {
+				auto expList = assignment->expList.get();
+				std::string preDefine = getPredefine(assignment);
+				transformChainValue(chainValue, out, ExpUsage::Assignment, expList);
+				out.back() = preDefine + out.back();
 				return;
 			}
 		}
@@ -1169,7 +1174,7 @@ private:
 	}
 
 	std::pair<std::list<Destructure>, ast_ptr<false, ExpListAssign_t>>
-		extractDestructureInfo(ExpListAssign_t* assignment) {
+		extractDestructureInfo(ExpListAssign_t* assignment, bool varDefOnly = false) {
 		auto x = assignment;
 		std::list<Destructure> destructs;
 		if (!assignment->action.is<Assign_t>()) return { destructs, nullptr };
@@ -1187,19 +1192,21 @@ private:
 			while (values.size() < size) values.emplace_back(nullNode);
 		}
 		using iter = node_container::iterator;
-		std::vector<std::pair<iter, iter>> destructPairs;
+		std::vector<std::pair<iter,iter>> destructPairs;
 		str_list temp;
 		for (auto i = exprs.begin(), j = values.begin(); i != exprs.end(); ++i, ++j) {
 			auto expr = *i;
 			ast_node* destructNode = expr->getByPath<Value_t, SimpleValue_t, TableLit_t>();
 			if (destructNode || (destructNode = expr->getByPath<Value_t, simple_table_t>())) {
 				destructPairs.push_back({i,j});
-				pushScope();
-				transformAssignItem(*j, temp);
-				popScope();
 				auto& destruct = destructs.emplace_back();
-				destruct.value = temp.back();
-				temp.pop_back();
+				if (!varDefOnly) {
+					pushScope();
+					transformAssignItem(*j, temp);
+					destruct.value = temp.back();
+					temp.pop_back();
+					popScope();
+				}
 				auto pairs = destructFromExp(expr);
 				destruct.items = std::move(pairs);
 			}
@@ -1244,7 +1251,7 @@ private:
 						BREAK_IF(!exp);
 						auto var = singleVariableFrom(exp);
 						BREAK_IF(!var.empty());
-						auto upVar = getUnusedName("_update_");
+						auto upVar = getUnusedName("_update_"sv);
 						auto assignment = x->new_ptr<ExpListAssign_t>();
 						assignment->expList.set(toAst<ExpList_t>(upVar, ExpList, x));
 						auto assign = x->new_ptr<Assign_t>();
@@ -1532,11 +1539,7 @@ private:
 			case "simple_table"_id: transform_simple_table(static_cast<simple_table_t*>(item), out); break;
 			case "ChainValue"_id: {
 				auto chainValue = static_cast<ChainValue_t*>(item);
-				if (isColonChain(chainValue)) {
-					transformColonChainClosure(chainValue, out);
-				} else {
-					transformChainValue(chainValue, out);
-				}
+				transformChainValue(chainValue, out);
 				break;
 			}
 			case "String"_id: transformString(static_cast<String_t*>(item), out); break;
@@ -1689,7 +1692,7 @@ private:
 							any->decls.push_back(var);
 						}
 					}
-					auto info = extractDestructureInfo(assignment);
+					auto info = extractDestructureInfo(assignment, true);
 					if (!info.first.empty()) {
 						for (const auto& destruct : info.first)
 							for (const auto& item : destruct.items)
@@ -1803,12 +1806,10 @@ private:
 					}
 				}
 				if (auto chainValue = singleValue->item.as<ChainValue_t>()) {
-					if (isColonChain(chainValue)) {
-						transformColonChain(chainValue, out, ExpUsage::Return);
-					} else {
+					if (isSpecialChainValue(chainValue)) {
 						transformChainValue(chainValue, out, ExpUsage::Return);
+						return;
 					}
-					return;
 				}
 				transformValue(singleValue, out);
 				out.back() = indent() + s("return "sv) + out.back() + nlr(returnNode);
@@ -1980,111 +1981,292 @@ private:
 		}
 	}
 
-	void transformColonChainClosure(ChainValue_t* chainValue, str_list& out) {
-		str_list temp;
-		temp.push_back(s("(function()"sv) + nll(chainValue));
-		pushScope();
-		transformColonChain(chainValue, temp, ExpUsage::Return);
-		popScope();
-		temp.push_back(indent() + s("end)()"sv));
-		out.push_back(join(temp));
+	bool transformChainEndWithEOP(const node_container& chainList, str_list& out, ExpUsage usage, ExpList_t*) {
+		auto x = chainList.front();
+		if (ast_cast<existential_op_t>(chainList.back())) {
+			auto parens = x->new_ptr<Parens_t>();
+			{
+				auto chainValue = x->new_ptr<ChainValue_t>();
+				for (auto item : chainList) {
+					chainValue->items.push_back(item);
+				}
+				chainValue->items.pop_back();
+				auto value = x->new_ptr<Value_t>();
+				value->item.set(chainValue);
+				auto opValue = x->new_ptr<exp_op_value_t>();
+				opValue->op.set(toAst<BinaryOperator_t>("!="sv, BinaryOperator, x));
+				opValue->value.set(toAst<Value_t>("nil"sv, Value, x));
+				auto exp = x->new_ptr<Exp_t>();
+				exp->value.set(value);
+				exp->opValues.push_back(opValue);
+				parens->expr.set(exp);
+			}
+			transformParens(parens, out);
+			if (usage == ExpUsage::Return) {
+				out.back().insert(0, indent() + s("return "sv));
+				out.back().append(nlr(x));
+			}
+			return true;
+		}
+		return false;
 	}
 
-	void transformColonChain(ChainValue_t* chainValue, str_list& out, ExpUsage usage = ExpUsage::Common, ExpList_t* expList = nullptr) {
-		auto x = chainValue;
-		const auto& chainList = chainValue->items.objects();
-		auto baseChain = x->new_ptr<ChainValue_t>();
-		switch (chainList.front()->getId()) {
-			case "DotChainItem"_id:
-			case "ColonChainItem"_id:
-				if (_withVars.empty()) {
-					throw std::logic_error(debugInfo("Short dot/colon syntax must be called within a with block."sv, chainList.front()));
-				} else {
-					baseChain->items.push_back(toAst<Callable_t>(_withVars.top(), Callable, x));
-				}
+	bool transformChainWithEOP(const node_container& chainList, str_list& out, ExpUsage usage, ExpList_t* assignList) {
+		auto opIt = std::find_if(chainList.begin(), chainList.end(), [](ast_node* node) { return ast_is<existential_op_t>(node); });
+		if (opIt != chainList.end()) {
+			auto x = chainList.front();
+			str_list temp;
+			if (usage == ExpUsage::Closure) {
+				temp.push_back(s("(function()"sv) + nll(x));
+				pushScope();
+			}
+			auto partOne = x->new_ptr<ChainValue_t>();
+			for (auto it = chainList.begin();it != opIt;++it) {
+				partOne->items.push_back(*it);
+			}
+			BLOCK_START
+			auto back = ast_cast<Callable_t>(partOne->items.back());
+			BREAK_IF(!back);
+			auto selfName = ast_cast<SelfName_t>(back->item);
+			BREAK_IF(!selfName);
+			if (auto sname = ast_cast<self_name_t>(selfName->name)) {
+				auto colonItem = x->new_ptr<ColonChainItem_t>();
+				colonItem->name.set(sname->name);
+				partOne->items.pop_back();
+				partOne->items.push_back(toAst<Callable_t>("@"sv, Callable, x));
+				partOne->items.push_back(colonItem);
 				break;
-		}
-		auto end = --chainList.end();
-		for (auto it = chainList.begin(); it != end; ++it) {
-			baseChain->items.push_back(*it);
-		}
-		auto colonChainItem = static_cast<ColonChainItem_t*>(chainList.back());
-		auto funcName = toString(colonChainItem->name);
-		if (usage != ExpUsage::Return) pushScope();
-		auto baseVar = getUnusedName("_base_"sv);
-		auto fnVar = getUnusedName("_fn_"sv);
-		str_list temp;
-		{
-			auto value = x->new_ptr<Value_t>();
-			value->item.set(baseChain);
-			auto exp = x->new_ptr<Exp_t>();
-			exp->value.set(value);
-			auto assign = x->new_ptr<Assign_t>();
-			assign->values.push_back(exp);
-			auto assignment = x->new_ptr<ExpListAssign_t>();
-			assignment->expList.set(toAst<ExpList_t>(baseVar, ExpList, x));
-			assignment->action.set(assign);
-			transformAssignment(assignment, temp);
-		}
-		{
-			auto assign = x->new_ptr<Assign_t>();
-			assign->values.push_back(toAst<Exp_t>(baseVar + "." + funcName, Exp, x));
-			auto assignment = x->new_ptr<ExpListAssign_t>();
-			assignment->expList.set(toAst<ExpList_t>(fnVar, ExpList, x));
-			assignment->action.set(assign);
-			transformAssignment(assignment, temp);
-		}
-		auto funLit = toAst<Exp_t>(s("(...)-> "sv) + fnVar + s(" "sv) + baseVar + s(", ..."sv), Exp, x);
-		switch (usage) {
-			case ExpUsage::Return:
-				transformExp(funLit, temp);
-				_buf << temp.front();
-				_buf << *(++temp.begin());
-				_buf << indent() << "return " << temp.back() << nll(chainValue);
+			}
+			if (auto cname = ast_cast<self_class_name_t>(selfName->name)) {
+				auto colonItem = x->new_ptr<ColonChainItem_t>();
+				colonItem->name.set(cname->name);
+				partOne->items.pop_back();
+				partOne->items.push_back(toAst<Callable_t>("@@"sv, Callable, x));
+				partOne->items.push_back(colonItem);
 				break;
-			case ExpUsage::Assignment: {
+			}
+			BLOCK_END
+			auto objVar = singleVariableFrom(partOne);
+			if (objVar.empty()) {
+				objVar = getUnusedName("_obj_"sv);
+				if (auto colonItem = ast_cast<ColonChainItem_t>(partOne->items.back())) {
+					auto chainValue = x->new_ptr<ChainValue_t>();
+					chainValue->items.dup(partOne->items);
+					chainValue->items.pop_back();
+					if (chainValue->items.empty()) {
+						if (_withVars.empty()) {
+							throw std::logic_error(debugInfo("Short dot/colon syntax must be called within a with block."sv, x));
+						}
+					chainValue->items.push_back(toAst<Callable_t>(_withVars.top(), Callable, x));
+					}
+					auto newObj = singleVariableFrom(chainValue);
+					if (!newObj.empty()) {
+						objVar = newObj;
+					} else {
+						auto value = x->new_ptr<Value_t>();
+						value->item.set(chainValue);
+						auto exp = x->new_ptr<Exp_t>();
+						exp->value.set(value);
+						auto assign = x->new_ptr<Assign_t>();
+						assign->values.push_back(exp);
+						auto expListAssign = x->new_ptr<ExpListAssign_t>();
+						expListAssign->expList.set(toAst<ExpList_t>(objVar, ExpList, x));
+						expListAssign->action.set(assign);
+						transformAssignment(expListAssign, temp);
+					}
+					auto dotItem = x->new_ptr<DotChainItem_t>();
+					auto name = colonItem->name.get();
+					if (auto keyword = ast_cast<LuaKeyword_t>(name)) {
+						name = keyword->name.get();
+					}
+					dotItem->name.set(name);
+					partOne->items.clear();
+					partOne->items.push_back(toAst<Callable_t>(objVar, Callable, x));
+					partOne->items.push_back(dotItem);
+					auto it = opIt; ++it;
+					if (it != chainList.end() && ast_is<Invoke_t, InvokeArgs_t>(*it)) {
+
+						if (auto invoke = ast_cast<Invoke_t>(*it)) {
+							invoke->args.push_front(toAst<Exp_t>(objVar, Exp, x));
+						} else {
+							auto invokeArgs = static_cast<InvokeArgs_t*>(*it);
+							invokeArgs->args.push_front(toAst<Exp_t>(objVar, Exp, x));
+						}
+					}
+					objVar = getUnusedName("_obj_"sv);
+				}
+				auto value = x->new_ptr<Value_t>();
+				value->item.set(partOne);
+				auto exp = x->new_ptr<Exp_t>();
+				exp->value.set(value);
+				auto assign = x->new_ptr<Assign_t>();
+				assign->values.push_back(exp);
+				auto expListAssign = x->new_ptr<ExpListAssign_t>();
+				expListAssign->expList.set(toAst<ExpList_t>(objVar, ExpList, x));
+				expListAssign->action.set(assign);
+				transformAssignment(expListAssign, temp);
+			}
+			_buf << indent() << "if "sv << objVar << " ~= nil then"sv << nll(x);
+			temp.push_back(clearBuf());
+			pushScope();
+			auto partTwo = x->new_ptr<ChainValue_t>();
+			partTwo->items.push_back(toAst<Callable_t>(objVar, Callable, x));
+			for (auto it = ++opIt;it != chainList.end();++it) {
+				partTwo->items.push_back(*it);
+			}
+			switch (usage) {
+				case ExpUsage::Common:
+					transformChainValue(partTwo, temp, ExpUsage::Common);
+					break;
+				case ExpUsage::Assignment: {
+					auto value = x->new_ptr<Value_t>();
+					value->item.set(partTwo);
+					auto exp = x->new_ptr<Exp_t>();
+					exp->value.set(value);
+					auto assign = x->new_ptr<Assign_t>();
+					assign->values.push_back(exp);
+					auto assignment = x->new_ptr<ExpListAssign_t>();
+					assignment->expList.set(assignList);
+					assignment->action.set(assign);
+					transformAssignment(assignment, temp);
+					break;
+				}
+				case ExpUsage::Return:
+				case ExpUsage::Closure: {
+					auto value = x->new_ptr<Value_t>();
+					value->item.set(partTwo);
+					auto exp = x->new_ptr<Exp_t>();
+					exp->value.set(value);
+					auto ret = x->new_ptr<Return_t>();
+					auto expListLow = x->new_ptr<ExpListLow_t>();
+					expListLow->exprs.push_back(exp);
+					ret->valueList.set(expListLow);
+					transformReturn(ret, temp);
+					break;
+				}
+			}
+			popScope();
+			temp.push_back(indent() + s("end"sv) + nlr(x));
+			switch (usage) {
+				case ExpUsage::Return:
+					temp.push_back(indent() + s("return nil"sv) + nlr(x));
+					break;
+				case ExpUsage::Closure:
+					temp.push_back(indent() + s("return nil"sv) + nlr(x));
+					popScope();
+					temp.push_back(indent() + s("end)()"sv));
+					break;
+				default:
+					break;
+			}
+			out.push_back(join(temp));
+			return true;
+		}
+		return false;
+	}
+
+	bool transformChainEndWithColonItem(const node_container& chainList, str_list& out, ExpUsage usage, ExpList_t* assignList) {
+		if (ast_is<ColonChainItem_t>(chainList.back())) {
+			auto x = chainList.front();
+			str_list temp;
+			switch (usage) {
+				case ExpUsage::Assignment:
+					temp.push_back(indent() + s("do"sv) + nll(x));
+					pushScope();
+					break;
+				case ExpUsage::Closure:
+					temp.push_back(s("(function()"sv) + nll(x));
+					pushScope();
+					break;
+				default:
+					break;
+			}
+			auto baseChain = x->new_ptr<ChainValue_t>();
+			switch (chainList.front()->getId()) {
+				case "DotChainItem"_id:
+				case "ColonChainItem"_id:
+					if (_withVars.empty()) {
+						throw std::logic_error(debugInfo("Short dot/colon syntax must be called within a with block."sv, chainList.front()));
+					} else {
+						baseChain->items.push_back(toAst<Callable_t>(_withVars.top(), Callable, x));
+					}
+					break;
+			}
+			auto end = --chainList.end();
+			for (auto it = chainList.begin(); it != end; ++it) {
+				baseChain->items.push_back(*it);
+			}
+			auto colonChainItem = static_cast<ColonChainItem_t*>(chainList.back());
+			auto funcName = toString(colonChainItem->name);
+			auto baseVar = getUnusedName("_base_"sv);
+			auto fnVar = getUnusedName("_fn_"sv);
+			{
+				auto value = x->new_ptr<Value_t>();
+				value->item.set(baseChain);
+				auto exp = x->new_ptr<Exp_t>();
+				exp->value.set(value);
 				auto assign = x->new_ptr<Assign_t>();
-				assign->values.push_back(funLit);
+				assign->values.push_back(exp);
 				auto assignment = x->new_ptr<ExpListAssign_t>();
-				assignment->expList.set(expList);
+				assignment->expList.set(toAst<ExpList_t>(baseVar, ExpList, x));
 				assignment->action.set(assign);
 				transformAssignment(assignment, temp);
-				_buf << indent(-1) << "do"sv << nll(chainValue);
-				_buf << temp.front();
-				_buf << *(++temp.begin());
-				_buf << temp.back();
-				popScope();
-				_buf << indent() << "end"sv << nll(chainValue);
-				break;
 			}
-			case ExpUsage::Common: {
+			{
 				auto assign = x->new_ptr<Assign_t>();
-				assign->values.push_back(funLit);
+				assign->values.push_back(toAst<Exp_t>(baseVar + "." + funcName, Exp, x));
 				auto assignment = x->new_ptr<ExpListAssign_t>();
-				assignment->expList.set(toAst<ExpList_t>("_"sv, ExpList, x));
+				assignment->expList.set(toAst<ExpList_t>(fnVar, ExpList, x));
 				assignment->action.set(assign);
 				transformAssignment(assignment, temp);
-				_buf << indent(-1) << "do"sv << nll(chainValue);
-				_buf << temp.front();
-				_buf << *(++temp.begin());
-				_buf << temp.back();
-				popScope();
-				_buf << indent() << "end"sv << nll(chainValue);
-				break;
 			}
-			default: break;
+			auto funLit = toAst<Exp_t>(s("(...)-> "sv) + fnVar + s(" "sv) + baseVar + s(", ..."sv), Exp, x);
+			switch (usage) {
+				case ExpUsage::Closure:
+				case ExpUsage::Return:
+					transformExp(funLit, temp);
+					_buf << temp.front();
+					_buf << *(++temp.begin());
+					_buf << indent() << "return " << temp.back() << nll(x);
+					break;
+				case ExpUsage::Assignment: {
+					auto assign = x->new_ptr<Assign_t>();
+					assign->values.push_back(funLit);
+					auto assignment = x->new_ptr<ExpListAssign_t>();
+					assignment->expList.set(assignList);
+					assignment->action.set(assign);
+					transformAssignment(assignment, temp);
+					break;
+				}
+				default:
+					break;
+			}
+			switch (usage) {
+				case ExpUsage::Assignment:
+					popScope();
+					temp.push_back(indent() + s("end"sv) + nlr(x));
+					break;
+				case ExpUsage::Closure:
+					popScope();
+					temp.push_back(indent() + s("end)()"sv));
+					break;
+				default:
+					break;
+			}
+			out.push_back(join(temp));
+			return true;
 		}
-		out.push_back(clearBuf());
+		return false;
 	}
 
 	void transformChainList(const node_container& chainList, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) {
 		auto x = chainList.front();
 		str_list temp;
-		switch (chainList.front()->getId()) {
+		switch (x->getId()) {
 			case "DotChainItem"_id:
 			case "ColonChainItem"_id:
 				if (_withVars.empty()) {
-					throw std::logic_error(debugInfo("Short dot/colon syntax must be called within a with block."sv, chainList.front()));
+					throw std::logic_error(debugInfo("Short dot/colon syntax must be called within a with block."sv, x));
 				} else {
 					temp.push_back(_withVars.top());
 				}
@@ -2101,8 +2283,20 @@ private:
 					break;
 				case "ColonChainItem"_id: {
 					auto colonItem = static_cast<ColonChainItem_t*>(item);
-					auto next = it; ++next;
+					auto current = it;
+					auto next = current; ++next;
 					auto followItem = next != chainList.end() ? *next : nullptr;
+					if (current != chainList.begin()) {
+						--current;
+						if (!ast_is<existential_op_t>(*current)) {
+							++current;
+						}
+					}
+					if (ast_is<existential_op_t>(followItem)) {
+						++next;
+						followItem = next != chainList.end() ? *next : nullptr;
+						--next;
+					}
 					if (!ast_is<Invoke_t, InvokeArgs_t>(followItem)) {
 						throw std::logic_error(debugInfo("Colon chain item must be followed by invoke arguments."sv, colonItem));
 					}
@@ -2117,7 +2311,7 @@ private:
 								chainValue->items.push_back(toAst<Callable_t>(_withVars.top(), Callable, x));
 									break;
 							}
-							for (auto i = chainList.begin(); i != it; ++i) {
+							for (auto i = chainList.begin(); i != current; ++i) {
 								chainValue->items.push_back(*i);
 							}
 							auto value = x->new_ptr<Value_t>();
@@ -2141,6 +2335,9 @@ private:
 							auto name = toString(colonItem->name);
 							auto chainValue = x->new_ptr<ChainValue_t>();
 							chainValue->items.push_back(toAst<Callable_t>(callVar, Callable, x));
+							if (ast_is<existential_op_t>(*current)) {
+								chainValue->items.push_back(x->new_ptr<existential_op_t>());
+							}
 							chainValue->items.push_back(toAst<Exp_t>(s("\""sv) + name + s("\""sv), Exp, x));
 							if (auto invoke = ast_cast<Invoke_t>(followItem)) {
 								invoke->args.push_front(toAst<Exp_t>(callVar, Exp, x));
@@ -2148,8 +2345,7 @@ private:
 								auto invokeArgs = static_cast<InvokeArgs_t*>(followItem);
 								invokeArgs->args.push_front(toAst<Exp_t>(callVar, Exp, x));
 							}
-							chainValue->items.push_back(followItem);
-							for (auto i = ++next; i != chainList.end(); ++i) {
+							for (auto i = next; i != chainList.end(); ++i) {
 								chainValue->items.push_back(*i);
 							}
 							auto value = x->new_ptr<Value_t>();
@@ -2244,7 +2440,17 @@ private:
 	}
 
 	void transformChainValue(ChainValue_t* chainValue, str_list& out, ExpUsage usage = ExpUsage::Closure, ExpList_t* assignList = nullptr) {
-		transformChainList(chainValue->items.objects(), out, usage, assignList);
+		const auto& chainList = chainValue->items.objects();
+		if (transformChainEndWithEOP(chainList, out, usage, assignList)) {
+			return;
+		}
+		if (transformChainWithEOP(chainList, out, usage, assignList)) {
+			return;
+		}
+		if (transformChainEndWithColonItem(chainList, out, usage, assignList)) {
+			return;
+		}
+		transformChainList(chainList, out, usage, assignList);
 	}
 
 	void transformAssignableChain(AssignableChain_t* chain, str_list& out) {
@@ -2957,7 +3163,7 @@ private:
 					if (auto assignment = assignmentFrom(statement)) {
 						auto names = transformAssignDefs(assignment->expList.get());
 						varDefs.insert(varDefs.end(), names.begin(), names.end());
-						auto info = extractDestructureInfo(assignment);
+						auto info = extractDestructureInfo(assignment, true);
 						if (!info.first.empty()) {
 							for (const auto& destruct : info.first)
 								for (const auto& item : destruct.items)
@@ -3342,7 +3548,7 @@ private:
 						if (!names.empty()) {
 							return traversal::Stop;
 						}
-						auto info = extractDestructureInfo(assignment);
+						auto info = extractDestructureInfo(assignment, true);
 						if (!info.first.empty()) {
 							for (const auto& destruct : info.first)
 								for (const auto& item : destruct.items)
diff --git a/src/MoonP/moon_parser.cpp b/src/MoonP/moon_parser.cpp
index 1005463..7cc4129 100644
--- a/src/MoonP/moon_parser.cpp
+++ b/src/MoonP/moon_parser.cpp
@@ -289,9 +289,9 @@ extern rule Value;
 rule exp_op_value = Space >> BinaryOperator >> *SpaceBreak >> Value;
 rule Exp = Value >> *exp_op_value;
 
-extern rule Chain, Callable, InvokeArgs;
+extern rule Chain, Callable, InvokeArgs, existential_op;
 
-rule ChainValue = Seperator >> (Chain | Callable) >> -InvokeArgs;
+rule ChainValue = Seperator >> (Chain | Callable) >> -existential_op >> -InvokeArgs;
 
 extern rule KeyValue, String, SimpleValue;
 
@@ -345,9 +345,10 @@ rule FnArgs = (symx('(') >> *SpaceBreak >> -FnArgsExpList >> *SpaceBreak >> sym(
 
 extern rule ChainItems, DotChainItem, ColonChain;
 
-rule chain_call = (Callable | String) >> ChainItems;
+rule existential_op = expr('?');
+rule chain_call = (Callable | String) >> -existential_op >> ChainItems;
 rule chain_item = and_(set(".\\")) >> ChainItems;
-rule chain_dot_chain = DotChainItem >> -ChainItems;
+rule chain_dot_chain = DotChainItem >> -existential_op >> -ChainItems;
 
 rule Chain = chain_call | chain_item |
 	Space >> (chain_dot_chain | ColonChain);
@@ -362,11 +363,11 @@ rule ChainItems = chain_with_colon | ColonChain;
 extern rule Invoke, Slice;
 
 rule Index = symx('[') >> Exp >> sym(']');
-rule ChainItem = Invoke | DotChainItem | Slice | Index;
+rule ChainItem = Invoke >> -existential_op | DotChainItem >> -existential_op | Slice | Index >> -existential_op;
 rule DotChainItem = symx('.') >> Name;
 rule ColonChainItem = symx('\\') >> (LuaKeyword | Name);
-rule invoke_chain = Invoke >> -ChainItems;
-rule ColonChain = ColonChainItem >> -invoke_chain;
+rule invoke_chain = Invoke >> -existential_op >> -ChainItems;
+rule ColonChain = ColonChainItem >> -existential_op >> -invoke_chain;
 
 rule default_value = true_();
 rule Slice =
diff --git a/src/moonc.cpp b/src/moonc.cpp
index 02d5275..4498bee 100644
--- a/src/moonc.cpp
+++ b/src/moonc.cpp
@@ -22,14 +22,13 @@ int main(int narg, const char** args) {
 "    -p          Write output to standard out\n"
 "    -b          Dump compile time (doesn't write output)\n"
 "    -l          Write line numbers from source codes\n"
-"    -a          Allow expression list not in the end of body block\n"
-"    -s          Use space over tab\n"
 "    -v          Print version\n";
 	if (narg == 0) {
 		std::cout << help;
 		return 0;
 	}
 	MoonP::MoonConfig config;
+	config.reserveLineNumber = false;
 	bool writeToFile = true;
 	bool dumpCompileTime = false;
 	std::string targetPath;
@@ -37,18 +36,9 @@ int main(int narg, const char** args) {
 	std::list<std::string> files;
 	for (int i = 1; i < narg; ++i) {
 		switch (hash(args[i])) {
-			case "-a"_id:
-				config.allowExprNotInTheEndOfBody = true;
-				break;
-			case "-s"_id:
-				config.spaceOverTab = true;
-				break;
 			case "-l"_id:
 				config.reserveLineNumber = true;
 				break;
-			case "-r"_id:
-				config.reuseVariable = true;
-				break;
 			case "-p"_id:
 				writeToFile = false;
 				break;
-- 
cgit v1.2.3-55-g6feb