%{
/*
 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.
*/

// on some systems, won't find an EOF definition 
#ifndef EOF
#define EOF (-1)
#endif

#include "AvroYacc.hh"

// this undef is a hack for my mac implementation
#undef yyFlexLexer
#include "Compiler.hh"

#define YY_STACK_USED 1

using std::cin;
using std::cout;
using std::cerr;

%}

%option c++
%option noyywrap

%{

int yylex(int *val, void *ctx)
{
    avro::CompilerContext *c = static_cast<avro::CompilerContext *>(ctx);
    int ret = c->lexer().yylex();
    if( ret > AVRO_LEX_OUTPUT_TEXT_BEGIN && ret < AVRO_LEX_OUTPUT_TEXT_END ) { 
        c->setText( c->lexer().YYText()) ;
    }
    return ret;
}

%}

%x READTYPE
%x STARTTYPE
%x STARTSCHEMA
%x READNAME
%x READFIELD
%x READFIELDS
%x READFIELDNAME
%x READSYMBOLS
%x READSYMBOL
%x READSIZE
%x INUNION
%x INOBJECT
%x READMETADATA
%x SKIPJSONSTRING
%x SKIPJSONARRAY
%x SKIPJSONOBJECT

ws [ \t\r\n]
nonws [^ \t\r\n]
delim {ws}*:{ws}*
avrotext [a-zA-Z_][a-zA-Z0-9_.]*
startunion \[
startobject \{
integer [0-9]+
anytext .*

%%
<READTYPE>int                   return AVRO_LEX_INT;
<READTYPE>long                  return AVRO_LEX_LONG;
<READTYPE>null                  return AVRO_LEX_NULL;
<READTYPE>boolean               return AVRO_LEX_BOOL;
<READTYPE>float                 return AVRO_LEX_FLOAT;
<READTYPE>double                return AVRO_LEX_DOUBLE;
<READTYPE>string                return AVRO_LEX_STRING;
<READTYPE>bytes                 return AVRO_LEX_BYTES;
<READTYPE>record                return AVRO_LEX_RECORD;
<READTYPE>enum                  return AVRO_LEX_ENUM;
<READTYPE>map                   return AVRO_LEX_MAP;
<READTYPE>array                 return AVRO_LEX_ARRAY;
<READTYPE>fixed                 return AVRO_LEX_FIXED;
<READTYPE>{avrotext}            return AVRO_LEX_NAMED_TYPE;
<READTYPE>\"                    yy_pop_state(); 

<READNAME>{avrotext}            return AVRO_LEX_NAME;
<READNAME>\"                    yy_pop_state();

<READSYMBOL>{avrotext}          return AVRO_LEX_SYMBOL;
<READSYMBOL>\"                  yy_pop_state();

<READFIELDNAME>{avrotext}       return AVRO_LEX_FIELD_NAME;
<READFIELDNAME>\"               yy_pop_state();

<READFIELD>\"type\"{delim}      yy_push_state(STARTSCHEMA); 
<READFIELD>\"name\"{delim}\"    yy_push_state(READFIELDNAME); 
<READFIELD>\}                   yy_pop_state(); return AVRO_LEX_FIELD_END;
<READFIELD>,                    return yytext[0];
<READFIELD>\"{avrotext}\"+{delim}      yy_push_state(READMETADATA); return AVRO_LEX_METADATA;
<READFIELD>{ws}                 ;

<READFIELDS>\{                  yy_push_state(READFIELD); return AVRO_LEX_FIELD;
<READFIELDS>\]                  yy_pop_state(); return AVRO_LEX_FIELDS_END;
<READFIELDS>,                   return yytext[0];
<READFIELDS>{ws}                ;

<READSYMBOLS>\"                 yy_push_state(READSYMBOL); 
<READSYMBOLS>,                  return yytext[0];
<READSYMBOLS>\]                 yy_pop_state(); return AVRO_LEX_SYMBOLS_END;
<READSYMBOLS>{ws}               ;

<READSIZE>{integer}             yy_pop_state(); return AVRO_LEX_SIZE;

<INUNION>\"                     yy_push_state(READTYPE); return AVRO_LEX_SIMPLE_TYPE;
<INUNION>{startobject}          yy_push_state(INOBJECT); return yytext[0];
<INUNION>\]                     yy_pop_state(); return yytext[0];
<INUNION>,                      return yytext[0];
<INUNION>{ws}                   ;

<SKIPJSONSTRING>\"              yy_pop_state();
<SKIPJSONSTRING>\\.             ;
<SKIPJSONSTRING>[^\"\\]+        ;

<SKIPJSONOBJECT>\}              yy_pop_state();
<SKIPJSONOBJECT>\{              yy_push_state(SKIPJSONOBJECT);
<SKIPJSONOBJECT>\"              yy_push_state(SKIPJSONSTRING);
<SKIPJSONOBJECT>[^\{\}\"]+      ;

<SKIPJSONARRAY>\]               yy_pop_state();
<SKIPJSONARRAY>\[               yy_push_state(SKIPJSONARRAY);
<SKIPJSONARRAY>\"               yy_push_state(SKIPJSONSTRING);
<SKIPJSONARRAY>[^\[\]\"]+       ;  

<READMETADATA>\"                yy_pop_state(); yy_push_state(SKIPJSONSTRING);
<READMETADATA>\{                yy_pop_state(); yy_push_state(SKIPJSONOBJECT);
<READMETADATA>\[                yy_pop_state(); yy_push_state(SKIPJSONARRAY);
<READMETADATA>[^\"\{\[,\}]+     yy_pop_state();

<INOBJECT>\"type\"{delim}       yy_push_state(STARTTYPE); return AVRO_LEX_TYPE;
<INOBJECT>\"name\"{delim}\"     yy_push_state(READNAME); 
<INOBJECT>\"size\"{delim}       yy_push_state(READSIZE);
<INOBJECT>\"items\"{delim}      yy_push_state(STARTSCHEMA); return AVRO_LEX_ITEMS;
<INOBJECT>\"values\"{delim}     yy_push_state(STARTSCHEMA); return AVRO_LEX_VALUES;
<INOBJECT>\"fields\"{delim}\[   yy_push_state(READFIELDS); return AVRO_LEX_FIELDS; 
<INOBJECT>\"symbols\"{delim}\[  yy_push_state(READSYMBOLS); return AVRO_LEX_SYMBOLS;
<INOBJECT>,                     return yytext[0];
<INOBJECT>\}                    yy_pop_state(); return yytext[0];
<INOBJECT>\"{avrotext}+\"{delim}       yy_push_state(READMETADATA); return AVRO_LEX_METADATA;
<INOBJECT>{ws}                  ;

<STARTTYPE>\"                   yy_pop_state(); yy_push_state(READTYPE); 
<STARTTYPE>{startunion}         yy_pop_state(); yy_push_state(INUNION); return yytext[0];
<STARTTYPE>{startobject}        yy_pop_state(); yy_push_state(INOBJECT); return yytext[0];

<STARTSCHEMA>\"                 yy_pop_state(); yy_push_state(READTYPE); return AVRO_LEX_SIMPLE_TYPE;
<STARTSCHEMA>{startunion}       yy_pop_state(); yy_push_state(INUNION); return yytext[0];
<STARTSCHEMA>{startobject}      yy_pop_state(); yy_push_state(INOBJECT); return yytext[0];

{startobject}                   yy_push_state(INOBJECT); return yytext[0];
{startunion}                    yy_push_state(INUNION); return yytext[0];
\"                              yy_push_state(READTYPE); return AVRO_LEX_SIMPLE_TYPE;
{ws}                            ;
<<EOF>>                         {
#if !YY_FLEX_SUBMINOR_VERSION || YY_FLEX_SUBMINOR_VERSION < 27
// The versions of flex before 3.5.27 do not free their stack when done, so explcitly free it.
// Note that versions before did not actually define a subminor macro.
                                    if (yy_start_stack) {
                                        yy_flex_free(yy_start_stack);
                                        yy_start_stack = 0;
                                    }
#endif
#if YY_FLEX_SUBMINOR_VERSION > 35
// At this time, 3.5.35 is the latest version.
#warning "Warning:  untested version of flex"
#endif
#if YY_FLEX_SUBMINOR_VERSION >= 31 && YY_FLEX_SUBMINOR_VERSION < 34
// The versions of flex starting 3.5.31 do not free yy_buffer_stack, so do so 
// explicitly (first yy_delete_buffer must be called to free pointers stored on the stack, then it is
// safe to remove the stack).  This was fixed in 3.4.34.
                                    if(yy_buffer_stack) {
                                        yy_delete_buffer(YY_CURRENT_BUFFER);
                                        yyfree(yy_buffer_stack);
                                        yy_buffer_stack = 0;
                                    }
#endif
                                    yyterminate();
                                }

%%

