[gtksourceview: 5/6] objj.lang: Fix/rewrite using updated JS highlighting



commit b9e2d2ddfd8a243a88423d39b32e68c1d7b12951
Author: Jeffery To <jeffery to gmail com>
Date:   Thu Oct 10 23:07:03 2019 +0800

    objj.lang: Fix/rewrite using updated JS highlighting

 data/language-specs/objj.lang    |  587 +++++++++++++++++---
 tests/syntax-highlighting/file.j | 1117 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 1638 insertions(+), 66 deletions(-)
---
diff --git a/data/language-specs/objj.lang b/data/language-specs/objj.lang
index c3bd4062..a40bef28 100644
--- a/data/language-specs/objj.lang
+++ b/data/language-specs/objj.lang
@@ -7,6 +7,7 @@
  Author: Patryk Zawadzki <patrys pld-linux org>
  Copyright (C) 2007 Yevgen Muntyan <muntyan math tamu edu>
  Copyright (C) 2010 Patryk Zawadzki <patrys pld-linux org>
+ Copyright (C) 2019 Jeffery To <jeffery to gmail com>
 
  GtkSourceView is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
@@ -32,96 +33,550 @@
   </metadata>
 
   <styles>
-    <style id="boolean"       name="Boolean"       map-to="js:boolean"/>
-    <style id="keyword"       name="Keyword"       map-to="js:keyword"/>
-    <style id="type"          name="Data Type"     map-to="js:type"/>
-    <style id="preprocessor"  name="Preprocessor"  map-to="def:preprocessor"/>
-    <style id="included-file" name="Included File" map-to="js:string"/>
-    <style id="string"        name="String"        map-to="js:string"/>
-    <style id="null-value"    name="Null Value"    map-to="js:null-value"/>
+    <style id="type"  name="Data type"  map-to="def:type"/>
   </styles>
 
+  <keyword-char-class>[a-zA-Z0-9_$]</keyword-char-class>
+
   <definitions>
-    <!-- Objective-J-specific stuff (i.e. stuff which is not JS) -->
-    <context id="headers">
-      <include>
-        <context style-ref="keyword">
-          <prefix>\@</prefix>
-          <keyword>catch</keyword>
-          <keyword>class</keyword>
-          <keyword>defs</keyword>
-          <keyword>encode</keyword>
-          <keyword>end</keyword>
-          <keyword>finally</keyword>
-          <keyword>implementation</keyword>
-          <keyword>interface</keyword>
-          <keyword>private</keyword>
-          <keyword>protected</keyword>
-          <keyword>protocol</keyword>
-          <keyword>public</keyword>
-          <keyword>selector</keyword>
-          <keyword>synchronized</keyword>
-          <keyword>throw</keyword>
-          <keyword>try</keyword>
-        </context>
 
-        <context style-ref="preprocessor">
-          <match extended="true">
-            \@
-            (import)\s*
-            (".*?"|&lt;.*&gt;)
-          </match>
+    <!-- Based on:
+         * The Cappuccino documentation, in particular the "Learning
+           Objective-J" page
+           (https://www.cappuccino.dev/learn/objective-j.html)
+         * The Objective-J compiler source code
+           (https://github.com/cappuccino/cappuccino/tree/master/Objective-J),
+           in particular acorn.js, ObjJAcornCompiler.js, and
+           Constants.js
+    -->
+
+
+    <!-- using a style from another lang file before referencing a
+         context from the file causes "style not defined" errors
+    -->
+    <context id="style-not-defined-error-workaround">
+      <include>
+        <context ref="js:js"/>
+      </include>
+    </context> <!-- /style-not-defined-error-workaround -->
+
+
+    <!-- # General -->
+
+    <!-- ## Preprocessor directives -->
+
+    <context id="preprocessor-directives" style-ref="js:directive" end-at-line-end="true">
+      <start extended="true">
+        \#
+        (?:
+          define |
+          elif |
+          else |
+          endif |
+          error |
+          if |
+          ifdef |
+          ifndef |
+          include |
+          pragma |
+          undef |
+          warning
+        )
+        \%]
+      </start>
+      <include>
+        <context ref="def:line-continue"/>
+      </include>
+    </context> <!-- /preprocessor-directives -->
+
+    <!-- ## Objective-J types -->
+
+    <context id="_common-types" style-ref="type">
+      <keyword>BOOL</keyword>
+      <keyword>byte</keyword>
+      <keyword>char</keyword>
+      <keyword>double</keyword>
+      <keyword>float</keyword>
+      <keyword>id</keyword>
+      <keyword>int</keyword>
+      <keyword>long</keyword>
+      <keyword>SEL</keyword>
+      <keyword>short</keyword>
+      <keyword>signed</keyword>
+      <keyword>unsigned</keyword>
+    </context> <!-- /_common-types -->
+
+    <context id="_variable-only-types">
+      <include>
+
+        <context id="_variable-only-type-keywords" style-ref="type">
+          <keyword>IBOutlet</keyword>
+        </context> <!-- /_variable-only-type-keywords -->
+
+        <context id="_variable-only-at-type-keywords" style-ref="type">
+          <prefix>@</prefix>
+          <keyword>outlet</keyword>
+        </context> <!-- /_variable-only-at-type-keywords -->
+
+      </include>
+    </context> <!-- /_variable-only-types -->
+
+    <context id="_method-return-only-types">
+      <include>
+
+        <context id="_method-return-only-type-keywords" style-ref="type">
+          <keyword>IBAction</keyword>
+          <keyword>void</keyword>
+        </context> <!-- /_method-return-only-type-keywords -->
+
+        <context id="_method-return-only-at-type-keywords" style-ref="type">
+          <prefix>@</prefix>
+          <keyword>action</keyword>
+        </context> <!-- /_method-return-only-at-type-keywords -->
+
+      </include>
+    </context> <!-- /_method-return-only-types -->
+
+
+    <!-- # @class statement -->
+
+    <context id="at-class-statements">
+      <start>@class\%]</start>
+      <end>\%{js:identifier}</end>
+      <include>
+        <context sub-pattern="0" where="start" style-ref="js:keyword"/>
+        <context ref="js:embedded-lang-hooks"/>
+        <context ref="js:comments"/>
+        <context id="_at-class-statement-content"/>
+      </include>
+    </context> <!-- /at-class-statements -->
+
+
+    <!-- # @global statement -->
+
+    <context id="at-global-statements">
+      <start>@global\%]</start>
+      <end>\%{js:identifier}</end>
+      <include>
+        <context sub-pattern="0" where="start" style-ref="js:keyword"/>
+        <context ref="js:embedded-lang-hooks"/>
+        <context ref="js:comments"/>
+        <context id="_at-global-statement-content"/>
+      </include>
+    </context> <!-- /at-global-statements -->
+
+
+    <!-- # @implementation declaration -->
+
+    <!-- ## Member variables -->
+
+    <context id="_at-implementation-variable-declaration-accessor-modifiers-end-parent" end-parent="true">
+      <start>\(</start>
+      <end>\)</end>
+      <include>
+        <context ref="js:embedded-lang-hooks"/>
+        <context ref="js:comments"/> <!-- allowed? -->
+
+        <context id="_at-implementation-variable-declaration-accessor-modifiers-content">
           <include>
-            <context id="included-file" sub-pattern="2" style-ref="included-file"/>
+
+            <context id="_at-implementation-variable-declaration-accessor-modifier-keywords" 
style-ref="js:keyword">
+              <keyword>copy</keyword>
+              <keyword>getter</keyword>
+              <keyword>property</keyword>
+              <keyword>readonly</keyword>
+              <keyword>readwrite</keyword>
+              <keyword>setter</keyword>
+            </context> <!-- /_at-implementation-variable-declaration-accessor-modifier-keywords -->
+
           </include>
-        </context>
+        </context> <!-- /_at-implementation-variable-declaration-accessor-modifiers-content -->
 
-        <context style-ref="string" end-at-line-end="true" class="string" class-disabled="no-spell-check">
-          <start>\@"</start>
-          <end>"</end>
-        </context>
+      </include>
+    </context> <!-- /_at-implementation-variable-declaration-accessor-modifiers-end-parent -->
+
+    <context id="_at-implementation-variable-declaration-accessors">
+      <start>@accessors\%]</start>
+      <end>\%{js:before-next-token}</end>
+      <include>
+        <context sub-pattern="0" where="start" style-ref="js:keyword"/>
+        <!-- no comments here -->
+
+        <context id="_at-implementation-variable-declaration-accessor-content">
+          <include>
+            <context ref="_at-implementation-variable-declaration-accessor-modifiers-end-parent"/>
+          </include>
+        </context> <!-- /_at-implementation-variable-declaration-accessor-content -->
+
+      </include>
+    </context> <!-- /_at-implementation-variable-declaration-accessors -->
+
+    <context id="_at-implementation-variable-declaration" once-only="true">
+      <start>{</start>
+      <end>}</end>
+      <include>
+        <context ref="js:embedded-lang-hooks"/>
+        <context ref="js:comments"/>
+
+        <context id="_at-implementation-variable-declaration-content">
+          <include>
+            <context ref="_common-types"/>
+            <context ref="_variable-only-types"/>
+            <context ref="_at-implementation-variable-declaration-accessors"/>
+          </include>
+        </context> <!-- /_at-implementation-variable-declaration-content -->
+
+      </include>
+    </context> <!-- /_at-implementation-variable-declaration -->
+
+    <!-- ## Member methods -->
+
+    <context id="_at-implementation-method-definitions">
+      <start>[+-]</start>
+      <include>
+        <context sub-pattern="0" where="start" style-ref="js:keyword"/>
+        <context ref="js:embedded-lang-hooks"/>
+        <context ref="js:comments"/>
+
+        <context id="_at-implementation-method-definition-content">
+          <include>
+            <context ref="_common-types"/>
+            <context ref="_method-return-only-types"/>
+
+            <context id="_at-implementation-method-definition-body" end-parent="true">
+              <start>{</start>
+              <end>}</end>
+              <include>
+                <context ref="js:embedded-lang-hooks"/>
+                <context ref="js:comments"/>
+                <context ref="js-fn:_function-body-content"/>
+              </include>
+            </context> <!-- /_at-implementation-method-definition-body -->
+
+          </include>
+        </context> <!-- /_at-implementation-method-definition-content -->
+
+      </include>
+    </context> <!-- /_at-implementation-method-definitions -->
+
+    <!-- ## @implementation declaration -->
+
+    <context id="at-implementation-declarations">
+      <start>@implementation\%]</start>
+      <end>@end\%]</end>
+      <include>
+        <context sub-pattern="0" where="start" style-ref="js:keyword"/>
+        <context sub-pattern="0" where="end" style-ref="js:keyword"/>
+        <context ref="js:embedded-lang-hooks"/>
+        <context ref="js:comments"/>
+
+        <context id="_at-implementation-declaration-content">
+          <include>
+            <context ref="_at-implementation-variable-declaration"/>
+            <context ref="_at-implementation-method-definitions"/>
+          </include>
+        </context> <!-- /_at-implementation-declaration-content -->
+
+      </include>
+    </context> <!-- /at-implementation-declarations -->
+
+
+    <!-- # @import statement -->
+
+    <context id="at-import-statements" style-ref="js:directive">
+      <start>@import\%]</start>
+      <include>
+        <context ref="js:embedded-lang-hooks"/>
+        <context ref="js:comments"/>
+
+        <context id="_at-import-statement-content">
+          <include>
+
+            <context id="_choice-at-import-framework-reference" style-ref="js:included-file" 
end-parent="true" class="path">
+              <start>&lt;</start>
+              <end>&gt;</end>
+            </context> <!-- /_choice-at-import-framework-reference -->
+
+            <context ref="js-lit:choice-string-path"/>
+          </include>
+        </context> <!-- /_at-import-statement-content -->
+
+      </include>
+    </context> <!-- /at-import-statements -->
+
+
+    <!-- # @protocol declaration -->
+
+    <context id="at-protocol-declarations">
+      <start>@protocol\%]</start>
+      <end>@end\%]</end>
+      <include>
+        <context sub-pattern="0" where="start" style-ref="js:keyword"/>
+        <context sub-pattern="0" where="end" style-ref="js:keyword"/>
+        <context ref="js:embedded-lang-hooks"/>
+        <context ref="js:comments"/>
+
+        <context id="_at-protocol-declaration-content">
+          <include>
+
+            <context id="_at-protocol-at-keywords" style-ref="js:keyword">
+              <prefix>@</prefix>
+              <keyword>optional</keyword>
+              <keyword>required</keyword>
+            </context> <!-- /_at-protocol-at-keywords -->
+
+            <context id="_at-protocol-method-types" style-ref="js:keyword">
+              <match>[+-]</match>
+            </context> <!-- /_at-protocol-method-types -->
+
+            <context ref="_common-types"/>
+            <context ref="_method-return-only-types"/>
+          </include>
+        </context> <!-- /_at-protocol-declaration-content -->
+
+      </include>
+    </context> <!-- /at-protocol-declarations -->
+
+
+    <!-- # @typedef statements -->
+
+    <context id="at-typedef-statements">
+      <start>@typedef\%]</start>
+      <end>\%{js:identifier}</end>
+      <include>
+        <context sub-pattern="0" where="start" style-ref="js:keyword"/>
+        <context ref="js:embedded-lang-hooks"/>
+        <context ref="js:comments"/>
+        <context id="_at-typedef-statement-content"/>
+      </include>
+    </context> <!-- /at-typedef-statements -->
+
+
+    <!-- # Messages -->
+
+    <context id="_message-parameter-data">
+      <start>:</start>
+      <end>\%{js:before-next-token}</end>
+      <include>
+        <context ref="js:embedded-lang-hooks"/>
+        <context ref="js:comments"/>
+
+        <context id="_message-parameter-data-content">
+          <include>
+            <context ref="js-expr:expression-without-comma"/>
+          </include>
+        </context> <!-- /_message-parameter-data-content -->
+
+      </include>
+    </context> <!-- /_message-parameter-data -->
+
+
+    <!-- # JavaScript additions -->
+
+    <!-- ## General -->
+
+    <context id="_embedded-lang-hooks">
+      <include>
+        <context ref="preprocessor-directives"/>
+        <context ref="js:embedded-lang-hooks" original="true"/>
+      </include>
+    </context> <!-- /_embedded-lang-hooks -->
+
+    <replace id="js:embedded-lang-hooks" ref="_embedded-lang-hooks"/>
+
+    <!-- ignore preprocessor directives inside comments -->
+    <context id="_in-comment" class-disabled="no-spell-check">
+      <include>
+        <context ref="def:in-comment" original="true"/>
+      </include>
+    </context> <!-- /_in-comment -->
+
+    <replace id="def:in-comment" ref="_in-comment"/>
+
+
+    <!-- ## Literals -->
+
+    <define-regex id="_at-function-keyword" extended="true">
+      (?: @ (?: deref | ref ) \%] )
+    </define-regex> <!-- /_at-function-keyword -->
+
+    <context id="_choice-at-function-keyword" style-ref="js:keyword" end-parent="true">
+      <start>(?=\%{_at-function-keyword})</start>
+      <end>\%{_at-function-keyword}</end>
+    </context> <!-- /_choice-at-function-keyword -->
+
+    <context id="_choice-at-selector-literal" end-parent="true">
+      <start>@selector\%]</start>
+      <include>
+        <context sub-pattern="0" where="start" style-ref="js:keyword"/>
+        <context ref="js:embedded-lang-hooks"/>
+        <context ref="js:comments"/>
+
+        <context id="_at-selector-literal-content">
+          <include>
+
+            <context id="_at-selector-literal-arguments-end-parent" end-parent="true">
+              <start>\(</start>
+              <end>\)</end>
+            </context> <!-- /_at-selector-literal-arguments-end-parent -->
+
+          </include>
+        </context> <!-- /_at-selector-literal-content -->
+
+      </include>
+    </context> <!-- /_choice-at-selector-literal -->
+
+    <context id="_choice-at-string" style-ref="js:string" end-parent="true">
+      <start>@(?=["'])</start>
+      <include>
+        <!-- no comments here -->
+        <context ref="js-lit:choice-string"/>
+      </include>
+    </context> <!-- /_choice-at-string -->
+
+    <context id="_choice-at-array-literal" style-ref="js:array-literal" end-parent="true">
+      <start>@(?=\[)</start>
+      <include>
+        <!-- no comments here -->
+        <context ref="js-lit:choice-array-literal"/>
+      </include>
+    </context> <!-- /_choice-at-array-literal -->
+
+    <context id="_choice-at-dictionary-literal" style-ref="js:object-literal" end-parent="true">
+      <start>@(?={)</start>
+      <include>
+        <!-- no comments here -->
+        <context ref="js-lit:choice-object-literal"/>
+      </include>
+    </context> <!-- /_choice-at-dictionary-literal -->
+
+    <!-- ### Array literal (message syntax) -->
+
+    <context id="_array-literal-content">
+      <include>
+        <context ref="js-lit:_array-literal-content" original="true"/>
+        <context ref="_message-parameter-data"/>
       </include>
     </context>
 
-    <!-- ObjJ-specific stuff (i.e. stuff which is not C), which isn't
-         good to highlight in C headers -->
-    <context id="sources">
+    <replace id="js-lit:_array-literal-content" ref="_array-literal-content"/>
+
+    <!-- ### Property name -->
+
+    <context id="_property-name-content">
       <include>
-        <context style-ref="boolean">
-          <keyword>YES</keyword>
+        <context ref="_choice-at-string"/>
+        <context ref="js-lit:_property-name-content" original="true"/>
+      </include>
+    </context> <!-- /_property-name-content -->
+
+    <replace id="js-lit:_property-name-content" ref="_property-name-content"/>
+
+
+    <!-- ## Values -->
+
+    <context id="_global-values">
+      <include>
+
+        <context id="_boolean-constants" style-ref="js:boolean">
           <keyword>NO</keyword>
+          <keyword>YES</keyword>
         </context>
 
-        <context style-ref="keyword">
-          <keyword>self</keyword>
-          <keyword>super</keyword>
-          <keyword>_cmd</keyword>
+        <context id="_null-constants" style-ref="js:null-value">
+          <keyword>nil</keyword>
+          <keyword>Nil</keyword>
+          <keyword>NULL</keyword>
         </context>
 
-        <context style-ref="type">
-          <keyword>BOOL</keyword>
-          <keyword>Class</keyword>
-          <keyword>id</keyword>
-          <keyword>int</keyword>
-          <keyword>IMP</keyword>
-          <keyword>SEL</keyword>
+        <context id="_math-constants" style-ref="js:built-in-value">
+          <keyword>E</keyword>
+          <keyword>LOG10E</keyword>
+          <keyword>LOG2E</keyword>
+          <keyword>LN10</keyword>
+          <keyword>LN2</keyword>
+          <keyword>PI</keyword>
+          <keyword>PI2</keyword>
+          <keyword>PI_2</keyword>
+          <keyword>SQRT1_2</keyword>
+          <keyword>SQRT2</keyword>
         </context>
 
-        <context style-ref="null-value">
-          <keyword>nil</keyword>
-          <keyword>Nil</keyword>
+        <context id="_math-functions" style-ref="js:built-in-function">
+          <keyword>ABS</keyword>
+          <keyword>ACOS</keyword>
+          <keyword>ASIN</keyword>
+          <keyword>ATAN</keyword>
+          <keyword>ATAN2</keyword>
+          <keyword>CEIL</keyword>
+          <keyword>COS</keyword>
+          <keyword>EXP</keyword>
+          <keyword>FLOOR</keyword>
+          <keyword>LOG</keyword>
+          <keyword>MAX</keyword>
+          <keyword>MIN</keyword>
+          <keyword>POW</keyword>
+          <keyword>RAND</keyword>
+          <keyword>ROUND</keyword>
+          <keyword>SIN</keyword>
+          <keyword>SQRT</keyword>
+          <keyword>TAN</keyword>
+        </context>
+
+        <!-- "super" is already highlighted by default -->
+        <context id="_object-keywords" style-ref="js:keyword">
+          <keyword>_cmd</keyword>
+          <keyword>self</keyword>
         </context>
+
+        <context ref="js-val:global-values" original="true"/>
       </include>
-    </context>
+    </context> <!-- /_global-values -->
+
+    <replace id="js-val:global-values" ref="_global-values"/>
+
+
+    <!-- ## Expressions -->
+
+    <context id="_primary-expression-content">
+      <include>
+        <context ref="_choice-at-function-keyword"/>
+        <context ref="_choice-at-selector-literal"/>
+        <context ref="_choice-at-string"/>
+        <context ref="_choice-at-array-literal"/>
+        <context ref="_choice-at-dictionary-literal"/>
+        <context ref="js-expr:_primary-expression-content" original="true"/>
+      </include>
+    </context> <!-- /_primary-expression-content -->
+
+    <replace id="js-expr:_primary-expression-content" ref="_primary-expression-content"/>
+
+    <!-- workaround for when a previous expression (statement) hasn't
+         ended (with a semicolon) before a message call -->
+    <context id="_bracket-property-accessor-content">
+      <include>
+        <context ref="js-expr:_bracket-property-accessor-content" original="true"/>
+        <context ref="_message-parameter-data"/>
+      </include>
+    </context> <!-- /_bracket-property-accessor-content -->
+
+    <replace id="js-expr:_bracket-property-accessor-content" ref="_bracket-property-accessor-content" />
+
+
+    <!-- # Main content -->
 
-    <!-- actual language definition: Objective-J-specific stuff plus everything from JS -->
     <context id="objj" class="no-spell-check">
       <include>
-        <context ref="headers"/>
-        <context ref="sources"/>
+        <!-- are these only allowed in top level? -->
+        <context ref="at-class-statements"/>
+        <context ref="at-global-statements"/>
+        <context ref="at-implementation-declarations"/>
+        <context ref="at-import-statements"/>
+        <context ref="at-protocol-declarations"/>
+        <context ref="at-typedef-statements"/>
         <context ref="js:js"/>
       </include>
-    </context>
-  </definitions>
+    </context> <!-- /objj -->
 
+  </definitions>
 </language>
diff --git a/tests/syntax-highlighting/file.j b/tests/syntax-highlighting/file.j
new file mode 100644
index 00000000..65ed611e
--- /dev/null
+++ b/tests/syntax-highlighting/file.j
@@ -0,0 +1,1117 @@
+/**
+ * Built-in types
+ */
+
+@implementation SomeClass
+{
+    id i;
+
+    BOOL i;
+    SEL i;
+
+    byte i;
+    char i;
+    short i;
+    int i;
+    long i;
+    float i;
+    double i;
+
+    signed i;
+    unsigned i;
+    signed char i;
+    unsigned long i;
+    unsigned long long i;
+}
+
++ (void)fn
+{
+}
+
+- (@action)fn
+{
+}
+
+- (IBAction)fn
+{
+}
+
+@end
+
+
+/**
+ * Built-in values / functions
+ */
+
+// keywords
+self;
+super;
+_cmd;
+
+// values
+YES;
+NO;
+nil;
+Nil;
+NULL;
+
+// math constants
+E;
+LOG10E;
+LOG2E;
+LN10;
+LN2;
+PI;
+PI2;
+PI_2;
+SQRT1_2;
+SQRT2;
+
+// math functions
+ABS();
+ACOS();
+ASIN();
+ATAN();
+ATAN2();
+CEIL();
+COS();
+EXP();
+FLOOR();
+LOG();
+MAX();
+MIN();
+POW();
+RAND();
+ROUND();
+SIN();
+SQRT();
+TAN();
+
+// reference / dereference
+var a, aRef = @ref(a);
+@deref(aRef) = 5;
+console.log(@deref(aRef));
+
+// method reference
+var a = @selector(setJobTitle:company:);
+
+
+/**
+ * Literals
+ */
+
+// string
+var a = @"foo";
+var a = @'bar';
+
+// array
+var a = @[1, 2, 3];
+
+// dictionary
+var a = @{
+    @"border-color": "#000",
+    @"border-width": 1.0,
+    @"content-margin": CGSizeMakeZero(),
+};
+
+
+/**
+ * Messages
+ */
+
+[self length];
+[self characterAtIndex:index];
+[myPerson setJobTitle:"Founder" company:"Cappuccino Foundation"];
+[[self alloc:42] initWithName:aName];
+
+// no semicolon between message calls
+[self length]
+[obj arg:self]
+[[obj arg:self] arg:@selector(foo:)];
+
+
+/**
+ * Declarations
+ */
+
+/* Forward class declaration */
+
+@class CPString
+
+
+// Forward global variable declaration */
+
+@global CPInvalidArgumentException
+
+
+/* Class declaration */
+
+@implementation Person : CPObject
+{
+    CPString name;
+
+    // accessors
+    CPString name         @accessors;
+    CPString _nickName    @accessors(property=nickName);
+    BOOL _cool            @accessors(getter=isCool, setter=setCool:);
+    id foo                @accessors(readonly);
+    id bar                @accessors(copy);
+    id baz                @accessors(readwrite);
+
+    // outlet
+    @outlet CPButton button;
+    IBOutlet CPCheckBox checkbox;
+}
+
+// static method
++ (id)personWithName:(CPString)aName
+{
+    return self;
+}
+
+// instance method
+- (id)initWithName:(CPString)aName
+{
+    self = [super init];
+
+    name = aName;
+
+    return self;
+}
+
+- (void)setName:(CPString)aName
+{
+    name = aName;
+}
+
+- (CPString)name
+{
+    return name;
+}
+
+@end
+
+
+// categories
+@implementation CPString (Reversing)
+- (CPString)reverse
+{
+    return reversedString;
+}
+
+@end
+
+// adopting protocol
+@implementation Person : CPObject <Move>
+{
+    CPString name;
+}
+
+@end
+
+
+/* Import */
+
+@import <Foundation/CPObject.j>
+@import "MyClass.j"
+
+
+/* Protocol definition */
+
+@protocol Move <CPObject>
+
+@required
++ (void)walk;
+
+@optional
+- (void)run;
+- (void)jump;
+
+@end
+
+
+/* Type definition */
+
+@typedef CPButtonType
+CPMomentaryLightButton  = 0;
+CPPushOnPushOffButton   = 1;
+CPToggleButton          = 2;
+
+
+/**
+ * Preprocessor directives
+ */
+
+#define foo 1
+#undef foo
+
+{
+#ifdef foo
+}
+
+function () {
+#ifndef foo
+}
+
+o = {
+#if foo == 1
+};
+
+@implementation SomeClass
+#elif defined(foo)
+{
+#else
+    id i;
+
+}
+#endif
+
++ (void)fn
+#pragma \
+mark foo
+{
+#include "foo.js"
+}
+
+@end
+
+@protocol Move <CPObject>
+#warning \
+Warning \
+message
+
+@required
++ (void)walk;
+
+@optional
+- (void)run;
+#error Error message
+- (void)jump;
+
+@end
+
+// commented out
+/*
+#define foo 1
+*/
+// #define foo 1
+
+
+// from file.js
+
+/*
+ * Expressions (in expression statements)
+ */
+
+/*
+ * Literals
+ */
+
+/* Keyword values */
+
+var NULL = null;
+var TRUE = true;
+var FALSE = false;
+
+
+/* Number */
+
+var decimal1 = 0;
+var decimal2 = 123.45;
+var decimal3 = .66667;
+var decimal4 = 10e20;
+var decimal5 = 0.2e+1;
+var decimal6 = .5E-20;
+var hex1 = 0xDEADBEEF;
+var hex2 = 0Xcafebabe;
+
+// ES2015 binary and octal numbers
+let binary1 = 0b1010;
+let binary2 = 0B00001111;
+let octal1 = 0o0123;
+let octal2 = 0O4567;
+
+// Legacy octal numbers
+var legacy_octal1 = 01;
+var legacy_octal2 = 007;
+
+// BigInt (ES2020)
+var decimal1 = 0n;
+var decimal2 = 123n;
+var hex1 = 0xDEADBEEFn;
+var hex2 = 0Xcafebaben;
+var binary1 = 0b1010n;
+var binary2 = 0B00001111n;
+var octal1 = 0o0123n;
+var octal2 = 0O4567n;
+
+
+/* String */
+
+// Escape sequences
+'\b\f\n\r\t\v\0\'\"\\'; // Single character escape
+"\1\01\001";            // Octal escape (Annex B)
+'\xA9';                 // Hexadecimal escape
+"\u00a9";               // Unicode escape
+'\u{1D306}';            // Unicode code point escape
+
+
+/* Array literal */
+
+[];
+[1];
+[1.0, 'two', 0x03];
+
+// Trailing comma
+[
+    [1,2,3],
+    [4,5,6],
+];
+
+// Spread syntax
+[1, ...a, 2];
+
+
+/* Object literal */
+
+a = {};
+a = { prop: 'value' };
+a = { prop: 'value', extends: 1 };
+
+// Trailing comma
+a = {
+    prop: 'value',
+    extends: 1,
+};
+
+// Shorthand property names
+a = { b, c, d };
+
+// Getter / setter
+a = {
+    _hidden: null,
+    get property() { return _hidden; },
+    set property(value) { this._hidden = value; }
+};
+
+// Shorthand function notation
+a = {
+    method() {},
+    *generator() {},
+
+    // Async function (ES2017)
+    async method() {},
+    async /* comment */ method() {},
+    async() {},// method called "async"
+    async: false, // property called "async"
+    async prop: 'val', // incorrectly highlighted (syntax error)
+
+    // Async generator (ES2018)
+    async *generator() {}
+};
+
+// Computed property names
+a = {
+    ['prop']: 1,
+    ['method']() {}
+};
+
+// Spread properties (ES2018)
+a = { ...b };
+
+
+/* Regular expression literal */
+
+/abc/;
+x = /abc/gi;
+function_with_regex_arg(/abc/);
+[ /abc/m, /def/u ];
+a = { regex: /abc/s }; // s (dotAll): ES2018
+(1 === 0) ? /abc/ : /def/;
+/abc/; /* Comment */
+/abc/; // Comment
+var matches = /abc/.exec('Alphabet ... that should contain abc, right?');
+
+// No regex here
+a = [thing / thing, thing / thing];
+x = a /b/ c / d;
+
+// Character groups with backslashes
+/[ab\\]/; // a, b or backslash
+/[ab\]]/; // a, b or ]
+/\\[ab]/; // a or b preceded by backslash
+/\[ab]/;  // Literally "[ab]"
+
+// Control escape
+/\cJ/;
+
+// Unicode property escape (ES2018)
+/\p{General_Category=Letter}/u;
+/\p{Letter}/u;
+
+// Named capture groups (ES2018)
+/(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/u;
+/(?<foobar>foo|bar)/u;
+/^(?<half>.*).\k<half>$/u; // backreference
+
+/* Template literal */
+
+console.log(`The sum of 2 and 2 is ${2 + 2}`);
+
+let y = 8;
+let my_string = `This is a multiline
+string that also contains
+a template ${y + (4.1 - 2.2)}`;
+
+
+/*
+ * Built-in values
+ */
+
+// global object values
+Infinity;
+NaN;
+undefined;
+
+// global object functions
+decodeURIComponent();
+decodeURI();
+encodeURIComponent();
+encodeURI();
+eval();
+isFinite();
+isNaN();
+parseFloat();
+parseInt();
+
+// constructors (subset)
+Array();
+BigInt(); // ES2020
+Boolean();
+Date();
+Error();
+Function();
+Map();
+Object();
+Promise();
+RegExp();
+Set();
+String();
+Symbol();
+
+// objects
+JSON.parse();
+Math.random();
+
+// object keywords
+arguments;
+globalThis; // ES2020
+new.target;
+new . /* comment */ target;
+super;
+this;
+new . /* comment
+*/ target; // not correctly highlighted
+new // comment
+.target; // not correctly highlighted
+
+// function keywords
+import(); // ES2020
+import /* comment */ (); // ES2020
+import /* comment
+*/ (); // not correctly highlighted (though it may appear correct)
+import // comment
+(); // not correctly highlighted (though it may appear correct)
+
+// properties (subset)
+array.length;
+Math.PI;
+Number.NaN;
+object.constructor;
+Class.prototype;
+Symbol.asyncIterator; // ES2018
+Symbol('desc').description; // ES2019
+
+// methods (subset)
+array.keys();
+date.toString();
+object.valueOf();
+re.test();
+array.includes(); // ES2016
+Object.values(); // ES2017
+Object.entries(); // ES2017
+string.padStart(); // ES2017
+string.padEnd(); // ES2017
+Object.getOwnPropertyDescriptors(); // ES2017
+promise.finally(); // ES2018
+Object.fromEntries(); // ES2019
+string.trimStart(); // ES2019
+string.trimEnd(); // ES2019
+array.flat(); // ES2019
+array.flatMap(); // ES2019
+string.matchAll(); // ES2020
+Promise.allSettled(); // ES2020
+BigInt.asUintN(); // ES2020
+
+
+/*
+ * Function expression, arrow function
+ */
+
+a = function () { return 1 };
+a = function fn() {
+    return;
+};
+a = function fn(x) {};
+a = function fn(x, y) {};
+
+// Arrow function
+x => -x;
+() => {};
+(x, y) => x + y;
+(x, y) => { return x + y; };
+(x, y) => /* comment */ { return x + y; } /* comment */ ;
+(x) => ({ a: x }); // return object
+
+// Default parameters
+a = function fn(x, y = 1) {};
+(x, y = 1) => x + y;
+
+// Parameter without default after default parameters
+a = function fn(x = 1, y) {};
+(x = 1, y) => x + y;
+
+// Array destructuring
+a = function fn([x]) {};
+a = function fn([x, y]) {};
+([x]) => x;
+([x, y]) => x + y;
+
+// Object destructuring
+a = function fn({ x }) {};
+a = function fn({ x, b: y }) {};
+({ x }) => x;
+({ x, b: y }) => x + y;
+
+// Destructuring and default value
+a = function f([x, y] = [1, 2], {c: z} = {c: 3}) {};
+([x, y] = [1, 2], {c: z} = {c: x + y}) => x + y + z;
+
+// Generator function
+a = function*fn() {};
+a = function * fn() {};
+
+// Rest parameters
+a = function fn(...rest) {};
+a = function fn(x, y, ...rest) {};
+(...rest) => rest;
+(x, y, ...rest) => rest;
+
+// Async function (ES2017)
+a = async function fn() {};
+a = async /* comment */ function fn() {};
+a = async /* comment
+*/ function fn() {}; // correctly highlighted, because async cannot be followed by a line terminator
+async x => x;
+async () => {};
+async /* comment */ () => {};
+async /* comment
+*/ () => {}; // correctly highlighted, because async cannot be followed by a line terminator
+async(); // incorrectly highlighted
+
+// Async generator (ES2018)
+a = async function * fn() {};
+
+// Trailing comma (ES2017)
+a = function fn(x, y,) {};
+(x, y,) => x + y;
+
+// Trailing comma after rest parameters (syntax error)
+a = function fn(x, y, ...rest,) {};
+(x, y, ...rest,) => rest;
+
+
+/*
+ * Class expression
+ */
+
+a = class Foo {
+    constructor() {
+    }
+    method(x, y) {
+        return x + y;
+    }
+    *generator() {}
+};
+a = class extends Bar {
+    constructor() {
+        this._value = null;
+    }
+    get property() {
+        return this._value;
+    }
+    set property(x) {
+        this._value = x;
+    }
+    static get bar() {
+        return 'bar';
+    }
+};
+
+
+/*
+ * Operators
+ * use groupings to test, as there can only be one expression (in the
+ * first grouping item)
+ */
+
+// Grouping
+( 1 + 2 );
+
+// Increment / decrement
+( ++a );
+( --a );
+( a++ );
+( a-- );
+
+// Keyword unary
+( await promise() ); // ES2017
+( delete obj.prop );
+( new Array() );
+( void 1 );
+( typeof 'str' );
+( yield 1 );
+( yield* fn() );
+
+// Arithmetic
+( 1 + 2 );
+( 1 - 2 );
+( 1 * 2 );
+( 1 / 2 );
+( 1 % 2 );
+( 1 ** 2 ); // ES2016
+( +1 );
+( -1 );
+
+// Keyword relational
+( prop in obj );
+( obj instanceof constructor );
+
+// Comparison
+( 1 == 2 );
+( 1 != 2 );
+( 1 === 2 );
+( 1 !== 2 );
+( 1 < 2 );
+( 1 > 2 );
+( 1 <= 2 );
+( 1 >= 2 );
+
+// Bitwise
+( 1 & 2 );
+( 1 | 2 );
+( 1 ^ 2 );
+( ~1 );
+( 1 << 2 );
+( 1 >> 2 );
+( 1 >>> 2 );
+
+// Logical
+( 1 && 2 );
+( 1 || 2 );
+( !1 );
+
+// Assignment
+( a = 1 );
+( a += 1 );
+( a -= 1 );
+( a *= 1 );
+( a /= 1 );
+( a %= 1 );
+( a **= 1 ); // ES2016
+( a <<= 1 );
+( a >>= 1 );
+( a >>>= 1 );
+( a &= 1 );
+( a |= 1 );
+( a ^= 1 );
+( [a, b] = [1, 2] ); // array destructuring
+( {a, b} = { a: 1, b: 2} ); // object destructuring
+
+// Comma
+1, 2 ;
+
+// Conditional / ternary
+( true ? 1 : 2 );
+( true ? : 2 ); // missing true value (syntax error)
+
+
+/*
+ * Property accessors
+ */
+
+// Dot notation
+arr.length;
+obj
+    . prototype
+    . constructor;
+
+// Bracket notation
+arr['length'];
+obj
+    ['prototype']
+    ['constructor'];
+
+// Mixed
+obj
+    ['prototype']
+    . constructor;
+obj
+    . prototype
+    ['constructor'];
+
+
+/*
+ * Function call
+ */
+
+fn();
+obj.fn(1);
+obj['fn'](1, 2);
+
+// Spread syntax
+fn(x, y, ...args);
+
+// Trailing comma (ES2017)
+fn(x, y,);
+
+
+/* Tagged template */
+
+myTag`That ${ person } is ${ age }`;
+
+
+/*
+ * Statements and declarations
+ */
+
+/* Use strict directive */
+
+"use strict";
+function () {
+    'use strict';
+}
+
+// invalid directives
+" use strict";
+'use strict ';
+"use  strict";
+'use   strict';
+"hello 'use strict' world";
+fn("use strict");
+{ 'use strict'; }
+
+
+/* Block statement */
+
+{
+    hello();
+    world();
+}
+{ hello(); world() }
+
+
+/* Break statement */
+
+break;
+break label;
+break       // end statement
+    label;  // separate statement
+{ break }
+
+
+/*
+ * Class declaration
+ */
+
+class Foo {
+    constructor() {
+    }
+    method(x, y) {
+        return x + y;
+    }
+    *generator() {}
+}
+class Foo extends Bar {
+    constructor() {
+        this._value = null;
+    }
+    get property() {
+        return this._value;
+    }
+    set property(x) {
+        this._value = x;
+    }
+    static get bar() {
+        return 'bar';
+    }
+}
+
+
+/* Continue statement */
+
+continue;
+continue label;
+continue    // end statement
+    label;  // separate statement
+{ continue }
+
+
+/* Debugger statement */
+
+debugger;
+debugger
+    ;
+
+
+/* Export / import statement */
+
+export { a };
+export { a, b, };
+export { x as a };
+export { x as a, y as b, };
+export var a;
+export let a, b;
+export const a = 1;
+export var a = 1, b = 2;
+export function fn() {}
+export function* fn() {}
+export class Class {}
+
+export default 1;
+export default function () {}
+export default function *fn() {}
+export default class {}
+export { a as default, b };
+
+export * from 'module';
+export { a, b } from 'module';
+export { x as a, y as b, } from 'module';
+export { default } from 'module';
+
+import a from "module";
+import * as ns from "module";
+import { a } from "module";
+import { a, b } from "module";
+import { x as a } from "module";
+import { x as a, y as b } from "module";
+import { default as a } from "module";
+import a, { b } from "module";
+import a, * as nm from "module";
+import "module";
+
+
+/* For statement */
+
+for (i = 0; i < 10; i++) something();
+for (var i = 10; i >= 0; i--) {
+    something();
+}
+for (i = 0, j = 0; i < 10; i++, j++) something();
+for (let i = 10, j = 0; i >= 0; i--, j += 1) {
+    something();
+}
+for (prop in obj) {} // matches "in" binary operator instead
+for (const prop in obj) {}
+for (val of generator()) {}
+for (var val of array) {}
+for await (let x of asyncIterable) {} // ES2018
+for /* comment */ await /* comment */ (let x of asyncIterable) {} // ES2018
+
+
+/* Function declaration statement */
+
+function fn() {
+    return;
+}
+async function fn() {} // ES2017
+async /* comment */ function fn() {} // ES2017
+async /* comment
+*/ function fn() {} // correctly highlighted, because async cannot be followed by a line terminator
+
+
+/* If..else statement */
+
+if (a < 0) lessThan(); else if (a > 0) greaterThan(); else equal();
+if (a < 0)
+    lessThan();
+else if (a > 0)
+    greaterThan();
+else
+    equal();
+if (a < 0) {
+    lessThan();
+} else if (a > 0) {
+    greaterThan();
+} else {
+    equal();
+}
+
+
+/* Label statement */
+
+outer: for (var i = 0; i < 10; i++) {
+inner /* comment */ : for (var j = 0; j < 2; j++) {}
+}
+loop /* comment
+*/ : for (var i in obj) {} // incorrectly highlighted (though it may appear correct)
+
+
+/* Return statement */
+
+return;
+return 1;
+return  // end statement
+    1;  // separate statement
+return (
+    1
+);
+{ return a }
+
+
+/* Switch statement */
+
+switch (foo) {
+case 1:
+    doIt();
+    break;
+case '2':
+    doSomethingElse();
+    break;
+default:
+    oops();
+}
+
+
+/* Throw statement */
+
+throw e;
+throw new Error();
+throw   // end statement (syntax error)
+    e;  // separate statement
+throw (
+    new Error()
+);
+{ throw new Error() }
+
+
+/* Try...catch statement */
+
+try {
+    somethingDangerous();
+}
+catch (e) {
+    didntWork(e);
+}
+catch { // ES2019
+    return false;
+}
+finally {
+    cleanup();
+}
+
+
+/* Variable declaration */
+
+// Declaration only
+const a;
+let a, b, c;
+var a
+    ,
+    b
+    ,
+    c
+    ;
+
+// With assignment
+const a = 1;
+let a = 1, b = [2, 3], c = 4;
+var a
+    =
+    1
+    ,
+    b
+    =
+    [
+    2
+    ,
+    3
+    ]
+    ,
+    c
+    =
+    4
+    ;
+
+// Array destructuring
+var [a, b] = [1, 2];
+var [
+    a
+    ,
+    b
+    ]
+    =
+    [
+    1
+    ,
+    2
+    ]
+    ;
+var [a = 5, b = 7] = [1]; // default values
+var [a, , b] = f(); // ignoring some returned values
+var [a, ...b] = [1, 2, 3]; // rest syntax
+
+// Object destructuring
+var { a, b } = { a: 1, b: 2 };
+var {
+    a
+    ,
+    b
+    }
+    =
+    {
+    a
+    :
+    1
+    ,
+    b
+    :
+    2
+    }
+    ;
+var { a: foo, b: bar } = { a: 1, b: 2 }; // assigning to new variable names
+var { a = 5, b = 7 } = { a: 1 }; // default values
+var { a: foo = 5, b: bar = 7 } = { a: 1 }; // assigning to new variable names and default values
+var { ['a']: foo, ['b']: bar } = { a: 1, b: 2 }; // computed property names
+var { a, b, ...rest } = { a: 1, b: 2, c: 3, d: 4 }; // rest properties (ES2018)
+
+
+/* While / do...while statement */
+
+while (true) something();
+while (1) {
+    something();
+}
+do something(); while (false);
+do {
+    something();
+} while (0);
+
+
+/* With statement */
+
+with (Math) {
+    a = PI * r * r;
+    x = r * cos(PI);
+    y = r * sin(PI / 2);
+}



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