diff --git a/json/gen/com/intellij/json/_JsonLexer.java b/json/gen/com/intellij/json/_JsonLexer.java index 32bbee8bf0a5..a46920fcdf54 100644 --- a/json/gen/com/intellij/json/_JsonLexer.java +++ b/json/gen/com/intellij/json/_JsonLexer.java @@ -1,4 +1,4 @@ -/* The following code was generated by JFlex 1.7.0-SNAPSHOT tweaked for IntelliJ platform */ +/* The following code was generated by JFlex 1.7.0 tweaked for IntelliJ platform */ package com.intellij.json; @@ -12,7 +12,7 @@ import static com.intellij.json.JsonElementTypes.*; /** * This class is a scanner generated by - * JFlex 1.7.0-SNAPSHOT + * JFlex 1.7.0 * from the specification file _JsonLexer.flex */ public class _JsonLexer implements FlexLexer { @@ -600,71 +600,88 @@ public class _JsonLexer implements FlexLexer { switch (zzAction < 0 ? zzAction : ZZ_ACTION[zzAction]) { case 1: { return BAD_CHARACTER; - } + } + // fall through case 18: break; case 2: { return WHITE_SPACE; - } + } + // fall through case 19: break; case 3: { return IDENTIFIER; - } + } + // fall through case 20: break; case 4: { return DOUBLE_QUOTED_STRING; - } + } + // fall through case 21: break; case 5: { return SINGLE_QUOTED_STRING; - } + } + // fall through case 22: break; case 6: { return NUMBER; - } + } + // fall through case 23: break; case 7: { return L_CURLY; - } + } + // fall through case 24: break; case 8: { return R_CURLY; - } + } + // fall through case 25: break; case 9: { return L_BRACKET; - } + } + // fall through case 26: break; case 10: { return R_BRACKET; - } + } + // fall through case 27: break; case 11: { return COMMA; - } + } + // fall through case 28: break; case 12: { return COLON; - } + } + // fall through case 29: break; case 13: { return LINE_COMMENT; - } + } + // fall through case 30: break; case 14: { return BLOCK_COMMENT; - } + } + // fall through case 31: break; case 15: { return TRUE; - } + } + // fall through case 32: break; case 16: { return NULL; - } + } + // fall through case 33: break; case 17: { return FALSE; - } + } + // fall through case 34: break; default: zzScanError(ZZ_NO_MATCH); diff --git a/json/gen/com/intellij/json/json5/_Json5Lexer.java b/json/gen/com/intellij/json/json5/_Json5Lexer.java new file mode 100644 index 000000000000..2beff9397079 --- /dev/null +++ b/json/gen/com/intellij/json/json5/_Json5Lexer.java @@ -0,0 +1,723 @@ +/* The following code was generated by JFlex 1.7.0 tweaked for IntelliJ platform */ + +package com.intellij.json.json5; + +import com.intellij.lexer.FlexLexer; +import com.intellij.psi.tree.IElementType; + +import static com.intellij.psi.TokenType.BAD_CHARACTER; +import static com.intellij.psi.TokenType.WHITE_SPACE; +import static com.intellij.json.JsonElementTypes.*; + + +/** + * This class is a scanner generated by + * JFlex 1.7.0 + * from the specification file _Json5Lexer.flex + */ +public class _Json5Lexer implements FlexLexer { + + /** This character denotes the end of file */ + public static final int YYEOF = -1; + + /** initial size of the lookahead buffer */ + private static final int ZZ_BUFFERSIZE = 16384; + + /** lexical states */ + public static final int YYINITIAL = 0; + + /** + * ZZ_LEXSTATE[l] is the state in the DFA for the lexical state l + * ZZ_LEXSTATE[l+1] is the state in the DFA for the lexical state l + * at the beginning of a line + * l is of the form l = 2*k, k a non negative integer + */ + private static final int ZZ_LEXSTATE[] = { + 0, 0 + }; + + /** + * Translates characters to character classes + * Chosen bits are [12, 6, 3] + * Total runtime size is 13376 bytes + */ + public static int ZZ_CMAP(int ch) { + return ZZ_CMAP_A[(ZZ_CMAP_Y[(ZZ_CMAP_Z[ch>>9]<<6)|((ch>>3)&0x3f)]<<3)|(ch&0x7)]; + } + + /* The ZZ_CMAP_Z table has 2176 entries */ + static final char ZZ_CMAP_Z[] = zzUnpackCMap( + "\1\0\1\1\1\2\1\3\1\4\1\5\1\6\1\7\1\10\1\11\1\12\1\13\1\14\1\15\1\16\1\17\1"+ + "\20\5\21\1\22\1\23\1\24\1\21\14\25\1\26\50\25\1\27\2\25\1\30\1\31\1\32\1\33"+ + "\25\25\1\34\20\21\1\35\1\36\1\37\1\40\1\41\1\42\1\43\1\21\1\44\1\45\1\46\1"+ + "\21\1\47\2\21\1\50\4\21\1\25\1\51\1\52\5\21\2\25\1\53\31\21\1\25\1\54\1\21"+ + "\1\55\40\21\1\56\17\21\1\57\1\60\1\61\1\62\13\21\1\63\10\21\123\25\1\64\7"+ + "\25\1\65\1\66\37\21\1\25\1\66\u0582\21\1\67\u017f\21"); + + /* The ZZ_CMAP_Y table has 3584 entries */ + static final char ZZ_CMAP_Y[] = zzUnpackCMap( + "\1\0\1\1\1\0\1\2\1\3\1\4\1\5\1\6\1\7\1\10\1\0\1\11\1\12\1\13\1\14\1\15\1\16"+ + "\3\0\1\17\1\20\1\21\1\22\2\0\1\23\3\0\1\23\71\0\1\24\1\0\1\25\1\26\1\27\1"+ + "\30\2\26\16\0\1\31\1\32\1\33\1\34\2\0\1\35\11\0\1\36\21\0\1\35\1\37\23\0\1"+ + "\26\1\40\3\0\1\23\1\41\1\40\4\0\1\42\1\40\4\0\1\36\1\43\1\26\3\0\2\44\1\26"+ + "\1\27\1\45\1\0\1\44\11\0\1\24\14\0\1\46\1\36\1\0\1\47\1\0\1\50\1\26\1\42\7"+ + "\0\1\51\14\0\1\25\1\26\6\0\1\52\1\22\5\0\1\52\2\26\3\0\1\2\10\26\1\47\1\27"+ + "\6\26\1\53\2\0\1\23\14\0\1\54\1\0\2\40\1\55\1\50\1\56\2\0\1\47\1\57\1\60\1"+ + "\50\1\61\1\42\1\62\1\54\1\0\1\2\1\45\1\55\1\63\1\56\2\0\1\47\1\64\1\65\1\63"+ + "\1\66\1\41\1\67\1\70\1\0\1\52\1\26\1\55\1\36\1\35\2\0\1\47\1\71\1\60\1\36"+ + "\1\72\1\73\1\26\1\54\1\0\1\41\1\26\1\55\1\50\1\56\2\0\1\47\1\71\1\60\1\50"+ + "\1\66\1\70\1\62\1\54\1\0\1\41\1\26\1\74\1\75\1\76\1\77\1\100\1\75\1\0\1\24"+ + "\1\75\1\76\1\101\1\26\1\70\1\0\1\26\1\41\1\55\1\31\1\47\2\0\1\47\1\46\1\102"+ + "\1\31\1\76\1\103\1\25\1\54\1\0\2\26\1\74\1\31\1\47\2\0\1\47\1\46\1\60\1\31"+ + "\1\76\1\103\1\33\1\54\1\0\1\104\1\26\1\74\1\31\1\47\4\0\1\51\1\31\1\105\1"+ + "\42\1\26\1\54\1\0\1\26\1\37\1\74\1\0\1\23\1\37\2\0\1\35\1\106\1\23\1\107\1"+ + "\110\1\0\2\26\1\111\1\26\1\40\6\0\1\63\1\0\1\23\1\0\1\25\4\26\1\112\1\113"+ + "\1\53\1\40\1\114\1\74\1\0\1\72\1\110\1\52\1\0\1\60\4\26\1\73\2\26\1\25\1\0"+ + "\1\25\1\115\1\116\1\0\1\40\3\0\1\27\1\40\1\0\1\31\2\0\1\40\3\0\1\27\1\33\7"+ + "\26\11\0\1\25\11\0\1\52\4\0\1\36\1\21\5\0\1\117\51\0\1\76\1\23\1\76\5\0\1"+ + "\76\4\0\1\76\1\23\1\76\1\0\1\23\7\0\1\76\10\0\1\51\4\26\2\0\2\26\12\0\1\27"+ + "\1\26\1\40\114\0\1\50\2\0\1\120\2\0\1\44\11\0\1\75\1\73\1\26\1\0\1\31\1\27"+ + "\1\26\2\0\1\27\1\26\2\0\1\2\1\26\1\0\1\31\1\121\1\26\12\0\1\122\1\123\1\0"+ + "\1\25\3\26\1\123\1\0\1\25\13\0\1\26\5\0\1\44\10\0\1\52\1\26\3\0\1\27\1\0\1"+ + "\2\1\0\1\2\1\70\4\0\1\52\1\27\1\26\5\0\1\2\3\0\1\25\1\0\1\25\4\26\3\0\1\2"+ + "\7\0\1\23\3\0\1\50\1\0\1\25\1\0\1\25\1\42\13\26\11\0\1\2\1\0\1\25\1\26\1\124"+ + "\1\2\1\26\16\0\1\2\1\26\7\0\1\26\1\0\1\102\5\0\1\52\12\26\1\117\3\0\1\23\1"+ + "\26\34\0\1\23\2\26\1\53\42\0\2\52\4\0\2\52\1\0\1\125\3\0\1\52\6\0\1\31\1\110"+ + "\1\126\1\27\1\54\1\2\1\0\1\27\1\126\1\27\1\127\1\130\3\26\1\131\1\26\1\42"+ + "\1\73\1\26\1\132\1\133\1\27\1\37\1\41\1\42\2\26\1\0\1\27\3\0\1\44\2\26\1\0"+ + "\1\27\1\134\1\0\1\73\1\26\1\107\1\37\1\106\1\135\1\30\1\136\1\0\1\60\1\137"+ + "\1\140\2\26\5\0\1\73\116\26\5\0\1\23\5\0\1\23\20\0\1\27\1\124\1\2\1\26\4\0"+ + "\1\36\1\21\7\0\1\42\1\26\1\42\2\0\1\23\1\26\10\23\4\0\5\26\1\42\72\26\1\141"+ + "\3\26\1\40\1\0\1\135\1\27\1\40\11\0\1\23\1\142\1\40\12\0\1\117\1\137\4\0\1"+ + "\52\1\40\12\0\1\23\2\26\3\0\1\44\6\26\170\0\1\52\11\26\71\0\1\27\6\26\21\0"+ + "\1\27\10\26\5\0\1\52\41\0\1\27\3\0\1\2\2\26\6\0\1\53\1\36\3\0\1\42\12\0\1"+ + "\25\3\26\1\42\1\0\1\37\14\0\1\61\1\2\1\26\1\0\1\44\11\26\6\0\2\26\1\73\6\0"+ + "\1\2\1\26\10\0\1\27\1\26\1\0\1\25\3\0\1\45\5\0\1\52\4\0\1\2\1\26\3\0\1\27"+ + "\10\0\1\73\1\42\1\0\1\25\4\26\6\0\1\23\1\26\1\0\1\52\1\0\1\25\2\0\1\23\1\111"+ + "\10\0\1\44\2\26\1\123\2\0\1\143\1\26\3\144\1\26\2\23\22\26\5\0\1\145\1\0\1"+ + "\25\64\0\1\2\1\26\2\0\1\23\1\124\5\0\1\2\40\26\55\0\1\52\15\0\1\25\4\26\1"+ + "\23\1\26\1\124\1\137\1\0\1\47\1\23\1\110\1\146\15\0\1\25\3\26\1\124\54\0\1"+ + "\52\2\26\10\0\1\37\6\0\5\26\1\0\1\27\2\0\2\26\1\23\1\26\1\100\2\26\1\137\3"+ + "\26\1\41\1\31\20\0\1\50\1\132\1\26\1\0\1\25\1\40\2\0\1\63\1\40\2\0\1\44\1"+ + "\70\12\0\1\23\3\37\1\147\1\150\2\26\1\151\1\0\1\46\2\0\1\23\2\0\1\152\1\0"+ + "\1\52\1\0\1\52\4\26\17\0\1\44\10\26\6\0\1\27\20\26\1\21\20\26\3\0\1\27\6\0"+ + "\1\73\5\26\3\0\1\23\2\26\3\0\1\44\6\26\3\0\1\52\4\0\1\2\1\0\1\135\5\26\23"+ + "\0\1\52\1\0\1\25\52\26\1\52\1\47\4\0\1\36\1\153\2\0\1\52\25\26\2\0\1\52\1"+ + "\26\3\0\1\25\10\26\7\0\1\70\10\26\1\154\1\53\1\46\1\40\2\0\1\2\1\63\4\26\3"+ + "\0\1\27\20\26\6\0\1\52\1\26\2\0\1\52\1\26\2\0\1\44\21\26\11\0\1\73\66\26\10"+ + "\0\1\23\3\26\1\70\1\0\2\26\7\0\1\155\2\26\3\0\1\73\1\0\1\25\6\0\1\31\1\0\10"+ + "\26\10\0\1\27\1\26\1\0\1\25\24\26\7\0\1\26\1\0\1\25\46\26\55\0\1\23\22\26"+ + "\14\0\1\44\63\26\5\0\1\23\72\26\7\0\1\73\130\26\10\0\1\27\1\26\5\0\1\23\1"+ + "\26\1\42\2\0\14\26\1\25\153\26\1\137\1\102\2\0\1\51\1\2\3\26\1\32\22\26\1"+ + "\147\67\26\12\0\1\31\10\0\1\31\1\156\1\157\1\0\1\160\1\46\7\0\1\36\1\51\2"+ + "\31\3\0\1\161\1\110\1\37\1\47\51\0\1\52\3\0\1\47\2\0\1\117\3\0\1\117\2\0\1"+ + "\31\3\0\1\31\2\0\1\23\3\0\1\23\3\0\1\47\3\0\1\47\2\0\1\117\1\54\6\0\1\46\3"+ + "\0\1\112\1\40\1\117\1\162\1\107\1\163\1\112\1\125\1\112\2\117\1\67\1\0\1\35"+ + "\1\0\1\2\1\55\1\35\1\0\1\2\50\26\32\0\1\23\5\26\106\0\1\27\1\26\33\0\1\52"+ + "\74\26\1\41\3\26\14\0\20\26\36\0\2\26"); + + /* The ZZ_CMAP_A table has 928 entries */ + static final char ZZ_CMAP_A[] = zzUnpackCMap( + "\11\35\1\12\1\2\1\1\1\7\1\3\6\35\4\0\1\12\1\35\1\13\1\0\1\35\2\0\1\15\2\35"+ + "\1\11\1\16\1\42\1\17\1\22\1\6\1\20\11\21\1\43\1\0\3\35\1\0\1\35\4\5\1\23\1"+ + "\5\2\35\1\25\4\35\1\33\1\35\1\24\2\35\1\40\1\14\1\41\2\35\1\0\1\34\3\5\1\46"+ + "\1\27\2\35\1\30\2\35\1\47\1\35\1\26\3\35\1\44\1\50\1\31\1\45\2\35\1\24\1\32"+ + "\1\35\1\36\1\0\1\37\7\35\1\10\2\35\1\4\1\0\4\35\4\0\1\35\2\0\1\35\7\0\1\35"+ + "\4\0\1\35\5\0\7\35\1\0\2\35\4\0\4\35\16\0\5\35\7\0\1\35\1\0\1\35\1\0\5\35"+ + "\1\0\2\35\2\0\4\35\10\0\1\35\1\0\3\35\1\0\1\35\1\0\4\35\1\0\13\35\1\0\1\35"+ + "\2\0\6\35\1\0\7\35\1\0\1\35\15\0\1\35\1\0\2\35\1\0\2\35\1\0\4\35\10\0\1\35"+ + "\4\0\4\35\1\0\4\35\1\0\13\35\2\0\4\35\2\0\11\35\6\0\10\35\2\0\2\35\1\0\3\35"+ + "\1\0\4\35\2\0\6\35\1\0\1\35\3\0\4\35\2\0\5\35\2\0\4\35\5\0\2\35\1\0\4\35\4"+ + "\0\2\35\1\0\2\35\1\0\2\35\1\0\2\35\2\0\1\35\1\0\3\35\2\0\3\35\3\0\4\35\1\0"+ + "\1\35\7\0\3\35\1\0\2\35\1\0\5\35\1\0\3\35\2\0\1\35\11\0\2\35\1\0\6\35\3\0"+ + "\3\35\1\0\4\35\3\0\2\35\1\0\1\35\1\0\2\35\3\0\2\35\3\0\1\35\6\0\3\35\3\0\3"+ + "\35\5\0\2\35\2\0\2\35\5\0\1\35\1\0\5\35\1\0\4\35\1\0\1\35\4\0\1\35\4\0\6\35"+ + "\1\0\1\35\3\0\2\35\5\0\2\35\1\0\1\35\2\0\2\35\1\0\1\35\2\0\1\35\3\0\3\35\1"+ + "\0\1\35\1\0\1\35\5\0\1\35\1\0\1\35\1\0\1\35\4\0\5\35\1\0\4\35\1\4\10\35\1"+ + "\0\2\35\4\0\4\35\3\0\1\35\3\0\3\35\5\0\5\35\1\0\1\35\1\0\1\35\1\0\1\35\1\0"+ + "\1\35\2\0\3\35\1\0\2\35\13\4\5\35\2\1\5\35\1\4\4\0\1\35\12\0\1\4\1\0\1\35"+ + "\3\0\3\35\1\0\5\35\2\0\1\35\1\0\4\35\1\0\1\35\5\0\5\35\4\0\1\35\1\0\1\4\4"+ + "\0\3\35\1\0\2\35\2\0\3\35\2\0\5\35\2\0\6\35\1\0\3\35\1\0\2\35\2\0\2\35\1\0"+ + "\2\35\1\0\2\35\2\0\3\35\3\0\2\35\3\0\2\35\2\0\3\35\4\0\3\35\1\0\2\35\1\0\2"+ + "\35\3\0\1\35\2\0\5\35\1\0\2\35\1\0\3\35\2\0\1\35\4\0\1\35\2\0\2\35\2\0\4\35"+ + "\1\0\4\35\1\0\1\35\1\0\5\35\1\0\4\35\2\0\1\35\1\0\1\35\5\0\1\35\1\0\1\35\1"+ + "\0\3\35"); + + /** + * Translates DFA states to action switch labels. + */ + private static final int [] ZZ_ACTION = zzUnpackAction(); + + private static final String ZZ_ACTION_PACKED_0 = + "\1\1\1\2\1\3\2\4\1\3\1\5\1\6\6\1"+ + "\5\4\1\7\1\10\1\11\1\12\1\13\1\14\1\15"+ + "\1\16\1\5\2\0\1\6\5\1\1\4\2\1\5\4"+ + "\1\15\1\16\1\4\2\5\2\6\1\1\4\4\1\1"+ + "\1\0\1\16\1\4\1\17\1\4\1\20\1\16\1\4"+ + "\1\21\2\4"; + + private static int [] zzUnpackAction() { + int [] result = new int[68]; + int offset = 0; + offset = zzUnpackAction(ZZ_ACTION_PACKED_0, offset, result); + return result; + } + + private static int zzUnpackAction(String packed, int offset, int [] result) { + int i = 0; /* index in packed string */ + int j = offset; /* index in unpacked array */ + int l = packed.length(); + while (i < l) { + int count = packed.charAt(i++); + int value = packed.charAt(i++); + do result[j++] = value; while (--count > 0); + } + return j; + } + + + /** + * Translates a state to a row index in the transition table + */ + private static final int [] ZZ_ROWMAP = zzUnpackRowMap(); + + private static final String ZZ_ROWMAP_PACKED_0 = + "\0\0\0\51\0\122\0\173\0\244\0\315\0\366\0\u011f"+ + "\0\u0148\0\u0171\0\u019a\0\u01c3\0\u01ec\0\u0215\0\u023e\0\u0267"+ + "\0\u0290\0\u02b9\0\u02e2\0\51\0\51\0\51\0\51\0\51"+ + "\0\51\0\u030b\0\u0334\0\51\0\u035d\0\u0386\0\51\0\u03af"+ + "\0\u03d8\0\u0401\0\u042a\0\u0453\0\u047c\0\u04a5\0\u04ce\0\u04f7"+ + "\0\u0520\0\u0549\0\u0572\0\u059b\0\u05c4\0\u05ed\0\u0616\0\u063f"+ + "\0\u0668\0\u0691\0\u06ba\0\u047c\0\u06e3\0\u070c\0\u0735\0\u075e"+ + "\0\173\0\u0787\0\173\0\u07b0\0\173\0\u07d9\0\173\0\51"+ + "\0\u0802\0\173\0\u082b\0\u0854"; + + private static int [] zzUnpackRowMap() { + int [] result = new int[68]; + int offset = 0; + offset = zzUnpackRowMap(ZZ_ROWMAP_PACKED_0, offset, result); + return result; + } + + private static int zzUnpackRowMap(String packed, int offset, int [] result) { + int i = 0; /* index in packed string */ + int j = offset; /* index in unpacked array */ + int l = packed.length(); + while (i < l) { + int high = packed.charAt(i++) << 16; + result[j++] = high | packed.charAt(i++); + } + return j; + } + + /** + * The transition table of the DFA + */ + private static final int [] ZZ_TRANS = zzUnpackTrans(); + + private static final String ZZ_TRANS_PACKED_0 = + "\1\2\4\3\1\4\1\5\1\3\1\6\1\4\1\3"+ + "\1\7\1\2\1\10\1\11\1\12\1\13\1\14\1\15"+ + "\1\16\1\4\1\17\1\20\1\21\1\4\1\22\1\4"+ + "\1\23\2\4\1\24\1\25\1\26\1\27\1\30\1\31"+ + "\2\4\1\16\2\4\52\0\4\3\2\0\2\3\1\0"+ + "\1\3\43\0\2\4\1\0\2\4\5\0\17\4\6\0"+ + "\5\4\5\0\1\4\1\32\1\0\1\4\1\33\5\0"+ + "\17\4\6\0\5\4\1\0\4\3\2\4\1\3\1\6"+ + "\1\4\1\3\4\0\17\4\6\0\5\4\2\7\2\0"+ + "\7\7\1\34\1\35\34\7\2\10\2\0\10\10\1\36"+ + "\1\37\33\10\20\0\1\40\1\41\1\42\1\43\22\0"+ + "\1\43\7\0\2\4\1\0\2\4\5\0\1\4\1\44"+ + "\1\14\1\15\1\16\1\4\1\17\5\4\1\23\2\4"+ + "\6\0\2\4\1\16\2\4\5\0\2\4\1\0\2\4"+ + "\5\0\1\4\3\15\1\16\1\45\11\4\6\0\2\4"+ + "\1\16\2\4\5\0\2\4\1\0\2\4\5\0\1\4"+ + "\2\14\1\15\1\16\12\4\6\0\2\4\1\16\2\4"+ + "\5\0\2\4\1\0\2\4\5\0\1\4\2\15\1\4"+ + "\1\16\12\4\6\0\2\4\1\16\2\4\5\0\2\4"+ + "\1\0\2\4\4\0\1\46\3\47\14\4\6\0\5\4"+ + "\5\0\2\4\1\0\2\4\5\0\7\4\1\50\7\4"+ + "\6\0\5\4\5\0\2\4\1\0\2\4\5\0\17\4"+ + "\6\0\1\4\1\51\3\4\5\0\2\4\1\0\2\4"+ + "\5\0\15\4\1\52\1\4\6\0\5\4\5\0\2\4"+ + "\1\0\2\4\5\0\17\4\6\0\1\53\4\4\5\0"+ + "\2\4\1\0\2\4\5\0\15\4\1\54\1\4\6\0"+ + "\5\4\1\55\3\0\1\55\2\32\1\0\1\4\1\32"+ + "\5\55\17\32\6\55\5\32\5\56\2\33\1\56\1\33"+ + "\1\57\5\56\17\33\6\56\5\33\3\7\1\60\3\7"+ + "\1\61\2\7\1\61\36\7\3\10\1\62\3\10\1\63"+ + "\2\10\1\63\36\10\20\0\3\42\1\43\22\0\1\43"+ + "\22\0\2\41\1\42\1\43\22\0\1\43\22\0\2\42"+ + "\1\0\1\43\22\0\1\43\20\0\4\46\34\0\2\4"+ + "\1\0\2\4\5\0\1\4\3\15\1\16\12\4\6\0"+ + "\2\4\1\16\2\4\5\0\1\64\1\4\1\0\2\4"+ + "\5\0\1\4\2\64\1\4\1\64\3\4\1\64\4\4"+ + "\1\64\1\4\6\0\2\4\1\64\2\4\20\0\2\46"+ + "\34\0\2\4\1\0\2\4\5\0\1\4\2\47\14\4"+ + "\6\0\5\4\5\0\2\4\1\0\2\4\5\0\10\4"+ + "\1\65\6\4\6\0\5\4\5\0\2\4\1\0\2\4"+ + "\5\0\17\4\6\0\3\4\1\66\1\4\5\0\2\4"+ + "\1\0\2\4\5\0\17\4\6\0\3\4\1\67\1\4"+ + "\5\0\2\4\1\0\2\4\5\0\17\4\6\0\1\4"+ + "\1\70\3\4\5\0\2\4\1\0\2\4\5\0\14\4"+ + "\1\71\2\4\6\0\5\4\1\55\3\0\3\55\2\0"+ + "\40\55\11\56\1\72\44\56\1\33\1\73\1\56\1\33"+ + "\1\57\5\56\17\33\6\56\5\33\3\7\1\0\7\7"+ + "\1\34\1\35\37\7\1\60\3\7\1\61\2\7\1\61"+ + "\1\34\1\35\34\7\3\10\1\0\10\10\1\36\1\37"+ + "\36\10\1\62\3\10\1\63\2\10\1\63\1\10\1\36"+ + "\1\37\33\10\5\0\2\4\1\0\2\4\5\0\11\4"+ + "\1\74\5\4\6\0\5\4\5\0\2\4\1\0\2\4"+ + "\5\0\17\4\6\0\3\4\1\75\1\4\5\0\2\4"+ + "\1\0\2\4\5\0\17\4\6\0\4\4\1\76\5\0"+ + "\2\4\1\0\2\4\5\0\17\4\6\0\2\4\1\77"+ + "\2\4\6\56\1\100\2\56\1\72\37\56\5\0\2\4"+ + "\1\0\2\4\5\0\7\4\1\101\7\4\6\0\5\4"+ + "\5\0\2\4\1\0\2\4\5\0\17\4\6\0\2\4"+ + "\1\102\2\4\5\0\2\4\1\0\2\4\5\0\11\4"+ + "\1\103\5\4\6\0\5\4\5\0\2\4\1\0\2\4"+ + "\5\0\12\4\1\104\4\4\6\0\5\4\5\0\2\4"+ + "\1\0\2\4\5\0\13\4\1\71\3\4\6\0\5\4"; + + private static int [] zzUnpackTrans() { + int [] result = new int[2173]; + int offset = 0; + offset = zzUnpackTrans(ZZ_TRANS_PACKED_0, offset, result); + return result; + } + + private static int zzUnpackTrans(String packed, int offset, int [] result) { + int i = 0; /* index in packed string */ + int j = offset; /* index in unpacked array */ + int l = packed.length(); + while (i < l) { + int count = packed.charAt(i++); + int value = packed.charAt(i++); + value--; + do result[j++] = value; while (--count > 0); + } + return j; + } + + + /* error codes */ + private static final int ZZ_UNKNOWN_ERROR = 0; + private static final int ZZ_NO_MATCH = 1; + private static final int ZZ_PUSHBACK_2BIG = 2; + + /* error messages for the codes above */ + private static final String[] ZZ_ERROR_MSG = { + "Unknown internal scanner error", + "Error: could not match input", + "Error: pushback value was too large" + }; + + /** + * ZZ_ATTRIBUTE[aState] contains the attributes of state aState + */ + private static final int [] ZZ_ATTRIBUTE = zzUnpackAttribute(); + + private static final String ZZ_ATTRIBUTE_PACKED_0 = + "\1\1\1\11\21\1\6\11\2\1\1\11\2\0\1\11"+ + "\32\1\1\0\5\1\1\11\4\1"; + + private static int [] zzUnpackAttribute() { + int [] result = new int[68]; + int offset = 0; + offset = zzUnpackAttribute(ZZ_ATTRIBUTE_PACKED_0, offset, result); + return result; + } + + private static int zzUnpackAttribute(String packed, int offset, int [] result) { + int i = 0; /* index in packed string */ + int j = offset; /* index in unpacked array */ + int l = packed.length(); + while (i < l) { + int count = packed.charAt(i++); + int value = packed.charAt(i++); + do result[j++] = value; while (--count > 0); + } + return j; + } + + /** the input device */ + private java.io.Reader zzReader; + + /** the current state of the DFA */ + private int zzState; + + /** the current lexical state */ + private int zzLexicalState = YYINITIAL; + + /** this buffer contains the current text to be matched and is + the source of the yytext() string */ + private CharSequence zzBuffer = ""; + + /** the textposition at the last accepting state */ + private int zzMarkedPos; + + /** the current text position in the buffer */ + private int zzCurrentPos; + + /** startRead marks the beginning of the yytext() string in the buffer */ + private int zzStartRead; + + /** endRead marks the last character in the buffer, that has been read + from input */ + private int zzEndRead; + + /** + * zzAtBOL == true <=> the scanner is currently at the beginning of a line + */ + private boolean zzAtBOL = true; + + /** zzAtEOF == true <=> the scanner is at the EOF */ + private boolean zzAtEOF; + + /** denotes if the user-EOF-code has already been executed */ + private boolean zzEOFDone; + + /* user code: */ + public _Json5Lexer() { + this((java.io.Reader)null); + } + + + /** + * Creates a new scanner + * + * @param in the java.io.Reader to read input from. + */ + public _Json5Lexer(java.io.Reader in) { + this.zzReader = in; + } + + + /** + * Unpacks the compressed character translation table. + * + * @param packed the packed character translation table + * @return the unpacked character translation table + */ + private static char [] zzUnpackCMap(String packed) { + int size = 0; + for (int i = 0, length = packed.length(); i < length; i += 2) { + size += packed.charAt(i); + } + char[] map = new char[size]; + int i = 0; /* index in packed string */ + int j = 0; /* index in unpacked array */ + while (i < packed.length()) { + int count = packed.charAt(i++); + char value = packed.charAt(i++); + do map[j++] = value; while (--count > 0); + } + return map; + } + + public final int getTokenStart() { + return zzStartRead; + } + + public final int getTokenEnd() { + return getTokenStart() + yylength(); + } + + public void reset(CharSequence buffer, int start, int end, int initialState) { + zzBuffer = buffer; + zzCurrentPos = zzMarkedPos = zzStartRead = start; + zzAtEOF = false; + zzAtBOL = true; + zzEndRead = end; + yybegin(initialState); + } + + /** + * Refills the input buffer. + * + * @return false, iff there was new input. + * + * @exception java.io.IOException if any I/O-Error occurs + */ + private boolean zzRefill() throws java.io.IOException { + return true; + } + + + /** + * Returns the current lexical state. + */ + public final int yystate() { + return zzLexicalState; + } + + + /** + * Enters a new lexical state + * + * @param newState the new lexical state + */ + public final void yybegin(int newState) { + zzLexicalState = newState; + } + + + /** + * Returns the text matched by the current regular expression. + */ + public final CharSequence yytext() { + return zzBuffer.subSequence(zzStartRead, zzMarkedPos); + } + + + /** + * Returns the character at position pos from the + * matched text. + * + * It is equivalent to yytext().charAt(pos), but faster + * + * @param pos the position of the character to fetch. + * A value from 0 to yylength()-1. + * + * @return the character at position pos + */ + public final char yycharat(int pos) { + return zzBuffer.charAt(zzStartRead+pos); + } + + + /** + * Returns the length of the matched text region. + */ + public final int yylength() { + return zzMarkedPos-zzStartRead; + } + + + /** + * Reports an error that occured while scanning. + * + * In a wellformed scanner (no or only correct usage of + * yypushback(int) and a match-all fallback rule) this method + * will only be called with things that "Can't Possibly Happen". + * If this method is called, something is seriously wrong + * (e.g. a JFlex bug producing a faulty scanner etc.). + * + * Usual syntax/scanner level error handling should be done + * in error fallback rules. + * + * @param errorCode the code of the errormessage to display + */ + private void zzScanError(int errorCode) { + String message; + try { + message = ZZ_ERROR_MSG[errorCode]; + } + catch (ArrayIndexOutOfBoundsException e) { + message = ZZ_ERROR_MSG[ZZ_UNKNOWN_ERROR]; + } + + throw new Error(message); + } + + + /** + * Pushes the specified amount of characters back into the input stream. + * + * They will be read again by then next call of the scanning method + * + * @param number the number of characters to be read again. + * This number must not be greater than yylength()! + */ + public void yypushback(int number) { + if ( number > yylength() ) + zzScanError(ZZ_PUSHBACK_2BIG); + + zzMarkedPos -= number; + } + + + /** + * Resumes scanning until the next regular expression is matched, + * the end of input is encountered or an I/O-Error occurs. + * + * @return the next token + * @exception java.io.IOException if any I/O-Error occurs + */ + public IElementType advance() throws java.io.IOException { + int zzInput; + int zzAction; + + // cached fields: + int zzCurrentPosL; + int zzMarkedPosL; + int zzEndReadL = zzEndRead; + CharSequence zzBufferL = zzBuffer; + + int [] zzTransL = ZZ_TRANS; + int [] zzRowMapL = ZZ_ROWMAP; + int [] zzAttrL = ZZ_ATTRIBUTE; + + while (true) { + zzMarkedPosL = zzMarkedPos; + + zzAction = -1; + + zzCurrentPosL = zzCurrentPos = zzStartRead = zzMarkedPosL; + + zzState = ZZ_LEXSTATE[zzLexicalState]; + + // set up zzAction for empty match case: + int zzAttributes = zzAttrL[zzState]; + if ( (zzAttributes & 1) == 1 ) { + zzAction = zzState; + } + + + zzForAction: { + while (true) { + + if (zzCurrentPosL < zzEndReadL) { + zzInput = Character.codePointAt(zzBufferL, zzCurrentPosL/*, zzEndReadL*/); + zzCurrentPosL += Character.charCount(zzInput); + } + else if (zzAtEOF) { + zzInput = YYEOF; + break zzForAction; + } + else { + // store back cached positions + zzCurrentPos = zzCurrentPosL; + zzMarkedPos = zzMarkedPosL; + boolean eof = zzRefill(); + // get translated positions and possibly new buffer + zzCurrentPosL = zzCurrentPos; + zzMarkedPosL = zzMarkedPos; + zzBufferL = zzBuffer; + zzEndReadL = zzEndRead; + if (eof) { + zzInput = YYEOF; + break zzForAction; + } + else { + zzInput = Character.codePointAt(zzBufferL, zzCurrentPosL/*, zzEndReadL*/); + zzCurrentPosL += Character.charCount(zzInput); + } + } + int zzNext = zzTransL[ zzRowMapL[zzState] + ZZ_CMAP(zzInput) ]; + if (zzNext == -1) break zzForAction; + zzState = zzNext; + + zzAttributes = zzAttrL[zzState]; + if ( (zzAttributes & 1) == 1 ) { + zzAction = zzState; + zzMarkedPosL = zzCurrentPosL; + if ( (zzAttributes & 8) == 8 ) break zzForAction; + } + + } + } + + // store back cached position + zzMarkedPos = zzMarkedPosL; + + if (zzInput == YYEOF && zzStartRead == zzCurrentPos) { + zzAtEOF = true; + return null; + } + else { + switch (zzAction < 0 ? zzAction : ZZ_ACTION[zzAction]) { + case 1: + { return NUMBER; + } + // fall through + case 18: break; + case 2: + { return BAD_CHARACTER; + } + // fall through + case 19: break; + case 3: + { return WHITE_SPACE; + } + // fall through + case 20: break; + case 4: + { return IDENTIFIER; + } + // fall through + case 21: break; + case 5: + { return DOUBLE_QUOTED_STRING; + } + // fall through + case 22: break; + case 6: + { return SINGLE_QUOTED_STRING; + } + // fall through + case 23: break; + case 7: + { return L_CURLY; + } + // fall through + case 24: break; + case 8: + { return R_CURLY; + } + // fall through + case 25: break; + case 9: + { return L_BRACKET; + } + // fall through + case 26: break; + case 10: + { return R_BRACKET; + } + // fall through + case 27: break; + case 11: + { return COMMA; + } + // fall through + case 28: break; + case 12: + { return COLON; + } + // fall through + case 29: break; + case 13: + { return LINE_COMMENT; + } + // fall through + case 30: break; + case 14: + { return BLOCK_COMMENT; + } + // fall through + case 31: break; + case 15: + { return NULL; + } + // fall through + case 32: break; + case 16: + { return TRUE; + } + // fall through + case 33: break; + case 17: + { return FALSE; + } + // fall through + case 34: break; + default: + zzScanError(ZZ_NO_MATCH); + } + } + } + } + + +} diff --git a/json/resources/inspectionDescriptions/Json5StandardCompliance.html b/json/resources/inspectionDescriptions/Json5StandardCompliance.html new file mode 100644 index 000000000000..8171150e6345 --- /dev/null +++ b/json/resources/inspectionDescriptions/Json5StandardCompliance.html @@ -0,0 +1,5 @@ + + +This inspection checks that JSON5 files conform to language specification (http://json5.org/).
+ + \ No newline at end of file diff --git a/json/src/com/intellij/json/JsonBundle.java b/json/src/com/intellij/json/JsonBundle.java index 836df2a05225..9ccab90f24f9 100644 --- a/json/src/com/intellij/json/JsonBundle.java +++ b/json/src/com/intellij/json/JsonBundle.java @@ -15,7 +15,7 @@ import java.util.ResourceBundle; public class JsonBundle { private static Reference ourBundle; - @NonNls private static final String BUNDLE = "com.intellij.json.JsonBundle"; + @NonNls public static final String BUNDLE = "com.intellij.json.JsonBundle"; private JsonBundle() { // empty diff --git a/json/src/com/intellij/json/JsonBundle.properties b/json/src/com/intellij/json/JsonBundle.properties index 55803d7ea4ca..bd1cd5e4b5a0 100644 --- a/json/src/com/intellij/json/JsonBundle.properties +++ b/json/src/com/intellij/json/JsonBundle.properties @@ -9,8 +9,10 @@ syntax.error.illegal.floating.point.literal=Illegal floating point literal # Inspections json.inspection.group=JSON +json.inspection5.group=JSON/JSON5 inspection.compliance.name=Compliance with JSON standard +inspection.compliance5.name=Compliance with JSON5 standard inspection.compliance.msg.comments=JSON standard does not allow comments. Use JSMin or similar tool to remove comments before parsing. inspection.compliance.msg.single.quoted.strings=JSON standard does not allow single quoted strings inspection.compliance.msg.bad.token=JSON standard does not allow such tokens diff --git a/json/src/com/intellij/json/JsonDialectUtil.java b/json/src/com/intellij/json/JsonDialectUtil.java new file mode 100644 index 000000000000..b2ffe61f0936 --- /dev/null +++ b/json/src/com/intellij/json/JsonDialectUtil.java @@ -0,0 +1,20 @@ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.json; + +import com.intellij.lang.Language; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import org.jetbrains.annotations.NotNull; + +public class JsonDialectUtil { + public static boolean isStandardJson(@NotNull PsiElement element) { + return getLanguage(element) == JsonLanguage.INSTANCE; + } + + public static Language getLanguage(@NotNull PsiElement element) { + PsiFile file = element.getContainingFile(); + if (file == null) return JsonLanguage.INSTANCE; + Language language = file.getLanguage(); + return language instanceof JsonLanguage ? language : JsonLanguage.INSTANCE; + } +} diff --git a/json/src/com/intellij/json/JsonFileType.java b/json/src/com/intellij/json/JsonFileType.java index c57408538077..6137ceea0e6d 100644 --- a/json/src/com/intellij/json/JsonFileType.java +++ b/json/src/com/intellij/json/JsonFileType.java @@ -1,11 +1,12 @@ package com.intellij.json; import com.intellij.icons.AllIcons; +import com.intellij.lang.Language; import com.intellij.openapi.fileTypes.LanguageFileType; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import javax.swing.Icon; +import javax.swing.*; /** * @author Mikhail Golubev @@ -14,6 +15,10 @@ public class JsonFileType extends LanguageFileType{ public static final JsonFileType INSTANCE = new JsonFileType(); public static final String DEFAULT_EXTENSION = "json"; + protected JsonFileType(Language language) { + super(language); + } + public JsonFileType() { super(JsonLanguage.INSTANCE); } diff --git a/json/src/com/intellij/json/JsonLanguage.java b/json/src/com/intellij/json/JsonLanguage.java index 7c5e4c4a1662..9d73f86a4389 100644 --- a/json/src/com/intellij/json/JsonLanguage.java +++ b/json/src/com/intellij/json/JsonLanguage.java @@ -5,6 +5,10 @@ import com.intellij.lang.Language; public class JsonLanguage extends Language { public static final JsonLanguage INSTANCE = new JsonLanguage(); + protected JsonLanguage(String ID, String... mimeTypes) { + super(INSTANCE, ID, mimeTypes); + } + private JsonLanguage() { super("JSON", "application/json", "application/vnd.api+json", "application/hal+json"); } diff --git a/json/src/com/intellij/json/JsonParserDefinition.java b/json/src/com/intellij/json/JsonParserDefinition.java index 2eca5d3d2119..c7f123c25a66 100644 --- a/json/src/com/intellij/json/JsonParserDefinition.java +++ b/json/src/com/intellij/json/JsonParserDefinition.java @@ -74,7 +74,7 @@ public class JsonParserDefinition implements ParserDefinition { @Override public PsiFile createFile(FileViewProvider fileViewProvider) { - return new JsonFileImpl(fileViewProvider); + return new JsonFileImpl(fileViewProvider, JsonLanguage.INSTANCE); } @Override diff --git a/json/src/com/intellij/json/codeinsight/JsonLiteralAnnotator.java b/json/src/com/intellij/json/codeinsight/JsonLiteralAnnotator.java index d2b098ae167d..e2537152a7d6 100644 --- a/json/src/com/intellij/json/codeinsight/JsonLiteralAnnotator.java +++ b/json/src/com/intellij/json/codeinsight/JsonLiteralAnnotator.java @@ -19,6 +19,7 @@ import com.intellij.json.JsonBundle; import com.intellij.json.highlighting.JsonSyntaxHighlighterFactory; import com.intellij.json.psi.JsonNumberLiteral; import com.intellij.json.psi.JsonPsiUtil; +import com.intellij.json.psi.JsonReferenceExpression; import com.intellij.json.psi.JsonStringLiteral; import com.intellij.lang.annotation.AnnotationHolder; import com.intellij.lang.annotation.Annotator; @@ -29,14 +30,11 @@ import com.intellij.psi.PsiElement; import org.jetbrains.annotations.NotNull; import java.util.List; -import java.util.regex.Pattern; /** * @author Mikhail Golubev */ public class JsonLiteralAnnotator implements Annotator { - private static final Pattern VALID_ESCAPE = Pattern.compile("\\\\([\"\\\\/bfnrt]|u[0-9a-fA-F]{4})"); - private static final Pattern VALID_NUMBER_LITERAL = Pattern.compile("-?(0|[1-9][0-9]*)(\\.[0-9]+)?([eE][+-]?[0-9]+)?"); private static class Holder { private static final boolean DEBUG = ApplicationManager.getApplication().isUnitTestMode(); @@ -45,12 +43,14 @@ public class JsonLiteralAnnotator implements Annotator { @Override public void annotate(@NotNull PsiElement element, @NotNull AnnotationHolder holder) { final String text = JsonPsiUtil.getElementTextWithoutHostEscaping(element); - if (element instanceof JsonStringLiteral) { + JsonLiteralChecker[] extensions = JsonLiteralChecker.EP_NAME.getExtensions(); + if (element instanceof JsonReferenceExpression) { + highlightPropertyKey(element, holder); + } + else if (element instanceof JsonStringLiteral) { final JsonStringLiteral stringLiteral = (JsonStringLiteral)element; final int elementOffset = element.getTextOffset(); - if (JsonPsiUtil.isPropertyKey(element)) { - holder.createInfoAnnotation(element, Holder.DEBUG ? "property key" : null).setTextAttributes(JsonSyntaxHighlighterFactory.JSON_PROPERTY_KEY); - } + highlightPropertyKey(element, holder); final int length = text.length(); // Check that string literal is closed properly @@ -60,24 +60,31 @@ public class JsonLiteralAnnotator implements Annotator { // Check escapes final List> fragments = stringLiteral.getTextFragments(); - for (Pair fragment : fragments) { - final String fragmentText = fragment.getSecond(); - if (fragmentText.startsWith("\\") && fragmentText.length() > 1 && !VALID_ESCAPE.matcher(fragmentText).matches()) { - final TextRange fragmentRange = fragment.getFirst(); - if (fragmentText.startsWith("\\u")) { - holder.createErrorAnnotation(fragmentRange.shiftRight(elementOffset), JsonBundle.message( - "syntax.error.illegal.unicode.escape.sequence")); - } - else { - holder.createErrorAnnotation(fragmentRange.shiftRight(elementOffset), JsonBundle.message("syntax.error.illegal.escape.sequence")); + for (Pair fragment: fragments) { + for (JsonLiteralChecker checker: extensions) { + if (!checker.isApplicable(element)) continue; + String error = checker.getErrorForStringFragment(fragment.getSecond()); + if (error != null) { + final TextRange fragmentRange = fragment.getFirst(); + holder.createErrorAnnotation(fragmentRange.shiftRight(elementOffset), error); } } } } else if (element instanceof JsonNumberLiteral) { - if (!VALID_NUMBER_LITERAL.matcher(text).matches()) { - holder.createErrorAnnotation(element, JsonBundle.message("syntax.error.illegal.floating.point.literal")); + for (JsonLiteralChecker checker: extensions) { + if (!checker.isApplicable(element)) continue; + String error = checker.getErrorForNumericLiteral(text); + if (error != null) { + holder.createErrorAnnotation(element, error); + } } } } + + private static void highlightPropertyKey(@NotNull PsiElement element, @NotNull AnnotationHolder holder) { + if (JsonPsiUtil.isPropertyKey(element)) { + holder.createInfoAnnotation(element, Holder.DEBUG ? "property key" : null).setTextAttributes(JsonSyntaxHighlighterFactory.JSON_PROPERTY_KEY); + } + } } diff --git a/json/src/com/intellij/json/codeinsight/JsonLiteralChecker.java b/json/src/com/intellij/json/codeinsight/JsonLiteralChecker.java new file mode 100644 index 000000000000..73480ad29bf7 --- /dev/null +++ b/json/src/com/intellij/json/codeinsight/JsonLiteralChecker.java @@ -0,0 +1,18 @@ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.json.codeinsight; + +import com.intellij.openapi.extensions.ExtensionPointName; +import com.intellij.psi.PsiElement; +import org.jetbrains.annotations.Nullable; + +public interface JsonLiteralChecker { + ExtensionPointName EP_NAME = ExtensionPointName.create("com.intellij.json.jsonLiteralChecker"); + + @Nullable + String getErrorForNumericLiteral(String literalText); + + @Nullable + String getErrorForStringFragment(String fragmentText); + + boolean isApplicable(PsiElement element); +} diff --git a/json/src/com/intellij/json/codeinsight/JsonStandardComplianceInspection.java b/json/src/com/intellij/json/codeinsight/JsonStandardComplianceInspection.java index c12c8df2272d..c1d01cae8a70 100644 --- a/json/src/com/intellij/json/codeinsight/JsonStandardComplianceInspection.java +++ b/json/src/com/intellij/json/codeinsight/JsonStandardComplianceInspection.java @@ -19,6 +19,7 @@ import com.intellij.codeHighlighting.HighlightDisplayLevel; import com.intellij.codeInspection.*; import com.intellij.codeInspection.ui.MultipleCheckboxOptionsPanel; import com.intellij.json.JsonBundle; +import com.intellij.json.JsonDialectUtil; import com.intellij.json.JsonElementTypes; import com.intellij.json.psi.*; import com.intellij.openapi.diagnostic.Logger; @@ -66,69 +67,8 @@ public class JsonStandardComplianceInspection extends LocalInspectionTool { @NotNull @Override public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, boolean isOnTheFly) { - return new JsonElementVisitor() { - @Override - public void visitComment(PsiComment comment) { - if (myWarnAboutComments) { - if (JsonStandardComplianceProvider.shouldWarnAboutComment(comment)) { - holder.registerProblem(comment, JsonBundle.message("inspection.compliance.msg.comments"), ProblemHighlightType.WEAK_WARNING); - } - } - } - - @Override - public void visitStringLiteral(@NotNull JsonStringLiteral stringLiteral) { - if (JsonPsiUtil.getElementTextWithoutHostEscaping(stringLiteral).startsWith("'")) { - holder.registerProblem(stringLiteral, JsonBundle.message("inspection.compliance.msg.single.quoted.strings"), - new AddDoubleQuotesFix()); - } - // May be illegal property key as well - super.visitStringLiteral(stringLiteral); - } - - @Override - public void visitLiteral(@NotNull JsonLiteral literal) { - if (JsonPsiUtil.isPropertyKey(literal) && !JsonPsiUtil.getElementTextWithoutHostEscaping(literal).startsWith("\"")) { - holder.registerProblem(literal, JsonBundle.message("inspection.compliance.msg.illegal.property.key"), new AddDoubleQuotesFix()); - } - super.visitLiteral(literal); - } - - @Override - public void visitReferenceExpression(@NotNull JsonReferenceExpression reference) { - holder.registerProblem(reference, JsonBundle.message("inspection.compliance.msg.bad.token"), new AddDoubleQuotesFix()); - // May be illegal property key as well - super.visitReferenceExpression(reference); - } - - @Override - public void visitArray(@NotNull JsonArray array) { - final PsiElement trailingComma = findTrailingComma(array, JsonElementTypes.R_BRACKET); - if (trailingComma != null) { - holder.registerProblem(trailingComma, JsonBundle.message("inspection.compliance.msg.trailing.comma")); - } - super.visitArray(array); - } - - @Override - public void visitObject(@NotNull JsonObject object) { - final PsiElement trailingComma = findTrailingComma(object, JsonElementTypes.R_CURLY); - if (trailingComma != null) { - holder.registerProblem(trailingComma, JsonBundle.message("inspection.compliance.msg.trailing.comma")); - } - super.visitObject(object); - } - - @Override - public void visitValue(@NotNull JsonValue value) { - if (value.getContainingFile() instanceof JsonFile) { - final JsonFile jsonFile = (JsonFile)value.getContainingFile(); - if (myWarnAboutMultipleTopLevelValues && value.getParent() == jsonFile && value != jsonFile.getTopLevelValue()) { - holder.registerProblem(value, JsonBundle.message("inspection.compliance.msg.multiple.top.level.values")); - } - } - } - }; + if (!JsonDialectUtil.isStandardJson(holder.getFile())) return PsiElementVisitor.EMPTY_VISITOR; + return new StandardJsonValidatingElementVisitor(holder); } @Nullable @@ -200,4 +140,87 @@ public class JsonStandardComplianceInspection extends LocalInspectionTool { return result.toString(); } } + + protected class StandardJsonValidatingElementVisitor extends JsonElementVisitor { + private final ProblemsHolder myHolder; + + public StandardJsonValidatingElementVisitor(ProblemsHolder holder) {myHolder = holder;} + + protected boolean allowComments() { return false; } + protected boolean allowSingleQuotes() { return false; } + protected boolean allowIdentifierPropertyNames() { return false; } + protected boolean allowTrailingCommas() { return false; } + + protected boolean isValidPropertyName(@NotNull PsiElement literal) { + return literal instanceof JsonLiteral && JsonPsiUtil.getElementTextWithoutHostEscaping(literal).startsWith("\""); + } + + @Override + public void visitComment(PsiComment comment) { + if (!allowComments() && myWarnAboutComments) { + if (JsonStandardComplianceProvider.shouldWarnAboutComment(comment)) { + myHolder.registerProblem(comment, JsonBundle.message("inspection.compliance.msg.comments"), ProblemHighlightType.WEAK_WARNING); + } + } + } + + @Override + public void visitStringLiteral(@NotNull JsonStringLiteral stringLiteral) { + if (!allowSingleQuotes() && JsonPsiUtil.getElementTextWithoutHostEscaping(stringLiteral).startsWith("'")) { + myHolder.registerProblem(stringLiteral, JsonBundle.message("inspection.compliance.msg.single.quoted.strings"), + new AddDoubleQuotesFix()); + } + // May be illegal property key as well + super.visitStringLiteral(stringLiteral); + } + + @Override + public void visitLiteral(@NotNull JsonLiteral literal) { + if (JsonPsiUtil.isPropertyKey(literal) && !isValidPropertyName(literal)) { + myHolder.registerProblem(literal, JsonBundle.message("inspection.compliance.msg.illegal.property.key"), new AddDoubleQuotesFix()); + } + super.visitLiteral(literal); + } + + @Override + public void visitReferenceExpression(@NotNull JsonReferenceExpression reference) { + if (!allowIdentifierPropertyNames() || !JsonPsiUtil.isPropertyKey(reference) || !isValidPropertyName(reference)) { + myHolder.registerProblem(reference, JsonBundle.message("inspection.compliance.msg.bad.token"), new AddDoubleQuotesFix()); + } + // May be illegal property key as well + super.visitReferenceExpression(reference); + } + + @Override + public void visitArray(@NotNull JsonArray array) { + if (!allowTrailingCommas()) { + final PsiElement trailingComma = findTrailingComma(array, JsonElementTypes.R_BRACKET); + if (trailingComma != null) { + myHolder.registerProblem(trailingComma, JsonBundle.message("inspection.compliance.msg.trailing.comma")); + } + } + super.visitArray(array); + } + + @Override + public void visitObject(@NotNull JsonObject object) { + if (!allowTrailingCommas()) { + final PsiElement trailingComma = findTrailingComma(object, JsonElementTypes.R_CURLY); + if (trailingComma != null) { + myHolder.registerProblem(trailingComma, JsonBundle.message("inspection.compliance.msg.trailing.comma")); + } + } + super.visitObject(object); + } + + @Override + public void visitValue(@NotNull JsonValue value) { + if (value.getContainingFile() instanceof JsonFile) { + final JsonFile jsonFile = (JsonFile)value.getContainingFile(); + if (myWarnAboutMultipleTopLevelValues && value.getParent() == jsonFile && value != jsonFile.getTopLevelValue()) { + myHolder.registerProblem(value, JsonBundle.message("inspection.compliance.msg.multiple.top.level.values")); + } + } + } + } } diff --git a/json/src/com/intellij/json/codeinsight/StandardJsonLiteralChecker.java b/json/src/com/intellij/json/codeinsight/StandardJsonLiteralChecker.java new file mode 100644 index 000000000000..21cf6adbbf3f --- /dev/null +++ b/json/src/com/intellij/json/codeinsight/StandardJsonLiteralChecker.java @@ -0,0 +1,47 @@ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.json.codeinsight; + +import com.intellij.json.JsonBundle; +import com.intellij.json.JsonDialectUtil; +import com.intellij.psi.PsiElement; +import org.jetbrains.annotations.Nullable; + +import java.util.regex.Pattern; + +public class StandardJsonLiteralChecker implements JsonLiteralChecker { + private static final Pattern VALID_ESCAPE = Pattern.compile("\\\\([\"\\\\/bfnrt]|u[0-9a-fA-F]{4})"); + private static final Pattern VALID_NUMBER_LITERAL = Pattern.compile("-?(0|[1-9][0-9]*)(\\.[0-9]+)?([eE][+-]?[0-9]+)?"); + + @Nullable + @Override + public String getErrorForNumericLiteral(String literalText) { + if (!VALID_NUMBER_LITERAL.matcher(literalText).matches()) { + return JsonBundle.message("syntax.error.illegal.floating.point.literal"); + } + return null; + } + + @Nullable + @Override + public String getErrorForStringFragment(String fragmentText) { + return getStringError(fragmentText); + } + + @Nullable + public static String getStringError(String fragmentText) { + if (fragmentText.startsWith("\\") && fragmentText.length() > 1 && !VALID_ESCAPE.matcher(fragmentText).matches()) { + if (fragmentText.startsWith("\\u")) { + return JsonBundle.message("syntax.error.illegal.unicode.escape.sequence"); + } + else { + return JsonBundle.message("syntax.error.illegal.escape.sequence"); + } + } + return null; + } + + @Override + public boolean isApplicable(PsiElement element) { + return JsonDialectUtil.isStandardJson(element); + } +} diff --git a/json/src/com/intellij/json/highlighting/JsonSyntaxHighlighterFactory.java b/json/src/com/intellij/json/highlighting/JsonSyntaxHighlighterFactory.java index 8871f7681299..7095a85b77ca 100644 --- a/json/src/com/intellij/json/highlighting/JsonSyntaxHighlighterFactory.java +++ b/json/src/com/intellij/json/highlighting/JsonSyntaxHighlighterFactory.java @@ -54,10 +54,9 @@ public class JsonSyntaxHighlighterFactory extends SyntaxHighlighterFactory { return new MyHighlighter(); } - private static class MyHighlighter extends SyntaxHighlighterBase { - private static final Map ourAttributes = new HashMap<>(); - - static { + private class MyHighlighter extends SyntaxHighlighterBase { + private final Map ourAttributes = new HashMap<>(); + { fillMap(ourAttributes, JSON_BRACES, JsonElementTypes.L_CURLY, JsonElementTypes.R_CURLY); fillMap(ourAttributes, JSON_BRACKETS, JsonElementTypes.L_BRACKET, JsonElementTypes.R_BRACKET); fillMap(ourAttributes, JSON_COMMA, JsonElementTypes.COMMA); @@ -80,10 +79,10 @@ public class JsonSyntaxHighlighterFactory extends SyntaxHighlighterFactory { @NotNull @Override public Lexer getHighlightingLexer() { - LayeredLexer layeredLexer = new LayeredLexer(new JsonLexer()); - layeredLexer.registerSelfStoppingLayer(new StringLiteralLexer('\"', JsonElementTypes.DOUBLE_QUOTED_STRING, false, "/", false, false), + LayeredLexer layeredLexer = new LayeredLexer(getLexer()); + layeredLexer.registerSelfStoppingLayer(new StringLiteralLexer('\"', JsonElementTypes.DOUBLE_QUOTED_STRING, isCanEscapeEol(), "/", false, false), new IElementType[]{JsonElementTypes.DOUBLE_QUOTED_STRING}, IElementType.EMPTY_ARRAY); - layeredLexer.registerSelfStoppingLayer(new StringLiteralLexer('\'', JsonElementTypes.SINGLE_QUOTED_STRING, false, "/", false, false), + layeredLexer.registerSelfStoppingLayer(new StringLiteralLexer('\'', JsonElementTypes.SINGLE_QUOTED_STRING, isCanEscapeEol(), "/", false, false), new IElementType[]{JsonElementTypes.SINGLE_QUOTED_STRING}, IElementType.EMPTY_ARRAY); return layeredLexer; } @@ -94,4 +93,13 @@ public class JsonSyntaxHighlighterFactory extends SyntaxHighlighterFactory { return pack(ourAttributes.get(type)); } } + + @NotNull + protected Lexer getLexer() { + return new JsonLexer(); + } + + protected boolean isCanEscapeEol() { + return false; + } } diff --git a/json/src/com/intellij/json/json5/Json5FileType.java b/json/src/com/intellij/json/json5/Json5FileType.java new file mode 100644 index 000000000000..a2b0d68bbe17 --- /dev/null +++ b/json/src/com/intellij/json/json5/Json5FileType.java @@ -0,0 +1,32 @@ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.json.json5; + +import com.intellij.json.JsonFileType; +import org.jetbrains.annotations.NotNull; + +public class Json5FileType extends JsonFileType { + public static final Json5FileType INSTANCE = new Json5FileType(); + public static final String DEFAULT_EXTENSION = "json5"; + + public Json5FileType() { + super(Json5Language.INSTANCE); + } + + @NotNull + @Override + public String getName() { + return "JSON5"; + } + + @NotNull + @Override + public String getDescription() { + return "JSON5 files"; + } + + @NotNull + @Override + public String getDefaultExtension() { + return DEFAULT_EXTENSION; + } +} diff --git a/json/src/com/intellij/json/json5/Json5FileTypeFactory.java b/json/src/com/intellij/json/json5/Json5FileTypeFactory.java new file mode 100644 index 000000000000..bf6a0254e0a9 --- /dev/null +++ b/json/src/com/intellij/json/json5/Json5FileTypeFactory.java @@ -0,0 +1,13 @@ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.json.json5; + +import com.intellij.openapi.fileTypes.FileTypeConsumer; +import com.intellij.openapi.fileTypes.FileTypeFactory; +import org.jetbrains.annotations.NotNull; + +public class Json5FileTypeFactory extends FileTypeFactory { + @Override + public void createFileTypes(@NotNull FileTypeConsumer consumer) { + consumer.consume(Json5FileType.INSTANCE, Json5FileType.DEFAULT_EXTENSION); + } +} diff --git a/json/src/com/intellij/json/json5/Json5Language.java b/json/src/com/intellij/json/json5/Json5Language.java new file mode 100644 index 000000000000..3bd1476f9c9c --- /dev/null +++ b/json/src/com/intellij/json/json5/Json5Language.java @@ -0,0 +1,12 @@ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.json.json5; + +import com.intellij.json.JsonLanguage; + +public class Json5Language extends JsonLanguage { + public static final Json5Language INSTANCE = new Json5Language(); + + protected Json5Language() { + super("JSON5", "application/json5"); + } +} diff --git a/json/src/com/intellij/json/json5/Json5Lexer.java b/json/src/com/intellij/json/json5/Json5Lexer.java new file mode 100644 index 000000000000..0617e3790a03 --- /dev/null +++ b/json/src/com/intellij/json/json5/Json5Lexer.java @@ -0,0 +1,10 @@ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.json.json5; + +import com.intellij.lexer.FlexAdapter; + +public class Json5Lexer extends FlexAdapter { + public Json5Lexer() { + super(new _Json5Lexer()); + } +} diff --git a/json/src/com/intellij/json/json5/Json5ParserDefinition.java b/json/src/com/intellij/json/json5/Json5ParserDefinition.java new file mode 100644 index 000000000000..d0b146bc0669 --- /dev/null +++ b/json/src/com/intellij/json/json5/Json5ParserDefinition.java @@ -0,0 +1,31 @@ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.json.json5; + +import com.intellij.json.JsonParserDefinition; +import com.intellij.json.psi.impl.JsonFileImpl; +import com.intellij.lexer.Lexer; +import com.intellij.openapi.project.Project; +import com.intellij.psi.FileViewProvider; +import com.intellij.psi.PsiFile; +import com.intellij.psi.tree.IFileElementType; +import org.jetbrains.annotations.NotNull; + +public class Json5ParserDefinition extends JsonParserDefinition { + public static final IFileElementType FILE = new IFileElementType(Json5Language.INSTANCE); + + @NotNull + @Override + public Lexer createLexer(Project project) { + return new Json5Lexer(); + } + + @Override + public PsiFile createFile(FileViewProvider fileViewProvider) { + return new JsonFileImpl(fileViewProvider, Json5Language.INSTANCE); + } + + @Override + public IFileElementType getFileNodeType() { + return FILE; + } +} diff --git a/json/src/com/intellij/json/json5/Json5PsiWalkerFactory.java b/json/src/com/intellij/json/json5/Json5PsiWalkerFactory.java new file mode 100644 index 000000000000..6ba518b40771 --- /dev/null +++ b/json/src/com/intellij/json/json5/Json5PsiWalkerFactory.java @@ -0,0 +1,36 @@ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.json.json5; + +import com.intellij.codeInsight.completion.CompletionUtil; +import com.intellij.json.JsonDialectUtil; +import com.intellij.psi.PsiElement; +import com.jetbrains.jsonSchema.extension.JsonLikePsiWalker; +import com.jetbrains.jsonSchema.extension.JsonLikePsiWalkerFactory; +import com.jetbrains.jsonSchema.impl.JsonOriginalPsiWalker; +import com.jetbrains.jsonSchema.impl.JsonSchemaObject; +import org.jetbrains.annotations.NotNull; + +public class Json5PsiWalkerFactory implements JsonLikePsiWalkerFactory { + @Override + public boolean handles(@NotNull PsiElement element) { + PsiElement parent = element.getParent(); + if (parent == null) return false; + return JsonDialectUtil.getLanguage(CompletionUtil.getOriginalOrSelf(parent)) == Json5Language.INSTANCE; + } + + @NotNull + @Override + public JsonLikePsiWalker create(@NotNull JsonSchemaObject schemaObject) { + return new JsonOriginalPsiWalker() { + @Override + public boolean isNameQuoted() { + return false; + } + + @Override + public boolean onlyDoubleQuotesForStringLiterals() { + return false; + } + }; + } +} diff --git a/json/src/com/intellij/json/json5/_Json5Lexer.flex b/json/src/com/intellij/json/json5/_Json5Lexer.flex new file mode 100644 index 000000000000..24df142cea20 --- /dev/null +++ b/json/src/com/intellij/json/json5/_Json5Lexer.flex @@ -0,0 +1,64 @@ +package com.intellij.json.json5; + +import com.intellij.lexer.FlexLexer; +import com.intellij.psi.tree.IElementType; + +import static com.intellij.psi.TokenType.BAD_CHARACTER; +import static com.intellij.psi.TokenType.WHITE_SPACE; +import static com.intellij.json.JsonElementTypes.*; + +%% + +%{ + public _Json5Lexer() { + this((java.io.Reader)null); + } +%} + +%public +%class _Json5Lexer +%implements FlexLexer +%function advance +%type IElementType +%unicode + +EOL=\R +WHITE_SPACE=\s+ +HEX_DIGIT=[0-9A-Fa-f] + +LINE_COMMENT="//".* +BLOCK_COMMENT="/"\*([^*]|\*+[^*/])*(\*+"/")? +LINE_TERMINATOR_SEQUENCE=\R +CRLF= [\ \t \f]* {LINE_TERMINATOR_SEQUENCE} +DOUBLE_QUOTED_STRING=\"([^\\\"\r\n]|\\[^\r\n]|\\{CRLF})*\"? +SINGLE_QUOTED_STRING='([^\\'\r\n]|\\[^\r\n]|\\{CRLF})*'? +JSON5_NUMBER=(\+|-)?(0|[1-9][0-9]*)?\.?([0-9]+)?([eE][+-]?[0-9]*)? +HEX_DIGITS=({HEX_DIGIT})+ +HEX_INTEGER_LITERAL=0[Xx]({HEX_DIGITS}) +NUMBER={JSON5_NUMBER}|{HEX_INTEGER_LITERAL}|Infinity|-Infinity|\+Infinity|NaN|-NaN|\+NaN +IDENTIFIER=[[:jletterdigit:]~!()*\-."/"@\^<>=]+ + +%% + { + {WHITE_SPACE} { return WHITE_SPACE; } + + "{" { return L_CURLY; } + "}" { return R_CURLY; } + "[" { return L_BRACKET; } + "]" { return R_BRACKET; } + "," { return COMMA; } + ":" { return COLON; } + "true" { return TRUE; } + "false" { return FALSE; } + "null" { return NULL; } + + {LINE_COMMENT} { return LINE_COMMENT; } + {BLOCK_COMMENT} { return BLOCK_COMMENT; } + {DOUBLE_QUOTED_STRING} { return DOUBLE_QUOTED_STRING; } + {SINGLE_QUOTED_STRING} { return SINGLE_QUOTED_STRING; } + {NUMBER} { return NUMBER; } + {IDENTIFIER} { return IDENTIFIER; } + +} + +[^] { return BAD_CHARACTER; } diff --git a/json/src/com/intellij/json/json5/codeinsight/Json5JsonLiteralChecker.java b/json/src/com/intellij/json/json5/codeinsight/Json5JsonLiteralChecker.java new file mode 100644 index 000000000000..629fb0104230 --- /dev/null +++ b/json/src/com/intellij/json/json5/codeinsight/Json5JsonLiteralChecker.java @@ -0,0 +1,34 @@ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.json.json5.codeinsight; + +import com.intellij.json.JsonDialectUtil; +import com.intellij.json.codeinsight.JsonLiteralChecker; +import com.intellij.json.codeinsight.StandardJsonLiteralChecker; +import com.intellij.json.json5.Json5Language; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.psi.PsiElement; +import org.jetbrains.annotations.Nullable; + +public class Json5JsonLiteralChecker implements JsonLiteralChecker { + @Nullable + @Override + public String getErrorForNumericLiteral(String literalText) { + return null; + } + + @Nullable + @Override + public String getErrorForStringFragment(String fragmentText) { + if (fragmentText.startsWith("\\") && fragmentText.length() > 1 && fragmentText.endsWith("\n")) { + if (StringUtil.isEmptyOrSpaces(fragmentText.substring(1, fragmentText.length() - 1))) { + return null; + } + } + return StandardJsonLiteralChecker.getStringError(fragmentText); + } + + @Override + public boolean isApplicable(PsiElement element) { + return JsonDialectUtil.getLanguage(element) == Json5Language.INSTANCE; + } +} diff --git a/json/src/com/intellij/json/json5/codeinsight/Json5StandardComplianceInspection.java b/json/src/com/intellij/json/json5/codeinsight/Json5StandardComplianceInspection.java new file mode 100644 index 000000000000..cd5b2412ea6e --- /dev/null +++ b/json/src/com/intellij/json/json5/codeinsight/Json5StandardComplianceInspection.java @@ -0,0 +1,66 @@ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.json.json5.codeinsight; + +import com.intellij.codeInspection.ProblemsHolder; +import com.intellij.json.JsonBundle; +import com.intellij.json.JsonDialectUtil; +import com.intellij.json.codeinsight.JsonStandardComplianceInspection; +import com.intellij.json.psi.JsonLiteral; +import com.intellij.json.psi.JsonPsiUtil; +import com.intellij.json.psi.JsonReferenceExpression; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiElementVisitor; +import org.jetbrains.annotations.NotNull; + +public class Json5StandardComplianceInspection extends JsonStandardComplianceInspection { + + @NotNull + public String getDisplayName() { + return JsonBundle.message("inspection.compliance5.name"); + } + + @NotNull + @Override + public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, boolean isOnTheFly) { + if (JsonDialectUtil.isStandardJson(holder.getFile())) return PsiElementVisitor.EMPTY_VISITOR; + return new StandardJson5ValidatingElementVisitor(holder); + } + + private class StandardJson5ValidatingElementVisitor extends StandardJsonValidatingElementVisitor { + public StandardJson5ValidatingElementVisitor(ProblemsHolder holder) { + super(holder); + } + + @Override + protected boolean allowComments() { + return true; + } + + @Override + protected boolean allowSingleQuotes() { + return true; + } + + @Override + protected boolean allowIdentifierPropertyNames() { + return true; + } + + @Override + protected boolean allowTrailingCommas() { + return true; + } + + protected boolean isValidPropertyName(@NotNull PsiElement literal) { + if (literal instanceof JsonLiteral) { + String textWithoutHostEscaping = JsonPsiUtil.getElementTextWithoutHostEscaping(literal); + return textWithoutHostEscaping.startsWith("\"") || textWithoutHostEscaping.startsWith("'"); + } + if (literal instanceof JsonReferenceExpression) { + return StringUtil.isJavaIdentifier(literal.getText()); + } + return false; + } + } +} diff --git a/json/src/com/intellij/json/json5/highlighting/Json5SyntaxHighlightingFactory.java b/json/src/com/intellij/json/json5/highlighting/Json5SyntaxHighlightingFactory.java new file mode 100644 index 000000000000..f20466f59ce9 --- /dev/null +++ b/json/src/com/intellij/json/json5/highlighting/Json5SyntaxHighlightingFactory.java @@ -0,0 +1,20 @@ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.json.json5.highlighting; + +import com.intellij.json.highlighting.JsonSyntaxHighlighterFactory; +import com.intellij.json.json5.Json5Lexer; +import com.intellij.lexer.Lexer; +import org.jetbrains.annotations.NotNull; + +public class Json5SyntaxHighlightingFactory extends JsonSyntaxHighlighterFactory { + @NotNull + @Override + protected Lexer getLexer() { + return new Json5Lexer(); + } + + @Override + protected boolean isCanEscapeEol() { + return true; + } +} diff --git a/json/src/com/intellij/json/psi/impl/JsonFileImpl.java b/json/src/com/intellij/json/psi/impl/JsonFileImpl.java index 9105ab4d24d1..8ddcdd2c11bf 100644 --- a/json/src/com/intellij/json/psi/impl/JsonFileImpl.java +++ b/json/src/com/intellij/json/psi/impl/JsonFileImpl.java @@ -1,9 +1,9 @@ package com.intellij.json.psi.impl; import com.intellij.extapi.psi.PsiFileBase; -import com.intellij.json.JsonLanguage; import com.intellij.json.psi.JsonFile; import com.intellij.json.psi.JsonValue; +import com.intellij.lang.Language; import com.intellij.openapi.fileTypes.FileType; import com.intellij.psi.FileViewProvider; import com.intellij.psi.util.PsiTreeUtil; @@ -14,8 +14,8 @@ import java.util.List; public class JsonFileImpl extends PsiFileBase implements JsonFile { - public JsonFileImpl(FileViewProvider fileViewProvider) { - super(fileViewProvider, JsonLanguage.INSTANCE); + public JsonFileImpl(FileViewProvider fileViewProvider, Language language) { + super(fileViewProvider, language); } @NotNull diff --git a/json/src/com/jetbrains/jsonSchema/impl/JsonOriginalPsiWalker.java b/json/src/com/jetbrains/jsonSchema/impl/JsonOriginalPsiWalker.java index 4dedbdeeabd0..0ff19e7f6816 100644 --- a/json/src/com/jetbrains/jsonSchema/impl/JsonOriginalPsiWalker.java +++ b/json/src/com/jetbrains/jsonSchema/impl/JsonOriginalPsiWalker.java @@ -1,6 +1,8 @@ // Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.jetbrains.jsonSchema.impl; +import com.intellij.codeInsight.completion.CompletionUtil; +import com.intellij.json.JsonDialectUtil; import com.intellij.json.JsonElementTypes; import com.intellij.json.psi.*; import com.intellij.openapi.util.text.StringUtil; @@ -28,7 +30,9 @@ public class JsonOriginalPsiWalker implements JsonLikePsiWalker { public static final JsonOriginalPsiWalker INSTANCE = new JsonOriginalPsiWalker(); public boolean handles(@NotNull PsiElement element) { - return element instanceof JsonElement || element instanceof LeafPsiElement && element.getParent() instanceof JsonElement; + PsiElement parent = element.getParent(); + return parent != null && (element instanceof JsonElement || element instanceof LeafPsiElement && parent instanceof JsonElement) + && JsonDialectUtil.isStandardJson(CompletionUtil.getOriginalOrSelf(parent)); } @Override @@ -138,7 +142,7 @@ public class JsonOriginalPsiWalker implements JsonLikePsiWalker { final JsonObject object = PsiTreeUtil.getParentOfType(element, JsonObject.class); if (object != null) { return object.getPropertyList().stream() - .filter(p -> p.getNameElement() instanceof JsonStringLiteral) + .filter(p -> !isNameQuoted() || p.getNameElement() instanceof JsonStringLiteral) .map(p -> StringUtil.unquoteString(p.getName())).collect(Collectors.toSet()); } return Collections.emptySet(); diff --git a/json/tests/test/com/intellij/json/JsonHighlightingTest.java b/json/tests/test/com/intellij/json/JsonHighlightingTest.java index 7c5746a63f56..eed398682b71 100644 --- a/json/tests/test/com/intellij/json/JsonHighlightingTest.java +++ b/json/tests/test/com/intellij/json/JsonHighlightingTest.java @@ -6,14 +6,11 @@ import com.intellij.json.codeinsight.JsonStandardComplianceInspection; /** * @author Mikhail Golubev */ -public class JsonHighlightingTest extends JsonTestCase { +public class JsonHighlightingTest extends JsonHighlightingTestBase { - private void doTest() { - doTestHighlighting(true, true, true); - } - - private long doTestHighlighting(boolean checkInfo, boolean checkWeakWarning, boolean checkWarning) { - return myFixture.testHighlighting(checkWarning, checkInfo, checkWeakWarning, "/highlighting/" + getTestName(false) + ".json"); + @Override + protected String getExtension() { + return "json"; } private void enableStandardComplianceInspection(boolean checkComments, boolean checkTopLevelValues) { diff --git a/json/tests/test/com/intellij/json/JsonHighlightingTestBase.java b/json/tests/test/com/intellij/json/JsonHighlightingTestBase.java new file mode 100644 index 000000000000..623f314fa34d --- /dev/null +++ b/json/tests/test/com/intellij/json/JsonHighlightingTestBase.java @@ -0,0 +1,14 @@ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.json; + +public abstract class JsonHighlightingTestBase extends JsonTestCase { + protected void doTest() { + doTestHighlighting(true, true, true); + } + + protected abstract String getExtension(); + + protected void doTestHighlighting(boolean checkInfo, boolean checkWeakWarning, boolean checkWarning) { + myFixture.testHighlighting(checkWarning, checkInfo, checkWeakWarning, "/highlighting/" + getTestName(false) + "." + getExtension()); + } +} diff --git a/json/tests/test/com/intellij/json/json5/Json5HighlightingTest.java b/json/tests/test/com/intellij/json/json5/Json5HighlightingTest.java new file mode 100644 index 000000000000..d4b7ffcb1b57 --- /dev/null +++ b/json/tests/test/com/intellij/json/json5/Json5HighlightingTest.java @@ -0,0 +1,18 @@ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.json.json5; + +import com.intellij.json.JsonHighlightingTestBase; +import com.intellij.json.json5.codeinsight.Json5StandardComplianceInspection; + +public class Json5HighlightingTest extends JsonHighlightingTestBase { + + @Override + protected String getExtension() { + return "json5"; + } + + public void testJSON5() { + myFixture.enableInspections(new Json5StandardComplianceInspection()); + doTestHighlighting(false, true, true); + } +} diff --git a/json/tests/test/com/intellij/json/json5/Json5ParsingTest.java b/json/tests/test/com/intellij/json/json5/Json5ParsingTest.java new file mode 100644 index 000000000000..a3fe4b9550c7 --- /dev/null +++ b/json/tests/test/com/intellij/json/json5/Json5ParsingTest.java @@ -0,0 +1,27 @@ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.json.json5; + +import com.intellij.json.JsonParserDefinition; +import com.intellij.testFramework.ParsingTestCase; +import com.intellij.testFramework.PlatformTestUtil; +import com.intellij.testFramework.TestDataPath; + +@TestDataPath("$CONTENT_ROOT/testData/psi/") +public class Json5ParsingTest extends ParsingTestCase { + public Json5ParsingTest() { + super("psi", "json5", new Json5ParserDefinition(), new JsonParserDefinition()); + } + + @Override + protected String getTestDataPath() { + return PlatformTestUtil.getCommunityPath() + "/json/tests/testData"; + } + + private void doTest() { + doTest(true); + } + + public void testJson5Syntax() { + doTest(); + } +} diff --git a/json/tests/test/com/jetbrains/jsonSchema/json5/Json5ByJsonSchemaCompletionTest.java b/json/tests/test/com/jetbrains/jsonSchema/json5/Json5ByJsonSchemaCompletionTest.java new file mode 100644 index 000000000000..8abd1fd568cb --- /dev/null +++ b/json/tests/test/com/jetbrains/jsonSchema/json5/Json5ByJsonSchemaCompletionTest.java @@ -0,0 +1,14 @@ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.jetbrains.jsonSchema.json5; + +import com.jetbrains.jsonSchema.impl.JsonBySchemaCompletionBaseTest; + +public class Json5ByJsonSchemaCompletionTest extends JsonBySchemaCompletionBaseTest { + public void testTopLevel() throws Exception { + testBySchema("{\"properties\": {\"prima\": {}, \"proto\": {}, \"primus\": {}}}", "{pri}", "json5", "prima", "primus", "proto"); + } + + public void testAlreadyInsertedProperty() throws Exception { + testBySchema("{\"properties\": {\"prima\": {}, \"proto\": {}, \"primus\": {}}}", "{prima: 1, pri}", "json5", "primus", "proto"); + } +} diff --git a/json/tests/testData/highlighting/JSON5.json5 b/json/tests/testData/highlighting/JSON5.json5 new file mode 100644 index 000000000000..42f324beb4d1 --- /dev/null +++ b/json/tests/testData/highlighting/JSON5.json5 @@ -0,0 +1,28 @@ +// no errors in this file! +{ + foo: 'bar', + while: true, + + this: 'is a \ +multi-line string', + + // this is an inline comment + here: 'is another', // inline comment + + /* this is a block comment + that continues on another line */ + + hex: 0xDEADbeef, + half: .5, + delta: +10, + to: Infinity, // and beyond! + + finally: 'a trailing comma', + oh: [ + "we shouldn't forget", + 'arrays can have', + 'trailing commas too', + ], + +} + diff --git a/json/tests/testData/psi/Json5Syntax.json5 b/json/tests/testData/psi/Json5Syntax.json5 new file mode 100644 index 000000000000..ff1c4a591947 --- /dev/null +++ b/json/tests/testData/psi/Json5Syntax.json5 @@ -0,0 +1,26 @@ +{ + foo: 'bar', + while: true, + + this: 'is a \ +multi-line string', + + // this is an inline comment + here: 'is another', // inline comment + + /* this is a block comment + that continues on another line */ + + hex: 0xDEADbeef, + half: .5, + delta: +10, + to: Infinity, // and beyond! + + finally: 'a trailing comma', + oh: [ + "we shouldn't forget", + 'arrays can have', + 'trailing commas too', + ], +} + diff --git a/json/tests/testData/psi/Json5Syntax.txt b/json/tests/testData/psi/Json5Syntax.txt new file mode 100644 index 000000000000..e9c956eb8903 --- /dev/null +++ b/json/tests/testData/psi/Json5Syntax.txt @@ -0,0 +1,117 @@ +JsonFile: Json5Syntax.json5 + JsonObject + PsiElement({)('{') + PsiWhiteSpace('\n ') + JsonProperty + JsonReferenceExpression + PsiElement(IDENTIFIER)('foo') + PsiElement(:)(':') + PsiWhiteSpace(' ') + JsonStringLiteral + PsiElement(SINGLE_QUOTED_STRING)(''bar'') + PsiElement(,)(',') + PsiWhiteSpace('\n ') + JsonProperty + JsonReferenceExpression + PsiElement(IDENTIFIER)('while') + PsiElement(:)(':') + PsiWhiteSpace(' ') + JsonBooleanLiteral + PsiElement(true)('true') + PsiElement(,)(',') + PsiWhiteSpace('\n\n ') + JsonProperty + JsonReferenceExpression + PsiElement(IDENTIFIER)('this') + PsiElement(:)(':') + PsiWhiteSpace(' ') + JsonStringLiteral + PsiElement(SINGLE_QUOTED_STRING)(''is a \\nmulti-line string'') + PsiElement(,)(',') + PsiWhiteSpace('\n\n ') + PsiComment(LINE_COMMENT)('// this is an inline comment') + PsiWhiteSpace('\n ') + JsonProperty + JsonReferenceExpression + PsiElement(IDENTIFIER)('here') + PsiElement(:)(':') + PsiWhiteSpace(' ') + JsonStringLiteral + PsiElement(SINGLE_QUOTED_STRING)(''is another'') + PsiElement(,)(',') + PsiWhiteSpace(' ') + PsiComment(LINE_COMMENT)('// inline comment') + PsiWhiteSpace('\n\n ') + PsiComment(BLOCK_COMMENT)('/* this is a block comment\n that continues on another line */') + PsiWhiteSpace('\n\n ') + JsonProperty + JsonReferenceExpression + PsiElement(IDENTIFIER)('hex') + PsiElement(:)(':') + PsiWhiteSpace(' ') + JsonNumberLiteral + PsiElement(NUMBER)('0xDEADbeef') + PsiElement(,)(',') + PsiWhiteSpace('\n ') + JsonProperty + JsonReferenceExpression + PsiElement(IDENTIFIER)('half') + PsiElement(:)(':') + PsiWhiteSpace(' ') + JsonNumberLiteral + PsiElement(NUMBER)('.5') + PsiElement(,)(',') + PsiWhiteSpace('\n ') + JsonProperty + JsonReferenceExpression + PsiElement(IDENTIFIER)('delta') + PsiElement(:)(':') + PsiWhiteSpace(' ') + JsonNumberLiteral + PsiElement(NUMBER)('+10') + PsiElement(,)(',') + PsiWhiteSpace('\n ') + JsonProperty + JsonReferenceExpression + PsiElement(IDENTIFIER)('to') + PsiElement(:)(':') + PsiWhiteSpace(' ') + JsonNumberLiteral + PsiElement(NUMBER)('Infinity') + PsiElement(,)(',') + PsiWhiteSpace(' ') + PsiComment(LINE_COMMENT)('// and beyond!') + PsiWhiteSpace('\n\n ') + JsonProperty + JsonReferenceExpression + PsiElement(IDENTIFIER)('finally') + PsiElement(:)(':') + PsiWhiteSpace(' ') + JsonStringLiteral + PsiElement(SINGLE_QUOTED_STRING)(''a trailing comma'') + PsiElement(,)(',') + PsiWhiteSpace('\n ') + JsonProperty + JsonReferenceExpression + PsiElement(IDENTIFIER)('oh') + PsiElement(:)(':') + PsiWhiteSpace(' ') + JsonArray + PsiElement([)('[') + PsiWhiteSpace('\n ') + JsonStringLiteral + PsiElement(DOUBLE_QUOTED_STRING)('"we shouldn't forget"') + PsiElement(,)(',') + PsiWhiteSpace('\n ') + JsonStringLiteral + PsiElement(SINGLE_QUOTED_STRING)(''arrays can have'') + PsiElement(,)(',') + PsiWhiteSpace('\n ') + JsonStringLiteral + PsiElement(SINGLE_QUOTED_STRING)(''trailing commas too'') + PsiElement(,)(',') + PsiWhiteSpace('\n ') + PsiElement(])(']') + PsiElement(,)(',') + PsiWhiteSpace('\n') + PsiElement(})('}') \ No newline at end of file diff --git a/platform/platform-resources/src/META-INF/JsonPlugin.xml b/platform/platform-resources/src/META-INF/JsonPlugin.xml index f2bf76dcacc0..65a70e5cba6b 100644 --- a/platform/platform-resources/src/META-INF/JsonPlugin.xml +++ b/platform/platform-resources/src/META-INF/JsonPlugin.xml @@ -16,9 +16,12 @@ + + + @@ -48,6 +51,9 @@ + + + @@ -56,6 +62,10 @@ bundle="com.intellij.json.JsonBundle" key="inspection.compliance.name" groupKey="json.inspection.group" enabledByDefault="true" level="ERROR" implementationClass="com.intellij.json.codeinsight.JsonStandardComplianceInspection"/> + + + + + + \ No newline at end of file