Change JSON grammar to allow usage of any literals and identifiers as property keys

This commit is contained in:
Mikhail Golubev
2014-09-11 16:23:26 +04:00
parent 64d7fcdef2
commit f7dac28085
10 changed files with 97 additions and 11 deletions

View File

@@ -297,14 +297,13 @@ public class JsonParser implements PsiParser {
}
/* ********************************************************** */
// string_literal (':' value)
// property_name (':' value)
public static boolean property(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "property")) return false;
if (!nextTokenIs(builder_, "<property>", DOUBLE_QUOTED_STRING, SINGLE_QUOTED_STRING)) return false;
boolean result_;
boolean pinned_;
Marker marker_ = enter_section_(builder_, level_, _NONE_, "<property>");
result_ = string_literal(builder_, level_ + 1);
result_ = property_name(builder_, level_ + 1);
pinned_ = result_; // pin = 1
result_ = result_ && property_1(builder_, level_ + 1);
exit_section_(builder_, level_, marker_, PROPERTY, result_, pinned_, null);
@@ -324,6 +323,18 @@ public class JsonParser implements PsiParser {
return result_ || pinned_;
}
/* ********************************************************** */
// literal | reference_expression
static boolean property_name(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "property_name")) return false;
boolean result_;
Marker marker_ = enter_section_(builder_);
result_ = literal(builder_, level_ + 1);
if (!result_) result_ = reference_expression(builder_, level_ + 1);
exit_section_(builder_, marker_, null, result_);
return result_;
}
/* ********************************************************** */
// INDENTIFIER
public static boolean reference_expression(PsiBuilder builder_, int level_) {

View File

@@ -12,7 +12,7 @@ public interface JsonProperty extends JsonElement, PsiNamedElement {
String getName();
@NotNull
JsonStringLiteral getNameElement();
JsonValue getNameElement();
@Nullable
JsonValue getValue();

View File

@@ -27,7 +27,7 @@ public class JsonPropertyImpl extends JsonPropertyMixin implements JsonProperty
}
@NotNull
public JsonStringLiteral getNameElement() {
public JsonValue getNameElement() {
return JsonPsiImplUtils.getNameElement(this);
}

View File

@@ -1,6 +1,9 @@
package com.intellij.json.editor.smartEnter;
import com.intellij.json.psi.*;
import com.intellij.json.psi.JsonArray;
import com.intellij.json.psi.JsonFile;
import com.intellij.json.psi.JsonProperty;
import com.intellij.json.psi.JsonValue;
import com.intellij.lang.SmartEnterProcessorWithFixers;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Document;
@@ -91,7 +94,7 @@ public class JsonSmartEnterProcessor extends SmartEnterProcessorWithFixers {
}
}
else {
final JsonStringLiteral propertyKey = ((JsonProperty)element).getNameElement();
final JsonValue propertyKey = ((JsonProperty)element).getNameElement();
final int keyEndOffset = propertyKey.getTextRange().getEndOffset();
//processor.myFirstErrorOffset = keyEndOffset;
if (terminatedOnCurrentLine(editor, propertyKey) && !isFollowedByTerminal(propertyKey, COLON)) {

View File

@@ -36,7 +36,7 @@ public class JsonElementGenerator {
* @param <T> type of the JSON value desired
* @return element created from given text
*
* @see {@link com.intellij.json.psi.JsonElementGenerator#createStringLiteral(String)}
* @see #createStringLiteral(String)
*/
@NotNull
public <T extends JsonValue> T createValue(@NotNull String content) {

View File

@@ -4,6 +4,7 @@ import com.intellij.json.JsonParserDefinition;
import com.intellij.json.psi.*;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiElement;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -16,9 +17,18 @@ public class JsonPsiImplUtils {
return StringUtil.stripQuotesAroundValue(property.getNameElement().getText());
}
/**
* Actually only JSON string literal should be accepted as valid name of property according to standard,
* but for compatibility with JavaScript integration any JSON literals as well as identifiers (unquoted words)
* are possible and highlighted as error later.
*
* @see com.intellij.json.codeinsight.JsonStandardComplianceAnnotator
*/
@NotNull
public static JsonStringLiteral getNameElement(@NotNull JsonProperty property) {
return (JsonStringLiteral)property.getFirstChild();
public static JsonValue getNameElement(@NotNull JsonProperty property) {
final PsiElement firstChild = property.getFirstChild();
assert firstChild instanceof JsonLiteral || firstChild instanceof JsonReferenceExpression;
return (JsonValue)firstChild;
}
@Nullable

View File

@@ -69,7 +69,7 @@ private object_element ::= property (','|&'}') {
pin = 1
}
property ::= string_literal (':' value) {
property ::= property_name (':' value) {
methods=[
getName
getNameElement
@@ -81,6 +81,8 @@ property ::= string_literal (':' value) {
pin(".*")=1
}
private property_name ::= literal | reference_expression
array ::= '[' array_element* ']' { pin=1 }
private array_element ::= value (','|&']') {

View File

@@ -58,6 +58,10 @@ public class JsonParsingTest extends ParsingTestCase {
doTest();
}
public void testNonStandardPropertyKeyValues() {
doTest();
}
// Moved from JavaScript
public void testSimple1() {

View File

@@ -0,0 +1,7 @@
{
42: null,
null: null,
false: null,
true: null,
identifier: null
}

View File

@@ -0,0 +1,49 @@
JsonFile: NonStandardPropertyKeyValues.json
JsonObject
PsiElement({)('{')
PsiWhiteSpace('\n ')
JsonProperty
JsonNumberLiteral
PsiElement(NUMBER)('42')
PsiElement(:)(':')
PsiWhiteSpace(' ')
JsonNullLiteral
PsiElement(null)('null')
PsiElement(,)(',')
PsiWhiteSpace('\n ')
JsonProperty
JsonNullLiteral
PsiElement(null)('null')
PsiElement(:)(':')
PsiWhiteSpace(' ')
JsonNullLiteral
PsiElement(null)('null')
PsiElement(,)(',')
PsiWhiteSpace('\n ')
JsonProperty
JsonBooleanLiteral
PsiElement(false)('false')
PsiElement(:)(':')
PsiWhiteSpace(' ')
JsonNullLiteral
PsiElement(null)('null')
PsiElement(,)(',')
PsiWhiteSpace('\n ')
JsonProperty
JsonBooleanLiteral
PsiElement(true)('true')
PsiElement(:)(':')
PsiWhiteSpace(' ')
JsonNullLiteral
PsiElement(null)('null')
PsiElement(,)(',')
PsiWhiteSpace('\n ')
JsonProperty
JsonReferenceExpression
PsiElement(INDENTIFIER)('identifier')
PsiElement(:)(':')
PsiWhiteSpace(' ')
JsonNullLiteral
PsiElement(null)('null')
PsiWhiteSpace('\n')
PsiElement(})('}')