| /* |
| * 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); |
| |