1
0
Fork 0
arangodb/lib/V8/v8-json.ll

478 lines
12 KiB
LLVM

%top{
////////////////////////////////////////////////////////////////////////////////
/// @brief json parser
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2011 triagens GmbH, Cologne, Germany
///
/// Licensed 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.
///
/// Copyright holder is triAGENS GmbH, Cologne, Germany
///
/// @author Dr. Frank Celler
/// @author Copyright 2011, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
#include "Basics/Common.h"
#include "Basics/tri-strings.h"
#include "V8/v8-json.h"
#include "V8/v8-globals.h"
#define YY_NO_INPUT
}
%option noyywrap nounput batch
%option 8bit
%option reentrant
%option extra-type="struct jsonData"
%option prefix="tri_v8_"
ZERO [0]
DIGIT [0-9]
DIGIT1 [1-9]
MINUS [-]
PLUS [+]
%{
#define END_OF_FILE 0
#define FALSE_CONSTANT 1
#define TRUE_CONSTANT 2
#define NULL_CONSTANT 3
#define NUMBER_CONSTANT 4
#define STRING_CONSTANT 5
#define OPEN_BRACE 6
#define CLOSE_BRACE 7
#define OPEN_BRACKET 8
#define CLOSE_BRACKET 9
#define COMMA 10
#define COLON 11
#define UNQUOTED_STRING 12
#define STRING_CONSTANT_ASCII 13
struct jsonData {
char const* _message;
};
#define YY_FATAL_ERROR(a) \
do { \
if (false) { \
yy_fatal_error(a, nullptr); \
} \
} \
while (0)
%}
%%
/* -----------------------------------------------------------------------------
* keywords
* ----------------------------------------------------------------------------- */
(?i:false) {
return FALSE_CONSTANT;
}
(?i:null) {
return NULL_CONSTANT;
}
(?i:true) {
return TRUE_CONSTANT;
}
/* -----------------------------------------------------------------------------
* strings
* ----------------------------------------------------------------------------- */
\"[ !\x23-\x5b\x5d-\x7f]*\" {
// performance optimization for all-ASCII strings without escape characters
// this matches the ASCII chars with ordinal numbers 35 (x23) to 127 (x7f),
// plus space (32) and ! (33) but no quotation marks (34, x22) and backslashes (92, x5c)
return STRING_CONSTANT_ASCII;
}
\"(\\.|[^\\\"])*\" {
return STRING_CONSTANT;
}
/* -----------------------------------------------------------------------------
* numbers
* ----------------------------------------------------------------------------- */
({MINUS}|{PLUS})?({ZERO}|({DIGIT1}{DIGIT}*))((\.{DIGIT}+)?([eE]({MINUS}|{PLUS})?{DIGIT}+)?)? {
return NUMBER_CONSTANT;
}
/* -----------------------------------------------------------------------------
* special characters
* ----------------------------------------------------------------------------- */
"{" {
return OPEN_BRACE;
}
"}" {
return CLOSE_BRACE;
}
"[" {
return OPEN_BRACKET;
}
"]" {
return CLOSE_BRACKET;
}
"," {
return COMMA;
}
":" {
return COLON;
}
/* -----------------------------------------------------------------------------
* Skip whitespaces. Whatever is left, should be an unquoted string appearing
* somewhere. This will be reported as an error.
* ----------------------------------------------------------------------------- */
[ \t\r\n]* {
}
. {
return UNQUOTED_STRING;
}
%%
// -----------------------------------------------------------------------------
// --SECTION-- forward declarations
// -----------------------------------------------------------------------------
static v8::Handle<v8::Value> ParseObject (v8::Isolate* isolate, yyscan_t scanner);
static v8::Handle<v8::Value> ParseValue (v8::Isolate* isolate, yyscan_t scanner, int c);
// -----------------------------------------------------------------------------
// --SECTION-- private functions
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief parses an array
////////////////////////////////////////////////////////////////////////////////
static v8::Handle<v8::Value> ParseArray (v8::Isolate* isolate,
yyscan_t scanner) {
struct yyguts_t* yyg = (struct yyguts_t*) scanner;
v8::Handle<v8::Array> array = v8::Array::New(isolate);
uint32_t pos = 0;
int c = yylex(scanner);
while (c != END_OF_FILE) {
if (c == CLOSE_BRACKET) {
return array;
}
if (pos > 0) {
if (c != COMMA) {
yyextra._message = "expecting comma";
return v8::Undefined(isolate);
}
c = yylex(scanner);
}
v8::Handle<v8::Value> sub = ParseValue(isolate, scanner, c);
if (sub->IsUndefined()) {
yyextra._message = "cannot create value";
return v8::Undefined(isolate);
}
array->Set(pos++, sub);
c = yylex(scanner);
}
yyextra._message = "expecting an array element, got end-of-file";
return v8::Undefined(isolate);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief parses an object
////////////////////////////////////////////////////////////////////////////////
static v8::Handle<v8::Value> ParseObject (v8::Isolate* isolate,
yyscan_t scanner) {
struct yyguts_t* yyg = (struct yyguts_t*) scanner;
v8::Handle<v8::Object> object = v8::Object::New(isolate);
bool comma = false;
int c = yylex(scanner);
while (c != END_OF_FILE) {
if (c == CLOSE_BRACE) {
return object;
}
if (comma) {
if (c != COMMA) {
yyextra._message = "expecting comma";
return v8::Undefined(isolate);
}
c = yylex(scanner);
}
else {
comma = true;
}
// attribute name
v8::Handle<v8::String> attributeName;
if (c == STRING_CONSTANT) {
// utf-8 attribute name
size_t outLength;
char* name = TRI_UnescapeUtf8String(yytext + 1, yyleng - 2, &outLength, true);
if (name == nullptr) {
yyextra._message = "out-of-memory";
return v8::Undefined(isolate);
}
attributeName = TRI_V8_PAIR_STRING(isolate, name, outLength);
TRI_FreeString(name);
}
else if (c == STRING_CONSTANT_ASCII) {
// ASCII-only attribute name
attributeName = TRI_V8_ASCII_PAIR_STRING(isolate, yytext + 1, yyleng - 2);
}
else {
yyextra._message = "expecting attribute name";
return v8::Undefined(isolate);
}
// followed by a colon
c = yylex(scanner);
if (c != COLON) {
yyextra._message = "expecting colon";
return v8::Undefined(isolate);
}
// followed by an object
c = yylex(scanner);
v8::Handle<v8::Value> sub = ParseValue(isolate, scanner, c);
if (sub->IsUndefined()) {
yyextra._message = "cannot create value";
return v8::Undefined(isolate);
}
object->Set(attributeName, sub);
c = yylex(scanner);
}
yyextra._message = "expecting an object attribute name or element, got end-of-file";
return v8::Undefined(isolate);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief parses an object
////////////////////////////////////////////////////////////////////////////////
static v8::Handle<v8::Value> ParseValue (v8::Isolate* isolate,
yyscan_t scanner,
int c) {
struct yyguts_t* yyg = (struct yyguts_t*) scanner;
switch (c) {
case END_OF_FILE: {
yyextra._message = "expecting atom, got end-of-file";
return v8::Undefined(isolate);
}
case FALSE_CONSTANT: {
return v8::False(isolate);
}
case TRUE_CONSTANT: {
return v8::True(isolate);
}
case NULL_CONSTANT: {
return v8::Null(isolate);
}
case NUMBER_CONSTANT: {
char* ep;
if ((size_t) yyleng >= 512) {
yyextra._message = "number too big";
return v8::Undefined(isolate);
}
// need to reset errno because return value of 0 is not distinguishable from an error on Linux
errno = 0;
// yytext is null-terminated. can use it directly without copying it into a temporary buffer
double d = strtod(yytext, &ep);
if (d == HUGE_VAL && errno == ERANGE) {
yyextra._message = "number too big";
return v8::Undefined(isolate);
}
if (d == 0.0 && errno == ERANGE) {
yyextra._message = "number too small";
return v8::Undefined(isolate);
}
if (ep != yytext + yyleng) {
yyextra._message = "cannot parse number";
return v8::Undefined(isolate);
}
return v8::Number::New(isolate, d);
}
case STRING_CONSTANT: {
if (yyleng <= 2) {
// string is empty
return v8::String::Empty(isolate);
}
// string is not empty
size_t outLength;
char* ptr = TRI_UnescapeUtf8String(yytext + 1, yyleng - 2, &outLength, true);
if (ptr == nullptr || outLength == 0) {
yyextra._message = "out-of-memory";
return v8::Undefined(isolate);
}
v8::Handle<v8::String> str = TRI_V8_PAIR_STRING(isolate, ptr, outLength);
TRI_FreeString(ptr);
return str;
}
case STRING_CONSTANT_ASCII: {
if (yyleng <= 2) {
// string is empty
return v8::String::Empty(isolate);
}
// string is not empty
return TRI_V8_ASCII_PAIR_STRING(isolate, yytext + 1, yyleng - 2);
}
case OPEN_BRACE: {
return ParseObject(isolate, scanner);
}
case CLOSE_BRACE: {
yyextra._message = "expected value, got '}'";
return v8::Undefined(isolate);
}
case OPEN_BRACKET: {
return ParseArray(isolate, scanner);
}
case CLOSE_BRACKET: {
yyextra._message = "expected value, got ']'";
return v8::Undefined(isolate);
}
case COMMA: {
yyextra._message = "expected value, got ','";
return v8::Undefined(isolate);
}
case COLON: {
yyextra._message = "expected value, got ':'";
return v8::Undefined(isolate);
}
case UNQUOTED_STRING: {
yyextra._message = "expected value, got unquoted string";
return v8::Undefined(isolate);
}
}
yyextra._message = "unknown atom";
return v8::Undefined(isolate);
}
// -----------------------------------------------------------------------------
// --SECTION-- public functions
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief parses a json string
////////////////////////////////////////////////////////////////////////////////
v8::Handle<v8::Value> TRI_FromJsonString (v8::Isolate* isolate,
char const* text,
size_t len,
char** error) {
yyscan_t scanner;
yylex_init(&scanner);
struct yyguts_t* yyg = (struct yyguts_t*) scanner;
YY_BUFFER_STATE buf = yy_scan_bytes(text, static_cast<int>(len), scanner);
int c = yylex(scanner);
v8::Handle<v8::Value> value = ParseValue(isolate, scanner, c);
if (!value->IsUndefined()) {
c = yylex(scanner);
if (c != END_OF_FILE) {
value = v8::Undefined(isolate);
}
}
if (error != nullptr) {
if (yyextra._message != nullptr) {
*error = TRI_DuplicateString(yyextra._message);
}
else {
*error = nullptr;
}
}
yy_delete_buffer(buf, scanner);
yylex_destroy(scanner);
return value;
}
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------
// Local Variables:
// mode: C
// mode: outline-minor
// outline-regexp: "^\\(/// @brief\\|/// @addtogroup\\|// --SECTION--\\)"
// End: