Removing unused operators from the operator table
[io/quag.git] / libs / iovm / source / IoMessage_opShuffle.c
blobf269c56350abf73c45fbbd19ce8f724d20498daa
1 /*
2 docCopyright("Jonathan Wright; Steve Dekorte (2002)", 2006)
3 docLicense("BSD revised")
4 */
6 #include "IoMessage_opShuffle.h"
7 #include "IoMap.h"
8 #include "IoNumber.h"
10 #define DATA(self) ((IoMessageData *)IoObject_dataPointer(self))
12 IoMap *IoState_createOperatorTable(IoState *state)
14 typedef struct OpTable {
15 char *symbol;
16 int precedence;
17 } OpTable;
19 OpTable ops[] = {
20 {"@", 0},
21 {"@@", 0},
22 {"?", 0},
24 {"**", 1},
26 {"*", 2},
27 {"/", 2},
28 {"%", 2},
30 {"+", 3},
31 {"-", 3},
33 {"<<", 4},
34 {">>", 4},
36 {">", 5},
37 {"<", 5},
38 {"<=", 5},
39 {">=", 5},
41 {"==", 6},
42 {"!=", 6},
44 {"&", 7},
46 {"^", 8},
48 {"|", 9},
50 {"and", 10},
51 {"&&", 10},
53 {"or", 11},
54 {"||", 11},
56 {"..", 12},
58 {"return", 13},
60 {NULL, 0},
63 IoMap *self = IoMap_new(state);
64 OpTable *op = ops;
66 while (op->symbol)
68 IoMap_rawAtPut(self, IOSYMBOL(op->symbol), IONUMBER(op->precedence));
69 op ++;
72 return self;
75 IoMap *IoState_createAssignOperatorTable(IoState *state)
77 typedef struct {
78 char *symbol;
79 char *name;
80 } OpTable;
82 OpTable ops[] = {
83 {":=", "setSlot"},
84 {"=", "updateSlot"},
85 {"::=", "newSlot"},
87 {NULL, 0},
90 IoMap *self = IoMap_new(state);
91 OpTable *op = ops;
93 while (op->symbol)
95 IoMap_rawAtPut(self, IOSYMBOL(op->symbol), IOSYMBOL(op->name));
96 op ++;
99 return self;
103 // TODO move the IO_OP_MAX_LEVEL define to be adjacent to the op table.
104 // TODO Set IO_OP_MAX_LEVEL to max-1 or something massive otherwise people playing with custom operators don't have many levels available
105 #define IO_OP_MAX_LEVEL 17
107 enum LevelType {ATTACH, ARG, NEW, UNUSED};
109 typedef struct {
110 IoMessage *message;
111 enum LevelType type;
112 int precedence;
113 } Level;
115 void Level_finish(Level *self);
116 void Level_attachAndReplace(Level *self, IoMessage *msg);
117 void Level_setAwaitingFirstArg(Level *self, IoMessage *msg, int precedence);
119 typedef struct {
120 Level pool[IO_OP_MAX_LEVEL];
121 int currentLevel;
123 List *stack;
124 IoMap *operatorTable;
125 IoMap *assignOperatorTable;
126 } Levels;
128 void Levels_reset(Levels *self)
130 int i;
131 self->currentLevel = 1;
133 for (i = 0; i < IO_OP_MAX_LEVEL; i ++)
135 Level *level = &self->pool[i];
136 level->type = UNUSED;
140 Level *level = &self->pool[0];
141 level->message = NULL;
142 level->type = NEW;
143 level->precedence = IO_OP_MAX_LEVEL;
146 List_removeAll(self->stack);
147 List_append_(self->stack, &self->pool[0]);
150 // --- Levels ----------------------------------------------------------
152 Levels *Levels_new(IoMessage *msg)
154 Levels *self = io_calloc(1, sizeof(Levels));
156 IoState *state = IoObject_state(msg);
157 IoSymbol *operatorTableSymbol = IoState_symbolWithCString_(state, "OperatorTable");
159 // Lets be ultra flexable, and try to use the first message's operator table.
160 IoObject *opTable = IoObject_rawGetSlot_(msg, operatorTableSymbol);
162 // Otherwise, use Core OperatorTable, and if that doesn't exist, create it.
163 if (opTable == NULL)
165 // There is a chance the message didn't have it, but the core did---due
166 // to the Core not being part of the message's protos. Use Core
167 // Message's OperatorTable
168 opTable = IoObject_rawGetSlot_(state->core, operatorTableSymbol);
170 // If Core doesn't have an OperatorTable, lets create it.
171 if (opTable == NULL)
173 opTable = IoObject_new(state);
174 IoObject_setSlot_to_(state->core, operatorTableSymbol, opTable);
179 IoSymbol *operatorsSymbol = IoState_symbolWithCString_(state, "operators");
180 IoObject *operators = IoObject_rawGetSlot_(opTable, operatorsSymbol);
182 if (operators && ISMAP(operators))
184 self->operatorTable = operators;
186 else
188 // Not strictly correct as if the message has it's own empty
189 // OperatorTable slot, we'll create one for it instead of using
190 // Core Message OperatorTable operators. Oh well.
192 self->operatorTable = IoState_createOperatorTable(state);
193 IoObject_setSlot_to_(opTable, operatorsSymbol, self->operatorTable);
198 IoSymbol *assignOperatorsSymbol = IoState_symbolWithCString_(state, "assignOperators");
199 IoObject *assignOperators = IoObject_rawGetSlot_(opTable, assignOperatorsSymbol);
201 if (assignOperators && ISMAP(assignOperators))
203 self->assignOperatorTable = assignOperators;
205 else
207 // Not strictly correct as if the message has it's own empty
208 // OperatorTable slot, we'll create one for it instead of using
209 // Core Message OperatorTable operators. Oh well.
211 self->assignOperatorTable = IoState_createAssignOperatorTable(state);
212 IoObject_setSlot_to_(opTable, assignOperatorsSymbol, self->assignOperatorTable);
216 self->stack = List_new();
217 Levels_reset(self);
218 return self;
221 void Levels_free(Levels *self)
223 List_free(self->stack);
224 io_free(self);
227 inline Level *Levels_currentLevel(Levels *self)
229 return List_top(self->stack);
232 void Levels_popDownTo(Levels *self, int targetLevel)
234 Level *level;
236 while (level = List_top(self->stack), level->precedence <= targetLevel && level->type != ARG)
238 Level_finish(List_pop(self->stack));
239 self->currentLevel--;
243 void Levels_attachToTopAndPush(Levels *self, IoMessage *msg, int precedence)
245 Level *level = NULL;
247 Level *top = List_top(self->stack);
248 Level_attachAndReplace(top, msg);
252 // TODO: Check for overflow of the pool.
253 if (self->currentLevel >= IO_OP_MAX_LEVEL)
255 IoState_error_(IoObject_state(msg), NULL, "compile error: Overflowed operator stack. Only %d levels of operators currently supported.", IO_OP_MAX_LEVEL-1);
258 level = &self->pool[self->currentLevel++];
259 Level_setAwaitingFirstArg(level, msg, precedence);
260 List_append_(self->stack, level);
264 void Level_finish(Level *self)
266 if (self->message)
268 IoMessage_rawSetNext(self->message, NULL);
270 // Remove extra () we added in for operators, but don't need any more
271 if ( IoMessage_argCount(self->message) == 1 )
273 IoMessage *arg = IoMessage_rawArgAt_(self->message, 0);
275 if ( IoSeq_rawSize(IoMessage_name(arg)) == 0 && IoMessage_argCount(arg) == 1 && IoMessage_rawNext(arg) == NULL )
277 List_copy_(IoMessage_rawArgList(self->message), IoMessage_rawArgList(arg));
278 List_removeAll(IoMessage_rawArgList(arg));
283 self->type = UNUSED;
286 void Level_attach(Level *self, IoMessage *msg)
288 switch (self->type)
290 case ATTACH:
291 IoMessage_rawSetNext(self->message, msg);
292 break;
294 case ARG:
295 IoMessage_addArg_(self->message, msg);
296 break;
298 case NEW:
299 self->message = msg;
300 break;
302 case UNUSED:
303 break;
307 void Level_attachAndReplace(Level *self, IoMessage *msg)
309 Level_attach(self, msg);
310 self->type = ATTACH;
311 self->message = msg;
314 void Level_setAwaitingFirstArg(Level *self, IoMessage *msg, int precedence)
316 self->type = ARG;
317 self->message = msg;
318 self->precedence = precedence;
321 void Level_setAlreadyHasArgs(Level *self, IoMessage *msg)
323 self->type = ATTACH;
324 self->message = msg;
327 int Levels_levelForOp(Levels *self, char *messageName, IoSymbol *messageSymbol, IoMessage *msg)
329 IoObject *value = IoMap_rawAt(self->operatorTable, messageSymbol);
331 if (!value)
333 return -1;
336 if (ISNUMBER(value))
338 return IoNumber_asInt((IoNumber*)value);
340 else
342 IoState_error_(IoObject_state(msg), msg, "compile error: Value for '%s' in Message OperatorTable operators is not a number. Values in the OperatorTable operators are numbers which indicate the precedence of the operator.", messageName);
343 return -1; // To keep the compiler happy.
347 int Levels_isAssignOperator(Levels *self, IoSymbol *operator)
349 return IoMap_rawAt(self->assignOperatorTable, operator) != NULL;
352 IoSymbol *Levels_nameForAssignOperator(Levels *self, IoState *state, IoSymbol *operator, IoSymbol *slotName, IoMessage *msg)
354 IoObject *value = IoMap_rawAt(self->assignOperatorTable, operator);
355 char *operatorString = CSTRING(operator);
357 if (value != NULL && ISSYMBOL(value))
359 if (strcmp(operatorString, ":=") == 0 && isupper(CSTRING(slotName)[0]))
361 return state->setSlotWithTypeSymbol;
363 else
365 return value;
368 else
370 IoState_error_(IoObject_state(msg), msg, "compile error: Value for '%s' in Message OperatorTable assignOperators is not a symbol. Values in the OperatorTable assignOperators are symbols which are the name of the operator.", operatorString);
371 return NULL; // To keep the compiler happy.
375 void Levels_attach(Levels *self, IoMessage *msg, List *expressions)
377 // TODO clean up this method.
379 IoState *state = IoObject_state(msg);
380 IoSymbol *messageSymbol = IoMessage_name(msg);
381 char *messageName = CSTRING(messageSymbol);
382 int precedence = Levels_levelForOp(self, messageName, messageSymbol, msg);
384 int msgArgCount = IoMessage_argCount(msg);
386 // `o a := b c ; d` becomes `o setSlot("a", b c) ; d`
388 // a attaching
389 // := msg
390 // b c msg->next
392 if (Levels_isAssignOperator(self, messageSymbol))
394 Level *currentLevel = Levels_currentLevel(self);
395 IoMessage *attaching = currentLevel->message;
396 IoSymbol *setSlotName;
398 if (attaching == NULL) // `:= b ;`
400 // Could be handled as, message(:= 42) -> setSlot(nil, 42)
402 IoState_error_(state, msg, "compile error: %s requires a symbol to its left.", messageName);
405 if (IoMessage_argCount(attaching) > 0) // `a(1,2,3) := b ;`
407 IoState_error_(state, msg, "compile error: The symbol to the left of %s cannot have arguments.", messageName);
412 // `a := b ;`
413 IoSymbol *slotName = DATA(attaching)->name;
414 IoSymbol *quotedSlotName = IoSeq_newSymbolWithFormat_(state, "\"%s\"", CSTRING(slotName));
415 IoMessage *slotNameMessage = IoMessage_newWithName_returnsValue_(state, quotedSlotName, slotName);
417 // `a := b ;` -> `a("a") := b ;`
418 IoMessage_addArg_(attaching, slotNameMessage);
420 setSlotName = Levels_nameForAssignOperator(self, state, messageSymbol, slotName, msg);
423 // `a("a") := b ;` -> `setSlot("a") := b ;`
424 DATA(attaching)->name = IoObject_addingRef_(attaching, setSlotName);
426 currentLevel->type = ATTACH;
428 if (msgArgCount > 1) // `setSlot("a") :=(b, c, d) e ;`
430 IoState_error_(state, msg, "compile error: Assign operator passed multiple arguments, e.g., a := (b, c).", messageName);
433 if (msgArgCount > 0) // `setSlot("a") :=(b c) d e ;`
435 // `b c`
436 IoMessage *arg = IoMessage_rawArgAt_(msg, 0);
438 if (DATA(msg)->next == NULL || IoMessage_rawIsEOL(DATA(msg)->next))
440 IoMessage_addArg_(attaching, arg);
442 else
444 // `()`
445 IoMessage *foo = IoMessage_newWithName_(state, IoState_symbolWithCString_(state, ""));
447 // `()` -> `(b c)`
448 IoMessage_addArg_(foo, arg);
450 // `(b c)` -> `(b c) d e ;`
451 IoMessage_rawSetNext(foo, DATA(msg)->next);
453 // `setSlot("a") :=(b c) d e ;` -> `setSlot("a", (b c) d e ;) :=(b c) d e ;`
454 IoMessage_addArg_(attaching, foo);
457 else // `setSlot("a") := b ;`
459 // `setSlot("a") :=` or `setSlot("a") := ;`
460 IoMessage *mn = DATA(msg)->next;
461 IoSymbol *name = mn ? DATA(mn)->name : NULL;
462 IoSymbol *semi = IoObject_state(msg)->semicolonSymbol;
464 //if (mn == NULL || IoMessage_rawIsEOL(mn))
465 if (mn == NULL || name == semi)
467 IoState_error_(state, msg, "compile error: %s must be followed by a value.", messageName);
470 // `setSlot("a") := b c ;` -> `setSlot("a", b c ;) := b c ;`
471 IoMessage_addArg_(attaching, DATA(msg)->next);
474 // process the value (`b c d`) later (`setSlot("a", b c d) := b c d ;`)
475 if (DATA(msg)->next != NULL && !IoMessage_rawIsEOL(DATA(msg)->next))
477 List_push_(expressions, DATA(msg)->next);
481 IoMessage *last = msg;
482 while (DATA(last)->next != NULL && !IoMessage_rawIsEOL(DATA(last)->next))
484 last = DATA(last)->next;
487 IoMessage_rawSetNext(attaching, DATA(last)->next);
489 // Continue processing in IoMessage_opShuffle loop
490 IoMessage_rawSetNext(msg, DATA(last)->next);
492 if (last != msg)
494 IoMessage_rawSetNext(last, NULL);
498 // make sure b in `1 := b` gets executed
499 IoMessage_cachedResult_(attaching, NULL);
501 else if (IoMessage_rawIsEOL(msg))
503 Levels_popDownTo(self, IO_OP_MAX_LEVEL-1);
504 Level_attachAndReplace(Levels_currentLevel(self), msg);
506 else if (precedence != -1) // is an operator
508 if (msgArgCount > 0)
510 // move arguments off to their own message to make () after operators behave like C's grouping ()
511 IoMessage *brackets = IoMessage_newWithName_(state, IoState_symbolWithCString_(state, ""));
513 List_copy_(IoMessage_rawArgList(brackets), IoMessage_rawArgList(msg));
514 List_removeAll(IoMessage_rawArgList(msg));
516 // Insert the brackets message between msg and it's next message
517 IoMessage_rawSetNext(brackets, DATA(msg)->next);
518 IoMessage_rawSetNext(msg, brackets);
521 Levels_popDownTo(self, precedence);
522 Levels_attachToTopAndPush(self, msg, precedence);
524 else
526 Level_attachAndReplace(Levels_currentLevel(self), msg);
530 void Levels_nextMessage(Levels *self)
532 Level *level;
534 while ((level = List_pop(self->stack)))
536 Level_finish(level);
539 Levels_reset(self);
542 void IoMessage_opShuffle_(IoMessage *self)
544 if (IoObject_rawGetSlot_(self, IOSTATE->opShuffleSymbol) && IoMessage_name(self) != IOSTATE->noShufflingSymbol)
546 IoMessage_locals_performOn_(IOSTATE->opShuffleMessage, IOSTATE->lobby, self);
550 IoMessage *IoMessage_opShuffle(IoMessage *self, IoObject *locals, IoMessage *m)
552 Levels *levels = Levels_new(self);
553 List *expressions = List_new();
555 List_push_(expressions, self);
557 while (List_size(expressions) >= 1)
559 IoMessage *n = List_pop(expressions);
563 Levels_attach(levels, n, expressions);
564 List_appendSeq_(expressions, DATA(n)->args);
565 } while (n = DATA(n)->next);
567 Levels_nextMessage(levels);
570 List_free(expressions);
571 Levels_free(levels);
573 return self;