Skip to content

Commit 6891cbd

Browse files
committed
added parser support for multi-expression function bodies
1 parent cc74446 commit 6891cbd

7 files changed

Lines changed: 123 additions & 17 deletions

File tree

examples/program1.txt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,20 @@ X MUTABLE = F * A 4.5 2.3
1111
E = func (x Float, y Float) Float -> C 77.0 88.0
1212
F2 Float = E 9.1 X
1313

14+
# Next up: Allow more than one expression in a function body
15+
G = func (x Int) Int ->
16+
y = x * 9 \ # ... Do not stop at the next NewLine
17+
+ 5 # expr: y = x * 9 + 5
18+
y / 4 - 92 # return: expr: y / 4 - 92
19+
20+
H = G 45
21+
22+
23+
# Todo: Control flow: if
24+
# Todo: Control flow: for
25+
# Todo: Control flow: while
26+
27+
1428
#E Float = D 3.1 # Should fail since D is not a callable
1529

1630
## A function definition
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Next up: Allow more than one expression in a function body
2+
#A = func (x Int) Int -> 12
3+
G = func (x Int) Int ->
4+
y = x * 9 \ # ... Do not stop at the next NewLine
5+
+ 5 # expr: y = x * 9 + 5
6+
y / 4 - 92 # return: expr: y / 4 - 92
7+
8+
H = G 45
9+
10+
# Todo: Control flow: if
11+
# Todo: Control flow: for
12+
# Todo: Control flow: while

src/codegen/_VisitorImplHeader.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ using namespace llvm;
2020
// String formatting helper.
2121
// std::string R_FMT(any << ..)
2222
//
23-
static std::ostringstream* _r_fmt_begin() { return new std::ostringstream; }
24-
static std::string _r_fmt_end(std::ostringstream* s) {
23+
static std::ostringstream* __attribute__((unused)) _r_fmt_begin() { return new std::ostringstream; }
24+
static std::string __attribute__((unused)) _r_fmt_end(std::ostringstream* s) {
2525
std::string str = s->str();
2626
delete s;
2727
return str;

src/main.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ int main(int argc, char **argv) {
4141
return 1;
4242
}
4343
std::cout << "Parsed module: " << moduleFunc->body()->toString() << std::endl;
44+
return 0; // xxx
4445

4546
// Generate code
4647
codegen::Visitor codegenVisitor;

src/parse/Parser.h

Lines changed: 88 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,15 @@
33
#define RSMS_PARSER_H
44

55
#include "TokenBuffer.h"
6+
#include "../Logger.h"
67
#include "../ast/Node.h"
78
#include "../ast/Block.h"
89
#include "../ast/Expression.h"
910
#include "../ast/Function.h"
1011

1112
#include <vector>
1213

13-
#define DEBUG_PARSER 0
14+
#define DEBUG_PARSER 1
1415
#if DEBUG_PARSER
1516
#include "../DebugTrace.h"
1617
#define DEBUG_TRACE_PARSER DEBUG_TRACE
@@ -29,9 +30,11 @@ static int BinaryOperatorPrecedence(const Token& token) {
2930
return -1;
3031
switch (token.stringValue[0]) {
3132
case '*': return 40;
33+
case '/': return 40;
3234
case '-': return 20;
3335
case '+': return 20;
3436
case '<': return 10;
37+
case '>': return 10;
3538
default: return -1;
3639
}
3740
}
@@ -60,6 +63,7 @@ class Parser {
6063
uint32_t previousLineIndentation_ = 0;
6164
uint32_t currentLineIndentation_ = 0;
6265

66+
std::vector<Token> recentComments_;
6367
std::vector<std::string> errors_;
6468
//std::vector<std::string> warnings_;
6569
//std::vector<std::string> notices_;
@@ -429,12 +433,42 @@ class Parser {
429433
return (Function*)error("Expected '->' after function interface");
430434
}
431435
nextToken(); // eat '->'
436+
437+
// Is this potentially a multi-expression function body?
438+
uint32_t bodyStartedAtLineIndentation = UINT32_MAX;
439+
if (token_.type == Token::NewLine) {
440+
rlog("Yup, potentially a multi-expression func body ahead. line ind (prev/curr): "
441+
<< previousLineIndentation_ << '/' << currentLineIndentation_);
442+
bodyStartedAtLineIndentation = currentLineIndentation_;
443+
}
432444

433445
// Parse function body
434-
Expression *body = parseExpression();
435-
if (body == 0) {
436-
delete interface;
437-
return 0;
446+
Block* body = new Block;
447+
448+
while (1) {
449+
// Read one expression
450+
Expression *expr = parseExpression();
451+
if (expr == 0) {
452+
delete interface;
453+
return 0;
454+
}
455+
456+
// Add the expression to the function body
457+
body->addNode(expr);
458+
459+
// If we know this is a single-expression body, break after the first expression
460+
if (bodyStartedAtLineIndentation == UINT32_MAX) {
461+
rlog("Body ended (single-expression body)");
462+
break;
463+
} else {
464+
465+
// Body ends when we either get a non-newline (e.g. a terminating) token, or the
466+
// line indentation drops below the first line of the body
467+
if (token_.type != Token::NewLine || currentLineIndentation_ < bodyStartedAtLineIndentation) {
468+
rlog("Body ended (" << (token_.type != Token::NewLine ? "line indent drop" : "terminating token") << ")");
469+
break;
470+
}
471+
}
438472
}
439473

440474
return new Function(interface, body);
@@ -491,6 +525,14 @@ class Parser {
491525
Expression *lhs = parsePrimary();
492526
if (!lhs) return 0;
493527

528+
//// Backslash means "ignore the following sequence of linebreaks and comments
529+
//// and treat whatever is after it as the same line"
530+
//if (token_.type == Token::Backslash) {
531+
// // Eat <comment>*<LF><comment>* and continue
532+
// while (nextToken(/* newLineUpdatesLineIndentation = */false).type == Token::NewLine
533+
// || token_.type == Token::Comment ) {}
534+
//}
535+
494536
if (token_.type == Token::BinaryOperator) {
495537
// LHS binop RHS
496538
return parseBinOpRHS(0, lhs);
@@ -501,12 +543,11 @@ class Parser {
501543
if (!assignment) delete lhs;
502544
return assignment;
503545
} else if (token_.type == Token::Unexpected) {
504-
error("Unexpected token when expecting a left-hand side expression");
546+
error("Unexpected token when expecting a left-hand-side expression");
505547
nextToken(); // Skip token for error recovery.
506548
delete lhs;
507549
return 0;
508550
} else {
509-
// LHS
510551
return lhs;
511552
}
512553
}
@@ -561,12 +602,23 @@ class Parser {
561602
nextToken();
562603
goto entry;
563604
}
564-
default: return error("Unexpected token when expecting an expression");
605+
default: return error("Unexpected token when expecting: id|intlit|floatlit|func|external|comment|newline");
565606
}
566607
}
567608

568609
// ------------------------------------------------------------------------
569610

611+
inline const Token& _nextToken() {
612+
if (token_.isNull()) {
613+
token_ = const_cast<Token&>(tokens_.next());
614+
futureToken_ = const_cast<Token&>(tokens_.next());
615+
} else {
616+
token_ = futureToken_;
617+
futureToken_ = const_cast<Token&>(tokens_.next());
618+
}
619+
return token_;
620+
}
621+
570622
// nextToken() -- Advances the token stream one token forward and returns
571623
// the new token (a reference to the token_ instance variable).
572624
//
@@ -587,14 +639,37 @@ class Parser {
587639
// The previous line number can be aquired from token_.line-1
588640
//
589641
const Token& nextToken() {
590-
if (token_.isNull()) {
591-
token_ = const_cast<Token&>(tokens_.next());
592-
futureToken_ = const_cast<Token&>(tokens_.next());
642+
_nextToken();
643+
644+
recentComments_.clear();
645+
646+
// Backslash means "ignore the following sequence of linebreaks and comments
647+
// and treat whatever is after it as the same line"
648+
if (token_.type == Token::Backslash) {
649+
// Eat <comment>*<LF><comment>*
650+
while (1) {
651+
_nextToken();
652+
if (token_.type == Token::Comment) {
653+
recentComments_.push_back(token_);
654+
} else if (token_.type != Token::NewLine) {
655+
break;
656+
}
657+
}
593658
} else {
594-
token_ = futureToken_;
595-
futureToken_ = const_cast<Token&>(tokens_.next());
659+
// Eat <comment>*
660+
while (token_.type == Token::Comment) {
661+
recentComments_.push_back(token_);
662+
_nextToken();
663+
}
596664
}
597665

666+
// if (recentComments_.size()) {
667+
// std::vector<Token>::const_iterator it = recentComments_.begin();
668+
// for (; it != recentComments_.end(); ++it) {
669+
// rlog("recentComments_[" << "] = " << (*it).toString());
670+
// }
671+
// }
672+
598673
#if DEBUG_PARSER
599674
fprintf(stderr, "\e[34;1m>> %s\e[0m\n", token_.toString().c_str());
600675
#endif

src/parse/Token.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ class Token {
3232
Comma, // ','
3333
Stop, // '.'
3434
Assignment, // '='
35+
Backslash, // '\'
36+
3537
NewLine,
3638

3739
// Literals
@@ -129,6 +131,7 @@ const TokenTypeInfo Token::TypeInfo[] = {
129131
{"Comma", 0,0,0},
130132
{"Stop", 0,0,0},
131133
{"Assignment", 0,0,0},
134+
{"Backslash", 0,0,0},
132135
{"NewLine", 0,0,0},
133136
{"IntLiteral", .hasStringValue = 1,0, .hasIntValue = 1}, // intValue = radix
134137
{"FloatLiteral", .hasStringValue = 1,0,0},

src/parse/Tokenizer.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -227,14 +227,14 @@ class Tokenizer {
227227
else {
228228

229229
switch (input_->current()) {
230-
case '<': {
230+
case '<': { // '<-'?
231231
if (input_->futureCount() > 0 && input_->future(0) == '-') {
232232
token_.type = Token::LeftArrow;
233233
nextByte(); // consume '-'
234234
break;
235235
}
236236
}
237-
case '-': {
237+
case '-': { // '->'?
238238
if (input_->futureCount() > 0 && input_->future(0) == '>') {
239239
token_.type = Token::RightArrow;
240240
nextByte(); // consume '>'
@@ -246,6 +246,7 @@ class Tokenizer {
246246
case '*':
247247
case '/': token_.type = Token::BinaryOperator; break;
248248

249+
case '\\':token_.type = Token::Backslash; break;
249250
case '=': token_.type = Token::Assignment; break;
250251
case '(': token_.type = Token::LeftParen; break;
251252
case ')': token_.type = Token::RightParen; break;

0 commit comments

Comments
 (0)