2.0
[hstore.git] / hstore_scan.l
1 %{
2 static string scanstring;
3
4 /* No reason to constrain amount of data slurped */
5 /* #define YY_READ_BUF_SIZE 16777216 */
6
7 /* Handles to the buffer that the lexer uses internally */
8 static YY_BUFFER_STATE scanbufhandle;
9 static char *scanbuf;
10 static int      scanbuflen;
11
12 static void addstring(bool init, char *s, int l);
13 static void addchar(bool init, char s);
14 static int checkSpecialVal(void); /* examine scanstring for the special value */
15
16 static bool     inputJSON = false;
17
18
19 %}
20
21 %option 8bit
22 %option never-interactive
23 %option nodefault
24 %option noinput
25 %option nounput
26 %option noyywrap
27 %option warn
28 %option prefix="hstore_yy"
29 %option bison-bridge
30
31 %x xQUOTED
32 %x xNONQUOTED
33
34 any                     [^\,\[\]\{\}\"\=\> \t\n\r\f\\\:]
35
36
37 %%
38
39 <INITIAL>[\,\{\}\[\]]                   { return *yytext; }
40
41 <INITIAL>\=\>                                   { return DELIMITER_P; }
42
43 <INITIAL>\:                                             { 
44                                                                         if (inputJSON)
45                                                                         {
46                                                                                 return DELIMITER_P;
47                                                                         }
48                                                                         else
49                                                                         {
50                                                                                 addchar(true, ':');
51                                                                                 BEGIN xNONQUOTED;
52                                                                         }
53                                                                 }
54
55 <INITIAL>[ \t\n\r\f]+                   { /* ignore */ }
56
57 <INITIAL>\=/[^\>]                               {
58                                                                         addchar(true, '=');
59                                                                         BEGIN xNONQUOTED;
60                                                                 }
61                                                                         
62 <INITIAL>\>                                             {
63                                                                         addchar(true, yytext[0]);
64                                                                         BEGIN xNONQUOTED;
65                                                                 }
66 <INITIAL>\\.                                    {
67                                                                         addchar(true, yytext[1]);
68                                                                         BEGIN xNONQUOTED;
69                                                                 }
70
71 <INITIAL>({any}|\>)+                    {
72                                                                         addstring(true, yytext, yyleng);
73                                                                         BEGIN xNONQUOTED;
74                                                                 }
75                                                                         
76 <INITIAL>\"                                     {
77                                                                         addchar(true, '\0');
78                                                                         BEGIN xQUOTED;
79                                                                 }
80
81 <INITIAL>\=                                             {       /* =<<EOF>> */
82                                                                         addchar(true, '=');
83                                                                         yylval->str = scanstring;
84                                                                         return STRING_P;
85                                                                 }
86
87 <xNONQUOTED>({any}|[\>\"\:])+   { 
88                                                                         addstring(false, yytext, yyleng); 
89                                                                 }
90
91 <xNONQUOTED>\=/[^\>]                    { addchar(false, *yytext); }
92
93 <xNONQUOTED>[ \t\n\r\f]+                { 
94                                                                         yylval->str = scanstring;
95                                                                         BEGIN INITIAL;
96                                                                         return checkSpecialVal();
97                                                                 }
98
99 <xNONQUOTED>\=                                  {       /* =<<EOF>> */
100                                                                         addchar(false, '=');
101                                                                         yylval->str = scanstring;
102                                                                         BEGIN INITIAL;
103                                                                         return STRING_P;
104                                                                 }
105
106 <xNONQUOTED>[\,\{\}\[\]]                {
107                                                                         yylval->str = scanstring;
108                                                                         yyless(0);
109                                                                         BEGIN INITIAL;
110                                                                         return checkSpecialVal();
111                                                                 }
112
113 <xNONQUOTED><<EOF>>                             { 
114                                                                         yylval->str = scanstring;
115                                                                         BEGIN INITIAL;
116                                                                         return checkSpecialVal();
117                                                                 }
118
119 <xNONQUOTED>\=\>                                {
120                                                                         yylval->str = scanstring;
121                                                                         yyless(0);
122                                                                         BEGIN INITIAL;
123                                                                         return checkSpecialVal();
124                                                                 }
125                                                                         
126
127 <xNONQUOTED,xQUOTED>\\.                 { addchar(false, yytext[1]); }
128
129 <INITIAL,xNONQUOTED,xQUOTED>\\  { yyerror("Unexpected end after backslesh"); }
130
131 <xQUOTED><<EOF>>                                { yyerror("Unexpected end of quoted string"); }
132
133 <xQUOTED>\"                                             {
134                                                                         yylval->str = scanstring;
135                                                                         BEGIN INITIAL;
136                                                                         return STRING_P;
137                                                                 }
138
139 <xQUOTED>[^\\\"]+                       { addstring(false, yytext, yyleng); }
140
141 <INITIAL><<EOF>>                                { yyterminate(); }
142
143 %%
144
145 void
146 yyerror(const char *message)
147 {
148         if (*yytext == YY_END_OF_BUFFER_CHAR)
149         {
150                 ereport(ERROR,
151                                 (errcode(ERRCODE_SYNTAX_ERROR),
152                                  errmsg("bad hstore representation"),
153                                  /* translator: %s is typically "syntax error" */
154                                  errdetail("%s at end of input", message)));
155         }
156         else
157         {
158                 ereport(ERROR,
159                                 (errcode(ERRCODE_SYNTAX_ERROR),
160                                  errmsg("bad hstore representation"),
161                                  /* translator: first %s is typically "syntax error" */
162                                  errdetail("%s at or near \"%s\"", message, yytext)));
163         }
164 }
165
166 static int
167 checkSpecialVal()
168 {
169         int res = STRING_P;
170
171         if (stringIsNumber(scanstring.val, scanstring.len, inputJSON))
172         {
173                 /* for numeric_in() call we need to make a correct C-string */
174                 addchar(false, '\0');
175                 res = NUMERIC_P;
176         }
177         else if (scanstring.len == 1)
178         {
179                 if (*scanstring.val == 't')
180                         res = TRUE_P;
181                 else if (*scanstring.val == 'f')
182                         res = FALSE_P;
183         }
184         else if (scanstring.len == 4)
185         {
186                 if (pg_strncasecmp("null", scanstring.val, scanstring.len) == 0)
187                         res = NULL_P;
188                 else if (pg_strncasecmp("true", scanstring.val, scanstring.len) == 0)
189                         res = TRUE_P;
190         }
191         else if (scanstring.len == 5)
192         {
193                 if (pg_strncasecmp("false", scanstring.val, scanstring.len) == 0)
194                         res = FALSE_P;
195         }
196
197         return res;
198 }
199 /*
200  * Called before any actual parsing is done
201  */
202 static void
203 hstore_scanner_init(const char *str, int slen)
204 {
205         if (slen <= 0)
206                 slen = strlen(str);
207
208         /*
209          * Might be left over after ereport()
210          */
211         if (YY_CURRENT_BUFFER)
212                 yy_delete_buffer(YY_CURRENT_BUFFER);
213
214         /*
215          * Make a scan buffer with special termination needed by flex.
216          */
217
218         scanbuflen = slen;
219         scanbuf = palloc(slen + 2);
220         memcpy(scanbuf, str, slen);
221         scanbuf[slen] = scanbuf[slen + 1] = YY_END_OF_BUFFER_CHAR;
222         scanbufhandle = yy_scan_buffer(scanbuf, slen + 2);
223
224         BEGIN(INITIAL);
225 }
226
227
228 /*
229  * Called after parsing is done to clean up after hstore_scanner_init()
230  */
231 static void
232 hstore_scanner_finish(void)
233 {
234         yy_delete_buffer(scanbufhandle);
235         pfree(scanbuf);
236 }
237
238 static void
239 addstring(bool init, char *s, int l) {
240         if (init) {
241                 scanstring.total = 32;
242                 scanstring.val = palloc(scanstring.total);
243                 scanstring.len = 0;
244         }
245
246         if (s && l) {
247                 while(scanstring.len + l + 1 >= scanstring.total) {
248                         scanstring.total *= 2;
249                         scanstring.val = repalloc(scanstring.val, scanstring.total);
250                 }
251
252                 memcpy(scanstring.val+scanstring.len, s, l);
253                 scanstring.len+=l;
254         }
255 }
256
257 static void
258 addchar(bool init, char s) {
259         if (init)
260         {
261                 scanstring.total = 32;
262                 scanstring.val = palloc(scanstring.total);
263                 scanstring.len = 0;
264         }
265         else if(scanstring.len + 1 >= scanstring.total)
266         {
267                 scanstring.total*=2;
268                 scanstring.val=repalloc(scanstring.val, scanstring.total);
269         }
270
271         scanstring.val[ scanstring.len ] = s;
272         if (s != '\0')
273                 scanstring.len++;
274 }
275
276 HStoreValue* 
277 parseHStore(const char *str, int len, bool json) {
278         HStoreValue             *parseresult;
279
280         inputJSON = json;
281
282         hstore_scanner_init(str, len);
283
284         if (hstore_yyparse((void*)&parseresult) != 0)
285                 hstore_yyerror("bugus input");
286
287         hstore_scanner_finish();
288
289         return parseresult;
290 }
291