Initial commit
[minnow.git] / src / minnow / parser.cpp
blob742abffcf88b14e4b9171594d6dcb5709d425786
1 #include <iostream>
3 #include "lexer.hpp"
4 #include "parser.hpp"
6 const int EQUATE_PREC = 2;
7 const int MSG_PREC = 4;
8 const int COMMA_GROUP_PREC = 5;
9 const int SCOPE_PREC = 6;
10 const int COMPARE_PREC = 10;
11 const int ADD_SUB_PREC = 20;
12 const int MULT_DIV_PREC = 30;
13 const int POWER_PREC = 40;
15 TypeInfo parse_typesig(std::vector<Token*>::iterator &iter,
16 std::vector<Token*>::iterator &end) {
18 TypeInfo ti;
19 if (iter == end) {
20 throw CompilerException("Incomplete type signature", *(--iter));
22 ti.declType = (*iter)->data;
24 ++iter;
26 if ((*iter)->data == "[") {
27 ++iter;
28 if (iter == end) {
29 throw CompilerException("Incomplete type signature", *(--iter));
31 if ((*iter)->data != "]") {
32 throw CompilerException("Unsupported type signature", *(--iter));
34 ++iter;
35 ti.containerType = ContainerType::Array;
37 TypeInfo containedType;
38 containedType.declType = ti.declType;
39 containedType.containerType = ContainerType::Scalar;
40 ti.containedTypes.push_back(containedType);
43 if (iter == end) {
44 throw CompilerException("Incomplete type signature", *(--iter));
47 return ti;
50 VarDeclExprAST* parse_variable_decl(std::vector<Token*>::iterator &iter,
51 std::vector<Token*>::iterator &end) {
53 bool isSpawn = false;
54 bool isAlloc = false;
56 VariableInfo *vi = new VariableInfo();
57 VarDeclExprAST *returnVal = NULL;
59 if (iter == end) {
60 throw CompilerException("Expected variable declaration", *(--iter));
63 if ((*iter)->data == "var") {
64 //nothing
65 ++iter;
67 //FIXME: this is the _old_ style
68 else if ((*iter)->data == "spawn") {
69 isSpawn = true;
70 ++iter;
72 else if ((*iter)->data == "new") {
73 isAlloc = true;
74 ++iter;
77 vi->type = parse_typesig(iter, end);
78 if ((*iter)->tokenType != TokenType::Id) {
79 std::ostringstream msg;
80 msg << "Invalid variable declaration for '" << (*iter)->data << "'";
81 throw CompilerException(msg.str(), *iter);
82 //throw CompilerException("Invalid variable declaration", *(iter));
84 vi->name = (*iter)->data;
86 returnVal = new VarDeclExprAST(vi, isSpawn, isAlloc);
87 returnVal->filepos = (*iter)->pos;
88 ++iter;
90 if (iter != end) {
91 if ((*iter)->data == "[") {
92 ++iter;
93 if (iter == end) {
94 throw CompilerException("Incomplete default size", *(--iter));
96 vi->size = parse_expression(iter, end);
98 vi->type.containerType = ContainerType::Array;
100 TypeInfo containedInfo;
101 containedInfo.containerType = ContainerType::Scalar;
102 containedInfo.declType = vi->type.declType;
103 vi->type.containedTypes.push_back(containedInfo);
105 if ((*iter)->data != "]") {
106 throw CompilerException("Incomplete default size", *(--iter));
108 ++iter;
112 return returnVal;
115 int get_precedence(const std::string &op) {
116 int binPrec = -1;
117 if (( op == "<") || ( op == ">") || (op == ">=") || (op == "<=") ||
118 (op == "==") || (op == "!=") ) {
120 binPrec = COMPARE_PREC;
122 else if (( op == "+") || ( op == "-")) {
123 binPrec = ADD_SUB_PREC;
125 else if (( op == "*") || ( op == "/")) {
126 binPrec = MULT_DIV_PREC;
128 else if ( op == "^") {
129 binPrec = POWER_PREC;
131 else if ( op == "=") {
132 binPrec = EQUATE_PREC;
134 else if ( (op == "!") || (op == "::") ) {
135 binPrec = MSG_PREC;
137 else if ( op == ".") {
138 binPrec = SCOPE_PREC;
140 else if ( op == ",") {
141 binPrec = COMMA_GROUP_PREC;
144 return binPrec;
147 ASTNode *parse_parens(std::vector<Token*>::iterator &iter,
148 std::vector<Token*>::iterator &end) {
149 ASTNode *returnVal;
150 ++iter;
151 if (iter == end) {
152 throw CompilerException("Unclosed parentheses", *(--iter));
154 else {
155 returnVal = parse_expression(iter, end);
156 returnVal->filepos = (*iter)->pos;
157 if ((*iter)->data != ")") {
158 throw CompilerException("Unclosed parentheses", *(--iter));
160 else {
161 ++iter;
165 return returnVal;
168 ASTNode *parse_array_index(std::vector<Token*>::iterator &iter,
169 std::vector<Token*>::iterator &end) {
170 ASTNode *returnVal;
171 ++iter;
172 if (iter == end) {
173 throw CompilerException("Unclosed square brackets", *(--iter));
175 else {
176 returnVal = parse_expression(iter, end);
177 returnVal->filepos = (*iter)->pos;
178 if ((*iter)->data != "]") {
179 throw CompilerException("Unclosed square brackets", *(--iter));
181 else {
182 ++iter;
186 return returnVal;
189 ASTNode *parse_fun_call(std::vector<Token*>::iterator &iter,
190 std::vector<Token*>::iterator &end) {
191 ASTNode *returnVal = NULL;
192 std::string name;
193 std::vector<ASTNode*> args;
194 std::vector<ASTNode*> unwinder;
196 name = (*iter)->data;
197 ++iter;
198 if ((iter == end) || ((*iter)->data != "(")) {
199 --iter;
200 throw CompilerException("Internal integrity error relating to function calls", *iter);
202 ++iter;
203 if (iter == end) {
204 throw CompilerException("Expecting ')' for function call", *iter);
206 while (((*iter)->data != ")") && (iter != end)) {
207 args.push_back(parse_expression(iter, end));
210 if (iter != end) {
211 //skip the trailing ')'
212 ++iter;
215 //what we have is probably a tree of args, but we want a flat list, so fix it
216 if (args.size() == 1) {
217 BinaryExprAST *beast = dynamic_cast<BinaryExprAST*>(args[0]);
218 ASTNode *LHS;
219 if ((beast != NULL) && (beast->op == ",")) {
220 while ((beast != NULL) && (beast->op == ",")) {
221 unwinder.push_back(beast->children[1]);
222 LHS = beast->children[0];
223 beast = dynamic_cast<BinaryExprAST*>(LHS);
225 unwinder.push_back(LHS);
227 else {
228 unwinder.push_back(args[0]);
231 args.clear();
232 for (std::vector<ASTNode*>::reverse_iterator riter=unwinder.rbegin(),
233 rend=unwinder.rend(); riter != rend; ++riter) {
234 args.push_back(*riter);
237 returnVal = new CallExprAST(name);
238 returnVal->children.swap(args);
240 returnVal->filepos = (*iter)->pos;
242 return returnVal;
245 ASTNode *parse_if_block(std::vector<Token*>::iterator &iter, std::vector<Token*>::iterator &end) {
246 IfExprAST *returnVal = new IfExprAST();
247 returnVal->filepos = (*iter)->pos;
249 ++iter;
250 if (iter == end) {
251 throw CompilerException("Expected if block", *(--iter));
254 returnVal->children.push_back(parse_expression(iter, end));
256 BlockAST *thenBlock = new BlockAST();
257 while ((iter != end) && ((*iter)->data != "end") && ((*iter)->data != "else")) {
258 thenBlock->children.push_back(parse_expression(iter, end));
260 returnVal->children.push_back(thenBlock);
262 if (iter == end) {
263 throw CompilerException("Expected 'end' to end if block", *(--iter));
266 BlockAST *elseBlock = new BlockAST();
267 if ((*iter)->data == "else") {
268 ++iter;
269 while ((iter != end) && ((*iter)->data != "end")) {
270 elseBlock->children.push_back(parse_expression(iter, end));
273 returnVal->children.push_back(elseBlock);
275 if (iter == end) {
276 throw CompilerException("Expected 'end' to end if block", *(--iter));
278 else {
279 ++iter;
282 return returnVal;
285 ASTNode *parse_while_block(std::vector<Token*>::iterator &iter,
286 std::vector<Token*>::iterator &end) {
288 WhileExprAST *returnVal = new WhileExprAST();
289 returnVal->filepos = (*iter)->pos;
291 ++iter;
292 if (iter == end) {
293 throw CompilerException("Expected while block", *(--iter));
296 returnVal->children.push_back(parse_expression(iter, end));
298 BlockAST *loopBlock = new BlockAST();
299 while ((iter != end) && ((*iter)->data != "end")) {
300 ASTNode *ast = parse_expression(iter, end);
301 loopBlock->children.push_back(ast);
303 returnVal->children.push_back(loopBlock);
305 if (iter == end) {
306 throw CompilerException("Expected 'end' to end while block", *(--iter));
308 else {
309 ++iter;
312 return returnVal;
316 ASTNode *parse_primary(std::vector<Token*>::iterator &iter,
317 std::vector<Token*>::iterator &end) {
318 ASTNode *returnVal = NULL;
319 ASTNode *index = NULL;
320 double val;
321 bool boolval;
323 std::string name, type;
325 switch ((*iter)->tokenType) {
326 case (TokenType::Num):
327 val = atof((*iter)->data.c_str());
328 returnVal = new NumberExprAST(val);
329 returnVal->filepos = (*iter)->pos;
330 ++iter;
331 break;
332 case (TokenType::String):
333 returnVal = new QuoteExprAST((*iter)->data);
334 returnVal->filepos = (*iter)->pos;
335 ++iter;
336 break;
337 case (TokenType::Id):
338 if ((*iter)->data == "end") {
339 returnVal = new EndExprAST();
340 returnVal->filepos = (*iter)->pos;
342 else if ((*iter)->data == "var") {
343 returnVal = parse_variable_decl(iter, end);
345 else if ((*iter)->data == "spawn") {
346 returnVal = parse_variable_decl(iter, end);
348 else if ((*iter)->data == "new") {
349 returnVal = parse_variable_decl(iter, end);
351 else if ((*iter)->data == "if") {
352 returnVal = parse_if_block(iter, end);
354 else if ((*iter)->data == "while") {
355 returnVal = parse_while_block(iter, end);
358 else if ((*iter)->data == "receive") {
359 returnVal = parseDataRecvBlock(iter, end);
362 else {
363 name = (*iter)->data;
364 ++iter;
366 if (iter == end) {
367 returnVal = new VariableExprAST(name);
368 returnVal->filepos = (*iter)->pos;
370 else {
371 if ((*iter)->data == "(") {
372 --iter;
373 returnVal = parse_fun_call(iter, end);
375 else if ((*iter)->data == "[") {
376 index = parse_array_index(iter, end);
377 returnVal = new ArrayIndexedExprAST(name, index);
378 returnVal->filepos = (*iter)->pos;
380 else {
381 returnVal = new VariableExprAST(name);
382 returnVal->filepos = (*iter)->pos;
386 break;
387 case (TokenType::EOL):
388 ++iter;
389 break;
390 case (TokenType::Symbol):
391 if ((*iter)->data == "(") {
392 returnVal = parse_parens(iter, end);
395 else if ((*iter)->data == "@") {
396 returnVal = parsePointcut(iter, end);
399 else {
400 //std::cout << "Element: " << (*iter)->data << std::endl;
401 throw CompilerException("Unknown symbol", *iter);
403 break;
404 case (TokenType::Bool):
405 if ((*iter)->data == "true") {
406 boolval = true;
408 else if ((*iter)->data == "false") {
409 boolval = false;
411 else {
412 throw CompilerException("Unknown boolean value", *iter);
414 returnVal = new BooleanExprAST(boolval);
415 returnVal->filepos = (*iter)->pos;
416 ++iter;
418 break;
419 default:
420 std::ostringstream msg;
421 msg << "Unknown token type:" << (*iter)->tokenType;
422 throw CompilerException(msg.str(), *iter);
425 return returnVal;
428 ASTNode *parse_binary_op(std::vector<Token*>::iterator &iter,
429 std::vector<Token*>::iterator &end, int currPrec, ASTNode *expr) {
431 //This uses Chris Lattner's cool precedence parsing trick
432 //For more information see his kaleidoscope tutorial on the llvm website
433 int binPrec;
434 //let's see if what we're sitting on is a math symbol
435 while (iter != end) {
436 std::string op = (*iter)->data;
437 binPrec = get_precedence(op);
438 if (binPrec < currPrec) {
439 //the next symbol in line is lower precedence than we need
440 return expr;
442 ++iter;
443 if (iter != end) {
444 //check the precedence of the next hop
445 ASTNode *rhs = parse_primary(iter, end);
446 if (rhs == NULL) {
447 throw CompilerException("Incomplete math equation", *iter);
450 //++iter;
452 if (iter != end) {
453 std::string op = (*iter)->data;
454 int nextPrec = get_precedence(op);
456 //std::cout << "Outside dive: " << (*iter)->data << " " << binPrec << " " << nextPrec << std::endl;
457 if (binPrec < nextPrec) {
458 //--iter;
459 //std::cout << "Diving in: " << (*iter)->data << std::endl;
460 rhs = parse_binary_op(iter, end, binPrec+1, rhs);
463 expr = new BinaryExprAST(op, expr, rhs);
464 expr->filepos = (*iter)->pos;
467 else {
468 throw CompilerException("Incomplete math equation", *(--iter));
471 return expr;
474 ASTNode *parse_expression(std::vector<Token*>::iterator &iter, std::vector<Token*>::iterator &end) {
475 ASTNode *lhs = parse_primary(iter, end);
476 if (lhs != NULL) {
477 return parse_binary_op(iter, end, 0, lhs);
479 else {
480 return NULL;
483 while (((*iter)->tokenType == TokenType::EOL) && (iter != end)) {
484 //skip EOL chars
485 ++iter;
489 PrototypeAST* parse_prototype(std::vector<Token*>::iterator &iter,
490 std::vector<Token*>::iterator &end) {
491 PrototypeAST* returnVal = new PrototypeAST();
492 returnVal->filepos = (*iter)->pos;
494 //parse the return type
495 returnVal->returnType = parse_typesig(iter, end);
497 if ((*iter)->data == "(") {
498 returnVal->name = returnVal->returnType.declType;
499 returnVal->returnType.declType = "void";
501 else {
502 returnVal->name = (*iter)->data;
503 ++iter;
504 if (iter == end) {
505 throw CompilerException("Expected prototype definition", *(--iter));
509 if ((*iter)->data == "(") {
510 ++iter;
512 else {
513 throw CompilerException("Incomplete function definition", *iter);
516 if (iter == end) {
517 throw CompilerException("Incomplete function definition", *iter);
520 while (((*iter)->data != ")") && (iter != end)) {
521 returnVal->children.push_back(parse_variable_decl(iter, end));
522 if ((iter != end) && ((*iter)->data == ",")) {
523 ++iter;
527 if (iter != end) {
528 //skip the trailing ')'
529 ++iter;
531 return returnVal;
534 FunctionAST* parse_function(std::vector<Token*>::iterator &iter,
535 std::vector<Token*>::iterator &end) {
537 FunctionAST* returnVal = NULL;
539 if ((iter != end) && ((*iter)->data == "extern")) {
540 ++iter;
541 if (iter != end) {
542 returnVal = new FunctionAST();
543 returnVal->filepos = (*iter)->pos;
544 PrototypeAST *proto = parse_prototype(iter, end);
545 if (proto == NULL) {
546 throw CompilerException("Expecting external function definition", *iter);
548 proto->isExtern = true;
549 returnVal->children.push_back(proto);
550 returnVal->children.push_back(new BlockAST()); //add the code empty code block for consistency
553 else if ((iter != end) && ((*iter)->data == "def")) {
554 //we may be at a definition
555 ++iter;
556 if (iter != end) {
557 returnVal = new FunctionAST();
558 returnVal->filepos = (*iter)->pos;
560 PrototypeAST *proto = parse_prototype(iter, end);
561 if (proto == NULL) {
562 throw CompilerException("Expecting function definition", *iter);
564 proto->isExtern = false;
565 returnVal->children.push_back(proto);
567 BlockAST *bodyBlock = new BlockAST();
568 ASTNode *ast = parse_expression(iter, end);
569 while (iter != end) {
570 if (ast != NULL) {
571 if (ast->type() == NodeType::End) {
572 ++iter;
573 break;
575 else {
576 bodyBlock->children.push_back(ast);
579 ast = parse_expression(iter, end);
581 returnVal->children.push_back(bodyBlock);
585 return returnVal;
588 ActionAST* parse_action(std::vector<Token*>::iterator &iter,
589 std::vector<Token*>::iterator &end) {
591 ActionAST* returnVal = NULL;
593 if ((iter != end) && ((*iter)->data == "action")) {
594 //we may be at a definition
595 ++iter;
596 if (iter != end) {
597 returnVal = new ActionAST();
598 returnVal->filepos = (*iter)->pos;
600 PrototypeAST *proto = parse_prototype(iter, end);
601 if (proto == NULL) {
602 throw CompilerException("Expecting function definition", *iter);
604 proto->isExtern = false;
605 returnVal->children.push_back(proto);
607 BlockAST *bodyBlock = new BlockAST();
608 ASTNode *ast = parse_expression(iter, end);
609 while (iter != end) {
610 if (ast != NULL) {
611 if (ast->type() == NodeType::End) {
612 ++iter;
613 break;
615 else {
616 bodyBlock->children.push_back(ast);
619 ast = parse_expression(iter, end);
621 returnVal->children.push_back(bodyBlock);
625 return returnVal;
628 ClassAST* parse_class(std::vector<Token*>::iterator &iter,
629 std::vector<Token*>::iterator &end) {
631 ClassAST *returnVal = NULL;
633 if ((iter != end) && ((*iter)->data == "class")) {
634 ++iter;
635 if (iter != end) {
636 returnVal = new ClassAST();
637 returnVal->name = (*iter)->data;
638 returnVal->filepos = (*iter)->pos;
640 ++iter;
641 while ((iter != end) && ((*iter)->data != "end")) {
642 if ((*iter)->data == "def") {
643 FunctionAST *fun = parse_function(iter, end);
644 if (fun != NULL) {
645 returnVal->children.push_back(fun);
648 else if ((*iter)->tokenType == TokenType::Id) {
649 VarDeclExprAST *varDecl = parse_variable_decl(iter, end);
650 if (varDecl != NULL) {
651 //FIXME: Check for duplicate definitions
652 returnVal->children.push_back(varDecl);
654 else {
655 throw CompilerException("Unknown element in class", *(--iter));
658 else {
659 //FIXME: Not sure if this is correct
660 if (iter != end) {
661 ++iter;
666 if (iter == end) {
667 throw CompilerException("Expected 'end' at end of class", *(--iter));
669 else {
670 ++iter;
675 return returnVal;
678 ActorAST* parse_actor(std::vector<Token*>::iterator &iter,
679 std::vector<Token*>::iterator &end) {
681 ActorAST *returnVal = NULL;
682 bool isIsolated = false;
684 if ((iter != end) && ((*iter)->data == "isolated")) {
685 isIsolated = true;
686 ++iter;
689 if ((iter != end) && ((*iter)->data == "actor")) {
690 ++iter;
691 if (iter != end) {
692 returnVal = new ActorAST(isIsolated);
693 returnVal->filepos = (*iter)->pos;
694 returnVal->name = (*iter)->data;
696 ++iter;
697 while ((iter != end) && ((*iter)->data != "end")) {
698 if ((*iter)->data == "def") {
699 FunctionAST *fun = parse_function(iter, end);
700 if (fun != NULL) {
701 returnVal->children.push_back(fun);
704 else if ((*iter)->data == "action") {
705 ActionAST *act = parse_action(iter, end);
706 if (act != NULL) {
707 returnVal->children.push_back(act);
710 else if ((*iter)->tokenType == TokenType::Id){
711 //std::cout << "Var decl enter" << std::endl;
712 VarDeclExprAST *varDecl = parse_variable_decl(iter, end);
713 //std::cout << "Var decl leave" << std::endl;
714 if (varDecl != NULL) {
715 //FIXME: Check for duplicate definitions
716 returnVal->children.push_back(varDecl);
718 else {
719 throw CompilerException("Unknown element in class", *(--iter));
722 else {
723 //FIXME: Not sure if this is correct
724 if (iter != end) {
725 ++iter;
730 if (iter == end) {
731 throw CompilerException("Expected 'end' at end of class", *(--iter));
733 else {
734 ++iter; //skip over "end"
739 return returnVal;
742 AppAST* parse(std::vector<Token*>::iterator &iter,
743 std::vector<Token*>::iterator &end) {
745 AppAST *returnVal;
746 ASTNode *child;
748 returnVal = new AppAST();
749 returnVal->filepos = (*iter)->pos;
751 while (iter != end) {
752 child = parse_function(iter, end);
753 if (child != NULL) {
754 //std::cout << "Pushing function" << std::endl;
755 returnVal->children.push_back(child);
756 continue;
758 child = parse_class(iter, end);
759 if (child != NULL) {
760 //std::cout << "Pushing class" << std::endl;
761 returnVal->children.push_back(child);
762 continue;
764 child = parse_actor(iter, end);
765 if (child != NULL) {
766 //std::cout << "Pushing actor" << std::endl;
767 returnVal->children.push_back(child);
768 continue;
770 child = parse_action(iter, end);
771 if (child != NULL) {
772 //std::cout << "Pushing action" << std::endl;
773 returnVal->children.push_back(child);
774 continue;
777 if ((*iter)->tokenType == TokenType::EOL) {
778 ++iter;
780 else {
781 std::ostringstream msg;
782 msg << "Unknown element '" << (*iter)->data << "' of type " << (*iter)->tokenType;
783 throw CompilerException(msg.str(), *iter);
787 return returnVal;