blob: afdcea85d7da64ffbd5702e62ef8aebcdb1ce795 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/**
*
* @author Tomas Zezula
*/
grammar Json;
options {
language=Java;
}
@lexer::header {
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.netbeans.modules.javascript2.json.parser;
}
@parser::header {
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.netbeans.modules.javascript2.json.parser;
}
@lexer::members {
public static final int WHITESPACES = 1;
public static final int COMMENTS = 2;
public static final int ERRORS = 3;
private static final Recovery[] RECOVERIES = {
Recovery.createLineCommentRecovery(),
Recovery.createCommentRecovery(),
Recovery.createStringRecovery()
};
private boolean isCommentSupported;
private boolean hasErrorToken;
public LexerState getLexerState() {
return new LexerState(getState());
}
public void setLexerState(LexerState state) {
this.setState(state.atnState);
}
public static final class LexerState {
final int atnState;
public LexerState(int atnState) {
this.atnState = atnState;
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final LexerState other = (LexerState) obj;
if (this.atnState != other.atnState) {
return false;
}
return true;
}
@Override
public int hashCode() {
int hash = 5;
hash = 29 * hash + this.atnState;
return hash;
}
}
public JsonLexer(
final CharStream input,
final boolean isCommentSupported) {
this(input, isCommentSupported, false);
}
public JsonLexer(
final CharStream input,
final boolean isCommentSupported,
final boolean hasErrorToken) {
this(input);
this.isCommentSupported = isCommentSupported;
this.hasErrorToken = hasErrorToken;
}
@Override
public void recover(LexerNoViableAltException e) {
final CharStream in = e.getInputStream();
final int current = in.index();
final int index = e.getStartIndex();
boolean resolved = false;
in.seek(index);
for (Recovery r : RECOVERIES) {
if (r.canRecover(in)) {
getInterpreter().setCharPositionInLine(_tokenStartCharPositionInLine);
getInterpreter().setLine(_tokenStartLine);
r.recover(in, getInterpreter());
resolved = true;
break;
}
}
if (!resolved) {
in.seek(current);
super.recover(e);
}
}
}
json : value?EOF;
value : (STRING | NUMBER | TRUE | FALSE | NULL | array | object);
object : LBRACE (pair (COMMA pair)*)? RBRACE;
pair : key COLON value;
key : STRING;
array : LBRACKET (value (COMMA value)*)? RBRACKET;
COLON : ':';
COMMA : ',';
DOT : '.';
PLUS : '+';
MINUS : '-';
LBRACE : '{';
RBRACE : '}';
LBRACKET : '[';
RBRACKET : ']';
TRUE : 'true';
FALSE : 'false';
NULL : 'null';
NUMBER : INTEGER FRACTION? EXPONENT?;
fragment INTEGER : (MINUS)? (DIGIT_0 | DIGIT_19 DIGIT*);
fragment DIGIT_0 : '0';
fragment DIGIT_19 : [1-9];
fragment DIGIT : DIGIT_0 | DIGIT_19;
fragment FRACTION : DOT DIGIT+;
fragment EXPONENT : ('e'|'E')(PLUS | MINUS)? DIGIT+;
STRING : QUOTE (CHAR)* QUOTE;
fragment QUOTE : '"';
fragment CHAR : ~[\u0000-\u001F"\\] | CONTROL;
fragment CONTROL : '\\' (["\\/bfnrt] | UNICODE);
fragment UNICODE : 'u' HEXDIGIT HEXDIGIT HEXDIGIT HEXDIGIT;
fragment HEXDIGIT : [0-9a-fA-F];
LINE_COMMENT : '//' .*? '\r'? '\n' {isCommentSupported}? -> channel(COMMENTS);
COMMENT : '/*' .*? '*/' {isCommentSupported}? -> channel(COMMENTS);
WS : [ \t\r\n]+ -> channel(WHITESPACES);
ERROR_COMMENT : '/*' (~'*' | ('*'+ ~'/'))* {hasErrorToken && isCommentSupported}? -> channel(ERRORS);
ERROR : . {hasErrorToken}? -> channel(ERRORS);