-
Notifications
You must be signed in to change notification settings - Fork 0
/
pllolcode_symbol.c
308 lines (282 loc) · 9.08 KB
/
pllolcode_symbol.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
/*
* PL/LOLCODE Symbol table functions
* $Id: pllolcode_symbol.c,v 1.15 2009/05/03 04:35:21 eggyknap Exp $
*/
#include "pllolcode.h"
#include "postgres.h"
#include "executor/spi.h"
#include "commands/trigger.h"
#include "fmgr.h"
#include "access/heapam.h"
#include "access/htup_details.h"
#include "utils/syscache.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/builtins.h"
#include "pllolcode_lang.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define LOL_MAX_VARS 255
lolIdent *IT;
/* TODO : Change this to some other implementation without a limited number of variables */
lolIdent lolVars[LOL_MAX_VARS];
int lolVarCount;
void
printSymbolTable(void)
{
int i;
elog(INFO, "Count; %d", lolVarCount);
for (i = 0; i < lolVarCount; i++)
{
elog(INFO, "Name: %s", lolVars[i].name);
switch (lolVars[i].type) {
case ident_YARN:
elog(INFO, "Yarn, value %s", lolVars[i].value.yarnVal);
break;
case ident_NUMBR:
elog(INFO, "Numbr, value %d", lolVars[i].value.numbrVal);
break;
case ident_NUMBAR:
elog(INFO, "Numbar value %f", lolVars[i].value.numbarVal);
break;
case ident_TROOF:
elog(INFO, "Troof, value %s", (lolVars[i].value.numbrVal == 1) ? "WIN" : "FAIL");
break;
case ident_NOOB:
elog(INFO, "NOOB value");
break;
default:
elog(INFO, "Unknown type %d", lolVars[i].type);
}
}
}
void
lolInitVars()
{
NodeVal val;
val.numbrVal = 0;
IT = &(lolVars[0]);
IT->name = pstrdup("IT");
IT->type = ident_NUMBR;
IT->value = val;
lolVarCount = 1;
/* printSymbolTable(); */
}
/* TODO: Make lolGetVar() and lolSetVar() use the same code to scan the variable list */
lolIdent *
lolGetVar(char *name)
{
int i;
if (name == NULL) return NULL;
for (i = 0; i < lolVarCount; i++)
{
if (strncmp(name, lolVars[i].name, 255) == 0)
return &(lolVars[i]);
}
return NULL;
}
void
lolSetVar(char *name, IdentType type, NodeVal value)
{
int i;
for(i = 0; i < lolVarCount; i++)
{
if (strncmp(name, lolVars[i].name, 255) == 0)
break;
}
if (i >= lolVarCount)
elog(INFO, "Tried to set PL/LOLCODE variable %s without declaring it first", name);
if (lolVars[i].type == ident_YARN && lolVars[i].value.yarnVal != NULL)
pfree(lolVars[i].value.yarnVal);
lolVars[i].type = type;
lolVars[i].value = value;
elog(DEBUG3, "Just set %s", name);
/*printSymbolTable(); */
}
void
lolDeclareVar(char *name)
{
if (lolVarCount >= LOL_MAX_VARS)
elog(ERROR, "Too many variables required for LOLCODE function");
lolVarCount++;
elog(DEBUG3, "Declaring %s as variable # %d", name, lolVarCount);
lolVars[lolVarCount-1].name = pstrdup(name);
lolVars[lolVarCount-1].type = ident_NOOB;
/* printSymbolTable(); */
}
/* Handle string type casting */
/* The _expl_ argument describes whether or not this cast was called
* explicitly. NOOB values cannot be implicitly cast to anything but TROOF
* values, so we need to know if this cast was explicit */
char *
lolVarGetString(lolIdent *var, bool expl)
{
char *tmpString;
/* TODO: Handle strings of more than 255 chars */
tmpString = palloc(255);
memset(tmpString, 0, 255);
if (var == NULL) return NULL;
switch (var->type) {
case ident_YARN:
return var->value.yarnVal;
case ident_NUMBR:
NUMBR2YARN(var->value.numbrVal, tmpString, 255);
return tmpString;
case ident_NUMBAR:
NUMBAR2YARN(var->value.numbarVal, tmpString, 255);
return tmpString;
case ident_TROOF:
TROOF2YARN(var->value.numbrVal, tmpString, 255);
return tmpString;
case ident_NOOB:
if (expl) return tmpString;
else elog(WARNING, "PL/LOLCODE: Cannot implicitly cast NOOB value to YARN in variable %s", var->name);
}
return NULL;
}
/* TODO: Error checking */
/* Type cast to NUMBR */
int
lolVarGetNumbr(lolIdent *var, bool expl) {
if (var == NULL) return 0;
switch (var->type) {
case ident_NUMBR:
return var->value.numbrVal;
case ident_NUMBAR:
return NUMBAR2NUMBR(var->value.numbarVal);
case ident_TROOF:
return TROOF2NUMBR(var->value.numbrVal);
case ident_YARN:
return YARN2NUMBR(var->value.yarnVal);
case ident_NOOB:
if (expl) return 0;
else elog(WARNING, "PL/LOLCODE: Cannot implicitly cast NOOB value to NUMBR in variable %s", var->name);
}
return 0;
}
/* Type cast to NUMBAR */
double
lolVarGetNumbar(lolIdent *var, bool expl) {
if (var == NULL) return 0;
switch (var->type) {
case ident_NUMBAR:
return var->value.numbarVal;
case ident_NUMBR:
return NUMBR2NUMBAR(var->value.numbrVal);
case ident_TROOF:
return TROOF2NUMBAR(var->value.numbrVal);
case ident_YARN:
return YARN2NUMBAR(var->value.yarnVal);
case ident_NOOB:
if (expl) return 0.0;
else elog(WARNING, "PL/LOLCODE: Cannot implicitly cast NOOB value to NUMBAR in variable %s", var->name);
}
return 0.0;
}
/* Type cast to TROOF */
/* Note that this function does *not* take an argument called "expl" like
* the other lolVarGet_type_ functions. This is because NOOBs *can* be
* implicitly cast to TROOF */
lolTroof
lolVarGetTroof(lolIdent *var) {
if (var == NULL) return lolFAIL;
switch (var->type) {
case ident_TROOF:
case ident_NUMBR:
return (var->value.numbrVal != 0) ? lolWIN : lolFAIL;
case ident_NUMBAR:
return NUMBAR2TROOF(var->value.numbarVal);
/* return (var->value.numbarVal != 0) ? lolWIN : lolFAIL; */
case ident_YARN:
return YARN2TROOF(var->value.yarnVal);
/* return (strlen(var->value.yarnVal) > 0) ? lolWIN : lolFAIL; */
case ident_NOOB:
return lolFAIL;
}
return lolFAIL;
}
/* Type cast to TROOF, convert to standard bool */
/* TODO : Convert to macro */
bool
lolVarGetBool(lolIdent *var) {
return lolVarGetTroof(var) == lolWIN ? true : false;
}
void
LOLifyString(char *str, Oid typeoid, char *lolVarName)
{
NodeVal nodeVal;
if (str == NULL) {
nodeVal.numbrVal = 0;
lolSetVar(lolVarName, ident_NOOB, nodeVal);
}
else {
/* Note: because the OutputFunctionCall gives me the
* data as a string, and because most casts happen
* implicitly so this shouldn't really bother anyone,
* I'm keeping the input data as a string. For now. */
SPI_push();
nodeVal.yarnVal = str;
SPI_pop();
switch (typeoid) {
case BOOLOID:
if (nodeVal.yarnVal[0] == 't')
nodeVal.numbrVal = 1;
else
nodeVal.numbrVal = 0;
lolSetVar(lolVarName, ident_TROOF, nodeVal);
break;
case INT2OID:
case INT4OID:
case INT8OID:
nodeVal.numbrVal = YARN2NUMBR(nodeVal.yarnVal);
lolSetVar(lolVarName, ident_NUMBR, nodeVal);
break;
case FLOAT4OID:
case FLOAT8OID:
case NUMERICOID:
nodeVal.numbarVal = YARN2NUMBAR(nodeVal.yarnVal);
lolSetVar(lolVarName, ident_NUMBAR, nodeVal);
break;
default:
lolSetVar(lolVarName, ident_YARN, nodeVal);
}
}
}
void
LOLifyDatum(Datum val, bool isnull, Oid typeoid, char *lolVarName)
{
HeapTuple typeTup;
FmgrInfo tmp_flinfo;
Form_pg_type typeStruct;
NodeVal nodeVal;
char *str;
typeTup = SearchSysCache(TYPEOID, ObjectIdGetDatum(typeoid), 0, 0, 0);
if (!HeapTupleIsValid(typeTup))
elog(ERROR,"Cache lookup failed for type %u", typeoid);
typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
/* TODO: improve support for non-basic types */
if (typeStruct->typtype != 'b')
elog(ERROR, "Cannot support pseudo-types, domain types, or composite types as function arguments, specifically %s",
format_type_be(typeoid));
fmgr_info_cxt(typeStruct->typoutput, &tmp_flinfo, CurTransactionContext);
ReleaseSysCache(typeTup);
lolDeclareVar(lolVarName);
if (isnull) {
/* Initialize this to something */
nodeVal.numbrVal = 0;
lolSetVar(lolVarName, ident_NOOB, nodeVal);
}
else {
/* Note: because the OutputFunctionCall gives me the
* data as a string, and because most casts happen
* implicitly so this shouldn't really bother anyone,
* I'm keeping the input data as a string. For now. */
SPI_push();
str = OutputFunctionCall(&tmp_flinfo, val);
SPI_pop();
LOLifyString(str, typeoid, lolVarName);
}
}