emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[nongnu] elpa/kotlin-mode 3a84689d0b 10/10: Merge pull request #53 from


From: ELPA Syncer
Subject: [nongnu] elpa/kotlin-mode 3a84689d0b 10/10: Merge pull request #53 from taku0/rewite-indentation
Date: Tue, 17 Jan 2023 15:08:10 -0500 (EST)

branch: elpa/kotlin-mode
commit 3a84689d0bce5eecd15008bc2f71c0e058ad7671
Merge: ff4637c4ea 70de2560a6
Author: Gregg Hernandez <greggory.hz@gmail.com>
Commit: GitHub <noreply@github.com>

    Merge pull request #53 from taku0/rewite-indentation
    
    Rewite indentation engine
---
 doc/indentation_logic/.gitignore          |    1 +
 doc/indentation_logic/Makefile            |   11 +
 doc/indentation_logic/pages.pdf           |  Bin 0 -> 272143 bytes
 doc/indentation_logic/src/pages.svg       | 3322 +++++++++++++++++++++++++++++
 doc/indentation_logic/src/split_pages.kts |   56 +
 kotlin-mode-indent.el                     | 1955 +++++++++++++++++
 kotlin-mode-lexer.el                      | 2309 +++++++++++++++++++-
 kotlin-mode.el                            |  345 +--
 test/kotlin-mode-test.el                  |  104 +-
 test/pathological.kt                      | 2150 +++++++++++++++++++
 test/sample.kt                            |   24 +-
 11 files changed, 9946 insertions(+), 331 deletions(-)

diff --git a/doc/indentation_logic/.gitignore b/doc/indentation_logic/.gitignore
new file mode 100644
index 0000000000..63fe867247
--- /dev/null
+++ b/doc/indentation_logic/.gitignore
@@ -0,0 +1 @@
+/pages
diff --git a/doc/indentation_logic/Makefile b/doc/indentation_logic/Makefile
new file mode 100644
index 0000000000..5a53c6f142
--- /dev/null
+++ b/doc/indentation_logic/Makefile
@@ -0,0 +1,11 @@
+pages.pdf: pages/page_000.pdf
+       pdfunite pages/page_*.pdf pages.pdf
+
+pages/page_000.pdf: pages/page_000.svg
+       for i in pages/page_*.svg ; do inkscape --export-pdf=pages/"$$( 
basename "$${i}" .svg )".pdf "$${i}" ; done
+
+pages/page_000.svg: src/pages.svg src/split_pages.kts
+       kotlinc-jvm -script src/split_pages.kts src/pages.svg
+
+clean:
+       rm -rf pages.pdf pages
diff --git a/doc/indentation_logic/pages.pdf b/doc/indentation_logic/pages.pdf
new file mode 100644
index 0000000000..b0d2fde34a
Binary files /dev/null and b/doc/indentation_logic/pages.pdf differ
diff --git a/doc/indentation_logic/src/pages.svg 
b/doc/indentation_logic/src/pages.svg
new file mode 100644
index 0000000000..13b414a76a
--- /dev/null
+++ b/doc/indentation_logic/src/pages.svg
@@ -0,0 +1,3322 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/";
+   xmlns:cc="http://creativecommons.org/ns#";
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#";
+   xmlns:svg="http://www.w3.org/2000/svg";
+   xmlns="http://www.w3.org/2000/svg";
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd";
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape";
+   width="1024"
+   height="768"
+   viewBox="0 0 1024 768.00003"
+   version="1.1"
+   id="svg8"
+   inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
+   sodipodi:docname="pages.svg">
+  <defs
+     id="defs2">
+    <marker
+       inkscape:stockid="Arrow1Mend"
+       orient="auto"
+       refY="0.0"
+       refX="0.0"
+       id="marker6988"
+       style="overflow:visible;"
+       inkscape:isstock="true">
+      <path
+         id="path6986"
+         d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
+         
style="fill-rule:evenodd;stroke:#3366cc;stroke-width:1pt;stroke-opacity:1;fill:#3366cc;fill-opacity:1"
+         transform="scale(0.4) rotate(180) translate(10,0)" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible;"
+       id="marker6406"
+       refX="0.0"
+       refY="0.0"
+       orient="auto"
+       inkscape:stockid="Arrow1Mend"
+       inkscape:collect="always">
+      <path
+         transform="scale(0.4) rotate(180) translate(10,0)"
+         
style="fill-rule:evenodd;stroke:#3366cc;stroke-width:1pt;stroke-opacity:1;fill:#3366cc;fill-opacity:1"
+         d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
+         id="path6404" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible;"
+       id="marker6390"
+       refX="0.0"
+       refY="0.0"
+       orient="auto"
+       inkscape:stockid="Arrow1Mend">
+      <path
+         transform="scale(0.4) rotate(180) translate(10,0)"
+         
style="fill-rule:evenodd;stroke:#3366cc;stroke-width:1pt;stroke-opacity:1;fill:#3366cc;fill-opacity:1"
+         d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
+         id="path6388" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible;"
+       id="marker6284"
+       refX="0.0"
+       refY="0.0"
+       orient="auto"
+       inkscape:stockid="Arrow1Mend">
+      <path
+         transform="scale(0.4) rotate(180) translate(10,0)"
+         
style="fill-rule:evenodd;stroke:#3366cc;stroke-width:1pt;stroke-opacity:1;fill:#3366cc;fill-opacity:1"
+         d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
+         id="path6282" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible;"
+       id="marker6252"
+       refX="0.0"
+       refY="0.0"
+       orient="auto"
+       inkscape:stockid="Arrow1Mend">
+      <path
+         transform="scale(0.4) rotate(180) translate(10,0)"
+         
style="fill-rule:evenodd;stroke:#3366cc;stroke-width:1pt;stroke-opacity:1;fill:#a020f0;fill-opacity:1"
+         d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
+         id="path6250" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Mend"
+       orient="auto"
+       refY="0.0"
+       refX="0.0"
+       id="marker6236"
+       style="overflow:visible;"
+       inkscape:isstock="true"
+       inkscape:collect="always">
+      <path
+         id="path6234"
+         d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
+         
style="fill-rule:evenodd;stroke:#3366cc;stroke-width:1pt;stroke-opacity:1;fill:#3366cc;fill-opacity:1"
+         transform="scale(0.4) rotate(180) translate(10,0)" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible;"
+       id="marker6200"
+       refX="0.0"
+       refY="0.0"
+       orient="auto"
+       inkscape:stockid="Arrow1Lend">
+      <path
+         transform="scale(0.8) rotate(180) translate(12.5,0)"
+         
style="fill-rule:evenodd;stroke:#3366cc;stroke-width:1pt;stroke-opacity:1;fill:#a020f0;fill-opacity:1"
+         d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
+         id="path6198" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible;"
+       id="marker6190"
+       refX="0.0"
+       refY="0.0"
+       orient="auto"
+       inkscape:stockid="Arrow1Lend">
+      <path
+         transform="scale(0.8) rotate(180) translate(12.5,0)"
+         
style="fill-rule:evenodd;stroke:#3366cc;stroke-width:1pt;stroke-opacity:1;fill:#a020f0;fill-opacity:1"
+         d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
+         id="path6188" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible;"
+       id="marker5954"
+       refX="0.0"
+       refY="0.0"
+       orient="auto"
+       inkscape:stockid="Arrow1Mend">
+      <path
+         transform="scale(0.4) rotate(180) translate(10,0)"
+         
style="fill-rule:evenodd;stroke:#3366cc;stroke-width:1pt;stroke-opacity:1;fill:#a020f0;fill-opacity:1"
+         d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
+         id="path5952" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Mend"
+       orient="auto"
+       refY="0.0"
+       refX="0.0"
+       id="marker3044"
+       style="overflow:visible;"
+       inkscape:isstock="true"
+       inkscape:collect="always">
+      <path
+         id="path3042"
+         d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
+         
style="fill-rule:evenodd;stroke:#3366cc;stroke-width:1pt;stroke-opacity:1;fill:#a020f0;fill-opacity:1"
+         transform="scale(0.4) rotate(180) translate(10,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Mend"
+       orient="auto"
+       refY="0.0"
+       refX="0.0"
+       id="marker2930"
+       style="overflow:visible;"
+       inkscape:isstock="true">
+      <path
+         id="path2928"
+         d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
+         
style="fill-rule:evenodd;stroke:#3366cc;stroke-width:1pt;stroke-opacity:1;fill:#ffffff;fill-opacity:1"
+         transform="scale(0.4) rotate(180) translate(10,0)" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker2890"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow1Mend">
+      <path
+         transform="matrix(-0.4,0,0,-0.4,-4,0)"
+         
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#3366cc;stroke-width:1.00000003pt;stroke-opacity:1"
+         d="M 0,0 5,-5 -12.5,0 5,5 Z"
+         id="path2888"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Mend"
+       orient="auto"
+       refY="0.0"
+       refX="0.0"
+       id="Arrow1Mend"
+       style="overflow:visible;"
+       inkscape:isstock="true">
+      <path
+         id="path1921"
+         d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
+         
style="fill-rule:evenodd;stroke:#3366cc;stroke-width:1pt;stroke-opacity:1;fill:#ffffff;fill-opacity:1"
+         transform="scale(0.4) rotate(180) translate(10,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0.0"
+       refX="0.0"
+       id="Arrow1Send"
+       style="overflow:visible;"
+       inkscape:isstock="true">
+      <path
+         id="path1927"
+         d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
+         
style="fill-rule:evenodd;stroke:#3366cc;stroke-width:1pt;stroke-opacity:1;fill:#3366cc;fill-opacity:1"
+         transform="scale(0.2) rotate(180) translate(6,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Mend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Mend-8"
+       style="overflow:visible"
+       inkscape:isstock="true"
+       inkscape:collect="always">
+      <path
+         inkscape:connector-curvature="0"
+         id="path1921-9"
+         d="M 0,0 5,-5 -12.5,0 5,5 Z"
+         
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#3366cc;stroke-width:1.00000003pt;stroke-opacity:1"
+         transform="matrix(-0.4,0,0,-0.4,-4,0)" />
+    </marker>
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="1"
+     inkscape:cx="403.97716"
+     inkscape:cy="84.798123"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer16"
+     showgrid="true"
+     units="px"
+     inkscape:pagecheckerboard="false"
+     inkscape:showpageshadow="false"
+     inkscape:window-width="2152"
+     inkscape:window-height="1810"
+     inkscape:window-x="0"
+     inkscape:window-y="1960"
+     inkscape:window-maximized="0"
+     showguides="true"
+     inkscape:snap-bbox="true"
+     inkscape:bbox-paths="true"
+     inkscape:bbox-nodes="true"
+     inkscape:snap-text-baseline="true"
+     inkscape:lockguides="false">
+    <inkscape:grid
+       type="xygrid"
+       id="grid815"
+       color="#0000ff"
+       opacity="0.0627451"
+       empcolor="#0000ff"
+       empopacity="0.1254902"
+       empspacing="4" />
+  </sodipodi:namedview>
+  <metadata
+     id="metadata5">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage"; />
+        <dc:title />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     style="display:inline">
+    <text
+       xml:space="preserve"
+       
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:53.33333206px;font-family:'Noto
 Sans';-inkscape-font-specification:'Noto Sans, 
Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:center;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;s
 [...]
+       x="512.52295"
+       y="398"
+       id="text819"><tspan
+         sodipodi:role="line"
+         id="tspan817"
+         x="512.52295"
+         y="398">Indentation logic of <tspan
+   
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'Noto
 Sans Mono';-inkscape-font-specification:'Noto Sans Mono'"
+   id="tspan821">kotlin-mode</tspan></tspan></text>
+    <text
+       id="text846"
+       y="695.46667"
+       x="998.72003"
+       
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:53.33333206px;line-height:60px;font-family:'Noto
 Sans';-inkscape-font-specification:'Noto Sans, 
Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:end;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linej
 [...]
+       xml:space="preserve"><tspan
+         y="695.46667"
+         x="998.72003"
+         sodipodi:role="line"
+         id="tspan848"
+         
style="line-height:37.5%;text-align:end;text-anchor:end">2019-12-01</tspan></text>
+  </g>
+  <g
+     inkscape:groupmode="layer"
+     id="layer2"
+     inkscape:label="Layer 2"
+     style="display:inline">
+    <text
+       xml:space="preserve"
+       
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:53.33333206px;font-family:'Noto
 Sans';-inkscape-font-specification:'Noto Sans, 
Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:center;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-l
 [...]
+       x="512.52295"
+       y="56"
+       id="text819-9"><tspan
+         sodipodi:role="line"
+         id="tspan817-1"
+         x="512.52295"
+         y="56">Basic idea (1/2)</tspan></text>
+    <text
+       xml:space="preserve"
+       
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:32px;font-family:'Noto
 sans';-inkscape-font-specification:'Noto 
sans';text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="62.540501"
+       y="120.48"
+       id="text885"><tspan
+         sodipodi:role="line"
+         id="tspan883"
+         x="62.540501"
+         y="120.48">Programs consist of...</tspan></text>
+    <text
+       xml:space="preserve"
+       
style="font-style:normal;font-weight:normal;font-size:10px;font-family:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="208.35275"
+       y="536"
+       id="text1019"><tspan
+         sodipodi:role="line"
+         id="tspan1017"
+         x="208.35275"
+         y="536"
+         
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:32px;font-family:'Noto
 Sans';-inkscape-font-specification:'Noto Sans, 
Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#000000">List
 of statements/expressions <tspan
+   style="fill:#3366cc;fill-opacity:1"
+   id="tspan5344">①</tspan>,</tspan><tspan
+         sodipodi:role="line"
+         x="208.35275"
+         y="579.04401"
+         id="tspan1021"
+         
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:32px;font-family:'Noto
 Sans';-inkscape-font-specification:'Noto Sans, 
Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#000000">sorrounded
 by (curly/round) brackets <tspan
+   style="fill:#3366cc;fill-opacity:1"
+   id="tspan5346">②</tspan>,</tspan><tspan
+         sodipodi:role="line"
+         x="208.35275"
+         y="622.08801"
+         id="tspan1023"
+         
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:32px;font-family:'Noto
 Sans';-inkscape-font-specification:'Noto Sans, 
Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#000000">preceded
 by some texts <tspan
+   style="fill:#3366cc;fill-opacity:1"
+   id="tspan5348">③</tspan></tspan></text>
+    <g
+       id="g1221"
+       transform="translate(108,-30.896)">
+      <text
+         xml:space="preserve"
+         
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:32px;font-family:'Noto
 Sans Mono';-inkscape-font-specification:'Noto Sans Mono, 
Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;
 [...]
+         x="72"
+         y="299.37601"
+         id="text889"><tspan
+           id="tspan893"
+           sodipodi:role="line"
+           x="72"
+           y="299.37601"><tspan
+   id="tspan1087"
+   style="fill:#a020f0;fill-opacity:1">for</tspan> (x <tspan
+   id="tspan1137"
+   style="fill:#a020f0">in</tspan> xs) {</tspan><tspan
+           id="tspan895"
+           sodipodi:role="line"
+           x="72"
+           y="339.37601">    print(x);</tspan><tspan
+           id="tspan897"
+           sodipodi:role="line"
+           x="72"
+           y="379.37601">    print(x);</tspan><tspan
+           id="tspan899"
+           sodipodi:role="line"
+           x="72"
+           y="419.37601">    print(x);</tspan><tspan
+           id="tspan917"
+           sodipodi:role="line"
+           x="72"
+           y="459.37601">}</tspan></text>
+      <g
+         style="stroke-width:1.33333337"
+         transform="matrix(0.75,0,0,0.75,289.65281,37.896)"
+         id="g1070">
+        <circle
+           
style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#3366cc;stroke-width:1.33333337;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
+           id="path1029"
+           cx="125.79625"
+           cy="444"
+           r="16" />
+        <text
+           xml:space="preserve"
+           
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:32px;font-family:'Noto
 Sans';-inkscape-font-specification:'Noto Sans, 
Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#3366cc;fill-opacity:1;stroke:none;stroke-width:1.33333337px;stroke-linecap:butt;stroke-linejoin:miter
 [...]
+           x="125.79625"
+           y="456"
+           id="text1027"><tspan
+             sodipodi:role="line"
+             id="tspan1025"
+             x="125.79625"
+             y="456"
+             
style="text-align:center;text-anchor:middle;stroke-width:1.33333337px">1</tspan></text>
+      </g>
+      <g
+         style="stroke-width:1.33333337"
+         transform="matrix(0.75,0,0,0.75,92,-16.000004)"
+         id="g1075">
+        <circle
+           r="16"
+           cy="372.41599"
+           cx="368"
+           id="circle1036"
+           
style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#3366cc;stroke-width:1.33333337;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
 />
+        <text
+           id="text1040"
+           y="384"
+           x="368"
+           
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:32px;font-family:'Noto
 Sans';-inkscape-font-specification:'Noto Sans, 
Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#3366cc;fill-opacity:1;stroke:none;stroke-width:1.33333337px;stroke-linecap:butt;stroke-linejoin:miter
 [...]
+           xml:space="preserve"><tspan
+             
style="text-align:center;text-anchor:middle;stroke-width:1.33333337px"
+             y="384"
+             x="368"
+             id="tspan1038"
+             sodipodi:role="line">2</tspan></text>
+      </g>
+      <g
+         style="stroke-width:1.33333337"
+         transform="matrix(0.75,0,0,0.75,99.443745,-42.719995)"
+         id="g1065">
+        <circle
+           
style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#3366cc;stroke-width:1.33333337;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
+           id="circle1042"
+           cx="128.48"
+           cy="344.25598"
+           r="16" />
+        <text
+           xml:space="preserve"
+           
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:32px;font-family:'Noto
 Sans';-inkscape-font-specification:'Noto Sans, 
Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#3366cc;fill-opacity:1;stroke:none;stroke-width:1.33333337px;stroke-linecap:butt;stroke-linejoin:miter
 [...]
+           x="128.67625"
+           y="355.67999"
+           id="text1046"><tspan
+             sodipodi:role="line"
+             id="tspan1044"
+             x="128.67625"
+             y="355.67999"
+             
style="text-align:center;text-anchor:middle;stroke-width:1.33333337px">3</tspan></text>
+      </g>
+      <path
+         sodipodi:nodetypes="csscccc"
+         inkscape:connector-curvature="0"
+         id="path1056"
+         d="m 69.781542,270.896 c 0,-8.83656 7.16344,-16 16,-16 H 180 c 
8.83656,0 16,-7.16344 16,-16 0,8.83656 7.16344,16 16,16 h 96 c 8.83656,0 
16,7.16344 16,16"
+         
style="opacity:1;vector-effect:none;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#3366cc;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
 />
+      <path
+         
style="opacity:1;vector-effect:none;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#3366cc;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
+         d="m 328,438.00523 c 8.83656,0 16,-7.16344 16,-16 v -33.57388 c 
0,-8.83656 7.16344,-16 16,-16 -8.83656,0 -16,-7.16344 -16,-16 V 326.896 c 
0,-8.83656 -7.16344,-16 -16,-16"
+         id="path1077"
+         inkscape:connector-curvature="0"
+         sodipodi:nodetypes="csscscc" />
+      <g
+         style="stroke-width:1.33333337"
+         transform="matrix(0.75,0,0,0.75,-172,192)"
+         id="g1085">
+        <circle
+           
style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#3366cc;stroke-width:1.33333337;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
+           id="circle1079"
+           cx="368"
+           cy="372.41599"
+           r="16" />
+        <text
+           xml:space="preserve"
+           
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:32px;font-family:'Noto
 Sans';-inkscape-font-specification:'Noto Sans, 
Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#3366cc;fill-opacity:1;stroke:none;stroke-width:1.33333337px;stroke-linecap:butt;stroke-linejoin:miter
 [...]
+           x="368"
+           y="384"
+           id="text1083"><tspan
+             sodipodi:role="line"
+             id="tspan1081"
+             x="368"
+             y="384"
+             
style="text-align:center;text-anchor:middle;stroke-width:1.33333337px">2</tspan></text>
+      </g>
+    </g>
+    <text
+       xml:space="preserve"
+       
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:32px;font-family:'Noto
 Sans';-inkscape-font-specification:'Noto Sans, 
Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="-160"
+       y="432"
+       id="text1135"><tspan
+         sodipodi:role="line"
+         id="tspan1133"
+         x="-160"
+         y="461.116" /></text>
+    <g
+       id="g1248"
+       transform="translate(-64,-20.736)">
+      <text
+         id="text949"
+         y="287.31198"
+         x="672"
+         
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:32px;font-family:'Noto
 Sans Mono';-inkscape-font-specification:'Noto Sans Mono, 
Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;
 [...]
+         xml:space="preserve"><tspan
+           y="287.31198"
+           x="672"
+           sodipodi:role="line"
+           id="tspan939"><tspan
+   id="tspan1139"
+   style="fill:#a020f0">return</tspan> foo(</tspan><tspan
+           y="327.31198"
+           x="672"
+           sodipodi:role="line"
+           id="tspan941">    a + b,</tspan><tspan
+           y="367.31198"
+           x="672"
+           sodipodi:role="line"
+           id="tspan943">    b + c,</tspan><tspan
+           y="407.31198"
+           x="672"
+           sodipodi:role="line"
+           id="tspan945">    c + d</tspan><tspan
+           y="447.31198"
+           x="672"
+           sodipodi:role="line"
+           id="tspan947">)</tspan></text>
+      <g
+         style="stroke-width:1.33333337"
+         id="g1147"
+         transform="matrix(0.75,0,0,0.75,833.65281,31.896)">
+        <circle
+           r="16"
+           cy="444"
+           cx="125.79625"
+           id="circle1141"
+           
style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#3366cc;stroke-width:1.33333337;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
 />
+        <text
+           id="text1145"
+           y="456"
+           x="125.79625"
+           
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:32px;font-family:'Noto
 Sans';-inkscape-font-specification:'Noto Sans, 
Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#3366cc;fill-opacity:1;stroke:none;stroke-width:1.33333337px;stroke-linecap:butt;stroke-linejoin:miter
 [...]
+           xml:space="preserve"><tspan
+             
style="text-align:center;text-anchor:middle;stroke-width:1.33333337px"
+             y="456"
+             x="125.79625"
+             id="tspan1143"
+             sodipodi:role="line">1</tspan></text>
+      </g>
+      <path
+         sodipodi:nodetypes="csscscc"
+         inkscape:connector-curvature="0"
+         id="path1149"
+         d="m 872,432.00523 c 8.83656,0 16,-7.16344 16,-16 v -33.57388 c 
0,-8.83656 7.16344,-16 16,-16 -8.83656,0 -16,-7.16344 -16,-16 V 320.896 c 
0,-8.83656 -7.16344,-16 -16,-16"
+         
style="opacity:1;vector-effect:none;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#3366cc;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
 />
+      <g
+         style="stroke-width:1.33333337"
+         id="g1157"
+         transform="matrix(0.75,0,0,0.75,620,-20.000004)">
+        <circle
+           
style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#3366cc;stroke-width:1.33333337;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
+           id="circle1151"
+           cx="368"
+           cy="372.41599"
+           r="16" />
+        <text
+           xml:space="preserve"
+           
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:32px;font-family:'Noto
 Sans';-inkscape-font-specification:'Noto Sans, 
Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#3366cc;fill-opacity:1;stroke:none;stroke-width:1.33333337px;stroke-linecap:butt;stroke-linejoin:miter
 [...]
+           x="368"
+           y="384"
+           id="text1155"><tspan
+             sodipodi:role="line"
+             id="tspan1153"
+             x="368"
+             y="384"
+             
style="text-align:center;text-anchor:middle;stroke-width:1.33333337px">2</tspan></text>
+      </g>
+      <g
+         style="stroke-width:1.33333337"
+         id="g1165"
+         transform="matrix(0.75,0,0,0.75,428,176)">
+        <circle
+           r="16"
+           cy="372.41599"
+           cx="368"
+           id="circle1159"
+           
style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#3366cc;stroke-width:1.33333337;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
 />
+        <text
+           id="text1163"
+           y="384"
+           x="368"
+           
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:32px;font-family:'Noto
 Sans';-inkscape-font-specification:'Noto Sans, 
Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#3366cc;fill-opacity:1;stroke:none;stroke-width:1.33333337px;stroke-linecap:butt;stroke-linejoin:miter
 [...]
+           xml:space="preserve"><tspan
+             
style="text-align:center;text-anchor:middle;stroke-width:1.33333337px"
+             y="384"
+             x="368"
+             id="tspan1161"
+             sodipodi:role="line">2</tspan></text>
+      </g>
+      <g
+         style="stroke-width:1.33333337"
+         id="g1173"
+         transform="matrix(0.75,0,0,0.75,671.64,-52.879995)">
+        <circle
+           r="16"
+           cy="344.25598"
+           cx="128.48"
+           id="circle1167"
+           
style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#3366cc;stroke-width:1.33333337;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
 />
+        <text
+           id="text1171"
+           y="355.67999"
+           x="128.67625"
+           
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:32px;font-family:'Noto
 Sans';-inkscape-font-specification:'Noto Sans, 
Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#3366cc;fill-opacity:1;stroke:none;stroke-width:1.33333337px;stroke-linecap:butt;stroke-linejoin:miter
 [...]
+           xml:space="preserve"><tspan
+             
style="text-align:center;text-anchor:middle;stroke-width:1.33333337px"
+             y="355.67999"
+             x="128.67625"
+             id="tspan1169"
+             sodipodi:role="line">3</tspan></text>
+      </g>
+      <path
+         
style="opacity:1;vector-effect:none;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#3366cc;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
+         d="m 669.78154,260.736 c 0,-8.83656 7.16344,-16 16,-16 H 752 c 
8.83656,0 16,-7.16344 16,-16 0,8.83656 7.16344,16 16,16 h 64.19625 c 8.83656,0 
16,7.16344 16,16"
+         id="path1175"
+         inkscape:connector-curvature="0"
+         sodipodi:nodetypes="csscccc" />
+    </g>
+    <text
+       xml:space="preserve"
+       
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:32px;font-family:'Noto
 Sans';-inkscape-font-specification:'Noto Sans, 
Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="832"
+       y="472"
+       id="text1187"><tspan
+         sodipodi:role="line"
+         id="tspan1185"
+         x="832"
+         y="501.116" /></text>
+  </g>
+  <g
+     inkscape:groupmode="layer"
+     id="layer3"
+     inkscape:label="Layer 3"
+     style="display:inline">
+    <text
+       id="text949-1"
+       y="266.944"
+       x="352"
+       
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:32px;font-family:'Noto
 Sans Mono';-inkscape-font-specification:'Noto Sans Mono, 
Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-li
 [...]
+       xml:space="preserve"><tspan
+         y="266.944"
+         x="352"
+         sodipodi:role="line"
+         id="tspan939-2"><tspan
+   id="tspan1139-2"
+   style="fill:#a020f0">return</tspan> foo(</tspan><tspan
+         y="306.944"
+         x="352"
+         sodipodi:role="line"
+         id="tspan941-1">    a + b,</tspan><tspan
+         y="346.944"
+         x="352"
+         sodipodi:role="line"
+         id="tspan943-6">    b + c,</tspan><tspan
+         y="386.944"
+         x="352"
+         sodipodi:role="line"
+         id="tspan945-2">    ccc +</tspan><tspan
+         y="426.944"
+         x="352"
+         sodipodi:role="line"
+         id="tspan1505">        ddd</tspan><tspan
+         y="466.944"
+         x="352"
+         sodipodi:role="line"
+         id="tspan947-0">)</tspan></text>
+    <text
+       xml:space="preserve"
+       
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:53.33333206px;font-family:'Noto
 Sans';-inkscape-font-specification:'Noto Sans, 
Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:center;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-l
 [...]
+       x="512.52295"
+       y="56.000004"
+       id="text819-9-5"><tspan
+         sodipodi:role="line"
+         id="tspan817-1-6"
+         x="512.52295"
+         y="56.000004">Basic idea (2/2)</tspan></text>
+    <text
+       xml:space="preserve"
+       
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:32px;font-family:'Noto
 sans';-inkscape-font-specification:'Noto 
sans';text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="62.652"
+       y="127.68"
+       id="text885-5"><tspan
+         sodipodi:role="line"
+         id="tspan883-6"
+         x="62.652"
+         y="127.68">We have four cases to indent</tspan></text>
+    <text
+       xml:space="preserve"
+       
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:32px;font-family:'Noto
 Sans';-inkscape-font-specification:'Noto Sans, 
Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="112"
+       y="240"
+       id="text1289"><tspan
+         sodipodi:role="line"
+         id="tspan1287"
+         x="112"
+         y="269.116" /></text>
+    <text
+       id="text1301"
+       y="584.47998"
+       x="30.048"
+       
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:32px;font-family:'Noto
 sans';-inkscape-font-specification:'Noto 
sans';text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       xml:space="preserve"><tspan
+         y="584.47998"
+         x="30.048"
+         id="tspan1299"
+         sodipodi:role="line">Case 1. after an element delimiter, such as 
semicolon or comma</tspan><tspan
+         y="624.47998"
+         x="30.048"
+         sodipodi:role="line"
+         id="tspan1303">Case 2. after an open bracket</tspan><tspan
+         y="664.47998"
+         x="30.048"
+         sodipodi:role="line"
+         id="tspan1305">Case 3. before close bracket</tspan><tspan
+         y="704.47998"
+         x="30.048"
+         sodipodi:role="line"
+         id="tspan1307">Case 4. other case, that is to say, inside a list 
element</tspan><tspan
+         y="744.47998"
+         x="30.048"
+         sodipodi:role="line"
+         id="tspan1309" /></text>
+    <g
+       id="g1070-4"
+       transform="matrix(0.75,0,0,0.75,309.65281,48)"
+       style="stroke-width:1.33333337">
+      <circle
+         r="16"
+         cy="444"
+         cx="125.79625"
+         id="path1029-5"
+         
style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#3366cc;stroke-width:1.33333337;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
 />
+      <text
+         id="text1027-0"
+         y="456"
+         x="125.79625"
+         
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:32px;font-family:'Noto
 Sans';-inkscape-font-specification:'Noto Sans, 
Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#3366cc;fill-opacity:1;stroke:none;stroke-width:1.33333337px;stroke-linecap:butt;stroke-linejoin:miter;s
 [...]
+         xml:space="preserve"><tspan
+           
style="text-align:center;text-anchor:middle;stroke-width:1.33333337px"
+           y="456"
+           x="125.79625"
+           id="tspan1025-5"
+           sodipodi:role="line">1</tspan></text>
+    </g>
+    <g
+       id="g1075-7"
+       transform="matrix(0.75,0,0,0.75,128,20.688011)"
+       style="stroke-width:1.33333337">
+      <circle
+         
style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#3366cc;stroke-width:1.33333337;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
+         id="circle1036-3"
+         cx="368"
+         cy="372.41599"
+         r="16" />
+      <text
+         xml:space="preserve"
+         
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:32px;font-family:'Noto
 Sans';-inkscape-font-specification:'Noto Sans, 
Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#3366cc;fill-opacity:1;stroke:none;stroke-width:1.33333337px;stroke-linecap:butt;stroke-linejoin:miter;s
 [...]
+         x="368"
+         y="384"
+         id="text1040-2"><tspan
+           sodipodi:role="line"
+           id="tspan1038-7"
+           x="368"
+           y="384"
+           
style="text-align:center;text-anchor:middle;stroke-width:1.33333337px">2</tspan></text>
+    </g>
+    <g
+       id="g1065-2"
+       transform="matrix(0.75,0,0,0.75,247.49281,201.24001)"
+       style="stroke-width:1.33333337">
+      <circle
+         r="16"
+         cy="344.25598"
+         cx="128.48"
+         id="circle1042-1"
+         
style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#3366cc;stroke-width:1.33333337;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
 />
+      <text
+         id="text1046-3"
+         y="355.67999"
+         x="128.67625"
+         
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:32px;font-family:'Noto
 Sans';-inkscape-font-specification:'Noto Sans, 
Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#3366cc;fill-opacity:1;stroke:none;stroke-width:1.33333337px;stroke-linecap:butt;stroke-linejoin:miter;s
 [...]
+         xml:space="preserve"><tspan
+           
style="text-align:center;text-anchor:middle;stroke-width:1.33333337px"
+           y="355.67999"
+           x="128.67625"
+           id="tspan1044-4"
+           sodipodi:role="line">3</tspan></text>
+    </g>
+    <g
+       style="stroke-width:1.33333337"
+       transform="matrix(0.75,0,0,0.75,395.49281,161.24001)"
+       id="g1436">
+      <circle
+         
style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#3366cc;stroke-width:1.33333337;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
+         id="circle1430"
+         cx="128.48"
+         cy="344.25598"
+         r="16" />
+      <text
+         xml:space="preserve"
+         
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:32px;font-family:'Noto
 Sans';-inkscape-font-specification:'Noto Sans, 
Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#3366cc;fill-opacity:1;stroke:none;stroke-width:1.33333337px;stroke-linecap:butt;stroke-linejoin:miter;s
 [...]
+         x="128.67625"
+         y="355.67999"
+         id="text1434"><tspan
+           sodipodi:role="line"
+           id="tspan1432"
+           x="128.67625"
+           y="355.67999"
+           
style="text-align:center;text-anchor:middle;stroke-width:1.33333337px">4</tspan></text>
+    </g>
+    <circle
+       
style="opacity:1;vector-effect:none;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#3366cc;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
+       id="path1511"
+       cx="534"
+       cy="348"
+       r="8" />
+    <path
+       sodipodi:nodetypes="cssc"
+       inkscape:connector-curvature="0"
+       id="path1056-2"
+       d="m 404,369 c 0,-3.31371 2.68629,-6 6,-6 h 116 c 3.3137,0 6,-2.68629 
6,-6"
+       
style="display:inline;opacity:1;vector-effect:none;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#3366cc;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
 />
+    <path
+       
style="display:inline;opacity:1;vector-effect:none;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#3366cc;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
+       d="m 404,288 c 0,-3.31371 2.68629,-6 6,-6 h 140 c 3.3137,0 6,-2.68629 
6,-6"
+       id="path1530"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cssc" />
+    <circle
+       r="17"
+       cy="259"
+       cx="556"
+       id="circle1532"
+       
style="opacity:1;vector-effect:none;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#3366cc;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
 />
+  </g>
+  <g
+     inkscape:groupmode="layer"
+     id="layer4"
+     inkscape:label="Layer 4"
+     style="display:inline">
+    <text
+       xml:space="preserve"
+       
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:53.33333206px;font-family:'Noto
 Sans';-inkscape-font-specification:'Noto Sans, 
Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:center;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-l
 [...]
+       x="512.52295"
+       y="56.000004"
+       id="text819-9-5-2"><tspan
+         sodipodi:role="line"
+         id="tspan817-1-6-9"
+         x="512.52295"
+         y="56.000004">Case 1: after an element delimiter</tspan></text>
+    <g
+       id="g2440"
+       transform="translate(0,-82.464005)">
+      <rect
+         y="314"
+         x="495.36499"
+         height="32"
+         width="19"
+         id="rect1685"
+         
style="opacity:1;vector-effect:none;fill:#747474;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
 />
+      <text
+         xml:space="preserve"
+         
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:32px;font-family:'Noto
 Sans Mono';-inkscape-font-specification:'Noto Sans Mono, 
Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-
 [...]
+         x="418.36499"
+         y="218.944"
+         id="text949-1-7"><tspan
+           id="tspan939-2-4"
+           sodipodi:role="line"
+           x="418.36499"
+           y="218.944"><tspan
+   style="fill:#a020f0"
+   id="tspan1139-2-3">return</tspan> foo(</tspan><tspan
+           id="tspan941-1-5"
+           sodipodi:role="line"
+           x="418.36499"
+           y="258.944">    a, b,</tspan><tspan
+           id="tspan943-6-6"
+           sodipodi:role="line"
+           x="418.36499"
+           y="298.944">    c, d,</tspan><tspan
+           id="tspan1505-4"
+           sodipodi:role="line"
+           x="418.36499"
+           y="338.944">    <tspan
+   id="tspan1659"
+   style="fill:#ffffff;fill-opacity:1">e</tspan>, f</tspan><tspan
+           id="tspan947-0-0"
+           sodipodi:role="line"
+           x="418.36499"
+           y="378.944">)</tspan></text>
+      <path
+         sodipodi:nodetypes="cc"
+         inkscape:connector-curvature="0"
+         id="path1649"
+         d="m 495.365,274 v 72"
+         
style="opacity:1;vector-effect:none;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#3366cc;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
 />
+    </g>
+    <text
+       xml:space="preserve"
+       
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:32px;font-family:'Noto
 sans';-inkscape-font-specification:'Noto 
sans';text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="64.32"
+       y="384.32001"
+       id="text885-5-3"><tspan
+         sodipodi:role="line"
+         x="64.32"
+         y="384.32001"
+         id="tspan1709">Align with the preceding element at the start of a 
line.</tspan><tspan
+         sodipodi:role="line"
+         x="64.32"
+         y="424.32001"
+         id="tspan2650" /><tspan
+         sodipodi:role="line"
+         x="64.32"
+         y="464.32001"
+         id="tspan2652">To seek the preceding element at the start of a 
line,</tspan><tspan
+         sodipodi:role="line"
+         x="64.32"
+         y="504.32001"
+         id="tspan2654">we seek an element delimiter (comma or semicolon) 
</tspan><tspan
+         sodipodi:role="line"
+         x="64.32"
+         y="544.32001"
+         id="tspan2656">at the end of a line or open bracket before the 
element.</tspan><tspan
+         sodipodi:role="line"
+         x="64.32"
+         y="584.32001"
+         id="tspan2658"></tspan><tspan
+         sodipodi:role="line"
+         x="64.32"
+         y="624.32001"
+         id="tspan5354">Then the next token is the token we align 
to.</tspan><tspan
+         sodipodi:role="line"
+         x="64.32"
+         y="664.32001"
+         id="tspan2660"></tspan><tspan
+         sodipodi:role="line"
+         x="64.32"
+         y="704.32001"
+         id="tspan5356">Elements may start with tokens of various 
types,</tspan><tspan
+         sodipodi:role="line"
+         x="64.32"
+         y="744.32001"
+         id="tspan2664">but it ends with tokens of handful types, so seeking 
it is easier.</tspan></text>
+    <circle
+       
style="display:inline;opacity:1;vector-effect:none;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#3366cc;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
+       id="path1511-5"
+       cx="581"
+       cy="176.536"
+       r="8" />
+    <text
+       xml:space="preserve"
+       
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:24px;font-family:'Noto
 sans';-inkscape-font-specification:'Noto 
sans';text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;display:inline;fill:#3366cc;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="595.15997"
+       y="185.29601"
+       id="text1851"><tspan
+         sodipodi:role="line"
+         x="595.15997"
+         y="185.29601"
+         id="tspan1880">←Seek this</tspan></text>
+    <text
+       id="text1886"
+       y="215.77599"
+       x="464.84"
+       
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:24px;font-family:'Noto
 sans';-inkscape-font-specification:'Noto 
sans';text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;display:inline;fill:#3366cc;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       xml:space="preserve"><tspan
+         id="tspan1884"
+         y="215.77599"
+         x="464.84"
+         sodipodi:role="line"
+         
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:24px;font-family:'Noto
 Sans';-inkscape-font-specification:'Noto Sans, 
Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:end;writing-mode:lr-tb;text-anchor:end">then
 align with the next token→</tspan></text>
+    <text
+       id="text1908"
+       y="269.53601"
+       x="606"
+       
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:24px;font-family:'Noto
 sans';-inkscape-font-specification:'Noto 
sans';text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;display:inline;fill:#3366cc;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       xml:space="preserve"><tspan
+         id="tspan1906"
+         y="269.53601"
+         x="606"
+         sodipodi:role="line">We call this token “parent”.</tspan></text>
+    <path
+       
style="display:inline;opacity:1;vector-effect:none;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#3366cc;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-end:url(#Arrow1Mend-8);paint-order:normal"
+       d="m 608,249.53601 -20,-60"
+       id="path1910"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <text
+       id="text1715"
+       y="424"
+       x="64"
+       
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:32px;font-family:'Noto
 sans';-inkscape-font-specification:'Noto 
sans';text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       xml:space="preserve"><tspan
+         y="453.116"
+         x="64"
+         sodipodi:role="line"
+         id="tspan1727" /></text>
+  </g>
+  <g
+     inkscape:groupmode="layer"
+     id="layer5"
+     inkscape:label="Layer 5"
+     style="display:inline">
+    <rect
+       
style="display:inline;opacity:1;vector-effect:none;fill:#747474;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
+       id="rect1685-2"
+       width="19"
+       height="32"
+       x="495"
+       y="287" />
+    <text
+       id="text949-1-7-0"
+       y="192"
+       x="418.36499"
+       
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:32px;font-family:'Noto
 Sans Mono';-inkscape-font-specification:'Noto Sans Mono, 
Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-li
 [...]
+       xml:space="preserve"><tspan
+         y="192"
+         x="418.36499"
+         sodipodi:role="line"
+         id="tspan939-2-4-6"
+         style="fill:#000000">bar();</tspan><tspan
+         y="232"
+         x="418.36499"
+         sodipodi:role="line"
+         id="tspan2546"><tspan
+           style="fill:#a020f0"
+           id="tspan2548" /></tspan><tspan
+         y="272"
+         x="418.36499"
+         sodipodi:role="line"
+         id="tspan2699"><tspan
+   style="fill:#a020f0"
+   id="tspan2701">return</tspan> foo(</tspan><tspan
+         y="312"
+         x="418.36499"
+         sodipodi:role="line"
+         id="tspan941-1-5-7">    <tspan
+   style="fill:#ffffff;fill-opacity:1"
+   id="tspan2801">a</tspan>, b,</tspan><tspan
+         y="352"
+         x="418.36499"
+         sodipodi:role="line"
+         id="tspan943-6-6-4">    c, d,</tspan><tspan
+         y="392"
+         x="418.36499"
+         sodipodi:role="line"
+         id="tspan1505-4-9">    e, f</tspan><tspan
+         y="432"
+         x="418.36499"
+         sodipodi:role="line"
+         id="tspan947-0-0-4">)</tspan></text>
+    <path
+       
style="display:inline;opacity:1;vector-effect:none;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#3366cc;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
+       d="m 495,287 v 32"
+       id="path1649-9"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <text
+       xml:space="preserve"
+       
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:53.33333206px;font-family:'Noto
 Sans';-inkscape-font-specification:'Noto Sans, 
Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:center;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-l
 [...]
+       x="512.52295"
+       y="56"
+       id="text819-9-5-2-1"><tspan
+         sodipodi:role="line"
+         id="tspan817-1-6-9-2"
+         x="512.52295"
+         y="56">Case 2. after an open bracket</tspan></text>
+    <text
+       xml:space="preserve"
+       
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:32px;font-family:'Noto
 Sans';-inkscape-font-specification:'Noto Sans, 
Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="352"
+       y="720"
+       id="text2552"><tspan
+         sodipodi:role="line"
+         id="tspan2550"
+         x="352"
+         y="749.11603" /></text>
+    <path
+       sodipodi:nodetypes="cc"
+       inkscape:connector-curvature="0"
+       id="path2558"
+       d="m 419,247 v 72"
+       
style="display:inline;opacity:1;vector-effect:none;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#3366cc;stroke-width:1.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
 />
+    <path
+       
style="opacity:1;vector-effect:none;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#3366cc;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
+       d="m 419,303 h 76"
+       id="path2560"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <path
+       
style="opacity:1;vector-effect:none;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#3366cc;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
+       d="m 483,294 12,9 -12,9"
+       id="path2562"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="ccc" />
+    <text
+       xml:space="preserve"
+       
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:32px;font-family:'Noto
 sans';-inkscape-font-specification:'Noto 
sans';text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="48"
+       y="504.48001"
+       id="text885-5-3-6"><tspan
+         sodipodi:role="line"
+         x="48"
+         y="504.48001"
+         id="tspan1709-0">Align with the start of the “preceding text” with 
offset.</tspan><tspan
+         sodipodi:role="line"
+         x="48"
+         y="544.47998"
+         id="tspan2582" /><tspan
+         sodipodi:role="line"
+         x="48"
+         y="584.47998"
+         id="tspan2584">The procedure of seeking the start of the preceding 
text is </tspan><tspan
+         sodipodi:role="line"
+         x="48"
+         y="624.47998"
+         id="tspan2586">same as the case 1.  Seek a parent token, then the 
next token </tspan><tspan
+         sodipodi:role="line"
+         x="48"
+         y="664.47998"
+         id="tspan5358">is the token align to.</tspan></text>
+    <ellipse
+       
style="display:inline;opacity:1;vector-effect:none;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#3366cc;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
+       id="path1511-5-6"
+       cx="524"
+       cy="182.48001"
+       rx="8"
+       ry="16" />
+    <text
+       xml:space="preserve"
+       
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:24px;font-family:'Noto
 sans';-inkscape-font-specification:'Noto 
sans';text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;display:inline;fill:#3366cc;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="535.15997"
+       y="190.24001"
+       id="text1851-4"><tspan
+         sodipodi:role="line"
+         x="535.15997"
+         y="190.24001"
+         id="tspan1880-0">←Seek this</tspan></text>
+    <text
+       id="text1886-9"
+       y="266.23999"
+       x="400.84"
+       
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:24px;font-family:'Noto
 Sans';-inkscape-font-specification:'Noto Sans, 
Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:end;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;display:inline;fill:#3366cc;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;s
 [...]
+       xml:space="preserve"><tspan
+         id="tspan1884-4"
+         y="266.23999"
+         x="400.84"
+         sodipodi:role="line">then align with the next token→</tspan></text>
+    <text
+       xml:space="preserve"
+       
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:24px;font-family:'Noto
 Sans';-inkscape-font-specification:'Noto Sans, 
Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:end;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;display:inline;fill:#3366cc;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;s
 [...]
+       x="376.53589"
+       y="306.23999"
+       id="text2697"><tspan
+         sodipodi:role="line"
+         x="376.53589"
+         y="306.23999"
+         id="tspan2695">with offset</tspan></text>
+  </g>
+  <g
+     inkscape:groupmode="layer"
+     id="layer6"
+     inkscape:label="Layer 6"
+     style="display:inline">
+    <rect
+       
style="display:inline;opacity:1;vector-effect:none;fill:#747474;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
+       id="rect1685-2-8"
+       width="20"
+       height="32"
+       x="418"
+       y="407" />
+    <text
+       id="text949-1-7-0-0"
+       y="192"
+       x="418.36499"
+       
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:32px;font-family:'Noto
 Sans Mono';-inkscape-font-specification:'Noto Sans Mono, 
Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-li
 [...]
+       xml:space="preserve"><tspan
+         y="192"
+         x="418.36499"
+         sodipodi:role="line"
+         id="tspan939-2-4-6-1"
+         style="fill:#000000">bar();</tspan><tspan
+         y="232"
+         x="418.36499"
+         sodipodi:role="line"
+         id="tspan2546-7" /><tspan
+         y="272"
+         x="418.36499"
+         sodipodi:role="line"
+         id="tspan2699-8"><tspan
+   style="fill:#a020f0"
+   id="tspan2701-0">return</tspan> foo(</tspan><tspan
+         y="312"
+         x="418.36499"
+         sodipodi:role="line"
+         id="tspan941-1-5-7-8">    a, b,</tspan><tspan
+         y="352"
+         x="418.36499"
+         sodipodi:role="line"
+         id="tspan943-6-6-4-9">    c, d,</tspan><tspan
+         y="392"
+         x="418.36499"
+         sodipodi:role="line"
+         id="tspan1505-4-9-7">    e, f</tspan><tspan
+         y="432"
+         x="418.36499"
+         sodipodi:role="line"
+         id="tspan947-0-0-4-8"
+         style="fill:#ffffff;fill-opacity:1">)</tspan></text>
+    <text
+       xml:space="preserve"
+       
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:53.33333206px;font-family:'Noto
 Sans';-inkscape-font-specification:'Noto Sans, 
Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:center;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-l
 [...]
+       x="512.52295"
+       y="56"
+       id="text819-9-5-2-1-3"><tspan
+         sodipodi:role="line"
+         id="tspan817-1-6-9-2-9"
+         x="512.52295"
+         y="56">Case 3. before close bracket</tspan></text>
+    <text
+       xml:space="preserve"
+       
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:32px;font-family:'Noto
 sans';-inkscape-font-specification:'Noto 
sans';text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="48"
+       y="504.48001"
+       id="text885-5-3-6-7"><tspan
+         sodipodi:role="line"
+         x="48"
+         y="504.48001"
+         id="tspan2586-2">Align with the start of the preceding text of the 
open bracket</tspan><tspan
+         sodipodi:role="line"
+         x="48"
+         y="544.47998"
+         id="tspan2780">without offset.</tspan><tspan
+         sodipodi:role="line"
+         x="48"
+         y="584.47998"
+         id="tspan2776" /><tspan
+         sodipodi:role="line"
+         x="48"
+         y="624.47998"
+         id="tspan2778">To find the open bracket, we can use the <tspan
+   
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'Noto
 Sans Mono';-inkscape-font-specification:'Noto Sans Mono'"
+   id="tspan2784">‘backward-list’</tspan>.</tspan></text>
+    <path
+       sodipodi:nodetypes="cc"
+       inkscape:connector-curvature="0"
+       id="path2558-4"
+       d="M 418,247 V 439"
+       
style="display:inline;opacity:1;vector-effect:none;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#3366cc;stroke-width:1.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
 />
+    <ellipse
+       
style="display:inline;opacity:1;vector-effect:none;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#3366cc;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
+       id="path1511-5-6-0"
+       cx="524"
+       cy="182.48001"
+       rx="8"
+       ry="16" />
+    <text
+       xml:space="preserve"
+       
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:24px;font-family:'Noto
 sans';-inkscape-font-specification:'Noto 
sans';text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;display:inline;fill:#3366cc;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="535.15997"
+       y="190.24001"
+       id="text1851-4-6"><tspan
+         sodipodi:role="line"
+         x="535.15997"
+         y="190.24001"
+         id="tspan1880-0-2">←then seek this</tspan></text>
+    <text
+       id="text1886-9-6"
+       y="266.23999"
+       x="400.84"
+       
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:24px;font-family:'Noto
 Sans';-inkscape-font-specification:'Noto Sans, 
Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:end;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;display:inline;fill:#3366cc;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;s
 [...]
+       xml:space="preserve"><tspan
+         id="tspan1884-4-5"
+         y="266.23999"
+         x="400.84"
+         sodipodi:role="line">then align with the next token→</tspan></text>
+    <text
+       id="text2864"
+       y="151.75999"
+       x="670.776"
+       
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:24px;font-family:'Noto
 sans';-inkscape-font-specification:'Noto 
sans';text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;display:inline;fill:#3366cc;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       xml:space="preserve"><tspan
+         id="tspan2862"
+         y="151.75999"
+         x="670.776"
+         sodipodi:role="line">Seek this</tspan></text>
+    <ellipse
+       ry="16"
+       rx="8"
+       cy="263"
+       cx="622"
+       id="ellipse2866"
+       
style="display:inline;opacity:1;vector-effect:none;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#3366cc;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
 />
+    <path
+       
style="opacity:1;vector-effect:none;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#3366cc;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-end:url(#marker3044);paint-order:normal"
+       d="m 736,156 c -2.53312,41.63464 -20.88173,86.15342 -96,104"
+       id="path2868"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+  </g>
+  <g
+     inkscape:groupmode="layer"
+     id="layer7"
+     inkscape:label="Layer 7"
+     style="display:inline">
+    <text
+       xml:space="preserve"
+       
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:53.33333206px;font-family:'Noto
 Sans';-inkscape-font-specification:'Noto Sans, 
Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:center;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-l
 [...]
+       x="512.52295"
+       y="56"
+       id="text819-9-5-2-1-3-7"><tspan
+         sodipodi:role="line"
+         id="tspan817-1-6-9-2-9-3"
+         x="512.52295"
+         y="56">Case 4. other case, inside a list element</tspan></text>
+    <g
+       id="g3372"
+       transform="translate(-42.113999)">
+      <rect
+         y="328"
+         x="280"
+         height="32"
+         width="19"
+         id="rect1685-2-8-2"
+         
style="display:inline;opacity:1;vector-effect:none;fill:#747474;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
 />
+      <text
+         xml:space="preserve"
+         
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:32px;font-family:'Noto
 Sans Mono';-inkscape-font-specification:'Noto Sans Mono, 
Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-
 [...]
+         x="203.36499"
+         y="233"
+         id="text949-1-7-0-0-5"><tspan
+           style="fill:#000000;fill-opacity:1"
+           id="tspan947-0-0-4-8-9"
+           sodipodi:role="line"
+           x="203.36499"
+           y="233">foo();</tspan><tspan
+           id="tspan3244"
+           style="fill:#000000;fill-opacity:1"
+           sodipodi:role="line"
+           x="203.36499"
+           y="273" /><tspan
+           id="tspan3240"
+           style="fill:#000000;fill-opacity:1"
+           sodipodi:role="line"
+           x="203.36499"
+           y="313"><tspan
+   id="tspan3242"
+   style="fill:#a020f0;fill-opacity:1">val</tspan> x =</tspan><tspan
+           id="tspan3176"
+           style="fill:#000000;fill-opacity:1"
+           sodipodi:role="line"
+           x="203.36499"
+           y="353">    <tspan
+   id="tspan3246"
+   style="fill:#ffffff;fill-opacity:1">1</tspan> +</tspan><tspan
+           id="tspan3172"
+           style="fill:#000000;fill-opacity:1"
+           sodipodi:role="line"
+           x="203.36499"
+           y="393">    2 +</tspan><tspan
+           id="tspan3174"
+           style="fill:#000000;fill-opacity:1"
+           sodipodi:role="line"
+           x="203.36499"
+           y="433">    3</tspan></text>
+      <path
+         
style="display:inline;opacity:1;vector-effect:none;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#3366cc;stroke-width:1.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
+         d="m 280,328 v 32"
+         id="path2558-4-1"
+         inkscape:connector-curvature="0"
+         sodipodi:nodetypes="cc" />
+      <path
+         sodipodi:nodetypes="cc"
+         inkscape:connector-curvature="0"
+         id="path3220"
+         d="m 203,289 v 71"
+         
style="display:inline;opacity:1;vector-effect:none;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#3366cc;stroke-width:1.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
 />
+      <path
+         sodipodi:nodetypes="cc"
+         inkscape:connector-curvature="0"
+         id="path2560-0"
+         d="m 203,344 h 74"
+         
style="display:inline;opacity:1;vector-effect:none;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#3366cc;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
 />
+      <path
+         sodipodi:nodetypes="ccc"
+         inkscape:connector-curvature="0"
+         id="path2562-2"
+         d="M 267,335.00001 279,344 l -12,9"
+         
style="display:inline;opacity:1;vector-effect:none;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#3366cc;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
 />
+    </g>
+    <g
+       id="g3385"
+       transform="translate(65)">
+      <rect
+         
style="display:inline;opacity:1;vector-effect:none;fill:#747474;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
+         id="rect3252"
+         width="19"
+         height="32"
+         x="672"
+         y="367.51999" />
+      <text
+         id="text3270"
+         y="233"
+         x="595.36499"
+         
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:32px;font-family:'Noto
 Sans Mono';-inkscape-font-specification:'Noto Sans Mono, 
Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-
 [...]
+         xml:space="preserve"><tspan
+           y="233"
+           x="595.36499"
+           sodipodi:role="line"
+           id="tspan3254"
+           style="fill:#000000;fill-opacity:1">foo();</tspan><tspan
+           y="273"
+           x="595.36499"
+           sodipodi:role="line"
+           style="fill:#000000;fill-opacity:1"
+           id="tspan3256" /><tspan
+           y="313"
+           x="595.36499"
+           sodipodi:role="line"
+           style="fill:#000000;fill-opacity:1"
+           id="tspan3260"><tspan
+   style="fill:#a020f0;fill-opacity:1"
+   id="tspan3258">val</tspan> x =</tspan><tspan
+           y="353"
+           x="595.36499"
+           sodipodi:role="line"
+           style="fill:#000000;fill-opacity:1"
+           id="tspan3264">    1 +</tspan><tspan
+           y="393"
+           x="595.36499"
+           sodipodi:role="line"
+           style="fill:#000000;fill-opacity:1"
+           id="tspan3266">    <tspan
+   id="tspan3282"
+   style="fill:#ffffff">2</tspan> +</tspan><tspan
+           y="433"
+           x="595.36499"
+           sodipodi:role="line"
+           style="fill:#000000;fill-opacity:1"
+           id="tspan3268">    3</tspan></text>
+      <path
+         sodipodi:nodetypes="cc"
+         inkscape:connector-curvature="0"
+         id="path3272"
+         d="m 672,328 v 71.51999"
+         
style="display:inline;opacity:1;vector-effect:none;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#3366cc;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
 />
+    </g>
+    <text
+       xml:space="preserve"
+       
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:32px;font-family:'Noto
 sans';-inkscape-font-specification:'Noto 
sans';text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="31.606001"
+       y="504.48001"
+       id="text885-5-3-6-7-0"><tspan
+         sodipodi:role="line"
+         x="31.606001"
+         y="504.48001"
+         id="tspan3329">If the line is the second line,</tspan><tspan
+         sodipodi:role="line"
+         x="31.606001"
+         y="544.47998"
+         id="tspan3333">align with the start of</tspan><tspan
+         sodipodi:role="line"
+         x="31.606001"
+         y="584.47998"
+         id="tspan3335">the element with offset.</tspan></text>
+    <text
+       id="text3343"
+       y="504.48001"
+       x="527.91553"
+       
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:32px;font-family:'Noto
 sans';-inkscape-font-specification:'Noto 
sans';text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       xml:space="preserve"><tspan
+         id="tspan3341"
+         y="504.48001"
+         x="527.91553"
+         sodipodi:role="line">If the line is the third or</tspan><tspan
+         y="544.47998"
+         x="527.91553"
+         sodipodi:role="line"
+         id="tspan3352">following lines,</tspan><tspan
+         y="584.47998"
+         x="527.91553"
+         sodipodi:role="line"
+         id="tspan3350">align with the the previous line.</tspan></text>
+  </g>
+  <g
+     inkscape:groupmode="layer"
+     id="layer8"
+     inkscape:label="Layer 8"
+     style="display:inline">
+    <text
+       xml:space="preserve"
+       
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:53.33333206px;font-family:'Noto
 Sans';-inkscape-font-specification:'Noto Sans, 
Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:center;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-l
 [...]
+       x="512.52295"
+       y="56.000004"
+       id="text819-9-5-2-1-3-7-8"><tspan
+         sodipodi:role="line"
+         id="tspan817-1-6-9-2-9-3-4"
+         x="512.52295"
+         y="56.000004"><tspan
+   
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'Noto
 Sans Mono';-inkscape-font-specification:'Noto Sans Mono'"
+   id="tspan3406"><tspan
+     style="fill:#a020f0;fill-opacity:1"
+     id="tspan3944">if<tspan
+   
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'Noto
 Sans';-inkscape-font-specification:'Noto Sans';fill:#000000;fill-opacity:1"
+   id="tspan3950">-</tspan>else</tspan></tspan> statement</tspan></text>
+    <rect
+       
style="display:inline;opacity:1;vector-effect:none;fill:#747474;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
+       id="rect1685-2-8-2-6"
+       width="19"
+       height="32"
+       x="709"
+       y="270" />
+    <text
+       id="text949-1-7-0-0-5-6"
+       y="95"
+       x="632.25098"
+       
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:32px;font-family:'Noto
 Sans Mono';-inkscape-font-specification:'Noto Sans Mono, 
Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-li
 [...]
+       xml:space="preserve"><tspan
+         id="tspan3490"
+         y="95"
+         x="632.25098"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1">aaa();</tspan><tspan
+         id="tspan3506"
+         y="135"
+         x="632.25098"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1" /><tspan
+         id="tspan3502"
+         y="175"
+         x="632.25098"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"><tspan
+   id="tspan3504"
+   style="fill:#a020f0;fill-opacity:1">if</tspan> (foo)</tspan><tspan
+         id="tspan3498"
+         y="215"
+         x="632.25098"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1">    bar()</tspan><tspan
+         id="tspan3494"
+         y="255"
+         x="632.25098"
+         sodipodi:role="line"
+         style="fill:#a020f0;fill-opacity:1">else</tspan><tspan
+         id="tspan3496"
+         y="295"
+         x="632.25098"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1">    <tspan
+   style="fill:#ffffff;fill-opacity:1"
+   id="tspan3547">b</tspan>az();</tspan></text>
+    <path
+       sodipodi:nodetypes="cc"
+       inkscape:connector-curvature="0"
+       id="path2558-4-1-5"
+       d="m 709,270 v 32"
+       
style="display:inline;opacity:1;vector-effect:none;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#3366cc;stroke-width:1.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
 />
+    <path
+       
style="display:inline;opacity:1;vector-effect:none;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#3366cc;stroke-width:1.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
+       d="m 632,230 v 71"
+       id="path3220-9"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <path
+       
style="display:inline;opacity:1;vector-effect:none;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#3366cc;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
+       d="m 632,285 h 74"
+       id="path2560-0-4"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <path
+       
style="display:inline;opacity:1;vector-effect:none;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#3366cc;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
+       d="M 696,276.00001 708,285 l -12,9"
+       id="path2562-2-3"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="ccc" />
+    <rect
+       y="230"
+       x="399"
+       height="32"
+       width="19"
+       id="rect3521"
+       
style="display:inline;opacity:1;vector-effect:none;fill:#747474;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
 />
+    <text
+       xml:space="preserve"
+       
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:32px;font-family:'Noto
 Sans Mono';-inkscape-font-specification:'Noto Sans Mono, 
Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-li
 [...]
+       x="399.25098"
+       y="95"
+       id="text3537"><tspan
+         style="fill:#000000;fill-opacity:1"
+         sodipodi:role="line"
+         x="399.25098"
+         y="95"
+         id="tspan3523">aaa();</tspan><tspan
+         style="fill:#000000;fill-opacity:1"
+         sodipodi:role="line"
+         x="399.25098"
+         y="135"
+         id="tspan3525" /><tspan
+         style="fill:#000000;fill-opacity:1"
+         sodipodi:role="line"
+         x="399.25098"
+         y="175"
+         id="tspan3529"><tspan
+   style="fill:#a020f0;fill-opacity:1"
+   id="tspan3527">if</tspan> (foo)</tspan><tspan
+         style="fill:#000000;fill-opacity:1"
+         sodipodi:role="line"
+         x="399.25098"
+         y="215"
+         id="tspan3531">    bar()</tspan><tspan
+         style="fill:#a020f0;fill-opacity:1"
+         sodipodi:role="line"
+         x="399.25098"
+         y="255"
+         id="tspan3533"><tspan
+   style="fill:#ffffff;fill-opacity:1"
+   id="tspan3553">e</tspan>lse</tspan><tspan
+         style="fill:#000000;fill-opacity:1"
+         sodipodi:role="line"
+         x="399.25098"
+         y="295"
+         id="tspan3535">    baz();</tspan></text>
+    <path
+       sodipodi:nodetypes="cc"
+       inkscape:connector-curvature="0"
+       id="path3541"
+       d="M 400,150 V 262"
+       
style="display:inline;opacity:1;vector-effect:none;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#3366cc;stroke-width:1.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
 />
+    <rect
+       
style="display:inline;opacity:1;vector-effect:none;fill:#747474;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
+       id="rect3559"
+       width="19"
+       height="32"
+       x="228"
+       y="190" />
+    <text
+       id="text3577"
+       y="95"
+       x="150.99249"
+       
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:32px;font-family:'Noto
 Sans Mono';-inkscape-font-specification:'Noto Sans Mono, 
Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-li
 [...]
+       xml:space="preserve"><tspan
+         id="tspan3561"
+         y="95"
+         x="150.99249"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1">aaa();</tspan><tspan
+         id="tspan3563"
+         y="135"
+         x="150.99249"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1" /><tspan
+         id="tspan3567"
+         y="175"
+         x="150.99249"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"><tspan
+   id="tspan3565"
+   style="fill:#a020f0;fill-opacity:1">if</tspan> (foo)</tspan><tspan
+         id="tspan3569"
+         y="215"
+         x="150.99249"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1">    <tspan
+   style="fill:#ffffff;fill-opacity:1"
+   id="tspan3583">b</tspan>ar()</tspan><tspan
+         id="tspan3573"
+         y="255"
+         x="150.99249"
+         sodipodi:role="line"
+         style="fill:#a020f0;fill-opacity:1">else</tspan><tspan
+         id="tspan3575"
+         y="295"
+         x="150.99249"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1">    baz();</tspan></text>
+    <path
+       sodipodi:nodetypes="cc"
+       inkscape:connector-curvature="0"
+       id="path2558-4-1-5-7"
+       d="m 228,190 v 32"
+       
style="display:inline;opacity:1;vector-effect:none;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#3366cc;stroke-width:1.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
 />
+    <path
+       
style="display:inline;opacity:1;vector-effect:none;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#3366cc;stroke-width:1.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
+       d="m 151,150 v 71"
+       id="path3220-9-8"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <path
+       
style="display:inline;opacity:1;vector-effect:none;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#3366cc;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
+       d="m 151,205 h 74"
+       id="path2560-0-4-2"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <path
+       
style="display:inline;opacity:1;vector-effect:none;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#3366cc;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
+       d="M 215,196.00001 227,205 l -12,9"
+       id="path2562-2-3-8"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="ccc" />
+    <text
+       xml:space="preserve"
+       
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:26.66666603px;font-family:'Noto
 sans';-inkscape-font-specification:'Noto 
sans';text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="47.706665"
+       y="340.39999"
+       id="text885-5-3-6-7-0-8"><tspan
+         sodipodi:role="line"
+         x="47.706665"
+         y="340.39999"
+         id="tspan3335-0">If the point is after <tspan
+   
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'Noto
 Sans Mono';-inkscape-font-specification:'Noto Sans Mono'"
+   id="tspan3656"><tspan
+   style="fill:#a020f0;fill-opacity:1"
+   id="tspan3676">if</tspan> (...)</tspan>, </tspan><tspan
+         sodipodi:role="line"
+         x="47.706665"
+         y="373.73334"
+         id="tspan3692">then align with the <tspan
+   
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'Noto
 sans Mono';-inkscape-font-specification:'Noto sans 
Mono';fill:#a020f0;fill-opacity:1"
+   id="tspan3658">if</tspan> token with offset.</tspan><tspan
+         sodipodi:role="line"
+         x="47.706665"
+         y="407.06665"
+         id="tspan3648" /><tspan
+         sodipodi:role="line"
+         x="47.706665"
+         y="440.39999"
+         id="tspan3704">If the point is before <tspan
+   
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'Noto
 Sans Mono';-inkscape-font-specification:'Noto Sans 
Mono';fill:#a020f0;fill-opacity:1"
+   id="tspan3660">else</tspan> token, </tspan><tspan
+         sodipodi:role="line"
+         x="47.706665"
+         y="473.73334"
+         id="tspan3695">then align with the matching <tspan
+   
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'Noto
 sans Mono';-inkscape-font-specification:'Noto sans 
Mono';fill:#a020f0;fill-opacity:1"
+   id="tspan3664">if</tspan> token without offset.</tspan><tspan
+         sodipodi:role="line"
+         x="47.706665"
+         y="507.06665"
+         id="tspan3650" /><tspan
+         sodipodi:role="line"
+         x="47.706665"
+         y="540.39996"
+         id="tspan3701">If the point is after <tspan
+   
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'Noto
 sans Mono';-inkscape-font-specification:'Noto sans 
Mono';fill:#a020f0;fill-opacity:1"
+   id="tspan3662">else</tspan> token, </tspan><tspan
+         sodipodi:role="line"
+         x="47.706665"
+         y="573.73334"
+         id="tspan3698">then align with the <tspan
+   
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'Noto
 sans Mono';-inkscape-font-specification:'Noto sans 
Mono';fill:#a020f0;fill-opacity:1"
+   id="tspan3666">else</tspan> token with offset.</tspan><tspan
+         sodipodi:role="line"
+         x="47.706665"
+         y="607.06665"
+         id="tspan3652" /><tspan
+         sodipodi:role="line"
+         x="47.706665"
+         y="640.39996"
+         id="tspan3654">Note that <tspan
+   
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'Noto
 sans Mono';-inkscape-font-specification:'Noto sans 
Mono';fill:#a020f0;fill-opacity:1"
+   id="tspan3668">if<tspan
+   
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'Noto
 sans';-inkscape-font-specification:'Noto sans';fill:#000000;fill-opacity:1"
+   id="tspan3716">-</tspan>else</tspan> can be nested, </tspan><tspan
+         sodipodi:role="line"
+         x="47.706665"
+         y="673.73334"
+         id="tspan3707">so when seeking the matching <tspan
+   
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'Noto
 sans Mono';-inkscape-font-specification:'Noto sans 
Mono';fill:#a020f0;fill-opacity:1"
+   id="tspan3670">if</tspan> token, </tspan><tspan
+         sodipodi:role="line"
+         x="47.706665"
+         y="707.06665"
+         id="tspan3712">we have to count number of <tspan
+   
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'Noto
 sans Mono';-inkscape-font-specification:'Noto sans 
Mono';fill:#a020f0;fill-opacity:1"
+   id="tspan3672">else</tspan> and <tspan
+   
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'Noto
 sans Mono';-inkscape-font-specification:'Noto sans 
Mono';fill:#a020f0;fill-opacity:1"
+   id="tspan3674">if</tspan> tokens.</tspan></text>
+    <text
+       id="text3782"
+       y="756.40002"
+       x="47.679996"
+       
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:26.66666603px;font-family:'Noto
 sans';-inkscape-font-specification:'Noto 
sans';text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       xml:space="preserve"><tspan
+         id="tspan3780"
+         y="756.40002"
+         x="47.679996"
+         sodipodi:role="line">We have similar rules for <tspan
+   
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'Noto
 sans Mono';-inkscape-font-specification:'Noto sans 
Mono';fill:#a020f0;fill-opacity:1"
+   id="tspan3922">for</tspan>, <tspan
+   
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'Noto
 sans Mono';-inkscape-font-specification:'Noto sans 
Mono';fill:#a020f0;fill-opacity:1"
+   id="tspan3924">while</tspan>, and <tspan
+   
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'Noto
 sans Mono';-inkscape-font-specification:'Noto sans 
Mono';fill:#a020f0;fill-opacity:1"
+   id="tspan3926">do</tspan>-<tspan
+   
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'Noto
 sans Mono';-inkscape-font-specification:'Noto sans 
Mono';fill:#a020f0;fill-opacity:1"
+   id="tspan3928">while</tspan>.</tspan></text>
+  </g>
+  <g
+     inkscape:groupmode="layer"
+     id="layer9"
+     inkscape:label="Layer 9"
+     style="display:inline">
+    <text
+       xml:space="preserve"
+       
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:53.33333206px;font-family:'Noto
 Sans';-inkscape-font-specification:'Noto Sans, 
Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:center;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-l
 [...]
+       x="512.52295"
+       y="397.86667"
+       id="text819-9-5-2-1-3-7-8-5"><tspan
+         sodipodi:role="line"
+         id="tspan817-1-6-9-2-9-3-4-5"
+         x="512.52295"
+         y="397.86667">Advanced topics</tspan></text>
+  </g>
+  <g
+     inkscape:groupmode="layer"
+     id="layer10"
+     inkscape:label="Layer 10"
+     style="display:inline">
+    <text
+       xml:space="preserve"
+       
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:53.33333206px;font-family:'Noto
 Sans';-inkscape-font-specification:'Noto Sans, 
Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:center;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-l
 [...]
+       x="512.52295"
+       y="56.000004"
+       id="text819-9-5-2-1-3-7-8-5-5"><tspan
+         sodipodi:role="line"
+         id="tspan817-1-6-9-2-9-3-4-5-7"
+         x="512.52295"
+         y="56.000004">Implicit semicolons</tspan></text>
+    <text
+       xml:space="preserve"
+       
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:29.33333397px;font-family:'Noto
 sans';-inkscape-font-specification:'Noto 
sans';text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="24"
+       y="128"
+       id="text885-5-3-6-7-0-6"><tspan
+         sodipodi:role="line"
+         x="24"
+         y="128"
+         id="tspan3335-5">In Kotlin and other languages, a statement may end 
with a newline.</tspan><tspan
+         sodipodi:role="line"
+         x="24"
+         y="164.66667"
+         id="tspan4079">We use a heuristic function ‘<tspan
+   
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'Noto
 Sans Mono';-inkscape-font-specification:'Noto Sans 
Mono';fill:#008b8b;fill-opacity:1"
+   id="tspan4085">kotlin-mode--implicit-semi-p</tspan>’ </tspan><tspan
+         sodipodi:role="line"
+         x="24"
+         y="201.33333"
+         id="tspan4093">to detect it.</tspan><tspan
+         sodipodi:role="line"
+         x="24"
+         y="238"
+         id="tspan4081">It examines tokens before and after the 
newline.</tspan><tspan
+         sodipodi:role="line"
+         x="24"
+         y="274.66666"
+         id="tspan4237" /><tspan
+         sodipodi:role="line"
+         x="24"
+         y="311.33334"
+         id="tspan4239">Example:</tspan><tspan
+         sodipodi:role="line"
+         x="24"
+         y="348"
+         id="tspan4083" /></text>
+    <text
+       id="text3577-3"
+       y="368"
+       x="112"
+       
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:32px;font-family:'Noto
 Sans Mono';-inkscape-font-specification:'Noto Sans Mono, 
Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-li
 [...]
+       xml:space="preserve"><tspan
+         id="tspan3575-6"
+         y="368"
+         x="112"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"><tspan
+   style="fill:#a020f0;fill-opacity:1"
+   id="tspan4195">for</tspan> (x <tspan
+   style="fill:#a020f0;fill-opacity:1"
+   id="tspan4197">in</tspan> xs) {</tspan><tspan
+         y="408"
+         x="112"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan4179">    aaa()</tspan><tspan
+         y="448"
+         x="112"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan4181">    <tspan
+   style="fill:#a020f0;fill-opacity:1"
+   id="tspan4199">if</tspan> (bbb)</tspan><tspan
+         y="488"
+         x="112"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan4187">        <tspan
+   style="fill:#a020f0;fill-opacity:1"
+   id="tspan4276">if</tspan> (ccc)</tspan><tspan
+         y="528"
+         x="112"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan4270">            ddd()</tspan><tspan
+         y="568"
+         x="112"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan4272">        <tspan
+   style="fill:#a020f0;fill-opacity:1"
+   id="tspan4278">else</tspan></tspan><tspan
+         y="608"
+         x="112"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan4274">            eee()</tspan><tspan
+         y="648"
+         x="112"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan4189">    fff()</tspan><tspan
+         y="688"
+         x="112"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan4191">}</tspan><tspan
+         y="728"
+         x="112"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan4193">ccc()</tspan></text>
+    <text
+       xml:space="preserve"
+       
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:24px;font-family:'Noto
 sans';-inkscape-font-specification:'Noto 
sans';text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;display:inline;fill:#3366cc;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="456"
+       y="530.23999"
+       id="text1851-6"><tspan
+         sodipodi:role="line"
+         x="456"
+         y="530.23999"
+         id="tspan1880-9">← No implicit semicolon here...</tspan></text>
+    <text
+       id="text4235"
+       y="690.23999"
+       x="159.16"
+       
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:24px;font-family:'Noto
 sans';-inkscape-font-specification:'Noto 
sans';text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;display:inline;fill:#3366cc;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       xml:space="preserve"><tspan
+         id="tspan4233"
+         y="690.23999"
+         x="159.16"
+         sodipodi:role="line">← Implicit semicolon here</tspan></text>
+    <text
+       id="text4243"
+       y="650.23999"
+       x="456"
+       
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:24px;font-family:'Noto
 sans';-inkscape-font-specification:'Noto 
sans';text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;display:inline;fill:#3366cc;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       xml:space="preserve"><tspan
+         id="tspan4241"
+         y="650.23999"
+         x="456"
+         sodipodi:role="line">← ... to aligh this line to the first if 
token</tspan><tspan
+         y="680.23999"
+         x="456"
+         sodipodi:role="line"
+         id="tspan4280">    rather than the else token.</tspan></text>
+    <text
+       id="text5389"
+       y="608"
+       x="456"
+       
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:24px;font-family:'Noto
 sans';-inkscape-font-specification:'Noto 
sans';text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;display:inline;fill:#3366cc;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       xml:space="preserve"><tspan
+         id="tspan5387"
+         y="608"
+         x="456"
+         sodipodi:role="line">← ... only here ...</tspan></text>
+    <text
+       xml:space="preserve"
+       
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:24px;font-family:'Noto
 sans';-inkscape-font-specification:'Noto 
sans';text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;display:inline;fill:#3366cc;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="231.16"
+       y="730.23999"
+       id="text5393"><tspan
+         sodipodi:role="line"
+         x="231.16"
+         y="730.23999"
+         id="tspan5391">← Implicit semicolon here</tspan></text>
+    <text
+       id="text5397"
+       y="410.23999"
+       x="311.16"
+       
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:24px;font-family:'Noto
 sans';-inkscape-font-specification:'Noto 
sans';text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;display:inline;fill:#3366cc;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       xml:space="preserve"><tspan
+         id="tspan5395"
+         y="410.23999"
+         x="311.16"
+         sodipodi:role="line">← Implicit semicolon here</tspan></text>
+  </g>
+  <g
+     inkscape:groupmode="layer"
+     id="layer11"
+     inkscape:label="Layer 11"
+     style="display:inline">
+    <text
+       xml:space="preserve"
+       
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:37.33333206px;font-family:'Noto
 Sans';-inkscape-font-specification:'Noto Sans, 
Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:center;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-l
 [...]
+       x="512.52295"
+       y="56.000004"
+       id="text819-9-5-2-1-3-7-8-5-5-7"><tspan
+         sodipodi:role="line"
+         id="tspan817-1-6-9-2-9-3-4-5-7-1"
+         x="512.52295"
+         y="56.000004">Ambiguous commas, colons, curly brackets, and 
objects</tspan></text>
+    <text
+       xml:space="preserve"
+       
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:26.66666603px;font-family:'Noto
 sans';-inkscape-font-specification:'Noto 
sans';text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="56"
+       y="112"
+       id="text885-5-3-6-7-0-4"><tspan
+         sodipodi:role="line"
+         x="56"
+         y="112"
+         id="tspan3335-2">Commas are not always contained by 
brackets.</tspan><tspan
+         sodipodi:role="line"
+         x="56"
+         y="145.33333"
+         id="tspan4330">Texts before brackets may contain another 
brackets.</tspan><tspan
+         sodipodi:role="line"
+         x="56"
+         y="178.66667"
+         id="tspan7200">We handle them carefully.</tspan><tspan
+         sodipodi:role="line"
+         x="56"
+         y="212"
+         id="tspan4332" /></text>
+    <text
+       id="text3577-3-4"
+       y="210"
+       x="352"
+       
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;font-family:'Noto
 Sans Mono';-inkscape-font-specification:'Noto Sans Mono, 
Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-li
 [...]
+       xml:space="preserve"><tspan
+         y="210"
+         x="352"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan4193-1"><tspan
+   style="fill:#a020f0;fill-opacity:1"
+   id="tspan5442">class</tspan> <tspan
+   style="fill:#228b22;fill-opacity:1"
+   id="tspan5444">C</tspan>: <tspan
+   style="fill:#228b22;fill-opacity:1"
+   id="tspan5446">A</tspan> <tspan
+   style="fill:#a020f0;fill-opacity:1"
+   id="tspan5448">by</tspan> <tspan
+   style="fill:#a020f0;fill-opacity:1"
+   id="tspan5450">object</tspan>: <tspan
+   style="fill:#228b22;fill-opacity:1"
+   id="tspan5452">A1</tspan>,</tspan><tspan
+         y="230"
+         x="352"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan4541">                      <tspan
+   style="fill:#228b22;fill-opacity:1"
+   id="tspan5455">A2</tspan> {</tspan><tspan
+         y="250"
+         x="352"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan4543">             <tspan
+   style="fill:#a020f0;fill-opacity:1"
+   id="tspan5458">fun</tspan> <tspan
+   style="fill:#0000ff;fill-opacity:1"
+   id="tspan5460">aaa</tspan>() {}</tspan><tspan
+         y="270"
+         x="352"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan4545">         },</tspan><tspan
+         y="290"
+         x="352"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan4547">         <tspan
+   style="fill:#228b22;fill-opacity:1"
+   id="tspan5464">B</tspan> <tspan
+   style="fill:#a020f0;fill-opacity:1"
+   id="tspan5466">by</tspan> <tspan
+   style="fill:#a020f0;fill-opacity:1"
+   id="tspan5468">object</tspan>: <tspan
+   style="fill:#228b22;fill-opacity:1"
+   id="tspan5470">B1</tspan>,</tspan><tspan
+         y="310"
+         x="352"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan4549">                      <tspan
+   style="fill:#228b22;fill-opacity:1"
+   id="tspan5473">B2</tspan> {</tspan><tspan
+         y="330"
+         x="352"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan4551">             <tspan
+   style="fill:#a020f0;fill-opacity:1"
+   id="tspan5476">fun</tspan> <tspan
+   style="fill:#0000ff;fill-opacity:1"
+   id="tspan5478">bbb</tspan>() {}</tspan><tspan
+         y="350"
+         x="352"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan4553">         } {</tspan><tspan
+         y="370"
+         x="352"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan4555">    <tspan
+   style="fill:#a020f0;fill-opacity:1"
+   id="tspan5482">fun</tspan> <tspan
+   style="fill:#0000ff;fill-opacity:1"
+   id="tspan5484">ccc</tspan>(x: <tspan
+   style="fill:#228b22;fill-opacity:1"
+   id="tspan5486">X</tspan>): <tspan
+   style="fill:#228b22;fill-opacity:1"
+   id="tspan5488">Int</tspan> {</tspan><tspan
+         y="390"
+         x="352"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan4557">        <tspan
+   style="fill:#a020f0;fill-opacity:1"
+   id="tspan5491">return</tspan> <tspan
+   style="fill:#a020f0;fill-opacity:1"
+   id="tspan5493">when</tspan> (x) {</tspan><tspan
+         y="410"
+         x="352"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan4559">            <tspan
+   style="fill:#a020f0;fill-opacity:1"
+   id="tspan5496">object</tspan>: <tspan
+   style="fill:#228b22;fill-opacity:1"
+   id="tspan5498">X1</tspan> <tspan
+   style="fill:#a020f0;fill-opacity:1"
+   id="tspan5500">by</tspan> <tspan
+   style="fill:#a020f0;fill-opacity:1"
+   id="tspan5502">object</tspan>: <tspan
+   style="fill:#228b22;fill-opacity:1"
+   id="tspan5504">XX1</tspan> {</tspan><tspan
+         y="430"
+         x="352"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan4561">                        <tspan
+   style="fill:#a020f0;fill-opacity:1"
+   id="tspan5507">fun</tspan> <tspan
+   style="fill:#0000ff;fill-opacity:1"
+   id="tspan5509">xxx1</tspan>() {}</tspan><tspan
+         y="450"
+         x="352"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan4563">                    },</tspan><tspan
+         y="470"
+         x="352"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan4565">                    <tspan
+   style="fill:#228b22;fill-opacity:1"
+   id="tspan5513">X2</tspan> {</tspan><tspan
+         y="490"
+         x="352"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan4567">                <tspan
+   style="fill:#a020f0;fill-opacity:1"
+   id="tspan5516">fun</tspan> <tspan
+   style="fill:#0000ff;fill-opacity:1"
+   id="tspan5518">xxx2</tspan>() {}</tspan><tspan
+         y="510"
+         x="352"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan4569">            },</tspan><tspan
+         y="530"
+         x="352"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan4571">            <tspan
+   style="fill:#a020f0;fill-opacity:1"
+   id="tspan5522">object</tspan>: <tspan
+   style="fill:#228b22;fill-opacity:1"
+   id="tspan5524">Y1</tspan>,</tspan><tspan
+         y="550"
+         x="352"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan4573">                    <tspan
+   style="fill:#228b22;fill-opacity:1"
+   id="tspan5527">Y2</tspan> {</tspan><tspan
+         y="570"
+         x="352"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan4575">                <tspan
+   style="fill:#a020f0;fill-opacity:1"
+   id="tspan5530">fun</tspan> <tspan
+   style="fill:#0000ff;fill-opacity:1"
+   id="tspan5532">yyy</tspan>() {}</tspan><tspan
+         y="590"
+         x="352"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan4577">            } -&gt;</tspan><tspan
+         y="610"
+         x="352"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan4579">                1</tspan><tspan
+         y="630"
+         x="352"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan4581" /><tspan
+         y="650"
+         x="352"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan4583">            <tspan
+   style="fill:#a020f0;fill-opacity:1"
+   id="tspan5538">else</tspan> -&gt;</tspan><tspan
+         y="670"
+         x="352"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan4585">                2</tspan><tspan
+         y="690"
+         x="352"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan4587">        }</tspan><tspan
+         y="710"
+         x="352"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan4589">    }</tspan><tspan
+         y="730"
+         x="352"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan4591">}</tspan><tspan
+         y="750"
+         x="352"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan4593" /></text>
+    <text
+       xml:space="preserve"
+       
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13.33333302px;font-family:'Noto
 sans';-inkscape-font-specification:'Noto 
sans';text-align:end;letter-spacing:0px;word-spacing:0px;text-anchor:end;display:inline;fill:#3366cc;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="377.76709"
+       y="278.79999"
+       id="text1851-6-6"><tspan
+         sodipodi:role="line"
+         x="377.76709"
+         y="278.79999"
+         id="tspan1880-9-0">When seeking the previous element of this 
line,</tspan></text>
+    <text
+       id="text5573"
+       y="302.79999"
+       x="376.7594"
+       
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13.33333302px;font-family:'Noto
 sans';-inkscape-font-specification:'Noto 
sans';text-align:end;letter-spacing:0px;word-spacing:0px;text-anchor:end;display:inline;fill:#3366cc;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       xml:space="preserve"><tspan
+         y="302.79999"
+         x="380.22293"
+         sodipodi:role="line"
+         id="tspan5575">if we got a pair of curly brackets, </tspan></text>
+    <text
+       xml:space="preserve"
+       
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13.33333302px;font-family:'Noto
 sans';-inkscape-font-specification:'Noto 
sans';text-align:end;letter-spacing:0px;word-spacing:0px;text-anchor:end;display:inline;fill:#3366cc;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="377.71378"
+       y="326"
+       id="text5581"><tspan
+         id="tspan5579"
+         sodipodi:role="line"
+         x="377.71378"
+         y="326">then jump to the object token</tspan><tspan
+         sodipodi:role="line"
+         x="377.71378"
+         y="342.66666"
+         id="tspan6156">and resume seeking,</tspan></text>
+    <path
+       
style="opacity:1;vector-effect:none;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#3366cc;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-end:url(#marker6236);paint-order:normal"
+       d="m 380,278 56,4"
+       id="path5598"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <path
+       inkscape:connector-curvature="0"
+       id="path5650"
+       d="m 380,298 60,-32"
+       
style="opacity:1;vector-effect:none;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#3366cc;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-end:url(#marker6390);paint-order:normal"
+       sodipodi:nodetypes="cc" />
+    <path
+       sodipodi:nodetypes="cc"
+       
style="opacity:1;vector-effect:none;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#3366cc;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-end:url(#marker6406);paint-order:normal"
+       d="m 380,323 c 84,4 128,-53 128,-105"
+       id="path5950"
+       inkscape:connector-curvature="0" />
+    <text
+       id="text6884"
+       y="366.13333"
+       x="377.71378"
+       
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13.33333302px;font-family:'Noto
 sans';-inkscape-font-specification:'Noto 
sans';text-align:end;letter-spacing:0px;word-spacing:0px;text-anchor:end;display:inline;fill:#3366cc;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       xml:space="preserve"><tspan
+         id="tspan6882"
+         y="366.13333"
+         x="377.71378"
+         sodipodi:role="line">to skip this comma.</tspan></text>
+    <path
+       inkscape:connector-curvature="0"
+       id="path6984"
+       d="M 380,362.80089 C 464,366.80089 588,270 588,218"
+       
style="opacity:1;vector-effect:none;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#3366cc;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-end:url(#marker6988);paint-order:normal"
+       sodipodi:nodetypes="cc" />
+  </g>
+  <g
+     inkscape:groupmode="layer"
+     id="layer12"
+     inkscape:label="Layer 12"
+     style="display:inline">
+    <text
+       xml:space="preserve"
+       
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:53.33333206px;font-family:'Noto
 Sans';-inkscape-font-specification:'Noto Sans, 
Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:center;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-l
 [...]
+       x="512.52295"
+       y="56.000004"
+       id="text819-9-5-2-1-3-7-8-5-5-2"><tspan
+         sodipodi:role="line"
+         id="tspan817-1-6-9-2-9-3-4-5-7-2"
+         x="512.52295"
+         y="56.000004">Ambiguous arrows</tspan></text>
+    <text
+       id="text3577-3-4-2"
+       y="208"
+       x="160"
+       
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20.65869713px;font-family:'Noto
 Sans Mono';-inkscape-font-specification:'Noto Sans Mono, 
Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;
 [...]
+       xml:space="preserve"><tspan
+         y="208"
+         x="160"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1;stroke-width:1px"
+         id="tspan4593-2"><tspan
+   style="fill:#a020f0;fill-opacity:1;stroke-width:1px"
+   id="tspan9087">val</tspan> f = { g:</tspan><tspan
+         y="233.82336"
+         x="160"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1;stroke-width:1px"
+         id="tspan8557">              (<tspan
+   style="fill:#228b22;fill-opacity:1;stroke-width:1px"
+   id="tspan9090">Int</tspan>) -&gt;</tspan><tspan
+         y="259.64673"
+         x="160"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1;stroke-width:1px"
+         id="tspan8559">              (<tspan
+   style="fill:#228b22;fill-opacity:1;stroke-width:1px"
+   id="tspan9093">Int</tspan>) -&gt;</tspan><tspan
+         y="285.47012"
+         x="160"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1;stroke-width:1px"
+         id="tspan8561">              <tspan
+   style="fill:#228b22;fill-opacity:1;stroke-width:1px"
+   id="tspan9096">Int</tspan> -&gt;</tspan><tspan
+         y="311.29349"
+         x="160"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1;stroke-width:1px"
+         id="tspan8563">    g(1, 2)</tspan><tspan
+         y="337.11685"
+         x="160"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1;stroke-width:1px"
+         id="tspan8565">}</tspan><tspan
+         y="362.94022"
+         x="160"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1;stroke-width:1px"
+         id="tspan8567" /><tspan
+         y="388.76361"
+         x="160"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1;stroke-width:1px"
+         id="tspan8569"><tspan
+   style="fill:#a020f0;fill-opacity:1;stroke-width:1px"
+   id="tspan9102">when</tspan> (x) {</tspan><tspan
+         y="414.58698"
+         x="160"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1;stroke-width:1px"
+         id="tspan8571">    1 -&gt;</tspan><tspan
+         y="440.41034"
+         x="160"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1;stroke-width:1px"
+         id="tspan8573">        f1 <tspan
+   style="fill:#a020f0;fill-opacity:1;stroke-width:1px"
+   id="tspan9106">as</tspan> (<tspan
+   style="fill:#228b22;fill-opacity:1;stroke-width:1px"
+   id="tspan9108">Int</tspan>) -&gt;</tspan><tspan
+         y="466.2337"
+         x="160"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1;stroke-width:1px"
+         id="tspan8575">              <tspan
+   style="fill:#228b22;fill-opacity:1;stroke-width:1px"
+   id="tspan9111">Int</tspan></tspan><tspan
+         y="492.0571"
+         x="160"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1;stroke-width:1px"
+         id="tspan8577" /><tspan
+         y="517.88043"
+         x="160"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1;stroke-width:1px"
+         id="tspan8579">    f2 <tspan
+   style="fill:#a020f0;fill-opacity:1;stroke-width:1px"
+   id="tspan9115">as</tspan> (<tspan
+   style="fill:#228b22;fill-opacity:1;stroke-width:1px"
+   id="tspan9117">Int</tspan>) -&gt;</tspan><tspan
+         y="543.70386"
+         x="160"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1;stroke-width:1px"
+         id="tspan8581">          <tspan
+   style="fill:#228b22;fill-opacity:1;stroke-width:1px"
+   id="tspan9120">Int</tspan> -&gt;</tspan><tspan
+         y="569.52722"
+         x="160"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1;stroke-width:1px"
+         id="tspan8583">        f3</tspan><tspan
+         y="595.35059"
+         x="160"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1;stroke-width:1px"
+         id="tspan8585" /><tspan
+         y="621.17395"
+         x="160"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1;stroke-width:1px"
+         id="tspan8587">    <tspan
+   style="fill:#a020f0;fill-opacity:1;stroke-width:1px"
+   id="tspan9140">is</tspan> (<tspan
+   style="fill:#228b22;fill-opacity:1;stroke-width:1px"
+   id="tspan9125">Int</tspan>) -&gt;</tspan><tspan
+         y="646.99731"
+         x="160"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1;stroke-width:1px"
+         id="tspan8589">       <tspan
+   style="fill:#228b22;fill-opacity:1;stroke-width:1px"
+   id="tspan9128">Int</tspan> -&gt;</tspan><tspan
+         y="672.82068"
+         x="160"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1;stroke-width:1px"
+         id="tspan8591">        f4</tspan><tspan
+         y="698.64404"
+         x="160"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1;stroke-width:1px"
+         id="tspan8595">}</tspan></text>
+    <text
+       xml:space="preserve"
+       
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:17.21557999px;font-family:'Noto
 sans';-inkscape-font-specification:'Noto 
sans';text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;display:inline;fill:#3366cc;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="448.6192"
+       y="232.27397"
+       id="text1851-6-6-3"><tspan
+         sodipodi:role="line"
+         x="448.6192"
+         y="232.27397"
+         id="tspan1880-9-0-6"
+         style="stroke-width:1px">← arrow for function type</tspan></text>
+    <text
+       id="text9162"
+       y="259.38849"
+       x="448.6192"
+       
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:17.21557999px;font-family:'Noto
 sans';-inkscape-font-specification:'Noto 
sans';text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;display:inline;fill:#3366cc;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       xml:space="preserve"><tspan
+         id="tspan9160"
+         y="259.38849"
+         x="448.6192"
+         sodipodi:role="line"
+         style="stroke-width:1px">← arrow for function type</tspan></text>
+    <text
+       xml:space="preserve"
+       
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:17.21557999px;font-family:'Noto
 sans';-inkscape-font-specification:'Noto 
sans';text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;display:inline;fill:#3366cc;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="448.6192"
+       y="283.92072"
+       id="text9166"><tspan
+         sodipodi:role="line"
+         x="448.6192"
+         y="283.92072"
+         id="tspan9164"
+         style="stroke-width:1px">← arrow for lambda parameters</tspan></text>
+    <text
+       id="text9170"
+       y="414.58701"
+       x="273.6228"
+       
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:17.21557999px;font-family:'Noto
 sans';-inkscape-font-specification:'Noto 
sans';text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;display:inline;fill:#3366cc;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       xml:space="preserve"><tspan
+         id="tspan9168"
+         y="414.58701"
+         x="273.6228"
+         sodipodi:role="line"
+         style="stroke-width:1px">← arrow for when-entry</tspan></text>
+    <text
+       xml:space="preserve"
+       
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:17.21557999px;font-family:'Noto
 sans';-inkscape-font-specification:'Noto 
sans';text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;display:inline;fill:#3366cc;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="448.6192"
+       y="441.44327"
+       id="text9174"><tspan
+         sodipodi:role="line"
+         x="448.6192"
+         y="441.44327"
+         id="tspan9172"
+         style="stroke-width:1px">← arrow for function type</tspan></text>
+    <text
+       id="text9178"
+       y="520.72107"
+       x="396.97247"
+       
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:17.21557999px;font-family:'Noto
 sans';-inkscape-font-specification:'Noto 
sans';text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;display:inline;fill:#3366cc;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       xml:space="preserve"><tspan
+         id="tspan9176"
+         y="520.72107"
+         x="396.97247"
+         sodipodi:role="line"
+         style="stroke-width:1px">← arrow for function type</tspan></text>
+    <text
+       xml:space="preserve"
+       
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:17.21557999px;font-family:'Noto
 sans';-inkscape-font-specification:'Noto 
sans';text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;display:inline;fill:#3366cc;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="396.97247"
+       y="544.73682"
+       id="text9182"><tspan
+         sodipodi:role="line"
+         x="396.97247"
+         y="544.73682"
+         id="tspan9180"
+         style="stroke-width:1px">← arrow for when-entry</tspan></text>
+    <text
+       id="text9186"
+       y="624.01453"
+       x="355.65503"
+       
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:17.21557999px;font-family:'Noto
 sans';-inkscape-font-specification:'Noto 
sans';text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;display:inline;fill:#3366cc;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       xml:space="preserve"><tspan
+         id="tspan9184"
+         y="624.01453"
+         x="355.65503"
+         sodipodi:role="line"
+         style="stroke-width:1px">← arrow for function type</tspan></text>
+    <text
+       xml:space="preserve"
+       
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:17.21557999px;font-family:'Noto
 sans';-inkscape-font-specification:'Noto 
sans';text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;display:inline;fill:#3366cc;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="355.65503"
+       y="648.03027"
+       id="text9190"><tspan
+         sodipodi:role="line"
+         x="355.65503"
+         y="648.03027"
+         id="tspan9188"
+         style="stroke-width:1px">← arrow for when-entry</tspan></text>
+    <text
+       xml:space="preserve"
+       
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:26.66666603px;font-family:'Noto
 sans';-inkscape-font-specification:'Noto 
sans';text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="88"
+       y="104"
+       id="text885-5-3-6-7-0-4-6"><tspan
+         sodipodi:role="line"
+         x="88"
+         y="104"
+         id="tspan4332-6">Arrows have many meanings and indentation 
rules.</tspan><tspan
+         sodipodi:role="line"
+         x="88"
+         y="137.33333"
+         id="tspan9228">We use heuristics for this, but it is not 
precise.</tspan></text>
+    <text
+       id="text9232"
+       y="562.03845"
+       x="653.71222"
+       
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:17.21557999px;font-family:'Noto
 sans';-inkscape-font-specification:'Noto 
sans';text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;display:inline;fill:#3366cc;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       xml:space="preserve"><tspan
+         id="tspan9230"
+         y="562.03845"
+         x="653.71222"
+         sodipodi:role="line"
+         style="stroke-width:1px">Cannot handle those cases for 
now.</tspan><tspan
+         y="583.55792"
+         x="653.71222"
+         sodipodi:role="line"
+         style="stroke-width:1px"
+         id="tspan5447">We assume all arrows inside a when-</tspan><tspan
+         y="605.07739"
+         x="653.71222"
+         sodipodi:role="line"
+         style="stroke-width:1px"
+         id="tspan5449">expression are parts of when-entries.</tspan></text>
+    <path
+       
style="opacity:1;vector-effect:none;fill:#a020f0;fill-opacity:1;fill-rule:evenodd;stroke:#3366cc;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
+       d="m 640.31471,450.7397 15.49403,92.96414"
+       id="path9234"
+       inkscape:connector-curvature="0" />
+    <path
+       inkscape:connector-curvature="0"
+       id="path9236"
+       d="m 609.32667,523.04514 41.31739,30.98805"
+       
style="opacity:1;vector-effect:none;fill:#a020f0;fill-opacity:1;fill-rule:evenodd;stroke:#3366cc;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
+       sodipodi:nodetypes="cc" />
+    <path
+       sodipodi:nodetypes="cc"
+       
style="opacity:1;vector-effect:none;fill:#a020f0;fill-opacity:1;fill-rule:evenodd;stroke:#3366cc;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
+       d="m 568.00927,616.00928 82.63479,-51.64675"
+       id="path9238"
+       inkscape:connector-curvature="0" />
+  </g>
+  <g
+     inkscape:groupmode="layer"
+     id="layer13"
+     inkscape:label="Layer 13"
+     style="display:inline">
+    <text
+       xml:space="preserve"
+       
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:53.33333206px;font-family:'Noto
 Sans';-inkscape-font-specification:'Noto Sans, 
Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:center;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-l
 [...]
+       x="512.52295"
+       y="56.000004"
+       id="text819-9-5-2-1-3-7-8-5-5-2-9"><tspan
+         sodipodi:role="line"
+         id="tspan817-1-6-9-2-9-3-4-5-7-2-6"
+         x="512.52295"
+         y="56.000004">Angle brackets <tspan
+   
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'Noto
 Sans Mono';-inkscape-font-specification:'Noto Sans Mono'"
+   id="tspan9259">&lt;&gt;</tspan></tspan></text>
+    <text
+       xml:space="preserve"
+       
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:32px;font-family:'Noto
 sans';-inkscape-font-specification:'Noto 
sans';text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="64"
+       y="168"
+       id="text885-5-3-6-7-09"><tspan
+         sodipodi:role="line"
+         x="64"
+         y="168"
+         id="tspan2778-7">Token ‘<tspan
+   
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'Noto
 sans Mono';-inkscape-font-specification:'Noto sans Mono'"
+   id="tspan9314">&lt;</tspan>’ and ‘<tspan
+   
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'Noto
 sans Mono';-inkscape-font-specification:'Noto sans Mono'"
+   id="tspan9316">&gt;</tspan>’ may be used as inequality operators or 
</tspan><tspan
+         sodipodi:role="line"
+         x="64"
+         y="208"
+         id="tspan9312">angle brackets for type parameters.</tspan><tspan
+         sodipodi:role="line"
+         x="64"
+         y="248"
+         id="tspan9300" /><tspan
+         sodipodi:role="line"
+         x="64"
+         y="288"
+         id="tspan9302">We use heuristics to distinguish them:</tspan><tspan
+         sodipodi:role="line"
+         x="64"
+         y="328"
+         id="tspan9304" /><tspan
+         sodipodi:role="line"
+         x="64"
+         y="368"
+         id="tspan9306">- Angle bracket must be balanced.</tspan><tspan
+         sodipodi:role="line"
+         x="64"
+         y="408"
+         id="tspan9308">- Angle bracket cannot contain some kind of 
tokens.</tspan><tspan
+         sodipodi:role="line"
+         x="64"
+         y="448"
+         id="tspan9310" /></text>
+  </g>
+  <g
+     inkscape:groupmode="layer"
+     id="layer14"
+     inkscape:label="Layer 14"
+     style="display:inline">
+    <text
+       xml:space="preserve"
+       
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:53.33333206px;font-family:'Noto
 Sans';-inkscape-font-specification:'Noto Sans, 
Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:center;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-l
 [...]
+       x="512.52295"
+       y="56.000004"
+       id="text819-9-5-2-1-3-7-8-5-5-2-9-0"><tspan
+         sodipodi:role="line"
+         id="tspan817-1-6-9-2-9-3-4-5-7-2-6-8"
+         x="512.52295"
+         y="56.000004">Ambiguous operators</tspan></text>
+    <text
+       xml:space="preserve"
+       
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:32px;font-family:'Noto
 sans';-inkscape-font-specification:'Noto 
sans';text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="64"
+       y="116.32"
+       id="text885-5-3-6-7-09-4"><tspan
+         sodipodi:role="line"
+         x="64"
+         y="116.32"
+         id="tspan9310-7">We cannot handle those cases for now.</tspan></text>
+    <text
+       id="text3577-3-4-0"
+       y="168.16"
+       x="96"
+       
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;font-family:'Noto
 Sans Mono';-inkscape-font-specification:'Noto Sans Mono, 
Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-li
 [...]
+       xml:space="preserve"><tspan
+         y="168.16"
+         x="96"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan4593-3"><tspan
+   style="fill:#a020f0"
+   id="tspan12605">var</tspan> shl = 1</tspan><tspan
+         y="188.16"
+         x="96"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan10770"><tspan
+   style="fill:#a020f0"
+   id="tspan12608">val</tspan> x = shl shl shl <tspan
+   style="fill:#b22222"
+   id="tspan12610">// The last “shl” is a variable named 
“shl”.</tspan></tspan><tspan
+         y="208.16"
+         x="96"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan10772">shl &lt; 100 &amp;&amp; foo() <tspan
+   style="fill:#b22222"
+   id="tspan12613">// This is not a continuation of the previous 
line.</tspan></tspan><tspan
+         y="228.16"
+         x="96"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan10774" /><tspan
+         y="248.16"
+         x="96"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan10776"><tspan
+   style="fill:#a020f0"
+   id="tspan12617">var</tspan> shl = 1</tspan><tspan
+         y="268.16"
+         x="96"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan10778"><tspan
+   style="fill:#a020f0"
+   id="tspan12620">val</tspan> x = shl shl <tspan
+   style="fill:#b22222"
+   id="tspan12622">// The last “shl” is a shift operator.</tspan></tspan><tspan
+         y="288.16"
+         x="96"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan10780">    shl &lt; 100 &amp;&amp; foo() <tspan
+   style="fill:#b22222"
+   id="tspan12625">// This is a continuation of the previous 
line.</tspan></tspan><tspan
+         y="308.16"
+         x="96"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan10782" /><tspan
+         y="328.16"
+         x="96"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan10784"><tspan
+   style="fill:#a020f0"
+   id="tspan12629">var</tspan> shl = 1</tspan><tspan
+         y="348.16"
+         x="96"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan10786"><tspan
+   style="fill:#a020f0"
+   id="tspan12632">val</tspan> x = shl shl shl ++ <tspan
+   style="fill:#b22222"
+   id="tspan12634">// postfix increment operator</tspan></tspan><tspan
+         y="368.16"
+         x="96"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan10788">shl &lt; 100 &amp;&amp; foo() <tspan
+   style="fill:#b22222"
+   id="tspan12637">// This is not a continuation of the previous 
line.</tspan></tspan><tspan
+         y="388.16"
+         x="96"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan10790" /><tspan
+         y="408.16"
+         x="96"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan10792"><tspan
+   style="fill:#a020f0"
+   id="tspan12641">var</tspan> shl = 1</tspan><tspan
+         y="428.16"
+         x="96"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan10794"><tspan
+   style="fill:#a020f0"
+   id="tspan12644">val</tspan> x = shl shl ++ <tspan
+   style="fill:#b22222"
+   id="tspan12646">// prefix increment operator</tspan></tspan><tspan
+         y="448.16"
+         x="96"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan10796">    shl &lt; 100 &amp;&amp; foo() <tspan
+   style="fill:#b22222"
+   id="tspan12649">// This is a continuation of the previous 
line.</tspan></tspan><tspan
+         y="468.16"
+         x="96"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan10798" /><tspan
+         y="488.16"
+         x="96"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan10800"><tspan
+   style="fill:#a020f0"
+   id="tspan12653">val</tspan> x = foo()!! <tspan
+   style="fill:#b22222"
+   id="tspan12655">// postfix operator</tspan></tspan><tspan
+         y="508.16"
+         x="96"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan10802">foo() <tspan
+   style="fill:#b22222"
+   id="tspan12658">// This is not a continuation of the previous 
line.</tspan></tspan><tspan
+         y="528.16003"
+         x="96"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan10804" /><tspan
+         y="548.16003"
+         x="96"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan10806"><tspan
+   style="fill:#a020f0"
+   id="tspan12662">val</tspan> x = !!  <tspan
+   style="fill:#b22222"
+   id="tspan12664">// two prefix operators</tspan></tspan><tspan
+         y="568.16003"
+         x="96"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan10808">    foo() <tspan
+   style="fill:#b22222"
+   id="tspan12667">// This is a continuation of the previous 
line.</tspan></tspan><tspan
+         y="588.16003"
+         x="96"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan10810" /></text>
+  </g>
+  <g
+     inkscape:groupmode="layer"
+     id="layer15"
+     inkscape:label="Layer 15"
+     style="display:inline">
+    <text
+       xml:space="preserve"
+       
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:53.33333206px;font-family:'Noto
 Sans';-inkscape-font-specification:'Noto Sans, 
Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:center;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-l
 [...]
+       x="512.52295"
+       y="56.000004"
+       id="text819-9-5-2-1-3-7-8-5-5-2-9-0-8"><tspan
+         sodipodi:role="line"
+         id="tspan817-1-6-9-2-9-3-4-5-7-2-6-8-5"
+         x="512.52295"
+         y="56.000004">Implementation</tspan></text>
+    <text
+       id="text3577-3-4-0-5"
+       y="152.74873"
+       x="6.5857863"
+       
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;font-family:'Noto
 Sans Mono';-inkscape-font-specification:'Noto Sans Mono, 
Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-li
 [...]
+       xml:space="preserve"><tspan
+         y="152.74873"
+         x="6.5857863"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan13461"><tspan
+   style="fill:#96b4b4"
+   id="tspan16816">kotlin-mode--</tspan><tspan
+   style="fill:#008b8b"
+   id="tspan16818">indent-line</tspan> <tspan
+   style="fill:#3366cc"
+   id="tspan16820">← entry point for indenting line</tspan></tspan><tspan
+         y="172.74873"
+         x="6.5857863"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan13927">  <tspan
+   style="fill:#96b4b4"
+   id="tspan16823">kotlin-mode--</tspan><tspan
+   style="fill:#008b8b"
+   id="tspan16825">calculate-indent</tspan> <tspan
+   style="fill:#3366cc"
+   id="tspan16827">← calculate the amount of the 
indentation</tspan></tspan><tspan
+         y="192.74873"
+         x="6.5857863"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan13929">    <tspan
+   style="fill:#96b4b4"
+   id="tspan16830">kotlin-mode--</tspan><tspan
+   style="fill:#008b8b"
+   id="tspan16832">calculate-indent-of-multiline-comment</tspan> <tspan
+   style="fill:#3366cc"
+   id="tspan16834">← when the point is inside a multiline 
comment</tspan></tspan><tspan
+         y="212.74873"
+         x="6.5857863"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan13931">    <tspan
+   style="fill:#96b4b4"
+   id="tspan16837">kotlin-mode--</tspan><tspan
+   style="fill:#008b8b"
+   id="tspan16839">calculate-indent-of-multiline-string</tspan> <tspan
+   style="fill:#3366cc"
+   id="tspan16841">← when the point is inside a multiline 
string</tspan></tspan><tspan
+         y="232.74873"
+         x="6.5857863"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan13933">    <tspan
+   style="fill:#96b4b4"
+   id="tspan16844">kotlin-mode--</tspan><tspan
+   style="fill:#008b8b"
+   id="tspan16846">calculate-indent-of-single-line-comment</tspan> <tspan
+   style="fill:#3366cc"
+   id="tspan16848">← when the point is before a single-line 
comment</tspan></tspan><tspan
+         y="252.74873"
+         x="6.5857863"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan13935">    <tspan
+   style="fill:#96b4b4"
+   id="tspan16851">kotlin-mode--</tspan><tspan
+   style="fill:#008b8b"
+   id="tspan16853">calculate-indent-of-code</tspan> <tspan
+   style="fill:#3366cc"
+   id="tspan16855">← other case, including before a single-line 
string</tspan></tspan><tspan
+         y="272.74872"
+         x="6.5857863"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan13937">      <tspan
+   style="fill:#96b4b4"
+   id="tspan16858">kotlin-mode--</tspan><tspan
+   style="fill:#008b8b"
+   id="tspan16860">forward-token</tspan> <tspan
+   style="fill:#3366cc"
+   id="tspan16862">← lexer</tspan></tspan><tspan
+         y="292.74872"
+         x="6.5857863"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan13939">        <tspan
+   style="fill:#96b4b4"
+   id="tspan16865">kotlin-mode--</tspan><tspan
+   style="fill:#008b8b"
+   id="tspan16867">forward-token-simple</tspan> <tspan
+   style="fill:#3366cc"
+   id="tspan16869">← lexer without unbounded recursion</tspan></tspan><tspan
+         y="312.74872"
+         x="6.5857863"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan13941">        <tspan
+   style="fill:#96b4b4"
+   id="tspan16872">kotlin-mode--</tspan><tspan
+   style="fill:#008b8b"
+   id="tspan16874">implicit-semi-p</tspan> <tspan
+   style="fill:#3366cc"
+   id="tspan16876">← determinate implicit semicolon</tspan></tspan><tspan
+         y="332.74872"
+         x="6.5857863"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan13943">        ...</tspan><tspan
+         y="352.74872"
+         x="6.5857863"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan13945">      <tspan
+   style="fill:#96b4b4"
+   id="tspan16880">kotlin-mode--</tspan><tspan
+   style="fill:#008b8b"
+   id="tspan16882">backward-token</tspan> <tspan
+   style="fill:#3366cc"
+   id="tspan16884">← lexer</tspan></tspan><tspan
+         y="372.74872"
+         x="6.5857863"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan13947">        <tspan
+   style="fill:#96b4b4"
+   id="tspan16887">kotlin-mode--</tspan><tspan
+   style="fill:#008b8b"
+   id="tspan16889">backward-token-simple</tspan> <tspan
+   style="fill:#3366cc"
+   id="tspan16891">← lexer without unbounded recursion</tspan></tspan><tspan
+         y="392.74872"
+         x="6.5857863"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan13949">        <tspan
+   style="fill:#96b4b4"
+   id="tspan16894">kotlin-mode--</tspan><tspan
+   style="fill:#008b8b"
+   id="tspan16896">implicit-semi-p</tspan></tspan><tspan
+         y="412.74872"
+         x="6.5857863"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan13951">        ...</tspan><tspan
+         y="432.74872"
+         x="6.5857863"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan13953">      <tspan
+   style="fill:#96b4b4"
+   id="tspan16900">kotlin-mode--</tspan><tspan
+   style="fill:#008b8b"
+   id="tspan16902">calculate-indent-after-open-curly-brace</tspan> <tspan
+   style="fill:#3366cc"
+   id="tspan16904">← when the point is after ‘{’</tspan></tspan><tspan
+         y="452.74872"
+         x="6.5857863"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan13955">        <tspan
+   style="fill:#96b4b4"
+   id="tspan16907">kotlin-mode--</tspan><tspan
+   style="fill:#008b8b"
+   id="tspan16909">curly-brace-type</tspan> <tspan
+   style="fill:#3366cc"
+   id="tspan16911">← determinate the type of the block</tspan></tspan><tspan
+         y="472.74872"
+         x="6.5857863"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan13957">        <tspan
+   style="fill:#96b4b4"
+   id="tspan16914">kotlin-mode--</tspan><tspan
+   style="fill:#008b8b"
+   id="tspan16916">find-parent-and-align-with-next</tspan></tspan><tspan
+         y="492.74872"
+         x="6.5857863"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan13959">          <tspan
+   style="fill:#96b4b4"
+   id="tspan16919">kotlin-mode--</tspan><tspan
+   style="fill:#008b8b"
+   id="tspan16921">backward-sexps-until</tspan></tspan><tspan
+         y="512.74872"
+         x="6.5857863"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan13961">            <tspan
+   style="fill:#96b4b4"
+   id="tspan16924">kotlin-mode--</tspan><tspan
+   style="fill:#008b8b"
+   id="tspan16926">backward-token-or-list</tspan></tspan><tspan
+         y="532.74872"
+         x="6.5857863"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan13963">              <tspan
+   style="fill:#96b4b4"
+   id="tspan16929">kotlin-mode--</tspan><tspan
+   style="fill:#008b8b"
+   id="tspan16931">backward-token</tspan></tspan><tspan
+         y="552.74872"
+         x="6.5857863"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan13965">            <tspan
+   style="fill:#96b4b4"
+   id="tspan16934">kotlin-mode--</tspan><tspan
+   style="fill:#008b8b"
+   id="tspan16936">forward-token-or-list</tspan></tspan><tspan
+         y="572.74872"
+         x="6.5857863"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan13967">              <tspan
+   style="fill:#96b4b4"
+   id="tspan16939">kotlin-mode--</tspan><tspan
+   style="fill:#008b8b"
+   id="tspan16941">forward-token</tspan></tspan><tspan
+         y="592.74872"
+         x="6.5857863"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan13969">      <tspan
+   style="fill:#96b4b4"
+   id="tspan16944">kotlin-mode--</tspan><tspan
+   style="fill:#008b8b"
+   id="tspan16946">calculate-indent-after-comma</tspan></tspan><tspan
+         y="612.74872"
+         x="6.5857863"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan13971">        ...</tspan><tspan
+         y="632.74872"
+         x="6.5857863"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan13973">      <tspan
+   style="fill:#96b4b4"
+   id="tspan16950">kotlin-mode--</tspan><tspan
+   style="fill:#008b8b"
+   id="tspan16952">calculate-indent-after-semicolon</tspan></tspan><tspan
+         y="652.74872"
+         x="6.5857863"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan13975">        ...</tspan><tspan
+         y="672.74872"
+         x="6.5857863"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan13977">      <tspan
+   style="fill:#96b4b4"
+   id="tspan16956">kotlin-mode--</tspan><tspan
+   style="fill:#008b8b"
+   id="tspan16958">calculate-indent-of-expression</tspan></tspan><tspan
+         y="692.74872"
+         x="6.5857863"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan13979">        ...</tspan><tspan
+         y="712.74872"
+         x="6.5857863"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan13981">      <tspan
+   style="fill:#96b4b4"
+   id="tspan16962">kotlin-mode--</tspan><tspan
+   style="fill:#008b8b"
+   id="tspan16964">find-parent-and-align-with-next</tspan></tspan><tspan
+         y="732.74872"
+         x="6.5857863"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan13983">        ...</tspan><tspan
+         y="752.74872"
+         x="6.5857863"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan13985">      ...</tspan><tspan
+         y="772.74872"
+         x="6.5857863"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan13987" /></text>
+    <text
+       xml:space="preserve"
+       
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:32px;font-family:'Noto
 sans';-inkscape-font-specification:'Noto 
sans';text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="16"
+       y="120"
+       id="text885-5-3-6-7-09-4-0"><tspan
+         sodipodi:role="line"
+         x="16"
+         y="120"
+         id="tspan9310-7-4">Overview of functions for indentation. Details are 
omitted.</tspan></text>
+  </g>
+  <g
+     inkscape:groupmode="layer"
+     id="layer16"
+     inkscape:label="Layer 16"
+     style="display:inline">
+    <text
+       xml:space="preserve"
+       
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:53.33333206px;font-family:'Noto
 Sans';-inkscape-font-specification:'Noto Sans, 
Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:center;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-l
 [...]
+       x="512.52295"
+       y="56.000004"
+       id="text819-9-5-2-1-3-7-8-5-5-2-9-0-8-8"><tspan
+         sodipodi:role="line"
+         id="tspan817-1-6-9-2-9-3-4-5-7-2-6-8-5-8"
+         x="512.52295"
+         y="56.000004">Data types</tspan></text>
+    <text
+       id="text3577-3-4-0-5-3"
+       y="124.24"
+       x="56"
+       
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;font-family:'Noto
 Sans Mono';-inkscape-font-specification:'Noto Sans Mono, 
Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-li
 [...]
+       xml:space="preserve"><tspan
+         y="124.24"
+         x="56"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan13987-7"><tspan
+           style="fill:#96b4b4"
+           id="tspan16816-2">kotlin-mode--</tspan><tspan
+           style="fill:#008b8b"
+           id="tspan16818-4">token</tspan></tspan><tspan
+         y="144.23999"
+         x="56"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan20839">  Lexical tokens.  Consists of the type, the text, 
and the location (start and end) of the token.</tspan><tspan
+         y="164.23999"
+         x="56"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan20841" /><tspan
+         y="184.23999"
+         x="56"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan20849"><tspan
+           style="fill:#96b4b4;fill-opacity:1"
+           id="tspan20853">kotlin-mode--</tspan><tspan
+           style="fill:#008b8b;fill-opacity:1"
+           id="tspan20851">indentation</tspan></tspan><tspan
+         y="204.23999"
+         x="56"
+         sodipodi:role="line"
+         style="fill:#000000;fill-opacity:1"
+         id="tspan20845">  Location of anchor point paired with 
offset.</tspan></text>
+    <text
+       id="text20857"
+       y="323.20001"
+       x="512.52295"
+       
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:53.33333206px;font-family:'Noto
 Sans';-inkscape-font-specification:'Noto Sans, 
Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:center;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-l
 [...]
+       xml:space="preserve"><tspan
+         y="323.20001"
+         x="512.52295"
+         id="tspan20855"
+         sodipodi:role="line">Other notable functions</tspan></text>
+    <text
+       xml:space="preserve"
+       
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;font-family:'Noto
 Sans Mono';-inkscape-font-specification:'Noto Sans Mono, 
Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-li
 [...]
+       x="56"
+       y="391.44"
+       id="text20877"><tspan
+         id="tspan20863"
+         style="fill:#000000;fill-opacity:1"
+         sodipodi:role="line"
+         x="56"
+         y="391.44"><tspan
+           id="tspan20859"
+           style="fill:#96b4b4">kotlin-mode--</tspan><tspan
+           id="tspan20861"
+           style="fill:#008b8b">indent-new-comment-line</tspan></tspan><tspan
+         id="tspan20865"
+         style="fill:#000000;fill-opacity:1"
+         sodipodi:role="line"
+         x="56"
+         y="411.44">  Replacement for indent-new-comment-line.  Break a line, 
indent it, and tweak comment delimiters.</tspan><tspan
+         id="tspan20867"
+         style="fill:#000000;fill-opacity:1"
+         sodipodi:role="line"
+         x="56"
+         y="431.44" /><tspan
+         id="tspan20873"
+         style="fill:#000000;fill-opacity:1"
+         sodipodi:role="line"
+         x="56"
+         y="451.44"><tspan
+           id="tspan20869"
+           style="fill:#96b4b4;fill-opacity:1">kotlin-mode--</tspan><tspan
+           id="tspan20871"
+           
style="fill:#008b8b;fill-opacity:1">post-self-insert</tspan></tspan><tspan
+         id="tspan20875"
+         style="fill:#000000;fill-opacity:1"
+         sodipodi:role="line"
+         x="56"
+         y="471.44">  Do electric indentation.</tspan></text>
+  </g>
+  <flowRoot
+     xml:space="preserve"
+     id="flowRoot2588"
+     
style="fill:black;stroke:none;stroke-opacity:1;stroke-width:1px;stroke-linejoin:miter;stroke-linecap:butt;fill-opacity:1;font-family:'Noto
 
Sans';font-style:normal;font-weight:normal;font-size:32px;letter-spacing:0px;word-spacing:0px;text-anchor:start;text-align:start;-inkscape-font-specification:'Noto
 Sans, 
Normal';font-stretch:normal;font-variant:normal;writing-mode:lr;font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal"><
 [...]
+       id="flowRegion2590"><rect
+         id="rect2592"
+         width="1232"
+         height="304"
+         x="-64"
+         y="384" /></flowRegion><flowPara
+       id="flowPara2594" /></flowRoot></svg>
diff --git a/doc/indentation_logic/src/split_pages.kts 
b/doc/indentation_logic/src/split_pages.kts
new file mode 100644
index 0000000000..a2f1334fb9
--- /dev/null
+++ b/doc/indentation_logic/src/split_pages.kts
@@ -0,0 +1,56 @@
+/**
+ * Write each layer of Inkscape SVG file into separate SVG files.
+ */
+import java.io.File
+import javax.xml.parsers.DocumentBuilderFactory
+import javax.xml.transform.TransformerFactory
+import javax.xml.transform.dom.DOMSource
+import javax.xml.transform.stream.StreamResult
+import org.w3c.dom.Element
+
+val INKSCAPE_NS = "http://www.inkscape.org/namespaces/inkscape";
+
+if (args.size < 1) {
+    System.err.println("Usage: kotlinc-jvm -script split_pages.kts pages.svg")
+    System.exit(-1)
+}
+
+val transformer = TransformerFactory.newInstance().newTransformer()
+
+val inputFile = File(args[0])
+val document = DocumentBuilderFactory
+    .newDefaultInstance()
+    .also { it.setNamespaceAware(true) }
+    .newDocumentBuilder()
+    .parse(inputFile)
+
+val svgElement = document.documentElement
+val childNodes = svgElement.childNodes
+val layers = 0.until(childNodes.length)
+    .map { childNodes.item(it) }
+    .filter { child ->
+        child is Element &&
+            child.localName == "g" &&
+            child.getAttributeNS(INKSCAPE_NS, "groupmode") == "layer"
+    }
+
+for (layer in layers) {
+    svgElement.removeChild(layer)
+}
+
+val outputDirectory = File("pages")
+
+outputDirectory.mkdirs()
+
+for ((index, layer) in layers.withIndex()) {
+    svgElement.appendChild(layer)
+
+    // Assuming `style="display:none"`
+    layer.attributes.removeNamedItem("style")
+
+    val outputFile = File(outputDirectory, "page_%03d.svg".format(index))
+
+    transformer.transform(DOMSource(document), StreamResult(outputFile))
+
+    svgElement.removeChild(layer)
+}
diff --git a/kotlin-mode-indent.el b/kotlin-mode-indent.el
new file mode 100644
index 0000000000..0ca7802ad8
--- /dev/null
+++ b/kotlin-mode-indent.el
@@ -0,0 +1,1955 @@
+;;; kotlin-mode-indent.el --- Major mode for kotlin, indentation -*- 
lexical-binding: t; -*-
+
+;; Copyright (C) 2019 taku0
+
+;; Authors: taku0 (http://github.com/taku0)
+;; Keywords: languages
+;; Package-Requires: ((emacs "24.3"))
+;; Version: 0.0.1
+;; URL: https://github.com/Emacs-Kotlin-Mode-Maintainers/kotlin-mode
+
+;; This file is not part of GNU Emacs.
+
+;; This program is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Routines for indentation
+
+;;; Code:
+
+(require 'rx)
+(require 'cl-lib)
+
+(require 'kotlin-mode-lexer)
+
+;;; Customizations
+
+(defcustom kotlin-mode--basic-offset 4
+  "Amount of indentation for block contents.
+
+Example:
+
+class Foo {
+    func foo() {} // offset of this line
+}"
+  :type 'integer
+  :group 'kotlin
+  :safe 'integerp)
+
+(defcustom kotlin-mode--parenthesized-expression-offset 4
+  "Amount of indentation inside parentheses and square brackets.
+
+Example:
+
+foo(
+    1 // offset of this line
+)"
+  :type 'integer
+  :group 'kotlin
+  :safe 'integerp)
+
+(defcustom kotlin-mode--multiline-statement-offset 4
+  "Amount of indentation for continuations of expressions.
+
+Example:
+
+val x = 1 +
+    2 // offset of this line"
+  :type 'integer
+  :group 'kotlin
+  :safe 'integerp)
+
+(defcustom kotlin-mode--prepend-asterisk-to-comment-line t
+  "Automatically insert a asterisk to each comment line if non-nil.
+
+Example: if the enter key is pressed when the point is after A below,
+
+/*
+ * A
+ */
+
+an asterisk is inserted to the newline:
+
+/*
+ * A
+ *
+ */"
+  :type 'boolean
+  :group 'kotlin
+  :safe 'booleanp)
+
+(defcustom kotlin-mode--insert-space-after-asterisk-in-comment t
+  "Automatically insert a space after asterisk in comment if non-nil.
+
+Example: if an asterisk is inserted before A below,
+
+/*
+A
+ */
+
+a space is inserted after asterisk:
+
+/*
+ * A
+ */"
+  :type 'boolean
+  :group 'kotlin
+  :safe 'booleanp)
+
+(defcustom kotlin-mode--auto-close-multiline-comment t
+  "If non-nil, `indent-new-comment-line' automatically close multiline comment.
+
+Example: when the enter key is pressed after unclosed comment below,
+
+/**
+
+a closing delimiter is inserted automatically:
+
+/**
+ * // cursor is here
+ */"
+  :type 'boolean
+  :group 'kotlin
+  :safe 'booleanp)
+
+(defcustom kotlin-mode--fix-comment-close t
+  "Fix \"* /\" in incomplete multiline comment to \"*/\" if non-nil.
+
+Example:
+
+/*
+ *
+ * // when a slash is inserted here
+
+/*
+ *
+ */ // it become like this
+
+
+/*
+ *
+ * / // rather than like this."
+  :type 'boolean
+  :group 'kotlin
+  :safe 'booleanp)
+
+(defcustom kotlin-mode--break-line-before-comment-close t
+  "If non-nil, break line before the closing delimiter of multiline comments.
+
+Example: if line break is inserted before A below,
+
+/** A */
+
+it becomes like this:
+
+/**
+ * A
+ */
+
+rather than like this:
+
+/**
+ * A */"
+  :type 'boolean
+  :group 'kotlin
+  :safe 'booleanp)
+
+(defcustom kotlin-mode--indent-nonempty-line-in-multiline-string nil
+  "If non-nil, indent nonempty line in multiline string.
+
+`indent-according-to-mode' is no-op otherwise."
+  :type 'boolean
+  :group 'kotlin
+  :safe 'booleanp)
+
+(defcustom kotlin-mode--highlight-anchor nil
+  "Highlight anchor point for indentation if non-nil.
+
+Intended for debugging."
+  :type 'boolean
+  :group 'kotlin
+  :safe 'booleanp)
+
+;;; Constants and variables
+
+(defconst kotlin-mode--statement-parent-tokens
+  '(\( \[ { anonymous-function-parameter-arrow when-expression-arrow
+    bare-else \(\)-before-control-structure-body \; implicit-\;)
+  "Parent tokens for statements.
+
+Parent tokens are tokens before the beginning of statements.")
+
+(defconst kotlin-mode--expression-parent-tokens
+  (append kotlin-mode--statement-parent-tokens
+          '(\, "where" string-chunk-before-template-expression))
+  "Parent tokens for expressions.
+
+Parent tokens are tokens before the beginning of expressions.")
+
+(defvar-local kotlin-mode--anchor-overlay nil)
+(defvar-local kotlin-mode--anchor-overlay-timer nil)
+
+;;; Indentation struct
+
+(defclass kotlin-mode--indentation ()
+  ((position :initarg :position
+             :type number
+             :accessor kotlin-mode--indentation-position
+             :documentation "the position of the anchor point, such as
+the start of the previous line or the start of the class declaration.")
+   (offset :initarg :offset
+           :type number
+           :initform 0
+           :accessor kotlin-mode--indentation-offset
+           :documentation "the offset from the anchor point.  For
+example, when indenting the first line of a class body, its anchor
+point is the start of the class declaration and its offset is
+`kotlin-mode--basic-offset'."))
+  "Indentation.")
+
+;;; Indentation logic
+
+(defun kotlin-mode--indent-line ()
+  "Indent the current line."
+  (let* ((indentation (save-excursion (kotlin-mode--calculate-indent)))
+         (indentation-column
+          (save-excursion
+            (goto-char (kotlin-mode--indentation-position indentation))
+            (+ (current-column) (kotlin-mode--indentation-offset 
indentation))))
+         (current-indent
+          (save-excursion (back-to-indentation) (current-column))))
+    (if (<= (current-column) current-indent)
+        ;; The point is on the left margin.
+        ;; Move the point to the new leftmost non-comment char.
+        (indent-line-to indentation-column)
+      ;; Keep current relative position from leftmost non-comment char.
+      (save-excursion (indent-line-to indentation-column)))
+    (when kotlin-mode--highlight-anchor
+      (kotlin-mode--highlight-anchor indentation))))
+
+(defun kotlin-mode--calculate-indent ()
+  "Return the indentation of the current line."
+  (back-to-indentation)
+
+  (let ((parser-state (syntax-ppss)))
+    (cond
+     ((nth 4 parser-state)
+      ;; If the 4th element of `(syntax-ppss)' is non-nil, the point is on
+      ;; the 2nd or following lines of a multiline comment, because:
+      ;;
+      ;; - The 4th element of `(syntax-ppss)' is nil on the comment starter.
+      ;; - We have called `back-to-indentation`.
+      (kotlin-mode--calculate-indent-of-multiline-comment))
+
+     ((eq (nth 3 parser-state) t)
+      (kotlin-mode--calculate-indent-of-multiline-string))
+
+     ((looking-at "//")
+      (kotlin-mode--calculate-indent-of-single-line-comment))
+
+     (t
+      (kotlin-mode--calculate-indent-of-code)))))
+
+(defun kotlin-mode--calculate-indent-of-multiline-comment ()
+  "Return the indentation of the current line inside a multiline comment."
+  (back-to-indentation)
+  (let ((comment-beginning-position (nth 8 (syntax-ppss)))
+        (starts-with-asterisk (eq (char-after) ?*)))
+    (forward-line -1)
+    (back-to-indentation)
+    (cond
+     ;; 2nd line of the comment
+     ((<= (point) comment-beginning-position)
+      ;; The point was on the 2nd line of the comment.
+      (goto-char comment-beginning-position)
+      (forward-char)
+      ;; If there are extra characters or spaces after asterisks, align with
+      ;; the first non-space character or end of line.  Otherwise, align with
+      ;; the first asterisk.
+      (when (and
+             (looking-at
+              (rx (seq (zero-or-more "*") (one-or-more (not (any "\n*"))))))
+             (not (and kotlin-mode--prepend-asterisk-to-comment-line
+                       starts-with-asterisk)))
+        (skip-chars-forward "*")
+        (skip-syntax-forward " "))
+      (make-instance 'kotlin-mode--indentation :position (point) :offset 0))
+
+     ;; The point was on the 3rd or following lines of the comment.
+
+     ;; Before closing delimiter
+     ((= (save-excursion
+           ;; Back to the original line.
+           (forward-line)
+           (back-to-indentation)
+           (point))
+         (save-excursion
+           ;; Goto just before the closing delimiter.
+           (goto-char comment-beginning-position)
+           (if (forward-comment 1)
+               (progn
+                 ;; slash
+                 (backward-char)
+                 (skip-chars-backward "*")
+                 (point))
+             -1)))
+      ;; Before the closing delimiter.  Align with the first asterisk of the
+      ;; opening delimiter.
+      ;;
+      ;; TODO: If there are multiple asterisks on the closing
+      ;; delimiter, and the middle lines have no leading asterisks,
+      ;; align with the slash of the opening delimiter
+      ;;
+      ;; Example:
+      ;;
+      ;; /*********
+      ;;    aaa
+      ;; **********/
+      (goto-char comment-beginning-position)
+      (forward-char)
+      (make-instance 'kotlin-mode--indentation :position (point) :offset 0))
+
+     ;; Otherwise, align with a non-empty preceding line.
+
+     ;; The previous line is empty
+     ((and (bolp) (eolp))
+      ;; Seek a non-empty-line.
+      (while (and (bolp) (eolp) (not (bobp)))
+        (forward-line -1))
+      (forward-line)
+      (kotlin-mode--calculate-indent-of-multiline-comment))
+
+     ;; The previous line is not empty
+     (t
+      ;; Align to this line.
+      (make-instance 'kotlin-mode--indentation :position (point) :offset 0)))))
+
+(defun kotlin-mode--calculate-indent-of-multiline-string ()
+  "Return the indentation of the current line inside a multiline string."
+  (back-to-indentation)
+  (let ((string-beginning-position
+         (save-excursion (kotlin-mode--beginning-of-string))))
+    (if (looking-at "\"\"\"")
+        ;; Indenting the closing delimiter.  Align with the start of containing
+        ;; expression with extra indentation.
+        ;;
+        ;; Example:
+        ;;
+        ;; val someString = """
+        ;;     Hello.
+        ;;     """
+        ;;
+        ;; When aligning to opening delimiter, align without offset:
+        ;; foo("""
+        ;;     aaa
+        ;;     """)
+        ;;
+        ;; Possible alternative indentation:
+        ;; val someString = """
+        ;;     Hello.
+        ;; """
+        (progn
+          (goto-char string-beginning-position)
+          (let ((indentation
+                 (kotlin-mode--calculate-indent-of-expression
+                  kotlin-mode--multiline-statement-offset)))
+            (if (= (kotlin-mode--indentation-position indentation)
+                   string-beginning-position)
+                (make-instance 'kotlin-mode--indentation
+                               :position string-beginning-position
+                               :offset 0)
+              indentation)))
+      ;; Other than the closing delimiter.
+      (if (and (not (eolp))
+               (not kotlin-mode--indent-nonempty-line-in-multiline-string))
+          ;; The user prefers to keep indentations inside multiline string.
+          (make-instance 'kotlin-mode--indentation :position (point) :offset 0)
+        ;; The user prefers to indent lines inside multiline string.
+        (beginning-of-line)
+        (backward-char)
+        (kotlin-mode--goto-non-template-expression-bol)
+        (back-to-indentation)
+        (cond
+         ;; 2nd line of string
+         ((<= (point) string-beginning-position)
+          ;; The point was on the 2nd line of the string.  Align
+          ;; with the start of containing expression with extra
+          ;; indentation.
+          (goto-char string-beginning-position)
+          (kotlin-mode--calculate-indent-of-expression
+           kotlin-mode--multiline-statement-offset))
+
+         ;; The point was on the 3rd or following lines of the string.
+         ;; Align with a non-empty preceding line.
+
+         ;; The previous line is empty
+         ((and (bolp) (eolp))
+          ;; Seek a non-empty-line.
+          (while (and (bolp) (eolp) (not (bobp)))
+            (forward-line -1))
+          (forward-line)
+          (kotlin-mode--calculate-indent-of-multiline-string))
+
+         ;; The previous line is not empty
+         (t
+          ;; Align to this line.
+          (make-instance 'kotlin-mode--indentation
+                         :position (point)
+                         :offset 0)))))))
+
+(defun kotlin-mode--goto-non-template-expression-bol ()
+  "Back to the beginning of line that is not inside a template expression."
+  (let ((chunk-beginning-position (nth 8 (syntax-ppss)))
+        (matching-bracket t))
+    (while (and matching-bracket
+                (< (line-beginning-position) chunk-beginning-position))
+      (setq matching-bracket
+            (get-text-property
+             chunk-beginning-position 'kotlin-property--matching-bracket))
+      (when matching-bracket
+        (goto-char matching-bracket)
+        (setq chunk-beginning-position (nth 8 (syntax-ppss)))))
+    (beginning-of-line)))
+
+(defun kotlin-mode--calculate-indent-of-single-line-comment ()
+  "Return the indentation of the current line inside a single-line comment."
+  (cond
+   ;; When the comment is beginning of the buffer, indent to the column 0.
+   ((save-excursion
+      (beginning-of-line)
+      (bobp))
+    (make-instance 'kotlin-mode--indentation :position (point-min) :offset 0))
+
+   ;; If the previous line is also a single-line comment, align with it.
+   ((save-excursion
+      (forward-line -1)
+      (skip-syntax-forward " ")
+      (looking-at "//"))
+    (forward-line -1)
+    (skip-syntax-forward " ")
+    (make-instance 'kotlin-mode--indentation :position (point) :offset 0))
+
+   ;; Otherwise, indent like a expression.
+   (t
+    (kotlin-mode--calculate-indent-of-code))))
+
+(defun kotlin-mode--calculate-indent-of-code ()
+  "Return the indentation of the current line outside comments or string."
+  (back-to-indentation)
+  (let* ((previous-token (save-excursion (kotlin-mode--backward-token)))
+         (previous-type (kotlin-mode--token-type previous-token))
+         (previous-text (kotlin-mode--token-text previous-token))
+         (next-token (save-excursion (kotlin-mode--forward-token)))
+         (next-type (kotlin-mode--token-type next-token))
+         (next-text (kotlin-mode--token-text next-token))
+         (next-is-on-current-line
+          (<= (kotlin-mode--token-start next-token) (line-end-position))))
+    (cond
+     ;; Beginning of the buffer
+     ((eq previous-type 'outside-of-buffer)
+      (make-instance 'kotlin-mode--indentation :position (point-min) :offset 
0))
+
+     ;; Before } on the current line.
+     ;; Align with the head of the statement.
+     ((and next-is-on-current-line (eq next-type '}))
+      (goto-char (kotlin-mode--token-end next-token))
+      (backward-list)
+      (kotlin-mode--calculate-indent-after-open-curly-brace 0))
+
+     ;; Before ) or ] on the current line.
+     ;; Align with the head of the expression.
+     ((and next-is-on-current-line
+           (memq next-type '(\) \)-before-control-structure-body \])))
+      (goto-char (kotlin-mode--token-end next-token))
+      (backward-list)
+      (kotlin-mode--calculate-indent-of-expression 0))
+
+     ;; Before close angle bracket for generics (>) on the current line.
+     ((and next-is-on-current-line
+           (equal next-text ">")
+           (save-excursion
+             (goto-char (kotlin-mode--token-end next-token))
+             (eq (kotlin-mode--token-type 
(kotlin-mode--backward-token-or-list))
+                 '<>)))
+      (goto-char (kotlin-mode--token-end next-token))
+      (kotlin-mode--backward-token-or-list)
+      (kotlin-mode--calculate-indent-of-expression 0))
+
+     ;; Before end of a template expression on the current line.
+     ((and next-is-on-current-line
+           (eq next-type 'string-chunk-after-template-expression))
+      (goto-char (get-text-property
+                  (kotlin-mode--token-start next-token)
+                  'kotlin-property--matching-bracket))
+      ;; Skip "${"
+      (forward-char 2)
+      (kotlin-mode--backward-string-chunk)
+      (kotlin-mode--calculate-indent-after-beginning-of-template-expression
+       0))
+
+     ;; Before { on the current line
+     ((and next-is-on-current-line (eq next-type '{))
+      (kotlin-mode--calculate-indent-after-open-curly-brace 0))
+
+     ;; Before "else" on the current line
+     ((and next-is-on-current-line (equal next-text "else"))
+      (kotlin-mode--calculate-indent-of-else))
+
+     ;; Before "where" on the current line
+     ((and next-is-on-current-line (equal next-text "where"))
+      (kotlin-mode--find-parent-and-align-with-next
+       kotlin-mode--statement-parent-tokens
+       kotlin-mode--multiline-statement-offset))
+
+     ;; Before "catch" or "finally" on the current line
+     ((and next-is-on-current-line (member next-text '("catch" "finally")))
+      (kotlin-mode--find-parent-and-align-with-next
+       kotlin-mode--statement-parent-tokens
+       0
+       '()
+       '("catch" "finally")
+       0))
+
+     ;; Before "=" on the current line
+     ;;
+     ;; fun <T> foo(): T
+     ;;     where
+     ;;         T: A,
+     ;;         T: B
+     ;;     = bar()
+     ((and next-is-on-current-line (equal next-text "="))
+      (kotlin-mode--find-parent-and-align-with-next
+       (remove '\, (remove "where" kotlin-mode--expression-parent-tokens))
+       kotlin-mode--multiline-statement-offset))
+
+     ;; Before "," on the current line
+     ((and next-is-on-current-line (eq next-type '\,))
+      (kotlin-mode--calculate-indent-of-prefix-comma))
+
+     ;; After ","
+     ((eq previous-type '\,)
+      (goto-char (kotlin-mode--token-start previous-token))
+      (kotlin-mode--calculate-indent-after-comma))
+
+     ;; After "catch".  Align with "try".
+     ((equal previous-text "catch")
+      (kotlin-mode--find-parent-and-align-with-next
+       kotlin-mode--statement-parent-tokens
+       kotlin-mode--multiline-statement-offset))
+
+     ;; After {
+     ((eq previous-type '{)
+      (goto-char (kotlin-mode--token-start previous-token))
+      (kotlin-mode--calculate-indent-after-open-curly-brace
+       kotlin-mode--basic-offset))
+
+     ;; After ( or [
+     ((memq previous-type '(\( \[))
+      (goto-char (kotlin-mode--token-start previous-token))
+      (kotlin-mode--calculate-indent-of-expression
+       kotlin-mode--parenthesized-expression-offset
+       kotlin-mode--parenthesized-expression-offset))
+
+     ;; After open angle bracket for generics (<)
+     ((and (equal previous-text "<")
+           (save-excursion
+             (goto-char (kotlin-mode--token-start previous-token))
+             (eq (kotlin-mode--token-type (kotlin-mode--forward-token-or-list))
+                 '<>)))
+      (goto-char (kotlin-mode--token-start previous-token))
+      (kotlin-mode--calculate-indent-of-expression
+       kotlin-mode--parenthesized-expression-offset
+       kotlin-mode--parenthesized-expression-offset))
+
+     ;; After beginning of a template expression
+     ((eq previous-type 'string-chunk-before-template-expression)
+      (goto-char (kotlin-mode--token-start previous-token))
+      (kotlin-mode--calculate-indent-after-beginning-of-template-expression
+       kotlin-mode--parenthesized-expression-offset))
+
+     ;; After ; or implicit-\;
+     ((memq previous-type '(\; implicit-\;))
+      (goto-char (kotlin-mode--token-start previous-token))
+      (kotlin-mode--calculate-indent-after-semicolon))
+
+     ;; After "->" of lambda parameters
+     ((eq previous-type 'anonymous-function-parameter-arrow)
+      (goto-char (cdr (kotlin-mode--find-containing-brackets
+                       (kotlin-mode--token-start previous-token))))
+      (kotlin-mode--calculate-indent-after-open-curly-brace
+       kotlin-mode--basic-offset))
+
+     ;; Before "->" of lambda parameters on the current line
+     ((and next-is-on-current-line
+           (eq next-type 'anonymous-function-parameter-arrow))
+      (if (eq (kotlin-mode--token-type (kotlin-mode--backward-token-or-list))
+              '{)
+          (kotlin-mode--calculate-indent-after-open-curly-brace
+           kotlin-mode--basic-offset)
+        (goto-char (cdr (kotlin-mode--find-containing-brackets
+                         (kotlin-mode--token-start next-token))))
+        (kotlin-mode--align-with-next-token (kotlin-mode--forward-token))))
+
+     ;; After "->" of when expression
+     ((eq previous-type 'when-expression-arrow)
+      (goto-char (kotlin-mode--token-start previous-token))
+      (kotlin-mode--find-parent-and-align-with-next
+       (cl-remove-if
+        (lambda (e)
+          (memq e '(when-expression-arrow
+                    bare-else \(\)-before-control-structure-body)))
+        kotlin-mode--statement-parent-tokens)
+       kotlin-mode--basic-offset))
+
+     ;; Before "->" of when expression on the current line
+     ((and next-is-on-current-line (eq next-type 'when-expression-arrow))
+      (if (equal (kotlin-mode--token-text previous-token) "else")
+          (kotlin-mode--align-with-token
+           previous-token
+           kotlin-mode--basic-offset)
+        (kotlin-mode--find-parent-and-align-with-next
+         (cl-remove-if
+          (lambda (e)
+            (memq e '(when-expression-arrow
+                      bare-else \(\)-before-control-structure-body)))
+          kotlin-mode--statement-parent-tokens)
+         kotlin-mode--basic-offset)))
+
+     ;; After "where"
+     ;;
+     ;; class Foo<T>
+     ;;     where
+     ;;         T: A // align with "where" with offset
+     ;;
+     ;; class Foo<T> where
+     ;;     T: A // align with "class" with offset
+     ((equal previous-text "where")
+      (goto-char (kotlin-mode--token-start previous-token))
+      (if (kotlin-mode--bol-other-than-comments-p)
+          (kotlin-mode--align-with-token
+           previous-token
+           kotlin-mode--multiline-statement-offset)
+        (kotlin-mode--find-parent-and-align-with-next
+         kotlin-mode--statement-parent-tokens
+         kotlin-mode--multiline-statement-offset)))
+
+     ;; After if, when, for, or while
+     ((member previous-text '("if" "when" "for" "while"))
+      (kotlin-mode--find-parent-and-align-with-next
+       kotlin-mode--statement-parent-tokens
+       kotlin-mode--multiline-statement-offset))
+
+     ;; After do
+     ((equal previous-text "do")
+      (kotlin-mode--align-with-token
+       previous-token
+       (if (equal next-text "while") 0 kotlin-mode--basic-offset)))
+
+     ;; After else
+     ((equal previous-text "else")
+      (kotlin-mode--align-with-token
+       previous-token
+       kotlin-mode--basic-offset))
+
+     ;; After "if ()", "while ()", or "for ()"
+     ((eq previous-type '\)-before-control-structure-body)
+      (kotlin-mode--backward-token-or-list)
+      (kotlin-mode--find-parent-and-align-with-next
+       kotlin-mode--statement-parent-tokens
+       kotlin-mode--basic-offset
+       '()
+       '("else")
+       kotlin-mode--basic-offset))
+
+     ;; Before ; on the current line
+     ((and next-is-on-current-line (eq next-type '\;))
+      (kotlin-mode--find-parent-and-align-with-next
+       (remove '\; (remove 'implicit-\; kotlin-mode--statement-parent-tokens))
+       0
+       '(\; implicit-\;)))
+
+     ;; Before "in" on the current line
+     ((and next-is-on-current-line (equal next-text "in"))
+      (kotlin-mode--calculate-indent-before-in))
+
+     ;; After "in"
+     ;;
+     ;; Examples:
+     ;; for (
+     ;;     x
+     ;;     in
+     ;;     xs
+     ;; ) {}
+     ;;
+     ;; for (x
+     ;;      in
+     ;;      xs) {[]}
+     ;;
+     ;; when (x) {
+     ;;     in
+     ;;         xs -> y in
+     ;;                   ys
+     ;;     in
+     ;;         zs -> 1
+     ;; }
+     ;;
+     ;; Foo<
+     ;;     in
+     ;;         X,
+     ;;     @AAA in
+     ;;         X
+     ;; >
+     ;;
+     ;; val x = 1 in
+     ;;     array
+     ((equal previous-text "in")
+      (let* ((type-and-parent
+              (save-excursion
+                (goto-char (kotlin-mode--token-start previous-token))
+                (kotlin-mode--find-parent-of-in)))
+             (type (car type-and-parent)))
+        (if (or (memq type '(for <>))
+                (save-excursion
+                  (goto-char (kotlin-mode--token-start previous-token))
+                  (not (kotlin-mode--bol-other-than-comments-p))))
+            ;; for-statement and type parameters, or "in" is not at
+            ;; the beginning of the line.
+            (progn
+              ;; Indent like a expression
+              (goto-char (kotlin-mode--token-start previous-token))
+              (kotlin-mode--calculate-indent-of-expression
+               kotlin-mode--multiline-statement-offset))
+          ;; After "in" at the beginning of the line.
+          ;;
+          ;; Example:
+          ;;
+          ;; when (x) {
+          ;;     in
+          ;;         xs -> 1
+          ;;     in
+          ;;         ys -> 1
+          ;; }
+          ;;
+          ;; Pretend a semicolon exists before "in"
+          (goto-char (kotlin-mode--token-start previous-token))
+          (kotlin-mode--align-with-next-token
+           (kotlin-mode--backward-token)
+           kotlin-mode--multiline-statement-offset))))
+
+     ;; Before "while" on the current line
+     ((and next-is-on-current-line (equal next-text "while"))
+      (let ((do-token (save-excursion (kotlin-mode--find-do-for-while))))
+        (if do-token
+            (kotlin-mode--align-with-token do-token)
+          (kotlin-mode--calculate-indent-after-semicolon))))
+
+     ;; Inside annotation
+     ((or (and (eq previous-type 'annotation)
+               (or
+                ;; @file
+                ;;     : // ← here
+                (eq next-type ':)
+                ;; @file:A
+                ;;     .B // ← here
+                ;; @file:A
+                ;;     <A> // ← here
+                (member next-text '("." "<"))))
+          ;; @file:
+          ;;     [ // ← here
+          (and (eq previous-type ':)
+               (eq next-type '\[)
+               (save-excursion
+                 (goto-char (kotlin-mode--token-start previous-token))
+                 (eq (kotlin-mode--token-type (kotlin-mode--backward-token))
+                     'annotation)))
+          ;; @file:
+          ;;     A // ← here
+          ;; @file:A
+          ;;     .
+          ;;     B // ← here
+          ;; @file:A
+          ;;     <
+          ;;         B
+          ;;     > // ← here
+          (and (or (eq next-type 'atom) (equal next-text ">"))
+               (eq (kotlin-mode--token-type
+                    (save-excursion
+                      (kotlin-mode--extend-annotation-token-backward
+                       next-token)))
+                   'annotation)))
+      (let ((start-of-annotation
+             (cond
+              ((eq previous-type 'annotation)
+               (kotlin-mode--token-start previous-token))
+
+              ((eq previous-type ':)
+               (save-excursion
+                 (goto-char (kotlin-mode--token-start previous-token))
+                 (kotlin-mode--token-start (kotlin-mode--backward-token))))
+
+              (t (kotlin-mode--token-start
+                  (save-excursion 
(kotlin-mode--extend-annotation-token-backward
+                                   next-token))))))
+            (start-of-previous-line
+             (save-excursion
+               (kotlin-mode--backward-token-or-list t)
+               (kotlin-mode--goto-non-comment-bol-with-same-nesting-level t)
+               (point))))
+        (goto-char (max start-of-annotation start-of-previous-line))
+        (kotlin-mode--align-with-current-line
+         (if (< start-of-annotation start-of-previous-line)
+             ;; 3rd or following lines of the annotation.
+             ;; Align with previous line without offset.
+             0
+           ;; 2nd line of the annotation.
+           ;; Align with the start of the annotation with offset.
+           kotlin-mode--multiline-statement-offset))))
+
+     ;; After annotations or labels
+     ((memq previous-type '(annotation label))
+      (goto-char (kotlin-mode--token-start previous-token))
+      ;; Align with preceding annotation or label at the beginning of
+      ;; a line, or indent like an expression if the annotations are in
+      ;; middle of a line.
+      (let ((token previous-token))
+        (while (and (memq (kotlin-mode--token-type token) '(annotation label))
+                    (not (kotlin-mode--bol-other-than-comments-p)))
+          (setq token (kotlin-mode--backward-token)))
+        (unless (memq (kotlin-mode--token-type token) '(annotation label))
+          ;; The annotations are in middle of a line.
+          (goto-char (kotlin-mode--token-end token))))
+      (if (kotlin-mode--bol-other-than-comments-p)
+          ;; The annotations are at the beginning of a line.
+          (kotlin-mode--align-with-current-line)
+        ;; The annotations are in middle of a line.
+        (kotlin-mode--align-with-next-token
+         (kotlin-mode--find-parent-of-expression))))
+
+     ;; Otherwise, it is continuation of the previous line
+     (t
+      (goto-char (kotlin-mode--token-end previous-token))
+      (kotlin-mode--backward-token-or-list)
+      (kotlin-mode--calculate-indent-of-expression
+       kotlin-mode--multiline-statement-offset)))))
+
+(defun kotlin-mode--find-parent-and-align-with-next
+    (parents
+     &optional
+     offset
+     stop-at-eol-token-types
+     stop-at-bol-token-types
+     bol-offset)
+  "Find the parent and return indentation based on it.
+
+A parent is, for example, the open bracket of the containing block or
+semicolon of the preceding statement.
+
+PARENTS is a list of token types that precedes the expression or the statement.
+OFFSET is the offset.  If it is omitted, assumed to be 0.
+See `kotlin-mode--backward-sexps-until' for the details of
+STOP-AT-EOL-TOKEN-TYPES and STOP-AT-BOL-TOKEN-TYPES.
+If scanning stops at STOP-AT-EOL-TOKEN-TYPES, align with the next token with
+BOL-OFFSET.
+If scanning stops at STOP-AT-BOL-TOKEN-TYPES, align with that token with
+BOL-OFFSET.
+If STOP-AT-BOL-TOKEN-TYPES or STOP-AT-BOL-TOKEN-TYPES is the symbol
+`any', it matches all tokens.
+The point is assumed to be on the previous line."
+  (save-excursion
+    (let* ((parent (kotlin-mode--backward-sexps-until
+                    parents
+                    stop-at-eol-token-types
+                    stop-at-bol-token-types))
+           (parent-end (kotlin-mode--token-end parent))
+           (stopped-at-parent
+            (or (memq (kotlin-mode--token-type parent) parents)
+                (member (kotlin-mode--token-text parent) parents)
+                (eq (kotlin-mode--token-type parent) 'outside-of-buffer)))
+           (stopped-at-eol
+            (and
+             (not stopped-at-parent)
+             stop-at-eol-token-types
+             (or
+              (eq stop-at-eol-token-types 'any)
+              (memq (kotlin-mode--token-type parent)
+                    stop-at-eol-token-types)
+              (member (kotlin-mode--token-text parent)
+                      stop-at-eol-token-types)))))
+      (if stopped-at-parent
+          (kotlin-mode--align-with-next-token parent offset)
+        (when stopped-at-eol
+          (goto-char parent-end)
+          (forward-comment (point-max)))
+        (kotlin-mode--align-with-current-line bol-offset)))))
+
+(defun kotlin-mode--calculate-indent-of-expression
+    (&optional
+     offset
+     bol-offset)
+  "Return indentation of the current expression.
+
+the point is assumed to be on the previous line.
+
+OFFSET is the offset.  If it is omitted, assumed to be 0.
+If scanning stops at eol, align with the next token with BOL-OFFSET."
+  (save-excursion
+    (let* ((pos (point))
+           (parent-of-previous-line
+            (save-excursion
+              (kotlin-mode--goto-non-comment-bol-with-same-nesting-level)
+              (kotlin-mode--backward-token)))
+           (parent-of-expression (kotlin-mode--find-parent-of-expression)))
+      ;; Skip annotations
+      (goto-char (kotlin-mode--token-end parent-of-expression))
+      (kotlin-mode--forward-annotations)
+      (kotlin-mode--goto-non-comment-bol-with-same-nesting-level)
+      (when (or (< (point) (kotlin-mode--token-end parent-of-expression))
+                (< pos (point)))
+        (goto-char (kotlin-mode--token-end parent-of-expression)))
+      (setq parent-of-expression (kotlin-mode--backward-token))
+      (if (<= (kotlin-mode--token-start parent-of-previous-line)
+              (kotlin-mode--token-start parent-of-expression))
+          ;; let x =
+          ;;   1 + // indenting here
+          ;;   2 +
+          ;;   3
+          ;;
+          ;; Aligns with the parent of the expression with offset.
+          (kotlin-mode--align-with-next-token parent-of-expression offset)
+        ;; let x =
+        ;;   1 +
+        ;;   2 + // indenting here
+        ;;   3   // or here
+        ;;
+        ;; Aligns with the previous line.
+        (kotlin-mode--align-with-next-token parent-of-previous-line
+                                            bol-offset)))))
+
+(defun kotlin-mode--forward-annotations ()
+  "Skip forward comments, whitespaces, labels, and annotations."
+  (let (token)
+    (while (progn
+             (forward-comment (point-max))
+             (setq token (kotlin-mode--forward-token))
+             (memq (kotlin-mode--token-type token) '(annotation label))))
+    (goto-char (kotlin-mode--token-start token))))
+
+(defun kotlin-mode--backward-annotations ()
+  "Skip backward comments, whitespaces, labels, and annotations."
+  (let (token)
+    (while (progn
+             (forward-comment (- (point)))
+             (setq token (kotlin-mode--backward-token))
+             (memq (kotlin-mode--token-type token) '(annotation label))))
+    (goto-char (kotlin-mode--token-end token))))
+
+(defun kotlin-mode--calculate-indent-after-open-curly-brace (offset)
+  "Return indentation after open curly braces.
+
+Assuming the point is on the open brace.
+OFFSET is the offset of the contents.
+This function is also used for close curly braces."
+  ;; If the statement is multiline expression, aligns with the start of
+  ;; the line on which the open brace is:
+  ;;
+  ;; foo()
+  ;;   .then { x ->
+  ;;       foo()
+  ;;       foo()
+  ;;   }
+  ;;   .then { x ->
+  ;;       foo()
+  ;;       foo()
+  ;;   }
+  ;;
+  ;; rather than
+  ;;
+  ;; foo()
+  ;;   .then { x ->
+  ;;     foo()
+  ;;     foo()
+  ;; }
+  ;;   .then { x ->
+  ;;     foo()
+  ;;     foo()
+  ;; }
+  ;;
+  ;; Otherwise, aligns with the start of the whole statement:
+  ;;
+  ;; class Foo:
+  ;;     Bar {
+  ;;     fun foo() {}
+  ;; }
+  ;;
+  ;; rather than
+  ;;
+  ;; class Foo:
+  ;;     Bar {
+  ;;         fun foo() {}
+  ;;     }
+  ;;
+  ;; POSSIBLE IMPROVEMENT: those behavior should be configurable.
+  ;;
+  ;; FIXME: curly braces after binary operator is a part of a
+  ;; multiline expression:
+  ;;
+  ;; class Foo:
+  ;;     Bar by xs someInfixOperator { x ->
+  ;;       // this is not the body of the class.
+  ;;     } {
+  ;;   // The body of the class.
+  ;; }
+  (let* ((brace-type-and-keyword-token (kotlin-mode--curly-brace-type))
+         (brace-type (car brace-type-and-keyword-token))
+         (keyword-token (cdr brace-type-and-keyword-token)))
+    (cond
+     ((memq brace-type
+            '(object-literal
+              lambda-literal
+              if-expression
+              try-expression
+              catch-block
+              finally-block
+              when-expression))
+      (goto-char (kotlin-mode--token-start keyword-token))
+      (kotlin-mode--backward-annotations)
+      (unless (eq brace-type 'lambda-literal)
+        (forward-comment (point-max)))
+      (kotlin-mode--calculate-indent-of-expression offset offset))
+
+     ((eq brace-type 'else-block)
+      (goto-char (kotlin-mode--token-start keyword-token))
+      (kotlin-mode--calculate-indent-of-else offset))
+
+     ((eq brace-type 'when-entry)
+      (goto-char (kotlin-mode--token-start keyword-token))
+      (if (equal (kotlin-mode--token-text
+                  (save-excursion (kotlin-mode--backward-token)))
+                 "else")
+          (kotlin-mode--align-with-token (kotlin-mode--backward-token) offset)
+        (kotlin-mode--find-parent-and-align-with-next
+         (remove 'when-expression-arrow kotlin-mode--statement-parent-tokens)
+         offset)))
+
+     ((memq brace-type '(getter setter))
+      (goto-char (kotlin-mode--token-start keyword-token))
+      (kotlin-mode--try-backward-modifiers)
+      (kotlin-mode--align-with-next-token (kotlin-mode--backward-token) 
offset))
+
+     (t
+      (goto-char (kotlin-mode--token-start keyword-token))
+      (kotlin-mode--find-parent-and-align-with-next
+       kotlin-mode--statement-parent-tokens
+       offset)))))
+
+(defun kotlin-mode--curly-brace-type ()
+  "Return information about curly brace.
+
+Return a cons (TYPE . KEYWORD-TOKEN) where TYPE is a symbol, and KEYWORD-TOKEN
+is the keyword token:
+- TYPE: class-declaration, KEYWORD-TOKEN: \"class\"
+- TYPE: interface-declaration, KEYWORD-TOKEN: \"interface\"
+- TYPE: object-declaration, KEYWORD-TOKEN: \"object\"
+- TYPE: enum-entry, KEYWORD-TOKEN: identifier
+- TYPE: object-literal, KEYWORD-TOKEN: \"object\"
+- TYPE: anonymous-initializer, KEYWORD-TOKEN: \"init\"
+- TYPE: function-declaration, KEYWORD-TOKEN: \"fun\"
+- TYPE: getter, KEYWORD-TOKEN: \"get\"
+- TYPE: setter, KEYWORD-TOKEN: \"set\"
+- TYPE: secondary-constructor, KEYWORD-TOKEN: \"constructor\"
+- TYPE: for-statement, KEYWORD-TOKEN: \"for\"
+- TYPE: while-statement, KEYWORD-TOKEN: \"while\"
+- TYPE: do-while-statement, KEYWORD-TOKEN: \"do\"
+- TYPE: if-expression, KEYWORD-TOKEN: \"if\"
+- TYPE: else-block, KEYWORD-TOKEN: \"else\"
+- TYPE: when-entry, KEYWORD-TOKEN: \"->\"
+- TYPE: try-expression, KEYWORD-TOKEN: \"try\"
+- TYPE: catch-block, KEYWORD-TOKEN: \"catch\"
+- TYPE: finally-block, KEYWORD-TOKEN: \"finally\"
+- TYPE: lambda-literal, KEYWORD-TOKEN: \"{\"
+- TYPE: when-expression, KEYWORD-TOKEN: \"when\"
+
+Assuming the point is just before the open curly brace."
+  ;; Other braces may appear between the keyword and the open brace:
+  ;;
+  ;; class Foo: Bar by if (aaa) {bbb} else {ccc} {
+  ;; }
+  ;;
+  ;; So we maintain stack of braces and match them with keywords.
+  (save-excursion
+    (let* ((pos (point))
+           (open-brace-points (list pos))
+           (containing-brackets (kotlin-mode--find-containing-brackets 
(point)))
+           previous-token
+           previous-type
+           previous-text
+           brace-type
+           result)
+      ;; Special handling for enumEntry.
+      (goto-char (cdr containing-brackets))
+      (when (eq (car containing-brackets) '{)
+        (let ((token (kotlin-mode--backward-sexps-until
+                      (append kotlin-mode--statement-parent-tokens
+                              '("enum")))))
+          (when (equal (kotlin-mode--token-text token) "enum")
+            (goto-char pos)
+            (when (eq (kotlin-mode--token-type
+                       (kotlin-mode--backward-sexps-until
+                        kotlin-mode--statement-parent-tokens))
+                      '{)
+              ;; This must be a enumEntry.
+              (goto-char pos)
+              (setq previous-token (kotlin-mode--backward-token-or-list))
+              (when (eq (kotlin-mode--token-type previous-token) '\(\))
+                (setq previous-token (kotlin-mode--backward-token-or-list)))
+              (setq result (cons 'enum-entry previous-token))))))
+      (unless result
+        ;;  Other cases
+        (goto-char pos)
+        (while open-brace-points
+          (setq previous-token (kotlin-mode--backward-token-or-list))
+          (setq previous-type (kotlin-mode--token-type previous-token))
+          (setq previous-text (kotlin-mode--token-text previous-token))
+
+          (cond
+           ;; whenEntry.
+           ;; Stop immediately.
+           ((eq previous-type 'when-expression-arrow)
+            (setq result (cons 'when-entry previous-token))
+            (setq open-brace-points nil))
+
+           ;; Hit beginning of the statement without seeing keyword.
+           ;; Assume it is a lambda expression and stop the loop.
+           ((or (eq previous-type 'outside-of-buffer)
+                (memq previous-type kotlin-mode--statement-parent-tokens)
+                (member previous-text kotlin-mode--statement-parent-tokens))
+            (setq result (cons 'lambda-literal
+                               (progn
+                                 (goto-char pos)
+                                 (kotlin-mode--forward-token))))
+            (setq open-brace-points nil))
+
+           ;; Found another braces.
+           ;; Push it to the stack and continue the loop.
+           ((eq previous-type '{})
+            (push (point) open-brace-points))
+
+           ;; Simple cases.
+           ;; Those cannot be a part of an expression.
+           ;; Stop immediately.
+           ((member previous-text
+                    '("class" "interface" "init" "fun" "get" "set"
+                      "for" "while" "do"))
+            (setq brace-type (assoc-default
+                              previous-text
+                              '(("class" . class-declaration)
+                                ("interface" . interface-declaration)
+                                ("init" . anonymous-initializer)
+                                ;; FIXME handle anonymous function
+                                ("fun" . function-declaration)
+                                ("get" . getter)
+                                ("set" . setter)
+                                ("for" . for-statement)
+                                ("while" . while-statement)
+                                ("do" . do-while-statement))))
+            (setq result (cons brace-type previous-token))
+            (setq open-brace-points nil))
+
+           ;; Semi-simple cases.
+           ;; Those can be a part of an expression and the braces are 
mandatory.
+           ((member previous-text '("try" "catch" "finally" "when"))
+            (pop open-brace-points)
+            (when (null open-brace-points)
+              (setq brace-type (assoc-default
+                                previous-text
+                                '(("try" . try-expression)
+                                  ("catch" . catch-block)
+                                  ("finally" . finally-block)
+                                  ("when" . when-expression))))
+              (setq result (cons brace-type previous-token))))
+
+           ;; If and else.
+           ;; Those can be a part of an expression and the braces are optional.
+           ((member previous-text '("if" "else"))
+            (save-excursion
+              (goto-char (kotlin-mode--token-end previous-token))
+              (when (equal previous-text "if")
+                (kotlin-mode--forward-token-or-list))
+
+              (forward-comment (point-max))
+              (when (= (point) (car open-brace-points))
+                (pop open-brace-points)
+                (when (null open-brace-points)
+                  (setq brace-type
+                        (if (equal previous-text "if")
+                            'if-expression
+                          'else-block))
+                  (setq result (cons brace-type previous-token))))))
+
+           ;; Object declaration or object literal.
+           ((equal previous-text "object")
+            (setq brace-type
+                  (cond
+                   ((save-excursion
+                      (equal (kotlin-mode--token-text
+                              (kotlin-mode--backward-token))
+                             "companion"))
+                    'object-declaration)
+                   ((save-excursion
+                      (goto-char (kotlin-mode--token-end previous-token))
+                      (eq (kotlin-mode--token-type 
(kotlin-mode--forward-token))
+                          'atom))
+                    'object-declaration)
+                   (t 'object-literal)))
+            (pop open-brace-points)
+            (when (or (null open-brace-points)
+                      (eq brace-type 'object-declaration))
+              (setq result (cons brace-type previous-token))
+              (setq open-brace-points nil)))
+
+           ;; Primary constructor or secondary constructor.
+           ((equal previous-text "constructor")
+            (let ((parent-token
+                   (kotlin-mode--backward-sexps-until
+                    (append kotlin-mode--statement-parent-tokens '("class")))))
+              (if (equal (kotlin-mode--token-text parent-token) "class")
+                  ;; primary constructor
+                  (setq result (cons 'class-declaration parent-token))
+                ;; secondary constructor
+                (setq result (cons 'secondary-constructor previous-token)))
+              (setq open-brace-points nil))))))
+      result)))
+
+(defun kotlin-mode--calculate-indent-of-else (&optional offset)
+  "Return indentation for \"else\" token with OFFSET."
+  ;; Align it with "if" token.
+  ;; Since if-else can be nested, we keep nesting level to find matching "if".
+  (let ((nesting-level 1)
+        previous-token)
+    (while (< 0 nesting-level)
+      (setq previous-token (kotlin-mode--backward-token-or-list))
+      (cond
+       ((equal (kotlin-mode--token-text previous-token) "else")
+        (setq nesting-level (1+ nesting-level)))
+
+       ((equal (kotlin-mode--token-text previous-token) "if")
+        (if (save-excursion
+              ;; "else if" on the same line
+              (and
+               (equal (kotlin-mode--token-text (kotlin-mode--backward-token))
+                      "else")
+               (= (progn (kotlin-mode--goto-non-comment-bol)
+                         (point))
+                  (progn (goto-char (kotlin-mode--token-start previous-token))
+                         (kotlin-mode--goto-non-comment-bol)
+                         (point)))))
+            ;; Skip "else-if" without changing nesting-level.
+            (kotlin-mode--backward-token)
+          (setq nesting-level (1- nesting-level))))
+
+       ((memq (kotlin-mode--token-type previous-token)
+              '({ \( outside-of-buffer))
+        ;; Unmatched if-else
+        (setq nesting-level 0)))))
+  (kotlin-mode--forward-token)
+  (kotlin-mode--calculate-indent-of-expression (or offset 0) (or offset 0)))
+
+(defun kotlin-mode--calculate-indent-of-prefix-comma ()
+  "Return indentation for prefix comma.
+
+Example:
+
+foo( 1
+   , 2
+   , 3
+)
+
+class Foo: A
+         , B
+         , C
+
+class D<A, B, C>
+    where A: AAA
+        , B: BBB
+        , C: CCC
+
+This is also known as Utrecht-style in the Haskell community."
+  (let ((parent (kotlin-mode--find-parent-of-list-element t)))
+    (if (eq (kotlin-mode--token-type parent) '\,)
+        ;; The comma was the 2nd or the following commas.
+        ;; Align with the previous comma.
+        (kotlin-mode--align-with-current-line)
+      ;; The comma was the 1st comma.
+      ;; Align with the end of the parent.
+      (goto-char (kotlin-mode--token-end parent))
+      (backward-char)
+      (make-instance 'kotlin-mode--indentation :position (point) :offset 0))))
+
+(defun kotlin-mode--calculate-indent-after-comma ()
+  "Return indentation after comma.
+
+Assuming the point is on the comma."
+  (kotlin-mode--align-with-next-token
+   (kotlin-mode--find-parent-of-list-element nil)))
+
+(defun kotlin-mode--find-parent-of-list-element (&optional utrecht-style)
+  "Move point backward to the parent token of the comma under the point.
+
+If UTRECHT-STYLE is non-nil, stop at a comma at bol.  Otherwise, stop at a
+comma at eol."
+  ;; Various examples:
+  ;;
+  ;; val x = foo( // simple case
+  ;;   1,
+  ;;   2,
+  ;;   3
+  ;; )
+  ;;
+  ;; val x = xs[
+  ;;   1,
+  ;;   2,
+  ;;   3
+  ;; ]
+  ;;
+  ;; class Foo<A>: A1(),
+  ;;               B1 by object: C1,
+  ;;                             C2 {
+  ;;               },
+  ;;               @AAA D1
+  ;;     where A: B,
+  ;;           A: C,
+  ;;           A: D {
+  ;; }
+  ;;
+  ;; when (foo) {
+  ;;     object: B1,
+  ;;             B2 {
+  ;;     },
+  ;;     object: B3 by object: B4 {
+  ;;             },
+  ;;             B5 {
+  ;;     } ->
+  ;;         1
+  ;; }
+  ;;
+  ;; fun <T>foo(x: T): Int
+  ;;     where
+  ;;         T: A,
+  ;;         T: B,
+  ;;         T: C {
+  ;; }
+  ;;
+  ;; val <T> A<T>.foo: Int
+  ;;     where
+  ;;         T: A,
+  ;;         T: B,
+  ;;         T: C
+  ;;     get() = aaa
+  ;;
+  ;; enum class Foo(x: Int) {
+  ;;   A(1), B(2) {},
+  ;;   C(3)
+  ;; }
+  (let ((parent (kotlin-mode--backward-sexps-until
+                 (append
+                  (remove '\, kotlin-mode--expression-parent-tokens)
+                  '("<" : {}))
+                 (if utrecht-style nil '(\,))
+                 (if utrecht-style '(\,) nil))))
+    (cond
+     ((equal (kotlin-mode--token-text parent) "<")
+      (if (save-excursion
+            (eq (kotlin-mode--token-type (kotlin-mode--forward-token-or-list))
+                '<>))
+          parent
+        (kotlin-mode--find-parent-of-list-element utrecht-style)))
+
+     ((eq (kotlin-mode--token-type parent) '{})
+      (let* ((brace-type-and-keyword-token (kotlin-mode--curly-brace-type))
+             (keyword-token (cdr brace-type-and-keyword-token)))
+        (goto-char (kotlin-mode--token-start keyword-token)))
+      (kotlin-mode--find-parent-of-list-element utrecht-style))
+
+     ((eq (kotlin-mode--token-type parent) ':)
+      (if (kotlin-mode--colon-before-delegation-specifiers-p parent)
+          parent
+        (kotlin-mode--find-parent-of-list-element utrecht-style)))
+
+     (t
+      parent))))
+
+(defun kotlin-mode--find-parent-of-expression ()
+  "Move point backward to the parent token of the expression under the point."
+  ;; TODO Unify with kotlin-mode--find-parent-of-list-element
+  (let ((parent (kotlin-mode--backward-sexps-until
+                 (append kotlin-mode--expression-parent-tokens '("<" : {})))))
+    (cond
+     ((equal (kotlin-mode--token-text parent) "<")
+      (if (save-excursion
+            (eq (kotlin-mode--token-type (kotlin-mode--forward-token-or-list))
+                '<>))
+          parent
+        (kotlin-mode--find-parent-of-expression)))
+
+     ((eq (kotlin-mode--token-type parent) '{})
+      (let* ((brace-type-and-keyword-token (kotlin-mode--curly-brace-type))
+             (keyword-token (cdr brace-type-and-keyword-token)))
+        (goto-char (kotlin-mode--token-start keyword-token)))
+      (kotlin-mode--find-parent-of-expression))
+
+     ((eq (kotlin-mode--token-type parent) ':)
+      (if (kotlin-mode--colon-before-delegation-specifiers-p parent)
+          parent
+        (kotlin-mode--find-parent-of-expression)))
+
+     (t
+      parent))))
+
+(defun kotlin-mode--colon-before-delegation-specifiers-p (token)
+  "Return non-nil if TOKEN is a colon before delegationSpecifiers."
+  (and
+   (eq (kotlin-mode--token-type token) ':)
+   (save-excursion
+     (goto-char (kotlin-mode--token-start token))
+     (let (previous-token)
+       ;; Try backward primaryConstructor.
+       (forward-comment (- (point)))
+       (when (eq (char-before) ?\))
+         (kotlin-mode--backward-token-or-list)
+         (setq previous-token (kotlin-mode--backward-token))
+         (if (equal (kotlin-mode--token-text previous-token) "constructor")
+             (kotlin-mode--try-backward-modifiers)
+           (goto-char (kotlin-mode--token-end previous-token))))
+       (kotlin-mode--try-backward-type-parameters)
+       (setq previous-token (kotlin-mode--backward-token-or-list))
+       (or
+        (equal (kotlin-mode--token-text previous-token) "object")
+        (and
+         (eq (kotlin-mode--token-type previous-token) 'atom)
+         (member (kotlin-mode--token-text 
(kotlin-mode--backward-token-or-list))
+                 '("class" "interface" "object"))))))))
+
+(defun kotlin-mode--calculate-indent-after-beginning-of-template-expression
+    (offset)
+  "Return indentation after the beginning of a template expression.
+
+It has offset specified with OFFSET.
+
+Assuming the point is before the string chunk."
+  (let ((pos (point)))
+    (kotlin-mode--forward-string-chunk)
+    (if (< pos (line-beginning-position))
+        ;; The chunk has multiple lines.  Align with this line with offset.
+        (progn
+          (back-to-indentation)
+          (make-instance 'kotlin-mode--indentation
+                         :position (point)
+                         :offset offset))
+      ;; The chunk is single line.  Indent like a expression.
+      (goto-char pos)
+      (kotlin-mode--calculate-indent-of-expression offset offset))))
+
+(defun kotlin-mode--calculate-indent-after-semicolon ()
+  "Return indentation after semicolon.
+
+Assuming the point is after the semicolon."
+  (while (save-excursion
+           (memq (kotlin-mode--token-type (kotlin-mode--backward-token))
+                 '(\; implicit-\;)))
+    (kotlin-mode--backward-token))
+  (kotlin-mode--find-parent-and-align-with-next
+   (cl-remove-if
+    (lambda (e)
+      (member e '(\; implicit-\; bare-else
+                  \(\)-before-control-structure-body when-expression-arrow)))
+    kotlin-mode--statement-parent-tokens)
+   0
+   '(\; implicit-\;)))
+
+(defun kotlin-mode--calculate-indent-before-in ()
+  "Return indentation after \"in\" token.
+
+Assuming the point is before the token.
+It is also assumed that the point is not just after \"{\" or \"<\"."
+  (let* ((type-and-parent (kotlin-mode--find-parent-of-in))
+         (type (car type-and-parent))
+         (parent (cdr type-and-parent)))
+    (if (memq type '(for when <>))
+        (kotlin-mode--align-with-next-token parent)
+      (kotlin-mode--calculate-indent-after-semicolon))))
+
+(defun kotlin-mode--find-parent-of-in ()
+  "Return parent token of \"in\" token.
+
+Return a cons (TYPE . PARENT) where TYPE is one of symbol `for',
+`when', `<>', or `other' and PARENT is the parent token, one of
+`;', `implicit-;', `(', `{', or \"<\".
+
+Assuming the point is before the token."
+  ;; Examples:
+  ;; for (
+  ;;     x
+  ;;     in // Align with token after "("
+  ;;     xs
+  ;; ) {}
+  ;;
+  ;; for (x
+  ;;      in
+  ;;      xs) {[]}
+  ;;
+  ;; when (x) {
+  ;;     in xs -> 1
+  ;;     in ys -> 1
+  ;; }
+  ;;
+  ;; Foo<
+  ;;     in X,
+  ;;     @AAA
+  ;;     in X
+  ;; >
+  ;;
+  ;; val x = 1 // Line breaks are prohibited before infix "in" operator.
+  ;; in array
+  (let ((parent (save-excursion (kotlin-mode--backward-sexps-until
+                                 '(\; implicit-\; \( { "<")))))
+    (cond
+     ;; Inside "for ()"
+     ((and
+       (eq (kotlin-mode--token-type parent) '\()
+       (save-excursion
+         (goto-char (kotlin-mode--token-start parent))
+         (equal (kotlin-mode--token-text (kotlin-mode--backward-token)) 
"for")))
+      (cons 'for parent))
+
+     ;; Inside "when () {}"
+     ((and
+       (eq (kotlin-mode--token-type parent) '{)
+       (save-excursion
+         (goto-char (kotlin-mode--token-start parent))
+         (eq (kotlin-mode--token-type (kotlin-mode--backward-token-or-list))
+             '\(\))
+         (equal (kotlin-mode--token-text (kotlin-mode--backward-token))
+                "when")))
+      (cons 'when parent))
+
+     ;; Inside type parameters
+     ((equal (kotlin-mode--token-text parent) "<")
+      (if (save-excursion
+            (goto-char (kotlin-mode--token-start parent))
+            (eq (kotlin-mode--token-type
+                 (kotlin-mode--forward-token-or-list))
+                '<>))
+          (cons '<> parent)
+        (save-excursion
+          (goto-char (kotlin-mode--token-start parent))
+          (kotlin-mode--find-parent-of-in))))
+
+     (t
+      (cons 'other parent)))))
+
+(defun kotlin-mode--backward-sexps-until (token-types
+                                          &optional
+                                          stop-at-eol-token-types
+                                          stop-at-bol-token-types)
+  "Backward sexps until a token with one of given token types appears.
+
+Return the token.
+When this function returns, the point is at the start of the token.
+
+TOKEN-TYPES is a list of guard token types.  This function backs to a
+token with one of those token types.
+STOP-AT-EOL-TOKEN-TYPES is a list of token types that if we skipped
+the end of a line just after a token with one of given token type, the
+function returns.  Typically, this is a list of token types that
+separates list elements (e.g.  ',', ';').  If STOP-AT-EOL-TOKEN-TYPES
+is the symbol `any', it matches all tokens.
+STOP-AT-BOL-TOKEN-TYPES is a list of token types that if we hit the
+beginning of a line just before a token with one of given token types,
+the function returns.  Typically, this is a list of token types that
+starts list element .  If STOP-AT-BOL-TOKEN-TYPES is the symbol `any',
+it matches all tokens."
+  (let*
+      ((parent (kotlin-mode--backward-token-or-list))
+       (type (kotlin-mode--token-type parent))
+       (text (kotlin-mode--token-text parent)))
+    (while (not
+            ;; Stop loop when...
+            (or
+             ;; Hit a guard token.
+             (memq type token-types)
+             (member text token-types)
+
+             ;; Beginning of the buffer.
+             (eq type 'outside-of-buffer)
+
+             ;; When this function is called on "," token before position (1),
+             ;; this function stops just before the "," token after "Foo".
+             ;;
+             ;; Foo,
+             ;; Bar, Baz, // (1)
+             ;; AAA
+             (and stop-at-eol-token-types
+                  (or (eq stop-at-eol-token-types 'any)
+                      (member type stop-at-eol-token-types)
+                      (member text stop-at-eol-token-types))
+                  (save-excursion
+                    (kotlin-mode--forward-token-or-list)
+                    (forward-comment (- (point)))
+                    (kotlin-mode--eol-other-than-comments-p)))
+
+             ;; When this function is called on "," token before position
+             ;; (1), this function stops just before ", Bar".
+             ;;
+             ;; , Foo
+             ;; , Bar, Baz:
+             ;; , AAA // (1)
+             (and stop-at-bol-token-types
+                  (and
+                   (or
+                    (eq stop-at-bol-token-types 'any)
+                    (member type stop-at-bol-token-types)
+                    (member text stop-at-bol-token-types))
+                   (kotlin-mode--bol-other-than-comments-p)))))
+      (setq parent (kotlin-mode--backward-token-or-list))
+      (setq type (kotlin-mode--token-type parent))
+      (setq text (kotlin-mode--token-text parent)))
+    parent))
+
+(defun kotlin-mode--align-with-next-token (parent &optional offset)
+  "Return indentation with the next token of PARENT with OFFSET.
+
+Example:
+
+Suppose indenting \"B\":
+
+foo {
+  /* */ A()
+  B()
+}
+
+The parent is \"{\".  We align with the comment before \"A\"."
+  (let ((parent-end (kotlin-mode--token-end parent)))
+    (goto-char parent-end)
+    (forward-comment (point-max))
+    (kotlin-mode--goto-non-comment-bol)
+    (when (< (point) parent-end)
+      (goto-char parent-end))
+    (kotlin-mode--skip-whitespaces)
+    (make-instance 'kotlin-mode--indentation
+                   :position (point)
+                   :offset (or offset 0))))
+
+(defun kotlin-mode--align-with-token (token &optional offset)
+  "Return indentation with the TOKEN with OFFSET.
+
+If the token is preceded by comments on the same line, align with that
+comments instead.
+
+Example:
+
+Suppose indenting \"B\":
+
+foo {
+  /* */ A()
+  B()
+}
+
+We align with the comment before \"A\"."
+  (goto-char (kotlin-mode--token-start token))
+  (forward-comment (- (point)))
+  (kotlin-mode--align-with-next-token (kotlin-mode--backward-token) offset))
+
+(defun kotlin-mode--align-with-current-line (&optional offset)
+  "Return indentation of the current line with OFFSET."
+  (kotlin-mode--goto-non-comment-bol)
+  (kotlin-mode--skip-whitespaces)
+  (make-instance 'kotlin-mode--indentation
+                 :position (point)
+                 :offset (or offset 0)))
+
+(defun kotlin-mode--goto-non-comment-bol-with-same-nesting-level
+    (&optional use-backward-token-simple)
+  "Back to the beginning of line that is not inside a comment.
+
+See `kotlin-mode--backward-token-or-list' for USE-BACKWARD-TOKEN-SIMPLE."
+  (while (not (kotlin-mode--bol-other-than-comments-p))
+    (kotlin-mode--backward-token-or-list use-backward-token-simple)))
+
+
+;;; indent-new-comment-line
+
+(defun kotlin-mode--indent-new-comment-line (&optional soft)
+  "Break the line at the point and indent the new line.
+
+If the point is inside a comment, continue the comment.  If the comment is a
+multiline comment, close the previous comment and start new one if
+`comment-multi-line' is nil.
+See `indent-new-comment-line' for SOFT."
+  (interactive)
+  (let* ((chunk (kotlin-mode--chunk-after))
+         (comment-beginning-position (kotlin-mode--chunk-start chunk)))
+    (if soft (insert-and-inherit ?\n) (newline 1))
+    (delete-horizontal-space)
+
+    ;; Insert a prefix and indent the line.
+    (cond
+     ((not (kotlin-mode--chunk-comment-p chunk))
+      (indent-according-to-mode))
+
+     ((kotlin-mode--chunk-single-line-comment-p chunk)
+      (insert-and-inherit
+       (save-excursion
+         (goto-char comment-beginning-position)
+         (looking-at "/+\\s *")
+         (match-string-no-properties 0)))
+      (indent-according-to-mode))
+
+     ((not comment-multi-line)
+      (insert-and-inherit
+       (save-excursion
+         (goto-char comment-beginning-position)
+         (looking-at "/\\*+\\s *")
+         (match-string-no-properties 0)))
+      ;; Clean up and close the previous line.
+      (save-excursion
+        (beginning-of-line)
+        (backward-char)
+        (delete-horizontal-space)
+        (insert-and-inherit " */"))
+      (indent-according-to-mode))
+
+     (t
+      (kotlin-mode--format-multiline-comment-line-after-newline chunk soft)))
+    ;; Clean up the previous line.
+    (save-excursion
+      (beginning-of-line)
+      (backward-char)
+      (delete-horizontal-space))))
+
+(defun kotlin-mode--format-multiline-comment-line-after-newline (chunk soft)
+  "Insert prefix and indent current line in multiline comment.
+
+The point is assumed inside multiline comment and just after newline.
+
+The closing delimiter is also inserted and/or formatted depending on custom
+variables `kotlin-mode--auto-close-multiline-comment' and
+`kotlin-mode--break-line-before-comment-close'.
+
+CHUNK is the comment chunk.
+
+See `indent-new-comment-line' for SOFT."
+  (let ((comment-beginning-position (kotlin-mode--chunk-start chunk)))
+    (cond
+     ((save-excursion
+        (forward-line -1)
+        (<= (point) comment-beginning-position))
+      ;; The point was on the 2nd line of the comment.
+
+      ;; If the comment have only one line, delete a space after asterisk.
+      ;;
+      ;; Example:
+      ;; /** aaa */
+      ;; ↓
+      ;; /**
+      ;;  * aaa
+      ;;  */
+      ;;
+      ;; /**  aaa */
+      ;; ↓
+      ;; /**
+      ;;  *  aaa
+      ;;  */
+      ;;
+      ;;
+      ;; If the comment spans several lines, keep spaces.
+      ;;
+      ;; /** aaa
+      ;;  */
+      ;; ↓
+      ;; /**
+      ;;  *  aaa
+      ;;  */
+      (when (= (line-beginning-position)
+               (save-excursion
+                 (goto-char comment-beginning-position)
+                 (forward-comment 1)
+                 (line-beginning-position)))
+        (save-excursion
+          (goto-char comment-beginning-position)
+          (forward-char)
+          (skip-chars-forward "*")
+          (when (looking-at " [ \t]*$")
+            (delete-char 1))))
+
+      ;; If the point is just before the closing delimiter, break the line.
+      (when (and kotlin-mode--break-line-before-comment-close
+                 (= (point)
+                    (save-excursion
+                      (goto-char comment-beginning-position)
+                      (if (forward-comment 1)
+                          (progn
+                            (backward-char)
+                            (skip-chars-backward "*")
+                            (point))
+                        -1))))
+        (save-excursion
+          (if soft (insert-and-inherit ?\n) (newline 1))
+          (indent-according-to-mode)))
+
+      ;; Invoke `kotlin-mode--indent-line`.
+      (indent-according-to-mode)
+
+      ;; Insert or replace a space to an asterisk.
+      (when kotlin-mode--prepend-asterisk-to-comment-line
+        (let ((columns-from-end (- (line-end-position) (point))))
+          (move-to-column
+           (save-excursion
+             (goto-char comment-beginning-position)
+             (forward-char)
+             (current-column)))
+          (insert-and-inherit "*")
+          (when (eq (char-after) ?\s)
+            (delete-char 1))
+          (when (and
+                 kotlin-mode--insert-space-after-asterisk-in-comment
+                 (not (eq (char-after) ?\s)))
+            (insert-and-inherit " "))
+          (goto-char (- (line-end-position) columns-from-end)))))
+
+     ;; The point was on the 3nd or following lines of
+     ;; the comment.
+     ;; Use the prefix of the previous line.
+
+     ((and
+       kotlin-mode--prepend-asterisk-to-comment-line
+       (save-excursion
+         (forward-line -1)
+         (looking-at "\\s *\\(\\*+\\s *\\)")))
+      ;; The previous line has a prefix.  Use it.
+      (insert-and-inherit (match-string-no-properties 1))
+      (indent-according-to-mode))
+
+     (t
+      ;; Use the default indentation.
+      (indent-according-to-mode)))
+
+    ;; Close incomplete multiline comment.
+    (when (and kotlin-mode--auto-close-multiline-comment
+               (kotlin-mode--incomplete-comment-p chunk))
+      (save-excursion
+        (end-of-line)
+        (when comment-multi-line
+          (if soft (insert-and-inherit ?\n) (newline 1)))
+        (insert-and-inherit "*/")
+        (indent-according-to-mode)))
+
+    ;; Make sure the closing delimiter is on its own line.
+    (when kotlin-mode--break-line-before-comment-close
+      (save-excursion
+        (goto-char comment-beginning-position)
+        (when (forward-comment 1)
+          (backward-char)
+          (skip-chars-backward "*")
+          (skip-syntax-backward " ")
+          (when (not (bolp))
+            (if soft (insert-and-inherit ?\n) (newline 1))
+            (indent-according-to-mode)))))))
+
+(defun kotlin-mode--post-self-insert ()
+  "Miscellaneous logic for electric indentation."
+  (cond
+   ;; Indent electrically and insert a space when "*" is inserted at the
+   ;; beginning of a line inside a multiline comment.
+   ((and
+     kotlin-mode--prepend-asterisk-to-comment-line
+     (eq last-command-event ?*)
+     (kotlin-mode--chunk-comment-p (kotlin-mode--chunk-after))
+     (save-excursion (backward-char) (skip-syntax-backward " ") (bolp)))
+    (when kotlin-mode--insert-space-after-asterisk-in-comment
+      (insert-and-inherit " "))
+    (when electric-indent-mode
+      (indent-according-to-mode)))
+
+   ;; Fixe "* /" at the end of a multiline comment to "*/".
+   ((and
+     kotlin-mode--fix-comment-close
+     (eq last-command-event ?/)
+     (let ((chunk (kotlin-mode--chunk-after))
+           (pos (point)))
+       (and
+        (kotlin-mode--chunk-comment-p chunk)
+        (save-excursion
+          (beginning-of-line)
+          (and
+           (looking-at "^\\s *\\*\\s +/")
+           (eq (match-end 0) pos)
+           (kotlin-mode--incomplete-comment-p chunk))))))
+    (backward-char)
+    (delete-horizontal-space)
+    (forward-char))
+
+   ;; Indent electrically when "}" is inserted at bol as the end of a string
+   ;; interpolation.
+   ((and
+     electric-indent-mode
+     (eq last-command-event ?\})
+     (save-excursion (backward-char) (skip-syntax-backward " ") (bolp))
+     (eq (kotlin-mode--chunk-start (kotlin-mode--chunk-after)) (1- (point))))
+    (indent-according-to-mode))
+
+   ;; Indent electrically after newline inside strings and comments.
+   ;; Unlike `electric-indent-mode', the previous line is not indented.
+   ((and
+     electric-indent-mode
+     (eq last-command-event ?\n))
+    (let ((chunk (kotlin-mode--chunk-after)))
+      (if (kotlin-mode--chunk-multiline-comment-p chunk)
+          (progn
+            (delete-horizontal-space)
+            (kotlin-mode--format-multiline-comment-line-after-newline
+             chunk
+             (not use-hard-newlines)))
+        (indent-according-to-mode)))
+    (save-excursion
+      (beginning-of-line)
+      (backward-char)
+      (delete-horizontal-space)))))
+
+(defun kotlin-mode--highlight-anchor (indentation)
+  "Highlight the anchor point of the INDENTATION."
+  (move-overlay
+   kotlin-mode--anchor-overlay
+   (kotlin-mode--indentation-position indentation)
+   (1+ (kotlin-mode--indentation-position indentation)))
+
+  (overlay-put kotlin-mode--anchor-overlay 'face 'highlight)
+
+  (when kotlin-mode--anchor-overlay-timer
+    (cancel-timer kotlin-mode--anchor-overlay-timer))
+
+  (let ((buffer (current-buffer)))
+    (setq kotlin-mode--anchor-overlay-timer
+          (run-at-time
+           "1 sec"
+           nil
+           (lambda ()
+             (when (buffer-live-p buffer)
+               (with-current-buffer buffer
+                 (delete-overlay kotlin-mode--anchor-overlay)
+                 (setq kotlin-mode--anchor-overlay-timer nil))))))))
+
+(provide 'kotlin-mode-indent)
+
+;;; kotlin-mode-indent.el ends here
diff --git a/kotlin-mode-lexer.el b/kotlin-mode-lexer.el
index 29576be8e7..c19e999bc4 100644
--- a/kotlin-mode-lexer.el
+++ b/kotlin-mode-lexer.el
@@ -1,8 +1,10 @@
 ;;; kotlin-mode-lexer.el --- Major mode for kotlin, lexer -*- lexical-binding: 
t; -*-
 
+;; Copyright © 2015 Shodai Yokoyama
 ;; Copyright © 2019 taku0
 
-;; Author: taku0 (http://github.com/taku0)
+;; Author: Shodai Yokoyama (quantumcars@gmail.com)
+;;         taku0 (http://github.com/taku0)
 ;; Keywords: languages
 ;; Package-Requires: ((emacs "24.3"))
 
@@ -51,6 +53,41 @@
 ;;
 ;;     This is not a official term; used only in kotlin-mode.
 
+;;; Brackets
+
+(defvar-local kotlin-mode--bracket-positions '()
+  "List of position of brackets.
+
+Element of the list is a cons (TYPE . POSITION) where TYPE is one of
+\(, ), {, }, [, or ], and POSITION is the position of the token.
+
+Elements are sorted by the position in descending order.")
+
+(defun kotlin-mode--clear-bracket-positions-after (position)
+  "Remove bracket positions after or equal to POSITION from cache."
+  (while (and kotlin-mode--bracket-positions
+              (<= position (cdar kotlin-mode--bracket-positions)))
+    (pop kotlin-mode--bracket-positions)))
+
+(defun kotlin-mode--find-containing-brackets (position)
+  "Return start position of innermost brackets containing POSITION.
+
+Return a cons (TYPE . POSITION) where TYPE is one of (, ), {, }, [, ],
+or outside-of-buffer, and POSITION is the position of the token."
+  (let ((brackets kotlin-mode--bracket-positions)
+        (nesting-level 1))
+    (while (and brackets (<= position (cdar brackets)))
+      (pop brackets))
+    (while (and brackets (not (zerop nesting-level)))
+      (if (memq (caar brackets) '(\( \[ {))
+          (setq nesting-level (1- nesting-level))
+        (setq nesting-level (1+ nesting-level)))
+      (unless (zerop nesting-level)
+        (pop brackets)))
+    (if brackets
+        (car brackets)
+      (cons 'outside-of-buffer (point-min)))))
+
 ;;; Text properties
 
 ;; See also doc/string_properties.png.
@@ -93,7 +130,9 @@ Mark the beginning of and the end of single-line/multiline
 strings, character literals, backquoted identifiers between the
 position START and END as general string delimiters.
 
-Intended for `syntax-propertize-function'."
+Intended for `syntax-propertize-function'.
+
+Also track position of brackets in `kotlin-mode--bracket-positions'."
   (remove-text-properties start end
                           '(syntax-table
                             nil
@@ -103,6 +142,7 @@ Intended for `syntax-propertize-function'."
                             nil
                             kotlin-property--interpolation
                             nil))
+  (kotlin-mode--clear-bracket-positions-after start)
   (let* ((chunk (kotlin-mode--chunk-after (syntax-ppss start))))
     (cond
      ((kotlin-mode--chunk-multiline-string-p chunk)
@@ -130,50 +170,70 @@ Mark the beginning of and the end of single-line/multiline
 strings and character literals between the current position and
 END as general string delimiters.
 
-Assuming the cursor is not on strings, character-literal,
+Assuming the point is not on strings, character-literal,
 backquoted identifier, nor comments.
 
 If NESTING-LEVEL is non-zero, nesting of brackets are tracked and
 the scan stops where the level becomes zero."
   (let ((found-matching-bracket nil)
-        (pattern (rx (or "\"\"\"" "\"" "//" "/*" "{" "}" "'" "`"))))
+        (pattern
+         (rx (or "\"\"\"" "\"" "//" "/*" "{" "}" "(" ")" "[" "]" "'" "`")))
+        match-string
+        start)
     (while (and (not found-matching-bracket)
                 (< (point) end)
                 (search-forward-regexp pattern end t))
+      (setq match-string (match-string-no-properties 0))
+      (setq start (match-beginning 0))
       (cond
-       ((member (match-string-no-properties 0) '("\"\"\"" "\"" "'" "`"))
-        (let ((start (match-beginning 0))
-              (quotation (match-string-no-properties 0)))
-          (put-text-property start (1+ start)
+       ;; Quotes
+       ((member match-string '("\"\"\"" "\"" "'" "`"))
+        ;; Mark the start of the quotes as a generic string delimiter.
+        (put-text-property start (1+ start)
+                           'syntax-table
+                           (string-to-syntax "|"))
+        ;; Scan until end of the string.
+        (kotlin-mode--syntax-propertize-end-of-string end match-string)
+        ;; Mark whole string, including template expressions,
+        ;; with `syntax-multiline'.  The property is used by
+        ;; `kotlin-mode--syntax-propertize-extend-region'.
+        (put-text-property start (point) 'syntax-multiline t)
+
+        (when (equal match-string "`")
+          ;; Backquotes cannot be escaped.  So declare the backslashes in
+          ;; the identifier are normal characters, not escape-syntax 
characters.
+          (put-text-property (1+ start) (1- (point))
                              'syntax-table
-                             (string-to-syntax "|"))
-          (kotlin-mode--syntax-propertize-end-of-string end quotation)
-          (put-text-property start (point) 'syntax-multiline t)
-
-          (when (equal quotation "`")
-            ;; Backquotes cannot be escaped. So declares the backslashes in
-            ;; the identifier are not a escape-syntax characters.
-            (put-text-property (1+ start) (1- (point))
-                               'syntax-table
-                               (string-to-syntax "w")))))
+                             (string-to-syntax "w"))))
 
-       ((equal "//" (match-string-no-properties 0))
-        (goto-char (match-beginning 0))
+       ;; Single-line comment
+       ((equal "//" match-string)
+        (goto-char start)
         (forward-comment (point-max)))
 
-       ((equal "/*" (match-string-no-properties 0))
-        (goto-char (match-beginning 0))
+       ;; Multiline comment
+       ((equal "/*" match-string)
+        (goto-char start)
         (forward-comment (point-max)))
 
-       ((and (equal "{" (match-string-no-properties 0))
+       ;; Open curly bracket
+       ((and (equal "{" match-string)
              (/= nesting-level 0))
+        (push (cons (intern match-string) start) 
kotlin-mode--bracket-positions)
         (setq nesting-level (1+ nesting-level)))
 
-       ((and (equal "}" (match-string-no-properties 0))
+       ;; Close curly bracket
+       ((and (equal "}" match-string)
              (/= nesting-level 0))
+        (push (cons (intern match-string) start) 
kotlin-mode--bracket-positions)
         (setq nesting-level (1- nesting-level))
         (when (= nesting-level 0)
-          (setq found-matching-bracket t)))))
+          (setq found-matching-bracket t)))
+
+       ;; Other brackets
+       ((member match-string '("(" ")" "[" "]" "{" "}"))
+        (push (cons (intern match-string) start)
+              kotlin-mode--bracket-positions))))
     (unless found-matching-bracket
       (goto-char end))
     found-matching-bracket))
@@ -181,7 +241,7 @@ the scan stops where the level becomes zero."
 (defun kotlin-mode--syntax-propertize-end-of-string (end quotation)
   "Move point to the end of single-line/multiline string.
 
-Assuming the cursor is on a string, a character literal, or a backquoted
+Assuming the point is on a string, a character literal, or a backquoted
 identifier.
 If the string go beyond END, stop there.
 The string should be terminated with QUOTATION."
@@ -195,12 +255,15 @@ The string should be terminated with QUOTATION."
                             (and "`" (+ (not (any "`\n"))) "`")))))
             end t))
       (cond
+       ;; End of the string
        ((and (equal quotation (match-string-no-properties 0))
              (or (equal quotation "`")  ; backquotes cannot be escaped
                  (not (kotlin-mode--escaped-p (match-beginning 0)))))
         (put-text-property (1- (point)) (point)
                            'syntax-table
                            (string-to-syntax "|")))
+
+       ;; Start of a template expression
        ((and (equal "${" (match-string-no-properties 0))
              (member quotation '("\"\"\"" "\""))
              ;; Dollar signs cannot be escaped, so we don't need to check it.
@@ -214,30 +277,39 @@ The string should be terminated with QUOTATION."
                  (backward-char) ;; {
                  (backward-char) ;; $
                  (point))))
-          ;; Declares the open bracket is a generic string delimiter.
+          ;; Keep the position of the open bracket.
+          (push (cons '{ (1+ start)) kotlin-mode--bracket-positions)
+          ;; Declare the open bracket is a generic string delimiter.
           (put-text-property
            (1- pos-after-open-bracket) pos-after-open-bracket
            'syntax-table
            (string-to-syntax "|"))
+          ;; Try to skip
           (when (kotlin-mode--syntax-propertize-scan end 1)
             ;; Found the matching bracket. Going further.
-            ;; Declares the close bracket is a generic string delimiter.
+            ;; Declare the close bracket is a generic string delimiter.
             (put-text-property (1- (point)) (point)
                                'syntax-table
                                (string-to-syntax "|"))
-            ;; Records the positions.
+            ;; Record the positions.
             (put-text-property (1- (point)) (point)
                                'kotlin-property--matching-bracket
                                start)
             (put-text-property start pos-after-open-bracket
                                'kotlin-property--matching-bracket
                                (1- (point)))
+            ;; Proceed.
             (kotlin-mode--syntax-propertize-end-of-string end quotation))))
-       ((match-string-no-properties 0)
+
+       ;; Template expression without braces
+       ((and (eq (aref (match-string-no-properties 0) 0) ?$)
+             (not (eq (aref (match-string-no-properties 0) 1) ?{)))
         (put-text-property (match-beginning 0) (1+ (match-beginning 0))
                            'kotlin-property--interpolation
                            (match-data))
         (kotlin-mode--syntax-propertize-end-of-string end quotation))
+
+       ;; Others
        (t
         (kotlin-mode--syntax-propertize-end-of-string end quotation)))
     (goto-char end)))
@@ -260,7 +332,6 @@ Return nil otherwise."
 (defclass kotlin-mode--chunk ()
   ((type :initarg :type
          :type symbol
-         :accessor kotlin-mode--chunk-type
          :documentation "The type of the chunk.
 
 Valid values:
@@ -272,12 +343,19 @@ Valid values:
 - backquoted-identifier")
    (start :initarg :start
           :type number
-          :accessor kotlin-mode--chunk-start
           :documentation "The start position of the chunk."))
   "String-chunks, comments, character literals, or backquoted identifiers.
 
 It have the type and the start position.")
 
+(defun kotlin-mode--chunk-type (chunk)
+  "Return the type of the CHUNK."
+  (and chunk (oref chunk type)))
+
+(defun kotlin-mode--chunk-start (chunk)
+  "Return the start position of the CHUNK."
+  (and chunk (oref chunk start)))
+
 (defun kotlin-mode--chunk-comment-p (chunk)
   "Return non-nil if the CHUNK is a comment."
   (and chunk
@@ -314,10 +392,19 @@ It have the type and the start position.")
   "Return non-nil if the CHUNK is a backquoted identifier."
   (and chunk (eq (kotlin-mode--chunk-type chunk) 'backquoted-identifier)))
 
+(defun kotlin-mode--incomplete-comment-p (chunk)
+  "Return t if the CHUNK is incomplete comment.
+
+Return nil otherwise."
+  (and (kotlin-mode--chunk-comment-p chunk)
+       (save-excursion
+         (goto-char (kotlin-mode--chunk-start chunk))
+         (not (forward-comment 1)))))
+
 (defun kotlin-mode--chunk-after (&optional parser-state)
-  "Return the chunk at the cursor.
+  "Return the chunk at the point.
 
-If the cursor is outside of strings and comments, return nil.
+If the point is outside of strings and comments, return nil.
 
 If PARSER-STATE is given, it is used instead of (syntax-ppss)."
   (save-excursion
@@ -330,14 +417,27 @@ If PARSER-STATE is given, it is used instead of 
(syntax-ppss)."
       ;; Syntax category "|" is attached to both single-line and multiline
       ;; string delimiters.  So (nth 3 parser-state) may be t even for
       ;; single-line string delimiters.
-      (if (save-excursion (goto-char (nth 8 parser-state))
-                          (looking-at "\"\"\""))
+      (save-excursion
+        (goto-char (nth 8 parser-state))
+        (forward-char)
+        (kotlin-mode--beginning-of-string)
+        (cond
+         ((looking-at "\"\"\"")
           (make-instance 'kotlin-mode--chunk
                          :type 'multiline-string
-                         :start (nth 8 parser-state))
-        (make-instance 'kotlin-mode--chunk
-                       :type 'single-line-string
-                       :start (nth 8 parser-state))))
+                         :start (nth 8 parser-state)))
+         ((looking-at "`")
+          (make-instance 'kotlin-mode--chunk
+                         :type 'backquoted-identifier
+                         :start (nth 8 parser-state)))
+         ((looking-at "'")
+          (make-instance 'kotlin-mode--chunk
+                         :type 'character-literal
+                         :start (nth 8 parser-state)))
+         (t
+          (make-instance 'kotlin-mode--chunk
+                         :type 'single-line-string
+                         :start (nth 8 parser-state))))))
      ((eq (nth 4 parser-state) t)
       (make-instance 'kotlin-mode--chunk
                      :type 'single-line-comment
@@ -357,6 +457,2135 @@ If PARSER-STATE is given, it is used instead of 
(syntax-ppss)."
      (t
       nil))))
 
+;; Syntax table
+
+(defvar kotlin-mode-syntax-table
+  (let ((st (make-syntax-table)))
+
+    ;; Strings
+    (modify-syntax-entry ?\" "\"" st)
+    (modify-syntax-entry ?\' "\"" st)
+    (modify-syntax-entry ?` "\"" st)
+
+    ;; `_' and `@' as being a valid part of a symbol
+    (modify-syntax-entry ?_ "_" st)
+    (modify-syntax-entry ?@ "_" st)
+
+    ;; b-style comment
+    (modify-syntax-entry ?/ ". 124b" st)
+    (modify-syntax-entry ?* ". 23n" st)
+    (modify-syntax-entry ?\n "> b" st)
+    (modify-syntax-entry ?\r "> b" st)
+    st))
+
+;; Token
+
+(defclass kotlin-mode--token ()
+  ((type :initarg :type
+         :type symbol
+         :documentation "The type of the token.
+
+Token types is one of the following symbols:
+
+- operator (including as, as?, is, !is, in, !in, ., and ->)
+- annotation
+  (e.g. @ABC, @ABC(def), @file:ABC, @[ABC DEF(ghi)], or @file:[ABC DEF(ghi)])
+- atom (including keywords, numbers, strings, and unknown tokens)
+- label
+- return (including return@identifier)
+- continue (including continue@identifier)
+- beak (including beak@identifier)
+- this (including this@identifier)
+- super (including super@identifier)
+- [
+- ]
+- {
+- }
+- (
+- )
+- )-before-control-structure-body
+- ,
+- ;
+- implicit-;
+- < (as an angle bracket)
+- > (as an angle bracket)
+- :
+- string-chunk-after-template-expression (part of a string ending with \"}\")
+- string-chunk-before-template-expression (part of a string ending with \"${\")
+- bare-else (\"else\" not followed by \"if\" on the same line, \"->\", or 
\"{\")
+- outside-of-buffer
+- anonymous-function-parameter-arrow
+- when-expression-arrow
+
+Additionally, `kotlin-mode--backward-token-or-list' may return a parenthesized
+expression as a token with one of the following types:
+- ()
+- ()-before-control-structure-body
+- []
+- {}
+- <>" )
+   (text :initarg :text
+         :type string
+         :documentation "The text of the token.")
+   (start :initarg :start
+          :type integer
+          :documentation "The start position of the token.")
+   (end :initarg :end
+        :type integer
+        :documentation "The point after the token."))
+  "Token of Kotlin.")
+
+(defun kotlin-mode--token-type (token)
+  "Return the type of TOKEN."
+  (and token (oref token type)))
+
+(defun kotlin-mode--token-text (token)
+  "Return the text of TOKEN."
+  (and token (oref token text)))
+
+(defun kotlin-mode--token-start (token)
+  "Return the start position of TOKEN."
+  (and token (oref token start)))
+
+(defun kotlin-mode--token-end (token)
+  "Return the end position of TOKEN."
+  (and token (oref token end)))
+
+;; Token level movements and predicates.
+
+(defconst kotlin-mode--inheritance-modifier-keywords
+  '("open" "final" "abstract"))
+
+(defconst kotlin-mode--visibility-modifier-keywords
+  '("public" "private" "internal" "protected"))
+
+(defconst kotlin-mode--member-modifier-keywords
+  '("lateinit" "override"))
+
+(defconst kotlin-mode--companion-modifier-keywords
+  '("companion"))
+
+(defconst kotlin-mode--class-modifier-keywords
+  '("enum" "sealed" "annotation" "data" "inner"))
+
+(defconst kotlin-mode--property-modifier-keywords
+  '("const"))
+
+(defconst kotlin-mode--platform-modifier-keywords
+  '("expect" "actual"))
+
+(defconst kotlin-mode--parameter-modifier-keywords
+  '("vararg" "crossinline" "noinline"))
+
+(defconst kotlin-mode--function-modifier-keywords
+  '("tailrec" "operator" "infix" "inline" "value" "external" "suspend"))
+
+(defconst kotlin-mode--modifier-keywords
+  (append kotlin-mode--inheritance-modifier-keywords
+          kotlin-mode--visibility-modifier-keywords
+          kotlin-mode--member-modifier-keywords
+          kotlin-mode--class-modifier-keywords
+          kotlin-mode--property-modifier-keywords
+          kotlin-mode--platform-modifier-keywords
+          kotlin-mode--parameter-modifier-keywords
+          kotlin-mode--function-modifier-keywords))
+
+(defun kotlin-mode--implicit-semi-p ()
+  "Return non-nil if the point is after the end of a statement."
+  (let ((previous-token (save-excursion
+                          (kotlin-mode--extend-annotation-token-backward
+                           (kotlin-mode--backward-token-simple))))
+        (next-token (save-excursion
+                      (kotlin-mode--extend-annotation-token-forward
+                       (kotlin-mode--forward-token-simple)))))
+    ;; If the point is on the empty line, pretend an identifier is on the line.
+    (when (and
+           (< (kotlin-mode--token-end previous-token) 
(line-beginning-position))
+           (< (line-end-position) (kotlin-mode--token-start next-token)))
+      (setq next-token (make-instance 'kotlin-mode--token
+                                      :type 'atom
+                                      :text ""
+                                      :start (point)
+                                      :end (point))))
+    (cond
+     ;; Tokens that end a statement
+     ((memq (kotlin-mode--token-text previous-token)
+            '("return" "continue" "break"))
+      t)
+
+     ;; .* in import declarations end a statement.
+     ((and (equal (kotlin-mode--token-text previous-token) "*")
+           (equal (kotlin-mode--token-text
+                   (save-excursion
+                     (goto-char (kotlin-mode--token-start previous-token))
+                     (kotlin-mode--backward-token-simple)))
+                  "."))
+      t)
+
+     ;; Suppress implicit semicolon after "if ()", "while ()", "for ()"
+     ((kotlin-mode--close-parenthesis-before-control-structure-body-p
+       previous-token)
+      nil)
+
+     ;; Annotations and modifiers, that cannot end a statement/declaration
+     ((or
+       ;; Annotations
+       (and
+        (eq (kotlin-mode--token-type previous-token) 'annotation)
+        ;; Exclude super<A>@label.  Note that this@label is handled by
+        ;; `kotlin-mode--backward-token-simple'
+        (not (save-excursion
+               (goto-char (kotlin-mode--token-start previous-token))
+               (and (eq (char-before) ?>)
+                    (kotlin-mode--try-backward-type-parameters)
+                    (equal (kotlin-mode--token-text
+                            (kotlin-mode--backward-token-simple))
+                           "super")))))
+       ;; Labels
+       (eq (kotlin-mode--token-type previous-token) 'label)
+       ;; Modifiers
+       (and (member (kotlin-mode--token-text previous-token)
+                    kotlin-mode--modifier-keywords)
+            (not (equal (kotlin-mode--token-text previous-token) "value"))))
+      nil)
+
+     ;; Tokens that cannot end a statement
+     ;;
+     ;; TODO prefix ++ and --
+     ;; TODO infix function call
+     ;; TODO prefix !, especially !!
+     ;;
+     ;; Example:
+     ;; var shl = 1
+     ;; val x = shl shl shl
+     ;; shl < 100 && foo() // this is not a continuation of the previous line.
+     ;;
+     ;; var shl = 1
+     ;; val x = shl shl
+     ;; shl < 100 && foo() // this is a continuation of the previous line.
+     ;;
+     ;; var shl = 1
+     ;; val x = shl shl shl ++
+     ;; shl < 100 && foo() // this is not a continuation of the previous line.
+     ;;
+     ;; var shl = 1
+     ;; val x = shl shl ++
+     ;; shl < 100 && foo() // this is a continuation of the previous line.
+     ;;
+     ;; val x = foo()!!
+     ;; foo() // this is not a continuation of the previous line.
+     ;;
+     ;; val x = !!
+     ;; foo() // this is a continuation of the previous line.
+     ((or
+       (memq
+        (kotlin-mode--token-type previous-token)
+        '(implicit-\; string-chunk-before-template-expression))
+       (member
+        (kotlin-mode--token-text previous-token)
+        '("(" "{" "[" "*" "%" "/" "+" "-" "&&" "||" ":" "&"
+          "=" "+=" "-=" "*=" "/=" "%="
+          "->" "." ".." "..<" "::" "?:" "?." "<=" ">=" "!=" "!==" "==" "==="
+          "as" "as?" "is" "!is" "in" "!in" "," ";" "{" "[" "("
+          ;; "class" will be handled later.
+          "package" "import" "interface" "fun" "object"
+          "val" "var" "typealias" "constructor" "by" "companion" "init"
+          "where" "if" "else" "when" "try" "catch" "finally" "for" "do"
+          "while" "throw" "out" "reified"))
+       ;; Inequality operator cannot end a statement/declaration.
+       (and (eq (kotlin-mode--token-type previous-token) 'operator)
+            (member (kotlin-mode--token-text previous-token) '("<" ">"))))
+      nil)
+
+     ;; "class" cannot end a statement unless preceded by "::".
+     ;;
+     ;; Example:
+     ;;
+     ;; class // No implicit semicolon here
+     ;;     Foo {
+     ;; }
+     ;;
+     ;; val x = Foo ::
+     ;;   class // Implicit semicolon here
+     ;; foo()
+     ((and (equal (kotlin-mode--token-text previous-token) "class")
+           (save-excursion
+             (goto-char (kotlin-mode--token-start previous-token))
+             (not (equal (kotlin-mode--token-text
+                          (kotlin-mode--backward-token-simple))
+                         "::"))))
+      nil)
+
+     ;; Annotations, labels, and modifiers, that start a statement/declaration,
+     ;; except for getter and setter.
+     ;;
+     ;; "suspend" is excluded because it can be used as type modifier.
+     ((or
+       (memq (kotlin-mode--token-type next-token) '(annotation label))
+       (member (kotlin-mode--token-text next-token)
+               (remove "suspend" kotlin-mode--modifier-keywords)))
+      (not (save-excursion
+             (kotlin-mode--try-forward-modifiers)
+             (member (kotlin-mode--token-text
+                      (kotlin-mode--forward-token-simple))
+                     '("get" "set")))))
+
+     ;; Tokens that start a statement/declaration
+     ((member
+       (kotlin-mode--token-text next-token)
+       ;; "class" will be handled later.
+       '("package" "import" "interface" "val" "var" "typealias"
+         "constructor" "companion" "init" "for" "do" "is"
+         ;; While we should insert a semicolon before "in" in a "when"
+         ;; expression or beginning of a expression, we should
+         ;; suppress a semicolon before "in" in "for", type
+         ;; parameters, or type arguments:
+         ;;
+         ;; when (x) {
+         ;;     1 -> 1 // implicit semicolon here
+         ;;     in xs -> 2
+         ;; }
+         ;;
+         ;; // line breaks are prohibited before infix "in" operator.
+         ;; val x = 1 // implicit semicolon here
+         ;; in xs // Though this is an invalid expression anyway.
+         ;;
+         ;; for (
+         ;;     x // no implicit semicolons here
+         ;;     in
+         ;;     xs
+         ;; ) {}
+         ;;
+         ;; Foo< // no implicit semicolons here
+         ;;   in X
+         ;; >
+         ;;
+         ;; Because detecting the context is hard at lexer level, we
+         ;; omit semicolon for now, and handle it later in the
+         ;; indentation code.
+         ))
+      t)
+
+     ;; While or do-while
+     ((equal (kotlin-mode--token-text next-token) "while")
+      ;; insert semicolon unless it is a part of do-while.
+      (save-excursion (not (kotlin-mode--find-do-for-while))))
+
+     ;; "class" starts a new declaration unless preceded by "::".
+     ;;
+     ;; Example:
+     ;;
+     ;; class Foo { // This start a class declaration.
+     ;; }
+     ;;
+     ;; Foo ::
+     ;;   class // This does not start a class declaration.
+     ((and (equal (kotlin-mode--token-text next-token) "class")
+           (not (equal (kotlin-mode--token-text previous-token) "::")))
+      t)
+
+     ;; Tokens that cannot start a statement/declaration.
+     ((or (memq
+           (kotlin-mode--token-type next-token)
+           '(implicit-\; string-chunk-after-template-expression))
+          (member
+           (kotlin-mode--token-text next-token)
+           '("*" "%" "/" "&" "&&" "||" ":" "=" "+=" "-=" "*=" "/=" "%="
+             "->" "." ".." "..<" "::" "?:" "?." "?" "<" ">" "<=" ">="
+             "!=" "!==" "==" "==="
+             "," ";" ")" "]" "}"
+             "as" "as?" "get" "set" "by" "where" "else" "catch" "finally"
+             ;; Because detecting the context is hard at lexer level,
+             ;; we omit semicolon before "in" for now, and handle it
+             ;; later in the indentation code.
+             "in"
+             ;; Strictly speaking, open curly bracket may start a statement
+             ;; as a part of lambda expression, it is rare case, so we
+             ;; suppress semicolon before it.
+             "{")))
+      nil)
+
+     ;; Open square bracket start a new statement unless preceded by a
+     ;; colon (already handled above).
+     ((eq (kotlin-mode--token-type next-token) '\[)
+      t)
+
+     ;; Open parenthesis start a new statement unless preceded by:
+     ;; - a colon (already handled above),
+     ;; - a comma (already handled above),
+     ;; - a dot (already handled above),
+     ;; - an equal sign (already handled above),
+     ;; - "->" (already handled above),
+     ;; - "is" (already handled above),
+     ;; - "!is" (already handled above),
+     ;; - "as" (already handled above),
+     ;; - "as?" (already handled above),
+     ;; - "if" (already handled above),
+     ;; - "while" (already handled above),
+     ;; - "for" (already handled above),
+     ;; - "when" (already handled above),
+     ;; - "catch" (already handled above),
+     ;; or is a part of:
+     ;; - secondary constructor declaration,
+     ;; - class declaration,
+     ;; - function declaration,
+     ;; - variable declaration,
+     ;; - getter declaration,
+     ;; - setter declaration,
+     ;; - constructor declaration call (example: constructor(): this(1)),
+     ;;
+     ;; Examples:
+     ;;
+     ;; public constructor() {}
+     ;;
+     ;; public class Foo() {}
+     ;; public class Foo <A>() {}
+     ;; public class Foo public constructor ()
+     ;; public class Foo <A> @AAA constructor ()
+     ;;
+     ;; fun foo() {}
+     ;; fun <A> foo() {}
+     ;; fun (A).foo() {}
+     ;; fun A.B<A, B>.C.foo() {}
+     ;; fun @AAA (A).foo() {}
+     ;; fun <A> (A).foo() {}
+     ;; fun <A> @AAA (A).foo() {}
+     ;; fun <A> @AAA A.B<A, B>.C.foo() {}
+     ;;
+     ;; fun () {}
+     ;; fun (A).() {}
+     ;; fun A.B<A, B>.C.() {}
+     ;;
+     ;; val (x, y) = foo()
+     ;; var (x, y) = foo()
+     ;; val <A> (x, y) = foo()
+     ;; val (A).(x, y) = foo()
+     ;; val <A> (A).(x, y) = foo()
+     ;; val <A> @AAA A.(x, y) = foo()
+     ;; val <A> @AAA A.B<A, B>.C.(x, y) = foo()
+     ;;
+     ;; get() {}
+     ;; set(value) {}
+     ;;
+     ;; constructor (): this(1)
+     ;; constructor (): super(1)
+     ;;
+     ;; Note that function argument cannot preceded by newline:
+     ;;
+     ;; val x = foo
+     ;; (bar()) // This is not a continuation of the previous line.
+     ((eq (kotlin-mode--token-type next-token) '\()
+      (and
+       (not (kotlin-mode--constructor-parameter-clause-p))
+       (not (kotlin-mode--function-parameter-clause-p))
+       (not (kotlin-mode--multi-variable-declaration-p))
+       (not (kotlin-mode--constructor-delegation-call-p))))
+
+     ;; Suppress implicit semicolon after the beginning of an interpolated
+     ;; expression.
+     ((eq (kotlin-mode--token-type previous-token)
+          'string-chunk-before-interpolated-expression)
+      nil)
+
+     ;; Otherwise, inserts implicit semicolon.
+     (t t))))
+
+(defun kotlin-mode--close-parenthesis-before-control-structure-body-p (token)
+  "Return t if TOKEN is close parenthesis before control structure body.
+
+Return t if TOKEN is the close-parenthesis of \"if (...)\",
+\"while(...)\", or \"for (...)\", but not followed by \"{\".
+
+Return nil otherwise."
+  (and
+   (eq (kotlin-mode--token-type token) '\))
+   (save-excursion
+     (goto-char (kotlin-mode--token-end token))
+     (not (eq (kotlin-mode--token-type (kotlin-mode--forward-token-simple))
+              '\{)))
+   (save-excursion
+     (goto-char (kotlin-mode--token-end token))
+     (condition-case nil
+         (progn
+           (backward-list)
+           (let ((previous-token (kotlin-mode--backward-token-simple)))
+             (or
+              (member (kotlin-mode--token-text previous-token) '("if" "for"))
+              (and
+               (equal (kotlin-mode--token-text previous-token) "while")
+               (not (save-excursion (kotlin-mode--find-do-for-while)))))))
+       (scan-error
+        nil)))))
+
+(defun kotlin-mode--find-do-for-while ()
+  "Return \"do\" token for \"while\" token.
+
+If \"while\" is not part of do-while, return nil.
+
+Assuming the point is before \"while\" token."
+  ;; Example:
+  ;;
+  ;; do
+  ;; while (false)
+  ;; print(1)
+  ;; while (false)
+  ;; print(2)
+  ;;
+  ;; is parsed as three statements:
+  ;;
+  ;; do while (false);
+  ;; print(1);
+  ;; while (false) print(2);
+  ;;
+  ;; So we don't need to worry about bare while-statement in body of do-while.
+  (let ((nesting-level 1)
+        previous-token)
+    (while (< 0 nesting-level)
+      (setq previous-token (kotlin-mode--backward-token-or-list t))
+      (cond
+       ((equal (kotlin-mode--token-text previous-token) "while")
+        (setq nesting-level (1+ nesting-level)))
+
+       ((equal (kotlin-mode--token-text previous-token) "do")
+        (setq nesting-level (1- nesting-level)))
+
+       ((memq (kotlin-mode--token-type previous-token) '(outside-of-buffer {))
+        ;; Unmatched
+        (setq nesting-level 0))))
+    (and (equal (kotlin-mode--token-text previous-token) "do")
+         previous-token)))
+
+(defun kotlin-mode--constructor-parameter-clause-p ()
+  "Return non-nil if the point is before parameters of constructor 
declaration."
+  ;; Examples:
+  ;;
+  ;; public constructor() {}
+  ;;
+  ;; public class Foo() {}
+  ;; public class Foo <A>() {}
+  ;; public class Foo public constructor ()
+  ;; public class Foo <A> @AAA constructor ()
+  (let ((previous-token (save-excursion (kotlin-mode--backward-token-simple))))
+    (or
+     (equal (kotlin-mode--token-text previous-token) "constructor")
+     (save-excursion
+       (kotlin-mode--try-backward-type-parameters)
+       (and
+        (eq (kotlin-mode--token-type (kotlin-mode--backward-token-simple))
+            'atom)
+        (equal (kotlin-mode--token-text (kotlin-mode--backward-token-simple))
+               "class"))))))
+
+(defun kotlin-mode--function-parameter-clause-p ()
+  "Return non-nil if the point is before parameters of function declaration."
+  ;; Examples:
+  ;;
+  ;; fun foo() {}
+  ;; fun <A> foo() {}
+  ;; fun (A).foo() {}
+  ;; fun A.B<A, B>.C.foo() {}
+  ;; fun @AAA (A).foo() {}
+  ;; fun <A> (A).foo() {}
+  ;; fun <A> @AAA (A).foo() {}
+  ;; fun <A> @AAA A.B<A, B>.C.foo() {}
+  ;;
+  ;; fun () {}
+  ;; fun (A).() {}
+  ;; fun A.B<A, B>.C.() {}
+  (let ((previous-token (save-excursion (kotlin-mode--backward-token-simple))))
+    (cond
+     ;; fun () {}
+     ;; fun (A).() {} // for first parenthesis
+     ;; fun (A).foo() {} // for first parenthesis
+     ((equal (kotlin-mode--token-text previous-token) "fun")
+      t)
+
+     ;; fun (A).() {}
+     ;; fun A.B<A, B>.C.() {}
+     ((equal (kotlin-mode--token-text previous-token) ".")
+      (save-excursion
+        (and (kotlin-mode--try-backward-receiver-type)
+             (equal (kotlin-mode--token-text
+                     (kotlin-mode--backward-token-simple))
+                    "fun"))))
+
+     ;; fun @AAA (A).foo() {} // for first parenthesis
+     ;; fun <A> (A).foo() {} // for first parenthesis
+     ;; fun <A> @AAA (A).foo() {} // for first parenthesis
+     ((save-excursion
+        (kotlin-mode--try-backward-type-modifiers)
+        (kotlin-mode--try-backward-type-parameters)
+        (equal (kotlin-mode--token-text
+                (kotlin-mode--backward-token-simple))
+               "fun"))
+      t)
+
+     ;; fun foo() {}
+     ;; fun <A> foo() {}
+     ;; fun (A).foo() {} // for second parenthesis
+     ;; fun A.B<A, B>.C.foo() {}
+     ;; fun @AAA (A).foo() {} // for second parenthesis
+     ;; fun <A> (A).foo() {} // for second parenthesis
+     ;; fun <A> @AAA (A).foo() {} // for second parenthesis
+     ;; fun <A> @AAA A.B<A, B>.C.foo() {}
+     ((eq (kotlin-mode--token-type previous-token) 'atom)
+      (save-excursion
+        (goto-char (kotlin-mode--token-start previous-token))
+        (kotlin-mode--try-backward-receiver-type)
+        (kotlin-mode--try-backward-type-parameters)
+        (equal (kotlin-mode--token-text
+                (kotlin-mode--backward-token-simple))
+               "fun"))))))
+
+(defun kotlin-mode--try-backward-receiver-type ()
+  "Try backward dot, type, and type modifiers.
+
+Return non-nil if succeeds.  Keep position and return nil otherwise."
+  (let ((pos (point))
+        (previous-token (kotlin-mode--backward-token-simple)))
+    (if (and (equal (kotlin-mode--token-text previous-token) ".")
+             (kotlin-mode--try-backward-type))
+        (progn
+          (kotlin-mode--try-backward-type-modifiers)
+          t)
+      (goto-char pos)
+      nil)))
+
+(defun kotlin-mode--try-backward-type ()
+  "Try backward type but not type modifiers.
+
+Return non-nil if succeeds.  Keep position and return nil otherwise."
+  ;; type
+  ;;   : typeModifiers?
+  ;;   ( parenthesizedType
+  ;;   | nullableType
+  ;;   | typeReference
+  ;;   | functionType)
+  ;;   ;
+  ;;
+  ;; typeReference
+  ;;   : userType
+  ;;   | DYNAMIC
+  ;;   ;
+  ;;
+  ;; userType
+  ;;     : simpleUserType (NL* DOT NL* simpleUserType)*
+  ;;     ;
+  ;;
+  ;; simpleUserType
+  ;;     : simpleIdentifier (NL* typeArguments)?
+  ;;     ;
+  ;;
+  ;; functionType
+  ;;   : (receiverType NL* DOT NL*)? functionTypeParameters NL* ARROW NL* type
+  ;;   ;
+  (let ((pos (point))
+        (previous-token (kotlin-mode--backward-token-simple))
+        result)
+    (setq
+     result
+     (cond
+      ;; parenthesizedType
+      ((equal (kotlin-mode--token-text previous-token) ")")
+       (goto-char (kotlin-mode--token-end previous-token))
+       (condition-case nil
+           (progn
+             (backward-list)
+             t)
+         (scan-error
+          (goto-char pos)
+          nil)))
+
+      ;; nullableType
+      ((equal (kotlin-mode--token-text previous-token) "?")
+       (kotlin-mode--try-backward-type))
+
+      ;; typeReference
+      (t
+       (goto-char (kotlin-mode--token-end previous-token))
+       (kotlin-mode--try-backward-type-reference))))
+    ;; functionType
+    (while (and result
+                (equal (kotlin-mode--token-text
+                        (save-excursion (kotlin-mode--backward-token-simple)))
+                       "->"))
+      ;; Skip "->"
+      (kotlin-mode--backward-token-simple)
+      ;; Skip parameters and a receiver type if any.
+      (setq result (condition-case nil
+                       (progn
+                         (backward-list)
+                         (kotlin-mode--try-backward-receiver-type)
+                         t)
+                     (scan-error
+                      nil))))
+    (unless result
+      (goto-char pos))
+    result))
+
+(defun kotlin-mode--try-forward-type-reference ()
+  "Try forward type reference.
+
+Return non-nil if succeeds.  Keep position and return nil otherwise."
+  ;; typeReference
+  ;;     : userType
+  ;;     | DYNAMIC
+  ;;     ;
+  ;; userType
+  ;;     : simpleUserType (NL* DOT NL* simpleUserType)*
+  ;;     ;
+  ;;
+  ;; simpleUserType
+  ;;     : simpleIdentifier (NL* typeArguments)?
+  ;;     ;
+  (let ((pos (point))
+        result)
+    (setq result (kotlin-mode--forward-simple-user-type))
+    (while (and result
+                (equal (kotlin-mode--token-text
+                        (save-excursion (kotlin-mode--forward-token-simple)))
+                       "."))
+      ;; Skip "."
+      (kotlin-mode--forward-token-simple)
+      (setq result (kotlin-mode--forward-simple-user-type)))
+    (unless result
+      (goto-char pos))
+    result))
+
+(defun kotlin-mode--forward-simple-user-type ()
+  "Forward simple user type.
+
+Return non-nil if succeeds.  Otherwise, return nil and the point is undefined."
+  ;; simpleUserType
+  ;;     : simpleIdentifier (NL* typeArguments)?
+  ;;     ;
+  (let ((next-token (save-excursion (kotlin-mode--forward-token-simple))))
+    (if (eq (kotlin-mode--token-type next-token) 'atom)
+        ;; Found simpleIdentifier
+        (progn
+          (goto-char (kotlin-mode--token-end next-token))
+          (when (equal (kotlin-mode--token-text
+                        (save-excursion (kotlin-mode--forward-token-simple)))
+                       "<")
+            ;; Maybe type paramters
+            (kotlin-mode--try-forward-type-parameters))
+          t)
+      ;; Not a simpleUserType
+      nil)))
+
+(defun kotlin-mode--try-backward-type-reference ()
+  "Try backward type reference.
+
+Return non-nil if succeeds.  Keep position and return nil otherwise."
+  ;; typeReference
+  ;;     : userType
+  ;;     | DYNAMIC
+  ;;     ;
+  ;; userType
+  ;;     : simpleUserType (NL* DOT NL* simpleUserType)*
+  ;;     ;
+  ;;
+  ;; simpleUserType
+  ;;     : simpleIdentifier (NL* typeArguments)?
+  ;;     ;
+  (let ((pos (point))
+        result)
+    (setq result (kotlin-mode--backward-simple-user-type))
+    (while (and result
+                (equal (kotlin-mode--token-text
+                        (save-excursion (kotlin-mode--backward-token-simple)))
+                       "."))
+      ;; Skip "."
+      (kotlin-mode--backward-token-simple)
+      (setq result (kotlin-mode--backward-simple-user-type)))
+    (unless result
+      (goto-char pos))
+    result))
+
+(defun kotlin-mode--backward-simple-user-type ()
+  "Backward simple user type.
+
+Return non-nil if succeeds.  Otherwise, return nil and the point is undefined."
+  ;; simpleUserType
+  ;;     : simpleIdentifier (NL* typeArguments)?
+  ;;     ;
+  (let ((pos (point))
+        (previous-token (save-excursion (kotlin-mode--backward-token-simple))))
+    (cond
+     ;; simpleUserType with type arguments
+     ((equal (kotlin-mode--token-text previous-token) ">")
+      (if (and (kotlin-mode--try-backward-type-parameters)
+               (eq (kotlin-mode--token-type
+                    (kotlin-mode--backward-token-simple))
+                   'atom))
+          t
+        (goto-char pos)
+        nil))
+
+     ;; Start of an annotation
+     ((eq (kotlin-mode--token-type previous-token) 'annotation)
+      (goto-char (kotlin-mode--token-start previous-token))
+      (forward-char)
+      t)
+
+     ;; Other simpleUserType
+     ((eq (kotlin-mode--token-type previous-token) 'atom)
+      (goto-char (kotlin-mode--token-start previous-token))
+      t)
+
+     ;; Not a simpleUserType
+     (t
+      nil))))
+
+(defun kotlin-mode--try-backward-type-modifiers ()
+  "Try backward type modifiers.
+
+Keep position if failed."
+  (let ((previous-token (save-excursion (kotlin-mode--backward-token-simple))))
+    (while (or
+            (eq (kotlin-mode--token-type previous-token) 'annotation)
+            (equal (kotlin-mode--token-text previous-token) "suspend"))
+      (goto-char (kotlin-mode--token-start previous-token))
+      (setq previous-token
+            (save-excursion (kotlin-mode--backward-token-simple))))))
+
+(defun kotlin-mode--multi-variable-declaration-p ()
+  "Return non-nil if the point is before multi variable declaration."
+  ;; Example:
+  ;;
+  ;; val (x, y) = foo()
+  ;; var (x, y) = foo()
+  ;; val <A> (x, y) = foo()
+  ;; val (A).(x, y) = foo()
+  ;; val <A> (A).(x, y) = foo()
+  ;; val <A> @AAA A.(x, y) = foo()
+  ;; val <A> @AAA A.B<A, B>.C.(x, y) = foo()
+  (save-excursion
+    (kotlin-mode--try-backward-receiver-type)
+    (kotlin-mode--try-backward-type-parameters)
+    (member (kotlin-mode--token-text
+             (kotlin-mode--backward-token-simple))
+            '("val" "var"))))
+
+(defun kotlin-mode--constructor-delegation-call-p ()
+  "Return non-nil if the point is before constructor delegation call 
arguments."
+  ;; Example:
+  ;;
+  ;; constructor (): this(1)
+  ;; constructor (): super(1)
+  (save-excursion
+    (and (member (kotlin-mode--token-text (kotlin-mode--backward-token-simple))
+                 '("this" "super"))
+         (eq (kotlin-mode--token-type (kotlin-mode--backward-token-simple))
+             ':))))
+
+(defun kotlin-mode--try-forward-modifiers ()
+  "Try forward modifiers.
+
+Keep position if failed."
+  (let ((next-token (save-excursion (kotlin-mode--forward-token-simple))))
+    (while (or
+            (eq (kotlin-mode--token-type next-token) 'annotation)
+            (member (kotlin-mode--token-text next-token)
+                    kotlin-mode--modifier-keywords))
+      (goto-char (kotlin-mode--token-end next-token))
+      (setq next-token (save-excursion (kotlin-mode--forward-token-simple))))))
+
+(defun kotlin-mode--try-backward-modifiers ()
+  "Try forward modifiers.
+
+Keep position if failed."
+  (let ((previous-token (save-excursion (kotlin-mode--backward-token-simple))))
+    (while (or
+            (eq (kotlin-mode--token-type previous-token) 'annotation)
+            (member (kotlin-mode--token-text previous-token)
+                    kotlin-mode--modifier-keywords))
+      (goto-char (kotlin-mode--token-start previous-token))
+      (setq previous-token
+            (save-excursion (kotlin-mode--backward-token-simple))))))
+
+(defun kotlin-mode--backward-token-or-list (&optional 
use-backward-token-simple)
+  "Move point to the start position of the previous token or list.
+
+Return the token skipped.
+
+If USE-BACKWARD-TOKEN-SIMPLE is non-nil, use
+`kotlin-mode--backward-token-simple' instead of
+`kotlin-mode--backward-token'."
+  (let* ((previous-token (if use-backward-token-simple
+                             (kotlin-mode--backward-token-simple)
+                           (kotlin-mode--backward-token)))
+         (previous-type (kotlin-mode--token-type previous-token))
+         (previous-text (kotlin-mode--token-text previous-token))
+         (previous-start (kotlin-mode--token-start previous-token))
+         (previous-end (kotlin-mode--token-end previous-token)))
+    (cond
+     ;; Maybe list
+     ((memq previous-type '(} \) \] \)-before-control-structure-body))
+      (goto-char previous-end)
+      (condition-case nil
+          (progn
+            (backward-list)
+            (make-instance
+             'kotlin-mode--token
+             :type (assoc-default
+                    previous-type
+                    '((} . {})
+                      (\) . \(\))
+                      (\)-before-control-structure-body .
+                       \(\)-before-control-structure-body)
+                      (\] . \[\])))
+             :text (buffer-substring-no-properties (point) previous-end)
+             :start (point)
+             :end previous-end))
+        (scan-error
+         (goto-char previous-start)
+         previous-token)))
+
+     ;; Maybe type parameter list
+     ((equal previous-text ">")
+      (goto-char previous-end)
+      (if (kotlin-mode--try-backward-type-parameters)
+          (make-instance
+           'kotlin-mode--token
+           :type '<>
+           :text (buffer-substring-no-properties (point) previous-end)
+           :start (point)
+           :end previous-end)
+        (goto-char previous-start)
+        previous-token))
+
+     ;; Other token
+     (t previous-token))))
+
+(defun kotlin-mode--forward-token-or-list (&optional use-forward-token-simple)
+  "Move point to the end position of the next token or list.
+
+Return the token skipped.
+
+If USE-FORWARD-TOKEN-SIMPLE is non-nil, use
+`kotlin-mode--forward-token-simple' instead of
+`kotlin-mode--forward-token'."
+  (let* ((next-token (if use-forward-token-simple
+                         (kotlin-mode--forward-token-simple)
+                       (kotlin-mode--forward-token)))
+         (next-type (kotlin-mode--token-type next-token))
+         (next-text (kotlin-mode--token-text next-token))
+         (next-start (kotlin-mode--token-start next-token))
+         (next-end (kotlin-mode--token-end next-token))
+         result-type)
+    (cond
+     ;; Maybe list
+     ((memq next-type '({ \( \[))
+      (goto-char next-start)
+      (condition-case nil
+          (progn
+            (forward-list)
+            (setq
+             result-type
+             (if 
(kotlin-mode--close-parenthesis-before-control-structure-body-p
+                  (save-excursion (kotlin-mode--backward-token-simple)))
+                 '\(\)-before-control-structure-body
+               (assoc-default next-type '(({ . {})
+                                          (\( . \(\))
+                                          (\[ . \[\])))))
+            (make-instance
+             'kotlin-mode--token
+             :type result-type
+             :text (buffer-substring-no-properties next-start (point))
+             :start next-start
+             :end (point)))
+        (scan-error
+         (goto-char next-end)
+         next-token)))
+
+     ;; Maybe type parameter list
+     ((equal next-text "<")
+      (goto-char next-start)
+      (if (kotlin-mode--try-forward-type-parameters)
+          (make-instance
+           'kotlin-mode--token
+           :type '<>
+           :text (buffer-substring-no-properties next-start (point))
+           :start next-start
+           :end (point))
+        (goto-char next-end)
+        next-token))
+
+     ;; Other token
+     (t next-token))))
+
+(defun kotlin-mode--try-backward-type-parameters ()
+  "Move point to the start of the type parameter list.
+
+Return non-nil if succeeds.  Keep position and return nil otherwise.
+
+It is a type parameter list if:
+- it has matching angle brackets, and
+- it does not have tokens that cannot appears in a type parameter list."
+  (let ((pos (point)))
+    (if (and
+         (equal (kotlin-mode--token-text (kotlin-mode--backward-token-simple))
+                ">")
+         (kotlin-mode--try-skip-type-parameters
+          (lambda () (kotlin-mode--backward-token-or-list t))
+          "<" ">"))
+        t
+      (goto-char pos)
+      nil)))
+
+(defun kotlin-mode--try-forward-type-parameters ()
+  "Move point to the end of the type parameter list.
+
+Return non-nil if succeeds.  Keep position and return nil otherwise.
+
+It is a type parameter list if:
+- it has matching angle brackets, and
+- it does not have tokens that cannot appears in a type parameter list."
+  (let ((pos (point)))
+    (if (and
+         (equal (kotlin-mode--token-text (kotlin-mode--forward-token-simple))
+                "<")
+         (kotlin-mode--try-skip-type-parameters
+          (lambda () (kotlin-mode--forward-token-or-list t))
+          ">" "<"))
+        t
+      (goto-char pos)
+      nil)))
+
+(defconst kotlin-mode--tokens-not-in-type-parameter-list
+  ;; Whitelisting tend to be fragile. So we list tokens that are
+  ;; unlikely to appear in type parameter lists in the current
+  ;; version and future ones.
+  ;;
+  ;; Example of type parameters:
+  ;; <
+  ;;   A: B,
+  ;;   @AAA(aaa) reified in C: @AAA suspend D<X, Y>.(x: Int) -> (X)?
+  ;; >
+  ;;
+  ;; Example of type arguments
+  ;; <
+  ;;   A,
+  ;;   @AAA(aaa) in *,
+  ;;   suspend D<X, Y>.(x: Int) -> (X)?
+  ;; >
+  ;;
+  ;; We don't need to consider the contents of inner brackets because
+  ;; they are skipped by `kotlin-mode--backward-token-or-list'.
+  ;;
+  ;; String literals and numbers are also excluded by
+  ;; `kotlin-mode--try-skip-type-parameters'.
+  `(outside-of-buffer
+    \;
+    { } \( \) \[ \]
+    "%" "/" "+" "-"
+    "++" "--"
+    "&&" "||"
+    "!==" "!="
+    ;; exclude "in"
+    "is" "!is" "!in" "as" "as?"
+    "!"
+    "=" "+=" "-=" "*=" "/=" "%="
+    ".." "..<" "::" "?:" "?." "<=" ">=" "==" "==="
+    "package" "import" "class" "interface" "fun" "object" "val" "var"
+    "typealias" "constructor" "by" "companion" "init" "if" "else" "when"
+    "try" "catch" "finally" "for" "do" "while" "throw"
+    return continue break "true" "false" "null"
+    ,@(remove "suspend" kotlin-mode--modifier-keywords)))
+
+(defun kotlin-mode--try-skip-type-parameters
+    (skip-token-or-list-function matching-bracket-text unmatching-bracket-text)
+  "Skip type parameters if the point is just before/after one.
+
+Return non-nil if succeeds.  Keep position and return nil otherwise.
+
+Assuming open/close bracket is already skipped.
+
+SKIP-TOKEN-OR-LIST-FUNCTION is a function skipping forward/backward a
+token or a list.
+MATCHING-BRACKET-TEXT is a text of the matching bracket.
+UNMATCHING-BRACKET-TEXT is a text of the current bracket."
+  (let ((pos (point))
+        result
+        (prohibited-tokens (cons
+                            unmatching-bracket-text
+                            kotlin-mode--tokens-not-in-type-parameter-list))
+        (next-token (funcall skip-token-or-list-function)))
+    (while
+        (cond
+         ;; Prohibited tokens
+         ((or
+           (memq (kotlin-mode--token-type next-token) prohibited-tokens)
+           (member (kotlin-mode--token-text next-token) prohibited-tokens)
+           (string-match-p "^[\"'0-9]" (kotlin-mode--token-text next-token)))
+          ;; Not a type parameter list.
+          ;; Return to the initial position and stop the loop.
+          (goto-char pos)
+          (setq result nil)
+          nil)
+
+         ;; Matching bracket
+         ((equal (kotlin-mode--token-text next-token) matching-bracket-text)
+          ;; Found the matching open angle bracket.  Stop the loop.
+          (setq result t)
+          nil)
+
+         ;; Otherwise, keep scanning
+         (t t))
+      (setq next-token (funcall skip-token-or-list-function)))
+    result))
+
+(defun kotlin-mode--forward-token ()
+  "Move point forward to the next position of the end of a token.
+
+Return the token object.  If no more tokens available, return a token with
+type `outside-of-buffer'."
+  (let ((pos (point)))
+    ;; Skip comments and whitespaces.
+    (let ((chunk (kotlin-mode--chunk-after)))
+      ;; If point is inside a comment, go back to the beginning of the
+      ;; comment before skipping it.
+      (when (kotlin-mode--chunk-comment-p chunk)
+        (goto-char (kotlin-mode--chunk-start chunk))))
+    (forward-comment (point-max))
+    (cond
+     ;; Outside of buffer
+     ((eobp)
+      (make-instance 'kotlin-mode--token
+                     :type 'outside-of-buffer
+                     :text ""
+                     :start (point)
+                     :end (point)))
+
+     ;; Implicit semicolon
+     ((and
+       ;; Check (forward-comment (point-max)) skipped a newline.
+       (< pos
+          (save-excursion
+            (kotlin-mode--goto-non-comment-bol)
+            (point)))
+       (save-excursion (goto-char pos) (kotlin-mode--implicit-semi-p)))
+      (make-instance 'kotlin-mode--token
+                     :type 'implicit-\;
+                     :text (buffer-substring-no-properties pos (point))
+                     :start pos
+                     :end (point)))
+
+     (t
+      (let ((token (kotlin-mode--extend-annotation-token-forward
+                    (kotlin-mode--forward-token-simple))))
+        (cond
+         ;; Close parenthesis of "if ()", "while ()", or "for ()"
+         ((kotlin-mode--close-parenthesis-before-control-structure-body-p 
token)
+          (make-instance 'kotlin-mode--token
+                         :type '\)-before-control-structure-body
+                         :text (kotlin-mode--token-text token)
+                         :start (kotlin-mode--token-start token)
+                         :end (kotlin-mode--token-end token)))
+
+         ;; "else" not followed by "if" on the same line or "{"
+         ((kotlin-mode--bare-else-p token)
+          (make-instance 'kotlin-mode--token
+                         :type 'bare-else
+                         :text (kotlin-mode--token-text token)
+                         :start (kotlin-mode--token-start token)
+                         :end (kotlin-mode--token-end token)))
+
+         ;; super<A>@label
+         ((save-excursion
+            (and (equal (kotlin-mode--token-text token) "super")
+                 (eq (char-after) ?<)
+                 (kotlin-mode--try-forward-type-parameters)
+                 (eq (char-after) ?@)))
+          (kotlin-mode--try-forward-type-parameters)
+          (forward-char)
+          (skip-syntax-forward "w")
+          (make-instance 'kotlin-mode--token
+                         :type 'super
+                         :text (buffer-substring-no-properties
+                                (kotlin-mode--token-start token)
+                                (point))
+                         :start (kotlin-mode--token-start token)
+                         :end (point)))
+
+         ;; "->" of lambda parameters
+         ((kotlin-mode--anonymous-function-parameter-arrow-p token)
+          (make-instance 'kotlin-mode--token
+                         :type 'anonymous-function-parameter-arrow
+                         :text (kotlin-mode--token-text token)
+                         :start (kotlin-mode--token-start token)
+                         :end (kotlin-mode--token-end token)))
+
+         ;; "->" of when expression
+         ((kotlin-mode--when-expression-arrow-p token)
+          (make-instance 'kotlin-mode--token
+                         :type 'when-expression-arrow
+                         :text (kotlin-mode--token-text token)
+                         :start (kotlin-mode--token-start token)
+                         :end (kotlin-mode--token-end token)))
+
+         (t token)))))))
+
+(defun kotlin-mode--bare-else-p (token)
+  "Return non-nil if TOKEN is bare \"else\" token.
+
+A bare \"else\" token is a \"else\" token not followed by \"if\" on
+the same line, \"->\",  or \"{\"."
+  (let ((next-token (save-excursion
+                      (goto-char (kotlin-mode--token-end token))
+                      (kotlin-mode--forward-token-simple))))
+    (and (equal (kotlin-mode--token-text token) "else")
+         (not (eq (kotlin-mode--token-type next-token) '{))
+         (not (eq (kotlin-mode--token-text next-token) "->"))
+         (not (and
+               (equal (kotlin-mode--token-text next-token) "if")
+               (save-excursion
+                 (= (progn
+                      (goto-char (kotlin-mode--token-start next-token))
+                      (kotlin-mode--goto-non-comment-bol)
+                      (point))
+                    (progn
+                      (goto-char (kotlin-mode--token-start token))
+                      (kotlin-mode--goto-non-comment-bol)
+                      (point)))))))))
+
+(defun kotlin-mode--anonymous-function-parameter-arrow-p (token)
+  "Return non-nil if TOKEN is an arrow of lambda parameters."
+  ;; Examples:
+  ;;
+  ;; { -> 1}
+  ;; { x -> 1 }
+  ;; { f: (Int) -> Int, x: Int -> f(x) }
+  ;; { f: (Int) -> Int -> f(1) }
+  ;; { f: (Int) -> (Int) -> Int -> f(1) }
+  ;; { (x: Int, y: Int) -> x + y }
+  ;;
+  ;; If an arrow is not preceded by a close parenthesis, it is an end
+  ;; of parameters.
+  ;;
+  ;; If an arrow is preceded by a close parenthesis and the
+  ;; parentheses are preceded by an open curly bracket, the arrow is
+  ;; an end of parameters.
+  ;;
+  ;; Otherwise, it is an arrow in function types.
+  ;;
+  ;; Furthermore, the curly open bracket should not be preceded by
+  ;; "when ()".
+  (and (equal (kotlin-mode--token-text token) "->")
+       (save-excursion
+         (goto-char (kotlin-mode--token-start token))
+         (forward-comment (- (point)))
+         (or
+          ;; The arrow is not preceded by a close parenthesis.
+          ;;
+          ;; Examples:
+          ;; { -> 1}
+          ;; { x -> 1 }
+          ;; { f: (Int) -> Int, x: Int -> f(x) } // last arrow
+          ;; { f: (Int) -> Int -> f(1) } // last arrow
+          ;; { f: (Int) -> (Int) -> Int -> f(1) } // last arrow
+          (not (eq (char-before) ?\)))
+          ;; The parentheses are preceded by an open curly bracket.
+          ;;
+          ;; Example:
+          ;; { (x: Int, y: Int) -> x + y }
+          (condition-case nil
+              (progn (backward-list)
+                     (forward-comment (- (point)))
+                     (eq (char-before) ?{))
+            (scan-error nil))))
+       (save-excursion
+         ;; The token is inside a curly brackets but not inside a
+         ;; when-expression.
+         (goto-char (kotlin-mode--token-start token))
+         (let ((containing-bracket
+                (kotlin-mode--find-containing-brackets (point))))
+           (and (eq (car containing-bracket) '{)
+                (not (kotlin-mode--inside-when-expression-p
+                      containing-bracket)))))))
+
+(defun kotlin-mode--when-expression-arrow-p (token)
+  "Return non-nil if TOKEN is an arrow of when expression."
+  ;; This function does not distinguish arrows of when expression and
+  ;; ones of function types.
+  (and (equal (kotlin-mode--token-text token) "->")
+       (save-excursion
+         (goto-char (kotlin-mode--token-start token))
+         (kotlin-mode--inside-when-expression-p))))
+
+(defun kotlin-mode--inside-when-expression-p (&optional containing-bracket)
+  "Return non-nil if point is inside a when expression.
+
+CONTAINING-BRACKET is a return value of
+`kotlin-mode--find-containing-brackets'.  If ommitted,
+\(kotlin-mode--find-containing-brackets (point)) is used."
+  (unless containing-bracket
+    (setq containing-bracket (kotlin-mode--find-containing-brackets (point))))
+  (goto-char (cdr containing-bracket))
+  (and (eq (car containing-bracket) '{)
+       (eq (kotlin-mode--token-type (kotlin-mode--backward-token-or-list t))
+           '\(\))
+       (equal (kotlin-mode--token-text (kotlin-mode--backward-token-simple))
+              "when")))
+
+(defun kotlin-mode--forward-token-simple ()
+  "Like `kotlin-mode--forward-token' without recursion.
+
+This function does not return `implicit-;'."
+  (forward-comment (point-max))
+  (cond
+   ;; Outside of buffer
+   ((eobp)
+    (make-instance 'kotlin-mode--token
+                   :type 'outside-of-buffer
+                   :text ""
+                   :start (point)
+                   :end (point)))
+
+   ;; End of template expression
+   ((and (eq (char-after) ?\})
+         (equal (get-text-property (point) 'syntax-table)
+                (string-to-syntax "|")))
+    (let ((pos-after-comment (point)))
+      (kotlin-mode--forward-string-chunk)
+      (make-instance
+       'kotlin-mode--token
+       :type 'string-chunk-after-template-expression
+       :text (buffer-substring-no-properties pos-after-comment (point))
+       :start pos-after-comment
+       :end (point))))
+
+   ;; ::
+   ((looking-at "::")
+    (forward-char 2)
+    (make-instance 'kotlin-mode--token
+                   :type 'operator
+                   :text "::"
+                   :start (- (point) 2)
+                   :end (point)))
+
+   ;; Separators and parentheses
+   ((memq (char-after) '(?, ?\; ?\{ ?\} ?\[ ?\] ?\( ?\) ?:))
+    (forward-char)
+    (make-instance 'kotlin-mode--token
+                   :type (intern (string (char-before)))
+                   :text (string (char-before))
+                   :start (1- (point))
+                   :end (point)))
+
+   ;; Open angle bracket for type parameters or type arguments
+   ;;
+   ;; We use a heuristic: spaces are inserted around inequality sign, but not
+   ;; for angle bracket, and a type parameter starts with upper case
+   ;; characters, parentheses, asterisk, keyword 'reified', keyword 'in',
+   ;; keyword 'out', keyword 'suspend', or annotations.
+   ((and (eq (char-after) ?<)
+         (looking-at
+          (rx (seq "<" (or (any "_(@[*" upper)
+                           (seq (or "reified" "in" "out" "suspend")
+                                word-end))))))
+    (forward-char)
+    (make-instance 'kotlin-mode--token
+                   :type '<
+                   :text "<"
+                   :start (1- (point))
+                   :end (point)))
+
+   ;; Close angle bracket for type parameters or type arguments
+   ;;
+   ;; Close angle bracket follows identifiers, parentheses, question symbols,
+   ;; or other angle brackets (e.g. Foo<Bar<(String)?>>)
+   ((and (eq (char-after) ?>)
+         (save-excursion
+           ;; You know that regular languages can be reversed.  Thus you may
+           ;; think that `looking-back' reverses the given regexp and scans
+           ;; chars backwards.  Nevertheless, `looking-back' function does not
+           ;; do that.  It just repeats `looking-at' with decrementing start
+           ;; position until it succeeds.  The document says that it is not
+           ;; recommended to use.  So we use combination of
+           ;; `skip-chars-backward', `skip-syntax-backward', and
+           ;; `looking-at' here.
+           (skip-chars-backward "?)>")
+           (skip-syntax-backward "w")
+           (looking-at "[[:upper:]_]")))
+    (forward-char)
+    (make-instance 'kotlin-mode--token
+                   :type '>
+                   :text ">"
+                   :start (1- (point))
+                   :end (point)))
+
+   ;; Operator (other than as, in, or is)
+   ((looking-at
+     (rx
+      (or
+       "++" "--"
+       "&&" "||"
+       "!==" "!="
+       (seq "!is" word-end) (seq "!in" word-end) "as?"
+       "!"
+       "->"
+       "..<" ".." "." "?:" "?." "?" "<" ">" "<=" ">=" "===" "=="
+       "=" "+=" "-=" "*=" "/=" "%="
+       "*" "%" "/" "+" "-" "&")))
+    (let ((text (match-string-no-properties 0))
+          (start (match-beginning 0))
+          (end (match-end 0)))
+      (goto-char end)
+      (make-instance 'kotlin-mode--token
+                     :type 'operator
+                     :text text
+                     :start start
+                     :end end)))
+
+   ;; Backquoted identifier or character literal
+   ((memq (char-after) '(?` ?'))
+    (let ((pos-after-comment (point)))
+      (kotlin-mode--forward-string-chunk)
+      (make-instance
+       'kotlin-mode--token
+       :type 'atom
+       :text (buffer-substring-no-properties pos-after-comment (point))
+       :start pos-after-comment
+       :end (point))))
+
+   ;; String
+   ((looking-at "\"")
+    (let ((pos-after-comment (point)))
+      (forward-char)
+      (kotlin-mode--end-of-string)
+      (make-instance
+       'kotlin-mode--token
+       :type 'atom
+       :text (buffer-substring-no-properties pos-after-comment (point))
+       :start pos-after-comment
+       :end (point))))
+
+   ;; Part of annotations.  Only @ and first identifier.
+   ;;
+   ;; This will be augmented by
+   ;; `kotlin-mode--extend-annotation-token-forward' later.
+   ((eq (char-after) ?@)
+    (let ((pos-after-comment (point)))
+      (forward-char)
+      (if (eq (char-after) ?`)
+          (kotlin-mode--forward-string-chunk)
+        (skip-syntax-forward "w"))
+      ;; Strictly speaking, single at sign is not an annotation, but
+      ;; we treat it as an annotation.
+      (make-instance
+       'kotlin-mode--token
+       :type 'annotation
+       :text (buffer-substring-no-properties pos-after-comment (point))
+       :start pos-after-comment
+       :end (point))))
+
+   ;; Other tokens including identifiers, keywords, labels, and numbers.
+   ;;
+   ;; Note that we parse 123.456e+2 as "123" "." "456e" "+" "2".
+   (t
+    (let* ((pos-after-comment (point))
+           (text
+            (cond
+             ;; return@label, continue@label, break@label, this@label,
+             ;; or super@label.
+             ((looking-at (rx (or "return@"
+                                  "continue@"
+                                  "break@"
+                                  "this@"
+                                  "super@")))
+              (skip-syntax-forward "w")
+              (forward-char)
+              (skip-syntax-forward "w")
+              (buffer-substring-no-properties pos-after-comment (point)))
+
+             ;; Identifiers, keywords, labels, or numbers
+             ((eq (syntax-class (syntax-after (point)))
+                  (syntax-class (string-to-syntax "w")))
+              (skip-syntax-forward "w")
+              ;; Skip an at sign if exists for label.
+              (when (eq (char-after) ?@)
+                (forward-char))
+              (buffer-substring-no-properties pos-after-comment (point)))
+             ;; Unknown character type. Treats as a single-letter token.
+             (t
+              (forward-char)
+              (string (char-before)))))
+           (type (cond
+                  ((member text '("is" "in" "as"))
+                   ;; Note that "as?" is already handled.
+                   'operator)
+
+                  ((eq (aref text (1- (length text))) ?@)
+                   'label)
+
+                  ((string-match "^return\\>" text)
+                   'return)
+
+                  ((string-match "^continue\\>" text)
+                   'return)
+
+                  ((string-match "^break\\>" text)
+                   'break)
+
+                  ((string-match "^this\\>" text)
+                   'this)
+
+                  ((string-match "^super\\>" text)
+                   'super)
+
+                  (t
+                   'atom))))
+      (make-instance 'kotlin-mode--token
+                     :type type
+                     :text text
+                     :start (- (point) (length text))
+                     :end (point))))))
+
+(defun kotlin-mode--extend-annotation-token-forward (token)
+  "Return annotation token if TOKEN is the start of an annotation.
+
+TOKEN is assumed to be a return value of `kotlin-mode--forward-token-simple'."
+  (if (eq (kotlin-mode--token-type token) 'annotation)
+      (let ((pos (point)))
+        (cond
+         ;; Example: @file:Abc(def)
+         ;; Example: @file:[Abc Def Ghi]
+         ((save-excursion
+            (forward-comment (point-max))
+            (eq (char-after) ?:))
+          (forward-comment (point-max))
+          (forward-char)
+          (unless (or (kotlin-mode--try-forward-multi-annotation-bracket)
+                      (kotlin-mode--try-forward-unescaped-annotation))
+            (goto-char pos)))
+
+         ;; Example: @[Abc Def Ghi]
+         ((equal (kotlin-mode--token-text token) "@")
+          (kotlin-mode--try-forward-multi-annotation-bracket))
+
+         ;; Example: @Abc(def)
+         (t
+          (goto-char (1+ (kotlin-mode--token-start token)))
+          (kotlin-mode--try-forward-unescaped-annotation)))
+        (make-instance 'kotlin-mode--token
+                       :type 'annotation
+                       :text (buffer-substring-no-properties
+                              (kotlin-mode--token-start token)
+                              (point))
+                       :start (kotlin-mode--token-start token)
+                       :end (point)))
+    token))
+
+(defun kotlin-mode--try-forward-multi-annotation-bracket ()
+  "Move point forward to the end of square brackets.
+
+Return non-nil if succeeds.  Keep position and return nil otherwise."
+  (let ((pos (point)))
+    (when (save-excursion
+            (forward-comment (point-max))
+            (eq (char-after) ?\[))
+      (condition-case nil
+          (progn
+            (forward-list)
+            t)
+        (scan-error
+         (goto-char pos)
+         nil)))))
+
+(defun kotlin-mode--try-forward-unescaped-annotation ()
+  "Move point forward to the end of unescapedAnnotation.
+
+Skip userType and constructor arguments if exists.
+
+Return non-nil if succeeds.  Keep position and return nil otherwise."
+  (if (kotlin-mode--try-forward-type-reference)
+      (let ((pos (point)))
+        (when (save-excursion
+                ;; Line breaks are prohibited before bracket.
+                (kotlin-mode--forward-comments-but-not-line-breaks)
+                (eq (char-after) ?\())
+          (condition-case nil
+              (forward-list)
+            (scan-error
+             (goto-char pos))))
+        t)
+    nil))
+
+(defun kotlin-mode--backward-token ()
+  "Move point backward to the previous position of the end of a token.
+
+Return the token object.  If no more tokens available, return a token with
+type `outside-of-buffer'."
+  (let ((pos (point)))
+    ;; Skip comments and whitespaces.
+    (let ((chunk (kotlin-mode--chunk-after)))
+      (when (kotlin-mode--chunk-comment-p chunk)
+        (goto-char (kotlin-mode--chunk-start chunk))))
+    (forward-comment (- (point)))
+    (cond
+     ;; Outside of buffer
+     ((bobp)
+      (make-instance 'kotlin-mode--token
+                     :type 'outside-of-buffer
+                     :text ""
+                     :start (point)
+                     :end (point)))
+
+     ;; Implicit semicolon
+     ((and
+       ;; Check (forward-comment (- (point))) skipped a newline.
+       (< (save-excursion
+            (kotlin-mode--goto-non-comment-eol)
+            (point))
+          pos)
+       (save-excursion (goto-char pos) (kotlin-mode--implicit-semi-p)))
+      (make-instance 'kotlin-mode--token
+                     :type 'implicit-\;
+                     :text (buffer-substring-no-properties (point) pos)
+                     :start (point)
+                     :end pos))
+
+     (t
+      (let ((token (kotlin-mode--extend-annotation-token-backward
+                    (kotlin-mode--backward-token-simple))))
+        (cond
+         ;; Close parenthesis of "if ()", "while ()", or "for ()"
+         ((kotlin-mode--close-parenthesis-before-control-structure-body-p 
token)
+          (make-instance 'kotlin-mode--token
+                         :type '\)-before-control-structure-body
+                         :text (kotlin-mode--token-text token)
+                         :start (kotlin-mode--token-start token)
+                         :end (kotlin-mode--token-end token)))
+
+         ;; "else" not followed by "if" on the same line or "{"
+         ((kotlin-mode--bare-else-p token)
+          (make-instance 'kotlin-mode--token
+                         :type 'bare-else
+                         :text (kotlin-mode--token-text token)
+                         :start (kotlin-mode--token-start token)
+                         :end (kotlin-mode--token-end token)))
+
+         ;; super<A>@label
+         ((save-excursion
+            (and (eq (kotlin-mode--token-type token) 'annotation)
+                 (eq (char-before) ?>)
+                 (kotlin-mode--try-backward-type-parameters)
+                 (equal (kotlin-mode--token-text
+                         (kotlin-mode--backward-token-simple))
+                        "super")))
+          (kotlin-mode--try-backward-type-parameters)
+          (kotlin-mode--backward-token-simple)
+          (make-instance 'kotlin-mode--token
+                         :type 'super
+                         :text (buffer-substring-no-properties
+                                (point)
+                                (kotlin-mode--token-end token))
+                         :start (point)
+                         :end (kotlin-mode--token-end token)))
+
+         ;; "->" of lambda parameters
+         ((kotlin-mode--anonymous-function-parameter-arrow-p token)
+          (make-instance 'kotlin-mode--token
+                         :type 'anonymous-function-parameter-arrow
+                         :text (kotlin-mode--token-text token)
+                         :start (kotlin-mode--token-start token)
+                         :end (kotlin-mode--token-end token)))
+
+         ;; "->" of when expression
+         ((kotlin-mode--when-expression-arrow-p token)
+          (make-instance 'kotlin-mode--token
+                         :type 'when-expression-arrow
+                         :text (kotlin-mode--token-text token)
+                         :start (kotlin-mode--token-start token)
+                         :end (kotlin-mode--token-end token)))
+
+         (t token)))))))
+
+(defun kotlin-mode--backward-token-simple ()
+  "Like `kotlin-mode--backward-token' without recursion.
+
+This function does not return `implicit-;'"
+  (forward-comment (- (point)))
+  (cond
+   ;; Outside of buffer
+   ((bobp)
+    (make-instance 'kotlin-mode--token
+                   :type 'outside-of-buffer
+                   :text ""
+                   :start (point)
+                   :end (point)))
+
+   ;; Beginning of template expression
+   ((and (eq (char-before) ?\{)
+         (equal (get-text-property (1- (point)) 'syntax-table)
+                (string-to-syntax "|")))
+    (let ((pos-before-comment (point)))
+      (kotlin-mode--backward-string-chunk)
+      (make-instance
+       'kotlin-mode--token
+       :type 'string-chunk-before-template-expression
+       :text (buffer-substring-no-properties (point) pos-before-comment)
+       :start (point)
+       :end pos-before-comment)))
+
+   ;; ::, ?:
+   ((member (buffer-substring-no-properties
+             (max (point-min) (- (point) 2))
+             (point))
+            '("::" "?:"))
+    (backward-char 2)
+    (make-instance 'kotlin-mode--token
+                   :type 'operator
+                   :text (buffer-substring-no-properties (point) (+ 2 (point)))
+                   :start (point)
+                   :end (+ 2 (point))))
+
+   ;; Separators and parentheses
+   ((memq (char-before) '(?, ?\; ?\{ ?\} ?\[ ?\] ?\( ?\) ?:))
+    (backward-char)
+    (make-instance 'kotlin-mode--token
+                   :type (intern (string (char-after)))
+                   :text (string (char-after))
+                   :start (point)
+                   :end (1+ (point))))
+
+   ;; Operator (3 letters)
+   ((member (buffer-substring-no-properties
+             (max (point-min) (- (point) 3))
+             (point))
+            '("===" "!==" "!is" "!in" "..<"))
+    (backward-char 3)
+    (make-instance 'kotlin-mode--token
+                   :type 'operator
+                   :text (buffer-substring-no-properties (point) (+ 3 (point)))
+                   :start (point)
+                   :end (+ 3 (point))))
+
+   ;; Operator (2 letters, other than as, in, or is)
+   ((member (buffer-substring-no-properties
+             (max (point-min) (- (point) 2))
+             (point))
+            '("++" "--"
+              "&&" "||"
+              "+=" "-=" "*=" "/=" "%="
+              ".." "?."
+              "<=" ">=" "!=" "=="
+              "->"))
+    (backward-char 2)
+    (make-instance 'kotlin-mode--token
+                   :type 'operator
+                   :text (buffer-substring-no-properties (point) (+ 2 (point)))
+                   :start (point)
+                   :end (+ 2 (point))))
+
+   ;; Open angle bracket for type parameters
+   ;;
+   ;; We use a heuristic: spaces are inserted around inequality sign,
+   ;; but not for angle bracket, and a type parameter starts with an
+   ;; upper case characters, parenthesis, or keyword 'reified',
+   ;; keyword 'in', keyword 'out', keyword 'suspend', or annotations.
+   ((and (eq (char-before) ?<)
+         (looking-at
+          (rx (or (any "_(@[*" upper)
+                  (seq (or "reified" "in" "out")
+                       word-end)))))
+    (backward-char)
+    (make-instance 'kotlin-mode--token
+                   :type '<
+                   :text "<"
+                   :start (point)
+                   :end (1+ (point))))
+
+   ;; Close angle bracket for type parameters
+   ;;
+   ;; Close angle bracket follows identifier, parentheses, question symbols,
+   ;; or other angle brackets (e.g. Foo<Bar<(String)?>>)
+   ((and (eq (char-before) ?>)
+         (save-excursion
+           (skip-chars-backward "?)>")
+           (skip-syntax-backward "w")
+           (looking-at "[[:upper:]_]")))
+    (backward-char)
+    (make-instance 'kotlin-mode--token
+                   :type '>
+                   :text ">"
+                   :start (point)
+                   :end (1+ (point))))
+
+   ;; ? or as?
+   ((eq (char-before) ??)
+    (let ((pos-before-comment (point)))
+      (backward-char)
+      (skip-syntax-backward "w")
+      (unless (looking-at (rx "as?"))
+        (goto-char pos-before-comment)
+        (backward-char))
+      (make-instance
+       'kotlin-mode--token
+       :type 'operator
+       :text (buffer-substring-no-properties (point) pos-before-comment)
+       :start (point)
+       :end pos-before-comment)))
+
+   ;; Operator (1 letter)
+   ((member (buffer-substring-no-properties
+             (max (point-min) (- (point) 1))
+             (point))
+            '("*" "%" "/" "+" "-" "!" "=" "." "?" "<" ">" "&"))
+    (backward-char)
+    (make-instance 'kotlin-mode--token
+                   :type 'operator
+                   :text (buffer-substring-no-properties (point) (1+ (point)))
+                   :start (point)
+                   :end (1+ (point))))
+
+   ;; Backquoted identifier
+   ((eq (char-before) ?`)
+    (let ((pos-before-comment (point)))
+      (kotlin-mode--backward-string-chunk)
+      (when (eq (char-before) ?@)
+        (backward-char))
+      (make-instance
+       'kotlin-mode--token
+       :type (if (eq (char-after) ?@) 'annotation 'atom)
+       :text (buffer-substring-no-properties (point) pos-before-comment)
+       :start (point)
+       :end pos-before-comment)))
+
+   ;; character literal
+   ((eq (char-before) ?')
+    (let ((pos-before-comment (point)))
+      (kotlin-mode--backward-string-chunk)
+      (make-instance
+       'kotlin-mode--token
+       :type 'atom
+       :text (buffer-substring-no-properties (point) pos-before-comment)
+       :start (point)
+       :end pos-before-comment)))
+
+   ;; String
+   ((eq (char-before) ?\")
+    (let ((pos-before-comment (point)))
+      (backward-char)
+      (kotlin-mode--beginning-of-string)
+      (make-instance
+       'kotlin-mode--token
+       :type 'atom
+       :text (buffer-substring-no-properties (point) pos-before-comment)
+       :start (point)
+       :end pos-before-comment)))
+
+   ;; Other tokens including identifiers, keywords, labels, numbers,
+   ;; and annotations without bracket.
+   ;;
+   ;; Note that we parse 123.456e+2 as "123" "." "456e" "+" "2".
+   (t
+    (let* ((pos-before-comment (point))
+           (text
+            (cond
+             ;; Labels (and single at sign)
+             ((eq (char-before) ?@)
+              (backward-char)
+              (skip-syntax-backward "w")
+              (buffer-substring-no-properties (point) pos-before-comment))
+
+             ;; Identifiers, keywords, numbers, (part of) annotations
+             ((eq (syntax-class (syntax-after (1- (point))))
+                  (syntax-class (string-to-syntax "w")))
+              (skip-syntax-backward "w")
+              (when (eq (char-before) ?@)
+                ;; Annotation, return@ or something like it.
+                (backward-char)
+                (let ((pos (point)))
+                  (skip-syntax-backward "w")
+                  (unless (looking-at
+                           (rx (or "return"
+                                   "continue"
+                                   "break"
+                                   "this"
+                                   "super")))
+                    (goto-char pos))))
+              (buffer-substring-no-properties (point) pos-before-comment))
+
+             ;; Unknown character type. Treats as a single-letter token.
+             (t (backward-char) (string (char-after)))))
+           (type (cond
+                  ((member text '("as" "in" "is"))
+                   'operator)
+
+                  ((string-prefix-p "@" text)
+                   ;; Strictly speaking, single at sign is not an
+                   ;; annotation, but we treat it as an annotation.
+                   'annotation)
+
+                  ((string-match "^return\\>" text)
+                   'return)
+
+                  ((string-match "^continue\\>" text)
+                   'return)
+
+                  ((string-match "^break\\>" text)
+                   'break)
+
+                  ((string-match "^this\\>" text)
+                   'this)
+
+                  ((string-match "^super\\>" text)
+                   'super)
+
+                  ((eq (aref text (1- (length text))) ?@)
+                   'label)
+
+                  (t
+                   'atom))))
+      (make-instance 'kotlin-mode--token
+                     :type type
+                     :text text
+                     :start (point)
+                     :end (+ (point) (length text)))))))
+
+(defun kotlin-mode--extend-annotation-token-backward (token)
+  "Return annotation token if TOKEN is the end of an annotation.
+
+TOKEN is assumed to be a return value of `kotlin-mode--backward-token-simple'."
+  (let ((pos (point)))
+    (goto-char (kotlin-mode--token-end token))
+    (cond
+     ;; Example: @[Abc Def Ghi]
+     ;; Example: @file:[Abc Def Ghi]
+     ((eq (char-before) ?\])
+      (condition-case nil
+          (progn
+            (backward-list)
+            (forward-comment (- (point)))
+            (if (or (and (eq (char-before) ?@) (prog1 t (backward-char)))
+                    (kotlin-mode--try-backward-annotation-use-site-target))
+                (make-instance 'kotlin-mode--token
+                               :type 'annotation
+                               :text (buffer-substring-no-properties
+                                      (point)
+                                      (kotlin-mode--token-end token))
+                               :start (point)
+                               :end (kotlin-mode--token-end token))
+              ;; Not an annotation.
+              (goto-char pos)
+              token))
+        (scan-error
+         ;; Not an annotation.
+         (goto-char pos)
+         token)))
+
+     ;; Example: @Abc<A>(def)
+     ;; Example: @file:Abc<A>(def)
+     ;; Example: @Abc<A>
+     ;; Example: @file:Abc<A>
+     ;; Example: @Abc
+     ((or (memq (char-before) '(?\) ?` ?>))
+          (eq (syntax-class (syntax-after (1- (point))))
+              (syntax-class (string-to-syntax "w"))))
+      (when (eq (char-before) ?\))
+        (condition-case nil
+            (progn
+              (backward-list)
+              ;; Line breaks are prohibited before bracket.
+              (kotlin-mode--backward-comments-but-not-line-breaks)
+              (unless (or (memq (char-before) '(?` ?>))
+                          (eq (syntax-class (syntax-after (1- (point))))
+                              (syntax-class (string-to-syntax "w"))))
+                (goto-char pos)))
+          (scan-error
+           (goto-char pos))))
+      (if (and
+           (kotlin-mode--try-backward-type-reference)
+           (or (and (eq (char-before) ?@) (prog1 t (backward-char)))
+               (kotlin-mode--try-backward-annotation-use-site-target)))
+          (make-instance 'kotlin-mode--token
+                         :type 'annotation
+                         :text (buffer-substring-no-properties
+                                (point)
+                                (kotlin-mode--token-end token))
+                         :start (point)
+                         :end (kotlin-mode--token-end token))
+        ;; Not an annotation.
+        (goto-char pos)
+        token))
+
+     ;; Not an annotation.
+     (t
+      (goto-char pos)
+      token))))
+
+(defun kotlin-mode--try-backward-annotation-use-site-target ()
+  "Try backward annotationUseSiteTarget.
+
+Try to skip colon, word, and at sign.
+
+Return non-nil if succeeds.  Keep position and return nil otherwise."
+  (let ((pos (point)))
+    (forward-comment (- (point)))
+    (if (eq (char-before) ?:)
+        (progn
+          (backward-char)
+          (forward-comment (- (point)))
+          (if (and (< (skip-syntax-backward "w") 0)
+                   (eq (char-before) ?@))
+              (progn
+                (backward-char)
+                t)
+            (goto-char pos)
+            nil))
+      (goto-char pos)
+      nil)))
+
+(defun kotlin-mode--forward-string-chunk ()
+  "Skip forward a string chunk.
+
+A string chunk is a part of single-line/multiline string delimited with
+quotation marks or template expressions."
+  (condition-case nil
+      (goto-char (scan-sexps (point) 1))
+    (scan-error (goto-char (point-max)))))
+
+(defun kotlin-mode--backward-string-chunk ()
+  "Skip backward a string chunk.
+
+A string chunk is a part of single-line/multiline string delimited with
+quotation marks or template expressions."
+  (condition-case nil
+      (goto-char (scan-sexps (point) -1))
+    (scan-error (goto-char (point-min)))))
+
+(defun kotlin-mode--beginning-of-string ()
+  "Move point to the beginning of single-line/multiline string.
+
+Return the point of the beginning.
+
+Assuming the point is on a string."
+  (goto-char (or (nth 8 (syntax-ppss)) (point)))
+  (let (matching-bracket)
+    (while (and
+            (setq matching-bracket
+                  (get-text-property
+                   (point)
+                   'kotlin-property--matching-bracket))
+            (< (point-min) matching-bracket))
+      (goto-char matching-bracket)
+      (goto-char (nth 8 (syntax-ppss))))
+    (point)))
+
+(defun kotlin-mode--end-of-string ()
+  "Move point to the end of single-line/multiline string.
+
+Assuming the point is on a string."
+  (goto-char (or (nth 8 (syntax-ppss)) (point)))
+  (let (matching-bracket)
+    (kotlin-mode--forward-string-chunk)
+    (while (and (setq matching-bracket
+                      (get-text-property
+                       (1- (point))
+                       'kotlin-property--matching-bracket))
+                (< matching-bracket (point-max)))
+      (goto-char matching-bracket)
+      (kotlin-mode--forward-string-chunk)))
+  (point))
+
+(defun kotlin-mode--goto-non-comment-bol ()
+  "Back to the beginning of line that is not inside a comment."
+  (beginning-of-line)
+  (let (chunk)
+    (while (progn
+             (setq chunk (kotlin-mode--chunk-after))
+             (kotlin-mode--chunk-comment-p chunk))
+      ;; The point is in a comment. Backs to the beginning of the comment.
+      (goto-char (kotlin-mode--chunk-start chunk))
+      (beginning-of-line))))
+
+(defun kotlin-mode--goto-non-comment-eol ()
+  "Proceed to the end of line that is not inside a comment.
+
+If this line ends with a single-line comment, goto just before the comment."
+  (end-of-line)
+  (let (chunk)
+    (while (progn
+             (setq chunk (kotlin-mode--chunk-after))
+             (kotlin-mode--chunk-comment-p chunk))
+      ;; The point is in a comment.
+      (if (kotlin-mode--chunk-single-line-comment-p chunk)
+          ;; This is a single-line comment
+          ;; Back to the beginning of the comment.
+          (goto-char (kotlin-mode--chunk-start chunk))
+        ;; This is a multiline comment
+        ;; Proceed to the end of the comment.
+        (goto-char (kotlin-mode--chunk-start chunk))
+        (forward-comment 1)
+        (end-of-line)
+        ;; If the comment is incomplete, back to the beginning of the comment.
+        (when (and (eobp) (kotlin-mode--chunk-after))
+          (goto-char (kotlin-mode--chunk-start 
(kotlin-mode--chunk-after))))))))
+
+(defun kotlin-mode--bol-other-than-comments-p ()
+  "Return t if there is nothing other than comments in the front of this line.
+
+Return nil otherwise.
+Newlines inside comments are ignored."
+  ;; Foo // ← bol
+  ;; /* */ Foo // ← bol
+  ;; X /* */ Foo // ← not bol
+  ;;
+  ;; /*
+  ;; */ /* */ /*
+  ;; */ Foo // ← bol
+  ;;
+  ;; X /*
+  ;; */ /* */ /*
+  ;; */ Foo // ← not bol
+  ;;
+  ;; X
+  ;; /* */ /*
+  ;; */ Foo // ← bol
+  (save-excursion
+    (let ((pos (point)))
+      (kotlin-mode--goto-non-comment-bol)
+      (forward-comment (point-max))
+      (<= pos (point)))))
+
+(defun kotlin-mode--eol-other-than-comments-p ()
+  "Return t if there is nothing other than comments until the end of this line.
+
+Return nil otherwise.
+Newlines inside comments are ignored."
+  (save-excursion
+    (let ((pos (point)))
+      (kotlin-mode--goto-non-comment-eol)
+      (forward-comment (- (point)))
+      (<= (point) pos))))
+
+(defun kotlin-mode--skip-whitespaces ()
+  "Skip forward whitespaces and newlines."
+  (skip-syntax-forward " >"))
+
+(defun kotlin-mode--forward-comments-but-not-line-breaks ()
+  "Skip forward comments but not line breaks."
+  (goto-char (min
+              (save-excursion
+                (kotlin-mode--goto-non-comment-eol)
+                (point))
+              (save-excursion
+                (forward-comment (point-max))
+                (point)))))
+
+(defun kotlin-mode--backward-comments-but-not-line-breaks ()
+  "Skip backward comments but not line breaks."
+  (goto-char (max
+              (save-excursion
+                (kotlin-mode--goto-non-comment-bol)
+                (point))
+              (save-excursion
+                (forward-comment (- (point)))
+                (point)))))
+
 (provide 'kotlin-mode-lexer)
 
 ;;; kotlin-mode-lexer.el ends here
diff --git a/kotlin-mode.el b/kotlin-mode.el
index 6b715a5b4d..eedbb35954 100644
--- a/kotlin-mode.el
+++ b/kotlin-mode.el
@@ -1,11 +1,12 @@
 ;;; kotlin-mode.el --- Major mode for kotlin -*- lexical-binding: t; -*-
 
-;; Copyright © 2015  Shodai Yokoyama
+;; Copyright © 2015 Shodai Yokoyama
 
 ;; Author: Shodai Yokoyama (quantumcars@gmail.com)
 ;; Version: 2.0.0
 ;; Keywords: languages
 ;; Package-Requires: ((emacs "24.3"))
+;; URL: https://github.com/Emacs-Kotlin-Mode-Maintainers/kotlin-mode
 
 ;; This program is free software; you can redistribute it and/or modify
 ;; it under the terms of the GNU General Public License as published by
@@ -22,7 +23,7 @@
 
 ;;; Commentary:
 
-;;
+;; Major-mode for Kotlin programming language.
 
 ;;; Code:
 
@@ -33,6 +34,7 @@
 (require 'eieio)
 
 (require 'kotlin-mode-lexer)
+(require 'kotlin-mode-indent)
 
 (defgroup kotlin nil
   "A Kotlin major mode."
@@ -59,18 +61,25 @@
   :type 'string
   :group 'kotlin)
 
+;; REPL
+
 (defun kotlin-do-and-repl-focus (f &rest args)
+  "Call function F with ARGS and pop to the REPL buffer."
   (apply f args)
   (pop-to-buffer kotlin-repl-buffer))
 
 (defun kotlin-send-region (start end)
-  "Send current region to Kotlin interpreter."
+  "Send current region to Kotlin interpreter.
+
+START and END define region within current buffer."
   (interactive "r")
   (comint-send-region kotlin-repl-buffer start end)
   (comint-send-string kotlin-repl-buffer "\n"))
 
 (defun kotlin-send-region-and-focus (start end)
-  "Send current region to Kotlin interpreter and switch to it."
+  "Send current region to Kotlin interpreter and switch to it.
+
+START and END define region within current buffer."
   (interactive "r")
   (kotlin-do-and-repl-focus 'kotlin-send-region start end))
 
@@ -97,6 +106,7 @@
   (kotlin-do-and-repl-focus 'kotlin-send-block))
 
 (defun kotlin-send-line ()
+  "Send current line to Kotlin interpreter."
   (interactive)
   (kotlin-send-region
    (line-beginning-position)
@@ -121,11 +131,13 @@
             kotlin-args-repl))
 
     (set (make-local-variable 'comint-preoutput-filter-functions)
-         (cons (lambda (string)
-                 (replace-regexp-in-string "\x1b\\[.[GJK]" "" string)) nil)))
+         (list (lambda (string)
+                 (replace-regexp-in-string "\x1b\\[.[GJK]" "" string)))))
 
   (pop-to-buffer kotlin-repl-buffer))
 
+;; Keymap
+
 (defvar kotlin-mode-map
   (let ((map (make-keymap)))
     (define-key map (kbd "C-c C-z") 'kotlin-repl)
@@ -133,37 +145,18 @@
     (define-key map (kbd "C-c C-r") 'kotlin-send-region)
     (define-key map (kbd "C-c C-c") 'kotlin-send-block)
     (define-key map (kbd "C-c C-b") 'kotlin-send-buffer)
+    (define-key map [remap indent-new-comment-line]
+      #'kotlin-mode--indent-new-comment-line)
     map)
-  "Keymap for kotlin-mode")
-
-(defvar kotlin-mode-syntax-table
-  (let ((st (make-syntax-table)))
-
-    ;; Strings
-    (modify-syntax-entry ?\" "\"" st)
-    (modify-syntax-entry ?\' "\"" st)
-    (modify-syntax-entry ?` "\"" st)
-
-    ;; `_' and `@' as being a valid part of a symbol
-    (modify-syntax-entry ?_ "_" st)
-    (modify-syntax-entry ?@ "_" st)
-
-    ;; b-style comment
-    (modify-syntax-entry ?/ ". 124b" st)
-    (modify-syntax-entry ?* ". 23n" st)
-    (modify-syntax-entry ?\n "> b" st)
-    (modify-syntax-entry ?\r "> b" st)
-    st))
-
-(defconst kotlin-mode--closing-brackets '(?} ?\) ?\]))
+  "Keymap for `kotlin-mode'.")
 
 ;;; Font Lock
 
-(defconst kotlin-mode--misc-keywords
+(defconst kotlin-mode--package-keywords
   '("package" "import"))
 
 (defconst kotlin-mode--type-decl-keywords
-  '("sealed" "inner" "data" "class" "interface" "trait" "typealias" "enum" 
"object"))
+  '("class" "interface" "typealias" "object"))
 
 (defconst kotlin-mode--fun-decl-keywords
   '("fun"))
@@ -187,8 +180,8 @@
 (defconst kotlin-mode--generic-type-parameter-keywords
   '("where"))
 
-(defvar kotlin-mode--keywords
-  (append kotlin-mode--misc-keywords
+(defvar kotlin-mode--misc-keywords
+  (append kotlin-mode--package-keywords
           kotlin-mode--type-decl-keywords
           kotlin-mode--fun-decl-keywords
           kotlin-mode--val-decl-keywords
@@ -200,15 +193,14 @@
 (defconst kotlin-mode--constants-keywords
   '("null" "true" "false"))
 
-(defconst kotlin-mode--modifier-keywords
-  '("open" "private" "protected" "public" "lateinit"
-    "override" "abstract" "final" "companion"
-    "annotation" "internal" "const" "in" "out"
-    "actual" "expect" "crossinline" "inline" "noinline" "external"
-    "infix" "operator" "reified" "suspend" "tailrec" "vararg"))
+(defconst kotlin-mode--variance-modifier-keywords
+  '("in" "out"))
+
+(defconst kotlin-mode--reification-modifier-keywords
+  '("reified"))
 
 (defconst kotlin-mode--property-keywords
-  '("by" "get" "set")) ;; "by" "get" "set"
+  '("by" "get" "set"))
 
 (defconst kotlin-mode--initializer-keywords
   '("init" "constructor"))
@@ -223,13 +215,13 @@
 (defvar kotlin-mode--font-lock-keywords
   `(;; Keywords
     (,(rx-to-string
-       `(and bow (group (or ,@kotlin-mode--keywords)) eow)
+       `(and bow (group (or ,@kotlin-mode--misc-keywords)) eow)
        t)
      1 font-lock-keyword-face)
 
     ;; Package names
     (,(rx-to-string
-       `(and (or ,@kotlin-mode--misc-keywords) (+ space)
+       `(and (or ,@kotlin-mode--package-keywords) (+ space)
              (group (+ (any word ?.))))
        t)
      1 font-lock-string-face)
@@ -273,11 +265,14 @@
        t)
      1 font-lock-function-name-face)
 
-    ;; Access modifier
-    ;; Access modifier is valid identifier being used as variable
+    ;; Modifiers
+    ;; Modifier is valid identifier being used as variable
     ;; TODO: Highlight only modifiers in the front of class/fun
     (,(rx-to-string
-       `(and bow (group (or ,@kotlin-mode--modifier-keywords))
+       `(and bow (group (or ,@kotlin-mode--modifier-keywords
+                            ,@kotlin-mode--companion-modifier-keywords
+                            ,@kotlin-mode--variance-modifier-keywords
+                            ,@kotlin-mode--reification-modifier-keywords))
              eow)
        t)
      1 font-lock-keyword-face)
@@ -312,9 +307,14 @@
 
     ;; String interpolation
     (kotlin-mode--match-interpolation 0 font-lock-variable-name-face t))
-  "Default highlighting expression for `kotlin-mode'")
+  "Default highlighting expression for `kotlin-mode'.")
 
 (defun kotlin-mode--match-interpolation (limit)
+  "Find template expression before LIMIT.
+
+Template expressions must be propertized by `kotlin-mode--syntax-propertize'.
+If a template expression is found, move to that point, set `match-data',
+and return non-nil.  Return nil otherwise."
   (let ((pos (next-single-char-property-change
               (point)
               'kotlin-property--interpolation
@@ -328,233 +328,56 @@
                    t)
           (kotlin-mode--match-interpolation limit))))))
 
-(defun kotlin-mode--prev-line ()
-  "Moves up to the nearest non-empty line"
-  (if (not (bobp))
-      (progn
-        (forward-line -1)
-        (while (and (looking-at "^[ \t]*$") (not (bobp)))
-          (forward-line -1)))))
-
-(defun kotlin-mode--prev-line-begins (pattern)
-  "Return whether the previous line begins with the given pattern"
-  (save-excursion
-    (kotlin-mode--prev-line)
-    (looking-at (format "^[ \t]*%s" pattern))))
-
-(defun kotlin-mode--prev-line-ends (pattern)
-  "Return whether the previous line ends with the given pattern"
-  (save-excursion
-    (kotlin-mode--prev-line)
-    (looking-at (format ".*%s[ \t]*$" pattern))))
-
-(defun kotlin-mode--line-begins (pattern)
-  "Return whether the current line begins with the given pattern"
-  (save-excursion
-    (beginning-of-line)
-    (looking-at (format "^[ \t]*%s" pattern))))
-
-(defun kotlin-mode--line-ends (pattern)
-  "Return whether the current line ends with the given pattern"
-  (save-excursion
-    (beginning-of-line)
-    (looking-at (format ".*%s[ \t]*$" pattern))))
-
-(defun kotlin-mode--line-contains (pattern)
-  "Return whether the current line contains the given pattern"
-  (save-excursion
-    (beginning-of-line)
-    (looking-at (format ".*%s.*" pattern))))
-
-(defun kotlin-mode--line-continuation()
-  "Return whether this line continues a statement in the previous line"
-  (or
-   (and (kotlin-mode--prev-line-begins "\\(if\\|for\\|while\\)[ \t]+(")
-        (kotlin-mode--prev-line-ends ")[[:space:]]*\\(\/\/.*\\|\\/\\*.*\\)?"))
-   (and (kotlin-mode--prev-line-begins "else[ \t]*")
-        (not (kotlin-mode--prev-line-begins "else [ \t]*->"))
-        (not (kotlin-mode--prev-line-ends "{.*")))
-   (or
-    (kotlin-mode--line-begins 
"\\([.=:]\\|->\\|\\(\\(private\\|public\\|protected\\|internal\\)[ 
\t]*\\)?[sg]et\\b\\)"))))
-
-(defun kotlin-mode--in-comment-block ()
-  "Return whether the cursor is within a standard comment block structure
-   of the following format:
-   /**
-    * Description here
-    */"
-  (save-excursion
-    (let ((in-comment-block nil)
-          (keep-going (and
-                       (not (kotlin-mode--line-begins "\\*\\*+/"))
-                       (not (kotlin-mode--line-begins "/\\*"))
-                       (nth 4 (syntax-ppss)))))
-      (while keep-going
-        (kotlin-mode--prev-line)
-        (cond
-         ((kotlin-mode--line-begins "/\\*")
-          (setq keep-going nil)
-          (setq in-comment-block t))
-         ((bobp)
-          (setq keep-going nil))
-         ((kotlin-mode--line-contains "\\*/")
-          (setq keep-going nil))))
-      in-comment-block)))
-
-(defun kotlin-mode--first-line-p ()
-  "Determine if point is on the first line."
-  (save-excursion
-    (beginning-of-line)
-    (bobp)
-    )
-  )
-
-(defun kotlin-mode--line-closes-block-p ()
-  "Return whether or not the start of the line closes its containing block."
-  (save-excursion
-    (back-to-indentation)
-    (memq (following-char) kotlin-mode--closing-brackets)
-    ))
-
-(defun kotlin-mode--get-opening-char-indentation (parser-state-index)
-  "Determine the indentation of the line that starts the current block.
-
-Caller must pass in PARSER-STATE-INDEX, which refers to the index
-of the list returned by `syntax-ppss'.
-
-If it does not exist, will return nil."
-  (save-excursion
-    (back-to-indentation)
-    (let ((opening-pos (nth parser-state-index (syntax-ppss))))
-      (when opening-pos
-        (goto-char opening-pos)
-        (current-indentation)))
-    )
-  )
-
-(defun kotlin-mode--indent-for-continuation ()
-  "Return the expected indentation for a continuation."
-  (kotlin-mode--prev-line)
-  (if (kotlin-mode--line-continuation)
-      (kotlin-mode--indent-for-continuation)
-    (+ kotlin-tab-width (current-indentation)))
-  )
-
-(defun kotlin-mode--indent-for-code ()
-  "Return the level that this line of code should be indented to."
-  (let ((indent-opening-block (kotlin-mode--get-opening-char-indentation 1)))
-    (cond
-     ((kotlin-mode--line-continuation) (save-excursion 
(kotlin-mode--indent-for-continuation)))
-     ((booleanp indent-opening-block) 0)
-     ((kotlin-mode--line-closes-block-p) indent-opening-block)
-     (t (+ indent-opening-block kotlin-tab-width)))
-    ))
-
-(defun kotlin-mode--indent-for-comment ()
-  "Return the level that this line of comment should be indented to."
-  (let ((opening-indentation (kotlin-mode--get-opening-char-indentation 8)))
-    (if opening-indentation
-        (1+ opening-indentation)
-      0)
-    ))
-
-(defun kotlin-mode--indent-line ()
-  "Indent the current line of Kotlin code."
-  (interactive)
-  (let ((follow-indentation-p
-         (and (<= (line-beginning-position) (point))
-              (>= (+ (line-beginning-position)
-                     (current-indentation))
-                  (point)))))
-    (save-excursion
-      (beginning-of-line)
-      (if (bobp) ; 1.)
-          (progn
-            (kotlin-mode--beginning-of-buffer-indent))
-        (let ((not-indented t) cur-indent)
-          (cond ((looking-at "^[ \t]*\\.") ; line starts with .
-                 (save-excursion
-                   (kotlin-mode--prev-line)
-                   (cond ((looking-at "^[ \t]*\\.")
-                          (setq cur-indent (current-indentation)))
-
-                         (t
-                          (setq cur-indent (+ (current-indentation) (* 2 
kotlin-tab-width)))))
-                   (if (< cur-indent 0)
-                       (setq cur-indent 0))))
-
-                ((looking-at "^[ \t]*}") ; line starts with }
-                 (save-excursion
-                   (kotlin-mode--prev-line)
-                   (while (and (or (looking-at "^[ \t]*$") (looking-at "^[ 
\t]*\\.")) (not (bobp)))
-                     (kotlin-mode--prev-line))
-                   (cond ((or (looking-at ".*{[ \t]*$") (looking-at ".*{.*->[ 
\t]*$"))
-                          (setq cur-indent (current-indentation)))
-                         (t
-                          (setq cur-indent (- (current-indentation) 
kotlin-tab-width)))))
-                 (if (< cur-indent 0)
-                     (setq cur-indent 0)))
-
-                ((looking-at "^[ \t]*)") ; line starts with )
-                 (save-excursion
-                   (kotlin-mode--prev-line)
-                   (setq cur-indent (- (current-indentation) 
kotlin-tab-width)))
-                 (if (< cur-indent 0)
-                     (setq cur-indent 0)))
-
-                (t
-                 (save-excursion
-                   (while not-indented
-                     (kotlin-mode--prev-line)
-                     (cond ((looking-at ".*{[ \t]*$") ; line ends with {
-                            (setq cur-indent (+ (current-indentation) 
kotlin-tab-width))
-                            (setq not-indented nil))
-
-                           ((looking-at "^[ \t]*}") ; line starts with }
-                            (setq cur-indent (current-indentation))
-                            (setq not-indented nil))
-
-                           ((looking-at ".*{.*->[ \t]*$") ; line ends with ->
-                            (setq cur-indent (+ (current-indentation) 
kotlin-tab-width))
-                            (setq not-indented nil))
-
-                           ((looking-at ".*([ \t]*$") ; line ends with (
-                            (setq cur-indent (+ (current-indentation) 
kotlin-tab-width))
-                            (setq not-indented nil))
-
-                           ((looking-at "^[ \t]*).*$") ; line starts with )
-                            (setq cur-indent (current-indentation))
-                            (setq not-indented nil))
-
-                           ((bobp) ; 5.)
-                            (setq not-indented nil)))))))
-          (if cur-indent
-              (indent-line-to cur-indent)
-            (indent-line-to 0)))))
-
-    (when follow-indentation-p
-      (back-to-indentation))))
-
-
-(defun kotlin-mode--beginning-of-buffer-indent ()
-  (indent-line-to 0))
+
+;; the Kotlin mode
 
 ;;;###autoload
 (define-derived-mode kotlin-mode prog-mode "Kotlin"
   "Major mode for editing Kotlin."
 
   (setq font-lock-defaults '((kotlin-mode--font-lock-keywords) nil nil))
+
   (setq-local parse-sexp-lookup-properties t)
   (add-hook 'syntax-propertize-extend-region-functions
             #'kotlin-mode--syntax-propertize-extend-region
             nil t)
   (setq-local syntax-propertize-function #'kotlin-mode--syntax-propertize)
-  (set (make-local-variable 'comment-start) "//")
-  (set (make-local-variable 'comment-padding) 1)
-  (set (make-local-variable 'comment-start-skip) "\\(//+\\|/\\*+\\)\\s *")
-  (set (make-local-variable 'comment-end) "")
-  (set (make-local-variable 'indent-line-function) 'kotlin-mode--indent-line)
-  (setq-local adaptive-fill-regexp comment-start-skip)
+
+  (setq-local comment-start "//")
+  (setq-local comment-end "")
+  (setq-local comment-padding 1)
+  (setq-local comment-start-skip
+              (rx (seq (zero-or-more (syntax whitespace))
+                       (or
+                        ;; Single-line comment
+                        (seq "/" (one-or-more "/"))
+                        ;; Multi-line comment
+                        (seq "/" (one-or-more "*"))
+                        ;; Middle of multi-line-comment
+                        (seq (one-or-more "*") " "))
+                       (zero-or-more (syntax whitespace)))))
+  (setq-local adaptive-fill-regexp
+              (rx (seq (zero-or-more (syntax whitespace))
+                       (or
+                        ;; Single-line comment
+                        (seq "/" (one-or-more "/"))
+                        ;; Middle of multi-line-comment
+                        (seq (one-or-more "*") " "))
+                       (zero-or-more (syntax whitespace)))))
+  (setq-local fill-indent-according-to-mode t)
+  (setq-local comment-multi-line t)
+
+  (setq-local indent-line-function 'kotlin-mode--indent-line)
+
+  (setq-local electric-indent-chars
+              (append "{}()[]:;,." electric-indent-chars))
+
+  (add-hook 'post-self-insert-hook #'kotlin-mode--post-self-insert nil t)
+
+  (setq-local kotlin-mode--anchor-overlay
+              (make-overlay (point-min) (point-min) nil t))
+
+  (delete-overlay kotlin-mode--anchor-overlay)
 
   :group 'kotlin
   :syntax-table kotlin-mode-syntax-table)
diff --git a/test/kotlin-mode-test.el b/test/kotlin-mode-test.el
index 9749006f2f..b6f1ebf4f6 100644
--- a/test/kotlin-mode-test.el
+++ b/test/kotlin-mode-test.el
@@ -76,7 +76,7 @@ println(arg)
 
       (should (equal (buffer-string) "fun test(args: Array<String>) {
     args.forEach(arg ->
-        println(arg)
+                     println(arg)
     )
 "))
       )))
@@ -180,26 +180,94 @@ println(arg)
   (while (and (looking-at "^[ \t]*$") (not (eobp)))
     (forward-line)))
 
-(ert-deftest kotlin-mode--sample-test ()
-  (with-temp-buffer
-    (insert-file-contents "test/sample.kt")
-    (goto-char (point-min))
-    (kotlin-mode)
-    (setq-local indent-tabs-mode nil)
-    (setq-local tab-width 4)
-    (setq-local kotlin-tab-width 4)
-    (while (not (eobp))
-      (let ((expected-line (thing-at-point 'line)))
+(defvar kotlin-mode--test-keep-going nil
+  "If non-nil, do not stop at error in `kotlin-mode--sample-test'.")
 
-        ;; Remove existing indentation
-        (beginning-of-line)
-        (delete-region (point) (progn (skip-chars-forward " \t") (point)))
+(ert-deftest kotlin-mode--sample-test ()
+  (dolist (filename '("test/sample.kt" "test/pathological.kt"))
+    (with-temp-buffer
+      (insert-file-contents filename)
+      (goto-char (point-min))
+      (kotlin-mode)
+      (setq-local indent-tabs-mode nil)
+      (setq-local tab-width 4)
+      (setq-local kotlin-tab-width 4)
 
-        ;; Indent the line
-        (kotlin-mode--indent-line)
+      (while (not (eobp))
+        (kotlin-mode--test-current-line filename nil)
 
-        ;; Check that the correct indentation is re-applied
-        (should (equal expected-line (thing-at-point 'line)))
+        ;; Indent without following lines
+        (narrow-to-region (point-min) (line-end-position))
+        (kotlin-mode--test-current-line filename t)
+        (widen)
 
         ;; Go to the next non-empty line
         (next-non-empty-line)))))
+
+(defun kotlin-mode--test-current-line (filename truncated)
+  (back-to-indentation)
+  (let (;; (thing-at-point 'line) returns string with property, so
+        ;; we use `buffer-substring-no-properties'.
+        (expected-line (buffer-substring-no-properties
+                        (line-beginning-position)
+                        (line-end-position)))
+        actual-line
+        (original-indent (current-column))
+        ;; Known bug when the following lines are not present.
+        (known-bug-when-truncated
+         (looking-at ".*//.*KNOWN_BUG_WHEN_TRUNCATED"))
+        (known-bug (looking-at ".*//.*KNOWN_BUG\\($\\| \\)")))
+    ;; Remove existing indentation, or indent to column 1 if expected
+    ;; indentation is column 0.
+    ;; Keep indent inside multiline string.
+    (unless (kotlin-mode--chunk-multiline-string-p
+             (kotlin-mode--chunk-after))
+      (if (= original-indent 0)
+          (indent-line-to 1)
+        (delete-horizontal-space)))
+
+    ;; Indent the line
+    (kotlin-mode--indent-line)
+
+    (setq actual-line (buffer-substring-no-properties
+                       (line-beginning-position)
+                       (line-end-position)))
+
+    ;; Check that the correct indentation is re-applied
+    (unless (and truncated known-bug)
+      (if (or known-bug (and truncated known-bug-when-truncated))
+          (if (equal expected-line actual-line)
+              (message "%s:%s:info: %s is fixed somehow"
+                       filename
+                       (line-number-at-pos)
+                       (if truncated "KNOWN_BUG_WHEN_TRUNCATED" "KNOWN_BUG"))
+            (back-to-indentation)
+            (message "%s:%s:warn: (known bug) %sexpected indentation to column 
%d but %d"
+                     filename
+                     (line-number-at-pos)
+                     (if truncated "(when code is truncated) " "")
+                     original-indent
+                     (current-column)))
+        (if (and kotlin-mode--test-keep-going
+                 (not (equal expected-line actual-line)))
+            (message "%s:%s:err: %sexpected indentation to column %d but %d"
+                     filename
+                     (line-number-at-pos)
+                     (if truncated "(when code is truncated) " "")
+                     original-indent
+                     (current-column))
+          (should
+           (equal
+            (format "%s:%s: %s%s"
+                    filename
+                    (line-number-at-pos)
+                    (if truncated "(when code is truncated) " "")
+                    expected-line)
+            (format "%s:%s: %s%s"
+                    filename
+                    (line-number-at-pos)
+                    (if truncated "(when code is truncated) " "")
+                    actual-line))))))
+
+    ;; Restore to original indentation for KNOWN_BUG line.
+    (indent-line-to original-indent)))
diff --git a/test/pathological.kt b/test/pathological.kt
new file mode 100644
index 0000000000..2c2624ad86
--- /dev/null
+++ b/test/pathological.kt
@@ -0,0 +1,2150 @@
+#!/usr/bin/kotlinc -script
+
+// fileAnnotation
+@file
+    :
+    [
+        A(a = 1) // No Comma here
+        B
+            .
+            C
+            .
+            D // No Comma here
+        E
+    ]
+
+@file
+    :
+    Foo
+    .
+    Bar<
+        A // KNOWN_BUG
+    > // KNOWN_BUG
+    .
+    Baz
+
+@file
+    :
+    Foo(aaa)
+
+// packageHeader
+package foo // Line breaks are prohibited after "package".
+    .bar // Line breaks are prohibited after dot.
+    .baz
+
+// importList, importHeader
+import a // Line breaks are prohibited after "import".
+    .b // Line breaks are prohibited after dot.
+    .c
+    .*
+
+// importAlias
+import a
+    . b
+    . c
+    as d
+
+// typeAlias
+@A
+public
+    typealias
+    A
+    <
+        B, // KNOWN_BUG_WHEN_TRUNCATED
+        C // KNOWN_BUG_WHEN_TRUNCATED
+    >
+    =
+    D
+
+// classDeclaration
+
+@A
+public
+    sealed
+    class
+    A
+    <
+        A, // KNOWN_BUG_WHEN_TRUNCATED
+        B // KNOWN_BUG_WHEN_TRUNCATED
+    >
+    // primaryConstructor
+    public
+    constructor
+    (
+        // classParameters
+        val
+            x
+            :
+            Foo
+            =
+            foo,
+        var
+            y
+            :
+            Foo
+            =
+            foo
+    )
+    :
+    // delegationSepcifiers
+    Base
+        by
+        x +
+        x,
+    B,
+    C,
+    D
+        .
+        (Int)
+        ->
+        Int
+    where
+        @A
+        A
+            :
+            A,
+        B
+            :
+            B {
+
+    public
+        interface
+        A {
+        fun a(): Int
+        fun b(): Int
+    }
+
+    // typeParameters
+    data
+        class
+        Bar<
+            @A // KNOWN_BUG_WHEN_TRUNCATED
+            out
+                A // KNOWN_BUG_WHEN_TRUNCATED
+                :
+                A,
+            @A // KNOWN_BUG_WHEN_TRUNCATED
+            in // KNOWN_BUG_WHEN_TRUNCATED
+                A
+                :
+                A
+        >
+    { // brace on its own line
+        fun a() {
+        }
+    }
+
+    inner
+        enum
+        class
+        A(val x: Int) {
+        // enumClassBody
+        A(1), B(1),
+        C(1) {
+            override fun a() = 2
+        }, D(1) {
+            override fun a() = 3
+        },
+        E(1);
+
+        fun a(): Int = x
+    }
+
+    // typeConstraints
+    public
+        class
+        Foo<
+            A // KNOWN_BUG_WHEN_TRUNCATED
+        >
+        :
+        X,
+        Y
+        where
+            A
+                :
+                B,
+            A
+                :
+                C {
+    }
+
+    public class Foo<A>: X, Y
+        where A
+                  :
+                  B,
+              A
+                  :
+                  C {
+    }
+
+    public class Foo<A>: X, Y where
+        A
+            :
+            B,
+        A
+            :
+            C {
+    }
+
+    public class Foo<A>: X, Y where A
+                                        :
+                                        B,
+                                    A
+                                        :
+                                        C {
+    }
+
+    fun <
+        A
+    > Foo.foo()
+        : A
+        where
+            A
+                :
+                B,
+            A
+                :
+                C {
+    }
+
+    fun <
+        A
+    > Foo.foo()
+        : A
+        where
+            A
+                :
+                B,
+            A
+                :
+                C
+        =
+        A()
+
+    val
+        <
+            A // KNOWN_BUG_WHEN_TRUNCATED
+        >
+        A
+        .
+        x
+        where
+            A
+                :
+                B,
+            A
+                :
+                C
+        =
+        1
+
+    val f = fun A.(): A
+        where
+            A:
+                B,
+            A:
+                C {
+    }
+
+    class Foo<T> where T: A
+                     , T: B
+                     , T: C
+
+    // anonymousInitializer
+    init {
+        a()
+    }
+
+    // companionObject
+    public
+        companion
+        object
+        A
+        :
+        B {
+        fun foo() {
+        }
+    }
+
+    // functionDeclaration
+    public
+        fun
+        <
+            A // KNOWN_BUG_WHEN_TRUNCATED
+        >
+        A
+        .
+        foo
+        // functionValueParameters // KNOWN_BUG
+        (
+            a: Int = 1
+        )
+        :
+        A
+        where
+            A : A {
+        a()
+    }
+
+    fun
+        foo(x)
+        =
+        x + 1
+
+    // propertyDeclaration
+    public
+        val
+        <
+            A // KNOWN_BUG_WHEN_TRUNCATED
+        >
+        A
+        .
+        @A
+        a
+        :
+        A
+        where
+            A
+                :
+                A
+        =
+        a
+        public get() = 1
+        public set(value) {
+            foo(value)
+        }
+
+    // delegated property
+    var
+        x : Int
+        by
+        foo
+
+    // multiVariableDeclaration
+    public
+        var
+        (
+            x: Int,
+            y: Int
+        )
+
+    // getter/setter with default implementation
+    var x = 1
+        @A get
+        @A set
+
+    // objectDeclaration
+    public
+        object
+        Foo
+        :
+        Bar {
+        fun foo() {
+            bar()
+        }
+    }
+
+    // secondaryConstructor
+    public
+        constructor
+        (
+        )
+        :
+        this
+        (
+            1
+        ) {
+        a()
+    }
+
+    public
+        constructor
+        (
+        )
+        :
+        super
+        (
+            1
+        )
+
+    // dynamic type
+    var x: dynamic = 1
+
+    // nullableType
+    var
+        x
+        :
+        A
+        <
+            X, // KNOWN_BUG_WHEN_TRUNCATED
+            *, // KNOWN_BUG_WHEN_TRUNCATED
+            out
+                Y,
+            in
+                Z
+        >
+        .
+        B
+        .
+        C
+        <
+            X // KNOWN_BUG_WHEN_TRUNCATED
+        >
+        ?
+        ?
+        ?
+        =
+        null
+
+    var
+        x
+        :
+        (
+            Int
+        )
+        ?
+        =
+        null
+
+    // functionType
+    var
+        f
+        :
+        // parehthesized nullable receiver type
+        (
+            A
+        )
+        ?
+        .
+        (
+            Int
+        )
+        ->
+        (
+            Int
+        )
+        ->
+        C
+
+    // definitelyNonNullableType
+    fun foo(
+        x:
+            A
+            &
+            Any
+    ) {
+    }
+
+    // value class
+
+    value
+        class Foo { // KNOWN_BUG
+    } // KNOWN_BUG
+}
+
+
+// statements
+fun foo() {
+    //explicit semicolons
+    /* aaa */ a(); b();
+    c();
+
+    // annotation
+    @A
+    @B
+        .D(aaa) @C
+    @[
+        A
+        B
+        C
+    ]
+    // label
+    aaa@
+    a()
+
+    // forStatement
+    for (
+        @A
+        a
+            :
+            A
+        in
+        aaa
+    ) {
+        a()
+    }
+
+    for
+        (
+            @A
+            (x, y)
+            in
+            aaa
+        )
+    {
+        a()
+    }
+
+    for (
+        a in aaa
+    )
+        a()
+
+    // whileStatement
+    while (
+        a()
+    ) {
+        a()
+    }
+
+    while
+        (
+            a()
+        )
+    {
+        a()
+    }
+
+    while (
+        a()
+    )
+        a()
+
+    while (
+        a()
+    )
+        ;
+
+    // doWhileStatement
+    do {
+        a()
+    } while (
+        a()
+    )
+
+    do
+    {
+        a()
+    }
+    while
+        (
+            a()
+        )
+
+    do
+        a() +
+        b()
+    while (a())
+
+    do
+    while (a())
+
+    while (a())
+        do
+            do
+            while(a())
+        while(a())
+
+    while(a())
+        do
+        while(a())
+
+    // assignment
+    (x, y) = // Line breaks are prohibited before assignment operators.
+        a()
+
+    aaa[x] =
+        1
+
+    a
+        .
+        b
+        ?.
+        c
+        .
+        d =
+        e
+
+    a
+        .
+        b +=
+        1
+
+    a
+        .
+        b -=
+        1
+
+    a
+        .
+        b *=
+        1
+
+    a
+        .
+        b %=
+        1
+
+    // expression
+    // various operators
+    val x =
+        a
+        ||
+        b
+        &&
+        c
+
+    val x =
+        a == // Line breaks are prohibited before equality operators
+        b
+
+    val x =
+        a !=
+        b
+
+    val x =
+        a ===
+        b
+
+    val x =
+        a !==
+        g
+
+    val x =
+        a < // Line breaks are prohibited before comparison operators
+        b
+
+    val x =
+        a >
+        b
+
+    val x =
+        a <=
+        b
+
+    val x =
+        a >=
+        b
+
+    val x =
+        foo(a) in // Line breaks are prohibited before in/is operators
+        b
+
+    val x =
+        a !in
+        b
+
+    when (a()) {
+        1 -> a()
+        // Line breaks are prohibited before in/is operators, So the following
+        // line should not be indented.
+        in aaa -> a()
+        !in aaa -> a()
+    }
+
+    val x =
+        a is
+        b
+
+    val x =
+        a !is
+        b
+
+    when (a()) {
+        1 -> a()
+        // Line breaks are prohibited before in/is operators, So the following
+        // line should not be indented.
+        is X -> a()
+        !is X -> a()
+    }
+
+    val x =
+        a
+        ?:
+        b
+
+    // infixFunctionCall
+    val x =
+        a shl // Line breaks are allowed after infix function.
+        b // KNOWN_BUG
+    val y = 1 // KNOWN_BUG
+
+    var shl = 1
+    val x = shl shl shl
+    shl < 100 && foo() // this is not a continuation of the previous line.
+
+    var shl = 1
+    val x = shl shl
+        shl < 100 && foo() // this is a continuation of the previous line. // 
KNOWN_BUG
+    val y = 1 // KNOWN_BUG
+
+    // This is not a infix function call; line breaks are
+    // prohibited before infix function.
+    val x =
+        a
+    f (b) // So this line should not indented.
+
+    val x =
+        a .. // Line breaks are prohibited before range operator.
+        b
+
+    val x =
+        a ..< // Line breaks are prohibited before closed range operator.
+        b
+
+    val x =
+        a + // Line breaks are prohibited before additive operators.
+        b -
+        c
+
+    a()
+    +a() // So this line should not be indented.
+    -a() // Nor should this line.
+
+    val x =
+        a * // Line breaks are prohibited before multiplicative operators.
+        b /
+        c %
+        d
+
+    val x =
+        a
+        as
+        A
+        as?
+        B
+
+    // prefixUnaryExpression
+    val x =
+        @a
+        a@ // label
+        +
+        -
+        ++
+        a // KNOWN_BUG
+
+    val x = // KNOWN_BUG
+        --
+        a // KNOWN_BUG
+
+    val x = // KNOWN_BUG
+        !
+        a // KNOWN_BUG
+
+    // postfixUnaryExpression // KNOWN_BUG
+    val x = // KNOWN_BUG
+        a++ // Line breaks are prohibited before postfix operators.
+
+    val x =
+        a
+    ++ a // So this line should not be indented.
+
+    val x =
+        a--
+
+    val x =
+        a
+    -- a // This line too.
+
+    var shl = 1
+    val x = shl shl shl ++
+    shl < 100 && foo() // this is not a continuation of the previous line.
+
+    var shl = 1
+    val x = shl shl ++
+        shl < 100 && foo() // this is a continuation of the previous line. // 
KNOWN_BUG
+
+    val x = // KNOWN_BUG
+        a!!
+
+    val x = foo()!!
+    foo() // this is not a continuation of the previous line.
+
+    val x = !!
+        foo() // this is a continuation of the previous line. // KNOWN_BUG
+
+    val x = // KNOWN_BUG
+        f< // Line breaks are prohibited before type arguments.
+            A // KNOWN_BUG_WHEN_TRUNCATED
+        >( // Line breaks are prohibited before function arguments.
+            x
+        )[ // Line breaks are prohibited before subscript.
+            x
+        ]
+        .
+        a
+        .
+        b
+
+    // lambda arguments
+    val x = f()
+    {
+        a()
+    }
+
+    val x = f()
+    @A
+    a@
+    {
+        a()
+    }
+
+    val x = f() @A a@ {
+        a()
+    }
+
+    val x = f
+    {
+        a()
+    }
+
+    val x = f
+    @A
+    a@
+    {
+        a()
+    }
+
+    val x = f @A a@ {
+        a()
+    }
+
+    val x = x
+        .foo {
+            a
+        }
+        .bar {
+            a
+        }
+
+    val x = x.foo {
+        a
+    }.bar {
+        a
+    }
+
+    val x =
+        f // Line breaks are prohibited before function arguments.
+    (1 + 1).also { print(it) } // So this line should not be indented.
+
+    val x =
+        a // Line breaks are prohibited before function arguments.
+    [g()].forEach { print(it) } // So this line should not be indented.
+
+    // parenthesizedExpression
+    val x = (
+        a()
+    )
+
+    // collectionLiteral
+    @A(x = [
+           1, 2, 3,
+           /* aaa */ 4, 5, 6,
+           7, 8, 9
+       ])
+    a()
+
+    // CharacterLiteral
+    val x =
+        'a'
+
+    val x =
+        '\''
+
+    val x =
+        '"'
+
+    // stringLiteral
+    val x = "abc\"def${
+        foo("abc")
+    }ghi${
+        "aaa\${ // dollar sign cannot be escaped
+            1
+        }bbb"
+    }jkl"
+
+    val x = """a
+               "b"
+               c${
+                   foo("""a
+                           b
+                            c
+                       """)
+               }d
+    e
+    f${
+        """aaa\${
+            1
+        }bbb"""
+    }ghi"""
+
+    val x =
+        a("'")
+
+    // lambdaLiteral
+    val f: () -> Unit = {
+        a()
+        a()
+        a()
+    }
+
+    val f: () -> Unit = { ->
+        a()
+        a()
+        a()
+    }
+
+    val f: () -> Unit = {
+        ->
+        a()
+        a()
+        a()
+    }
+
+    val f: () -> Unit = { x,
+                          @A
+                          y
+                              :
+                              Int,
+                          (
+                              z1,
+                              z2
+                          )
+                              :
+                              AAA
+                          ->
+        a()
+        a()
+        a()
+    }
+
+    val f: () -> Unit = {
+        x,
+        y,
+        z
+        ->
+        a()
+        a()
+        a()
+    }
+
+    val f: () -> Unit = {
+        (x,
+         y,
+         z)
+        ->
+        a()
+        a()
+        a()
+    }
+
+    // functionLiteral
+
+    val f =
+        fun
+        A
+        .
+        (
+            x: Int
+        )
+        :
+        AAA
+        where
+            A
+                :
+                A,
+            B
+                :
+                B {
+            a() // KNOWN_BUG
+        } // KNOWN_BUG
+
+    val f = fun
+    {
+        a()
+    }
+
+    // objectLiteral
+    val object: A by a, B by b {
+        fun foo() {
+        }
+    }
+
+    val x =
+        object
+        :
+        A,
+        B
+            by
+            b,
+        C {
+            fun foo() {
+            }
+        }
+
+    val x = object
+    {
+        fun foo() {
+        }
+    }
+
+    // thisExpression
+    val x =
+        this
+
+    val x =
+        this@Foo
+
+    // superExpression
+    val x =
+        super
+
+    val x =
+        super@Foo
+
+    val x =
+        super<
+            Int // KNOWN_BUG_WHEN_TRUNCATED
+        >@Foo
+
+    // ifExpression
+    val x = if (
+        a +
+            1
+    ) {
+        a()
+    }
+
+    val x = if
+        (
+            a +
+                1
+        )
+    {
+        a()
+    }
+
+    val x = if (
+        a
+    )
+        a()
+
+    val x = if (
+        a
+    )
+        ;
+
+    val x = if (
+        a
+    ) {
+        a()
+    } else {
+        a()
+    }
+
+    val x = if
+        (
+            a
+        )
+    {
+        a()
+    }
+    else
+    {
+        a()
+    }
+
+    val x = if (
+        a
+    )
+        a()
+    else
+        a()
+
+    val x = if (
+        a
+    )
+        ;
+    else
+        ;
+
+    val x = if (
+        a
+    )
+    else
+        ;
+
+    val x =
+        if (
+            a
+        ) {
+            a()
+        } else {
+            a()
+        }
+
+    val x = if (foo) 1
+    else 2 // should be indented?
+
+    val x =
+        if (foo) 1
+        else 2
+
+    val x = if (foo) 1 +
+                         1
+    else 2 +
+             1
+
+    val x = if (foo)
+        if (bar)
+            aaa() +
+                1
+        else
+            if (baz)
+                if (aaa) aaa else bbb +
+                                      1
+            else
+                if (aaa) aaa else
+                                 bbb +
+                                     1
+    else
+        if (bar)
+            if (aaa)
+                if (bbb)
+                    ccc +
+                        1 +
+                        2
+                else
+                    ccc +
+                        1 +
+                        2
+            else
+                ccc +
+                    1 +
+                    2
+        else
+            aaa() +
+                1
+
+    val x = if (foo)
+        while (false) {
+            aaa() +
+                1
+        }
+    else
+        while (false) {
+            aaa() +
+                1
+        }
+
+    val x = if (a)
+        foo() +
+            1
+    else if (e)
+        foo() +
+            1
+    else
+        foo() +
+            1
+
+    val x = if (a) {
+        foo() +
+            1
+    } else if (e) {
+        foo() +
+            1
+    } else {
+        foo() +
+            1
+    }
+
+    val x = if (a) {
+        foo() +
+            1
+    } else
+          if (e) {
+              foo() +
+                  1
+          } else {
+              foo() +
+                  1
+          }
+
+    val x = if (a)
+    {
+        foo() +
+            1
+    }
+    else if (e)
+    {
+        foo() +
+            1
+    }
+    else
+    {
+        foo() +
+            1
+    }
+
+    val x = if (a) if (a) 1 +
+                              1 else 1 else
+                                           if (a) if (a) 1 +
+                                                             1 else 1 else
+                                                                          1
+
+    // whenExpression
+
+    val x = when (
+        @A
+        val
+            a
+            =
+            a()
+    ) {
+        a(), b(),
+        c(), d()
+            ->
+        {
+            a()
+        }
+
+        a() -> {
+            a()
+        }
+
+        in
+            a()
+            ->
+        {
+            a ()
+        }
+
+        is
+            A
+            ->
+        {
+        }
+
+        a()
+            ->
+            if (x) {
+                1
+            } else {
+                2
+            }
+
+        if (x)
+            1
+        else
+            2
+            ->
+            if (x)
+                1
+            else
+                2
+
+        else
+            ->
+        {
+            a()
+        }
+    }
+
+    val x = when
+        (
+            a()
+        )
+    {
+        a -> 1
+    }
+
+    // tryExpression
+    val x = try {
+        a()
+    } catch(@A e: E) {
+        a()
+    } catch(@A e: E) {
+        a()
+    } finally {
+        a()
+    }
+
+    val x =
+        try {
+            a()
+        } catch(@A e: E) {
+            a()
+        } catch(@A e: E) {
+            a()
+        } finally {
+            a()
+        }
+
+    val x = try
+    {
+        a()
+    }
+    catch
+        (
+            @A e: E
+        )
+    {
+        a()
+    }
+    finally
+    {
+        a()
+    }
+
+    val x = try {
+        a()
+    } finally {
+        a()
+    }
+
+    val x = try
+    {
+        a()
+    }
+    finally
+    {
+        a()
+    }
+
+    // jumpExpression
+    val x =
+        throw
+        a()
+
+    val x =
+        return a() // Line breaks are prohibited after return.
+
+    val x =
+        return // Line breaks are prohibited after return.
+    a() // So this line should not be indented.
+
+    val x =
+        return@A a() // Line breaks are prohibited after return.
+
+    val x =
+        return@A // Line breaks are prohibited after return.
+    a() // So this line should not be indented.
+
+    val x =
+        continue
+
+    val x =
+        continue@A
+
+    val x =
+        break
+
+    val x =
+        break@A
+
+    // callableReference
+    val x =
+        Foo
+        ::
+        foo
+
+    val x =
+        Foo
+        ::
+        class
+
+    // typeModifier
+    val f:
+        suspend
+        () -> Unit
+        =
+        suspend
+        {
+            a()
+        }
+}
+
+class Foo: Base {
+    // memberModifier
+    public
+        override
+        fun f() {
+    }
+
+    public
+        lateinit
+        var x: Int
+
+
+    // visibilityModifier
+    override
+        public
+        fun f() {
+    }
+
+    override
+        private
+        fun f() {
+    }
+
+    override
+        internal
+        fun f() {
+    }
+
+    override
+        protected
+        fun f() {
+    }
+
+    // functionModifier
+    public
+        tailrec
+        infix
+        inline
+        fun A.f(): A {
+        return a()
+    }
+
+    public
+        operator
+        fun A.unaryPlus(): A {
+        return a()
+    }
+
+    public
+        suspend
+        fun foo() {
+        a()
+    }
+}
+
+public
+    external
+    fun foo() {
+    a()
+}
+
+class Foo {
+    // propertyModifier
+    public
+        const
+        val
+        x = 1
+}
+
+// inheritanceModifier
+public
+    abstract
+    class Foo {
+    fun foo() {
+        bar()
+    }
+}
+
+public
+    final
+    class Foo {
+    fun foo() {
+        bar()
+    }
+}
+
+public
+    open
+    class Foo {
+    fun foo() {
+    }
+}
+
+class Foo {
+    // parameterModifier
+    fun foo(
+        @A
+        crossinline
+            body: () -> Unit
+    ) {
+    }
+
+    fun foo(
+        @A
+        noinline
+            body: () -> Unit
+    ) {
+    }
+
+    fun foo(
+        @A
+        vararg
+            a: A
+    ) {
+    }
+
+    // reificationModifier
+    inline fun <
+        @A
+        reified
+            T // KNOWN_BUG_WHEN_TRUNCATED
+    > foo() {
+        a()
+    }
+}
+
+// platformModifier
+public
+    expect
+    class Foo {
+    fun foo()
+}
+
+public
+    actual
+    class Foo {
+    fun foo()
+}
+
+
+// Ambiguous commas, colons, curly brackets, and objects.
+
+class C: A by object: B1,
+                      B2 {
+             fun foo() {}
+         },
+         B by object: B3,
+                      B4 {
+             fun foo() {}
+         } {
+    fun <T> foo(x: T): Int {
+        return when (x) {
+            object: B1 by object: B1 {
+                        fun foo() {}
+                    },
+                    B2 {
+                fun foo() {}
+            },
+            object: B3,
+                    B4 {
+                fun foo() {}
+            } ->
+                1
+
+            else ->
+                2
+        }
+    }
+}
+
+// Curly braces may appar at:
+// classBody
+//   class (optional)
+//   interface (optional)
+//   companionObject (optional)
+//   objectDeclaration (optional)
+//   enumEntry (optional)
+//   objectLiteral
+// block
+//   init
+//   functionBody
+//     fun (optional)
+//     getter
+//     setter
+//     anonymousFunction
+//   constructor (optional)
+//   controlStructureBody (optional)
+//     for
+//     while
+//     do
+//     if
+//     else
+//     whenEntry
+//   try
+//   catch
+//   finally
+// lambda
+// when
+
+class C:
+    A by foo bar { // infix function call
+        aaa() // this is not a class body // KNOWN_BUG
+    } { // KNOWN_BUG
+    // this is the class body
+
+    fun foo() {
+        aaa()
+    }
+}
+
+// Ambiguous arrows
+
+val f = { g:
+              (Int) ->
+              (Int) ->
+              Int ->
+    g(1, 2)
+}
+
+when (x) {
+    1 ->
+        f as
+            (Int) ->
+            Int // KNOWN_BUG
+    f as (Int) ->
+        Int ->
+        f as
+            (Int) ->
+            Int // KNOWN_BUG
+    f(1) ->
+        f as
+            (Int) ->
+            Int // KNOWN_BUG
+    (f) ->
+        f as
+            (Int) ->
+            Int // KNOWN_BUG
+    is (Int) ->
+        Int ->
+        f as
+            (Int) ->
+            Int // KNOWN_BUG
+    is Foo<(Int) ->
+               Int, // KNOWN_BUG
+           (Int) -> // KNOWN_BUG
+               Int> -> // KNOWN_BUG
+        f as
+            (Int) ->
+            Int // KNOWN_BUG
+    1 < (2), (f) ->
+        f as
+            (Int) ->
+            Int // KNOWN_BUG
+    else ->
+        f as
+            (Int) ->
+            Int // KNOWN_BUG
+}
+
+// various identifiers
+
+val `abc` =
+    1
+
+val `abc def 'ghi "aaa ${ aaa \` = // backquotes cannot be escaped
+    a()
+
+// UNICODE_CLASS_ND
+val 
_0123456789٠١٢٣٤٥٦٧٨٩۰۱۲۳۴۵۶۷۸۹߀߁߂߃߄߅߆߇߈߉०१२३४५६७८९০১২৩৪৫৬৭৮৯੦੧੨੩੪੫੬੭੮੯૦૧૨૩૪૫૬૭૮૯୦୧୨୩୪୫୬୭୮୯௦௧௨௩௪௫௬௭௮௯౦౧౨౩౪౫౬౭౮౯೦೧೨೩೪೫೬೭೮೯൦൧൨൩൪൫൬൭൮൯෦෧෨෩෪෫෬෭෮෯๐๑๒๓๔๕๖๗๘๙໐໑໒໓໔໕໖໗໘໙༠༡༢༣༤༥༦༧༨༩၀၁၂၃၄၅၆၇၈၉႐႑႒႓႔႕႖႗႘႙០១២៣៤៥៦៧៨៩᠐᠑᠒᠓᠔᠕᠖᠗᠘᠙᥆᥇᥈᥉᥊᥋᥌᥍᥎᥏᧐᧑᧒᧓᧔᧕᧖᧗᧘᧙᪀᪁᪂᪃᪄᪅᪆᪇᪈᪉᪐᪑᪒᪓᪔᪕᪖᪗᪘᪙᭐᭑᭒᭓᭔᭕᭖᭗᭘᭙᮰᮱᮲᮳᮴᮵᮶᮷᮸᮹᱀᱁᱂᱃᱄᱅᱆᱇᱈᱉᱐᱑᱒᱓᱔᱕᱖᱗᱘᱙꘠꘡꘢꘣꘤꘥꘦꘧꘨꘩꣐꣑꣒꣓꣔꣕꣖꣗꣘꣙꤀꤁꤂꤃꤄꤅꤆꤇꤈꤉꧐꧑꧒꧓꧔꧕꧖꧗꧘꧙꧰꧱꧲꧳꧴꧵꧶꧷꧸꧹꩐꩑꩒꩓꩔꩕꩖�
 ��꩘꩙꯰꯱꯲꯳꯴꯵꯶꯷꯸꯹0123456789𐒠𐒡𐒢𐒣𐒤𐒥𐒦𐒧𐒨𐒩 =
+    1
+
+// Some characters are not supported while they are in the unicode category Nd.
+// val _𐴰 =
+//     1
+// val _𐴱 =
+//     1
+// val _𐴲 =
+//     1
+// val _𐴳 =
+//     1
+// val _𐴴 =
+//     1
+// val _𐴵 =
+//     1
+// val _𐴶 =
+//     1
+// val _𐴷 =
+//     1
+// val _𐴸 =
+//     1
+// val _𐴹 =
+//     1
+val _𑁦 =
+    1
+val _𑁧 =
+    1
+val _𑁨 =
+    1
+val _𑁩 =
+    1
+val _𑁪 =
+    1
+val _𑁫 =
+    1
+val _𑁬 =
+    1
+val _𑁭 =
+    1
+val _𑁮 =
+    1
+val _𑁯 =
+    1
+val _𑃰 =
+    1
+val _𑃱 =
+    1
+val _𑃲 =
+    1
+val _𑃳 =
+    1
+val _𑃴 =
+    1
+val _𑃵 =
+    1
+val _𑃶 =
+    1
+val _𑃷 =
+    1
+val _𑃸 =
+    1
+val _𑃹 =
+    1
+val _𑄶 =
+    1
+val _𑄷 =
+    1
+val _𑄸 =
+    1
+val _𑄹 =
+    1
+val _𑄺 =
+    1
+val _𑄻 =
+    1
+val _𑄼 =
+    1
+val _𑄽 =
+    1
+val _𑄾 =
+    1
+val _𑄿 =
+    1
+val _𑇐 =
+    1
+val _𑇑 =
+    1
+val _𑇒 =
+    1
+val _𑇓 =
+    1
+val _𑇔 =
+    1
+val _𑇕 =
+    1
+val _𑇖 =
+    1
+val _𑇗 =
+    1
+val _𑇘 =
+    1
+val _𑇙 =
+    1
+val _𑋰 =
+    1
+val _𑋱 =
+    1
+val _𑋲 =
+    1
+val _𑋳 =
+    1
+val _𑋴 =
+    1
+val _𑋵 =
+    1
+val _𑋶 =
+    1
+val _𑋷 =
+    1
+val _𑋸 =
+    1
+val _𑋹 =
+    1
+val _𑑐 =
+    1
+val _𑑑 =
+    1
+val _𑑒 =
+    1
+val _𑑓 =
+    1
+val _𑑔 =
+    1
+val _𑑕 =
+    1
+val _𑑖 =
+    1
+val _𑑗 =
+    1
+val _𑑘 =
+    1
+val _𑑙 =
+    1
+val _𑓐 =
+    1
+val _𑓑 =
+    1
+val _𑓒 =
+    1
+val _𑓓 =
+    1
+val _𑓔 =
+    1
+val _𑓕 =
+    1
+val _𑓖 =
+    1
+val _𑓗 =
+    1
+val _𑓘 =
+    1
+val _𑓙 =
+    1
+val _𑙐 =
+    1
+val _𑙑 =
+    1
+val _𑙒 =
+    1
+val _𑙓 =
+    1
+val _𑙔 =
+    1
+val _𑙕 =
+    1
+val _𑙖 =
+    1
+val _𑙗 =
+    1
+val _𑙘 =
+    1
+val _𑙙 =
+    1
+val _𑛀 =
+    1
+val _𑛁 =
+    1
+val _𑛂 =
+    1
+val _𑛃 =
+    1
+val _𑛄 =
+    1
+val _𑛅 =
+    1
+val _𑛆 =
+    1
+val _𑛇 =
+    1
+val _𑛈 =
+    1
+val _𑛉 =
+    1
+val _𑜰 =
+    1
+val _𑜱 =
+    1
+val _𑜲 =
+    1
+val _𑜳 =
+    1
+val _𑜴 =
+    1
+val _𑜵 =
+    1
+val _𑜶 =
+    1
+val _𑜷 =
+    1
+val _𑜸 =
+    1
+val _𑜹 =
+    1
+val _𑣠 =
+    1
+val _𑣡 =
+    1
+val _𑣢 =
+    1
+val _𑣣 =
+    1
+val _𑣤 =
+    1
+val _𑣥 =
+    1
+val _𑣦 =
+    1
+val _𑣧 =
+    1
+val _𑣨 =
+    1
+val _𑣩 =
+    1
+val _𑱐 =
+    1
+val _𑱑 =
+    1
+val _𑱒 =
+    1
+val _𑱓 =
+    1
+val _𑱔 =
+    1
+val _𑱕 =
+    1
+val _𑱖 =
+    1
+val _𑱗 =
+    1
+val _𑱘 =
+    1
+val _𑱙 =
+    1
+// val _𑵐 =
+//     1
+// val _𑵑 =
+//     1
+// val _𑵒 =
+//     1
+// val _𑵓 =
+//     1
+// val _𑵔 =
+//     1
+// val _𑵕 =
+//     1
+// val _𑵖 =
+//     1
+// val _𑵗 =
+//     1
+// val _𑵘 =
+//     1
+// val _𑵙 =
+//     1
+// val _𑶠 =
+//     1
+// val _𑶡 =
+//     1
+// val _𑶢 =
+//     1
+// val _𑶣 =
+//     1
+// val _𑶤 =
+//     1
+// val _𑶥 =
+//     1
+// val _𑶦 =
+//     1
+// val _𑶧 =
+//     1
+// val _𑶨 =
+//     1
+// val _𑶩 =
+//     1
+val _𖩠 =
+    1
+val _𖩡 =
+    1
+val _𖩢 =
+    1
+val _𖩣 =
+    1
+val _𖩤 =
+    1
+val _𖩥 =
+    1
+val _𖩦 =
+    1
+val _𖩧 =
+    1
+val _𖩨 =
+    1
+val _𖩩 =
+    1
+val _𖭐 =
+    1
+val _𖭑 =
+    1
+val _𖭒 =
+    1
+val _𖭓 =
+    1
+val _𖭔 =
+    1
+val _𖭕 =
+    1
+val _𖭖 =
+    1
+val _𖭗 =
+    1
+val _𖭘 =
+    1
+val _𖭙 =
+    1
+val _𝟎 =
+    1
+val _𝟏 =
+    1
+val _𝟐 =
+    1
+val _𝟑 =
+    1
+val _𝟒 =
+    1
+val _𝟓 =
+    1
+val _𝟔 =
+    1
+val _𝟕 =
+    1
+val _𝟖 =
+    1
+val _𝟗 =
+    1
+val _𝟘 =
+    1
+val _𝟙 =
+    1
+val _𝟚 =
+    1
+val _𝟛 =
+    1
+val _𝟜 =
+    1
+val _𝟝 =
+    1
+val _𝟞 =
+    1
+val _𝟟 =
+    1
+val _𝟠 =
+    1
+val _𝟡 =
+    1
+val _𝟢 =
+    1
+val _𝟣 =
+    1
+val _𝟤 =
+    1
+val _𝟥 =
+    1
+val _𝟦 =
+    1
+val _𝟧 =
+    1
+val _𝟨 =
+    1
+val _𝟩 =
+    1
+val _𝟪 =
+    1
+val _𝟫 =
+    1
+val _𝟬 =
+    1
+val _𝟭 =
+    1
+val _𝟮 =
+    1
+val _𝟯 =
+    1
+val _𝟰 =
+    1
+val _𝟱 =
+    1
+val _𝟲 =
+    1
+val _𝟳 =
+    1
+val _𝟴 =
+    1
+val _𝟵 =
+    1
+val _𝟶 =
+    1
+val _𝟷 =
+    1
+val _𝟸 =
+    1
+val _𝟹 =
+    1
+val _𝟺 =
+    1
+val _𝟻 =
+    1
+val _𝟼 =
+    1
+val _𝟽 =
+    1
+val _𝟾 =
+    1
+val _𝟿 =
+    1
+// val _𞅀 =
+//     1
+// val _𞅁 =
+//     1
+// val _𞅂 =
+//     1
+// val _𞅃 =
+//     1
+// val _𞅄 =
+//     1
+// val _𞅅 =
+//     1
+// val _𞅆 =
+//     1
+// val _𞅇 =
+//     1
+// val _𞅈 =
+//     1
+// val _𞅉 =
+//     1
+// val _𞋰 =
+//     1
+// val _𞋱 =
+//     1
+// val _𞋲 =
+//     1
+// val _𞋳 =
+//     1
+// val _𞋴 =
+//     1
+// val _𞋵 =
+//     1
+// val _𞋶 =
+//     1
+// val _𞋷 =
+//     1
+// val _𞋸 =
+//     1
+// val _𞋹 =
+//     1
+val _𞥐 =
+    1
+val _𞥑 =
+    1
+val _𞥒 =
+    1
+val _𞥓 =
+    1
+val _𞥔 =
+    1
+val _𞥕 =
+    1
+val _𞥖 =
+    1
+val _𞥗 =
+    1
+val _𞥘 =
+    1
+val _𞥙 =
+    1
+
+// UNICODE_CLASS_LL
+// UNICODE_CLASS_LM
+// UNICODE_CLASS_LO
+// UNICODE_CLASS_LT
+// UNICODE_CLASS_LU
+val aʰªDžA =
+    1
+
+// UNICODE_CLASS_NL (rejected for some reason)
+// val ᛮ =
+//     1
diff --git a/test/sample.kt b/test/sample.kt
index 7dd47b5eee..cb8c56ac6a 100644
--- a/test/sample.kt
+++ b/test/sample.kt
@@ -13,7 +13,7 @@ import bar.Bar as bBar
 /****************************************************************
  Multiline comment
  without leading "*"
-****************************************************************/
+****************************************************************/ // KNOWN_BUG
 
 fun sum(a: Int, b: Int): Int {
     return a + b
@@ -367,7 +367,7 @@ var setterVisibility: String = "abc"
     private set // the setter is private and has the default implementation
 
 var setterWithAnnotation: Any? = null
-@Inject set // annotate the setter with Inject
+    @Inject set // annotate the setter with Inject
 
 var counter = 0 // the initializer value is written directly to the backing 
field
     set(value) {
@@ -555,8 +555,8 @@ fun <T : Comparable<T>> sort(list: List<T>) {
 }
 
 fun <T> cloneWhenGreater(list: List<T>, threshold: T): List<T>
-where T : Comparable,
-T : Cloneable {
+    where T : Comparable,
+          T : Cloneable {
     return list.filter { it > threshold }.map { it.clone() }
 }
 
@@ -591,8 +591,7 @@ window.addMouseListener(
         override fun mouseEntered(e: MouseEvent) {
             // ...
         }
-    }
-)
+    })
 
 val adHoc = object {
     var x: Int = 0
@@ -613,8 +612,7 @@ fun countClicks(window: JComponent) {
             override fun mouseEntered(e: MouseEvent) {
                 enterCount++
             }
-        }
-    )
+        })
     // ...
 }
 
@@ -683,13 +681,13 @@ val doubled = ints.map { it -> it * 2 }
 strings.filter { it.length == 5 }.sortBy { it }.map { it.toUpperCase() }
 
 max(strings, { a, b -> a.length < b.length
-})
+             })
 
 fun <T> max(collection: Collection<T>, less: (T, T) -> Boolean): T? {
     var max: T? = null
     for (it in collection)
         if (max == null || less(max, it))
-        max = it
+            max = it
     return max
 }
 
@@ -733,8 +731,10 @@ inline fun <reified T> TreeNode.findParentOfType(): T? {
 class Test {
     fun tryAdd(a: Int?, b: Int?) : Int? {
         var result: Int? = null
-        a?.let { lhs ->
-            b?.let { rhs ->
+        a?.let {
+            lhs ->
+            b?.let {
+                rhs ->
                 result = lhs + rhs
             }
         }



reply via email to

[Prev in Thread] Current Thread [Next in Thread]