aboutsummaryrefslogtreecommitdiff
path: root/src/parser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/parser.cpp')
-rw-r--r--src/parser.cpp174
1 files changed, 151 insertions, 23 deletions
diff --git a/src/parser.cpp b/src/parser.cpp
index 4de1b9c2d4..cd90e8e97a 100644
--- a/src/parser.cpp
+++ b/src/parser.cpp
@@ -20,8 +20,12 @@ const char *node_type_str(NodeType node_type) {
switch (node_type) {
case NodeTypeRoot:
return "Root";
+ case NodeTypeFnDef:
+ return "FnDef";
case NodeTypeFnDecl:
return "FnDecl";
+ case NodeTypeFnProto:
+ return "FnProto";
case NodeTypeParamDecl:
return "ParamDecl";
case NodeTypeType:
@@ -34,6 +38,8 @@ const char *node_type_str(NodeType node_type) {
return "Expression";
case NodeTypeFnCall:
return "FnCall";
+ case NodeTypeExternBlock:
+ return "ExternBlock";
}
zig_unreachable();
}
@@ -46,24 +52,30 @@ void ast_print(AstNode *node, int indent) {
switch (node->type) {
case NodeTypeRoot:
fprintf(stderr, "%s\n", node_type_str(node->type));
- for (int i = 0; i < node->data.root.fn_decls.length; i += 1) {
- AstNode *child = node->data.root.fn_decls.at(i);
+ for (int i = 0; i < node->data.root.top_level_decls.length; i += 1) {
+ AstNode *child = node->data.root.top_level_decls.at(i);
ast_print(child, indent + 2);
}
break;
- case NodeTypeFnDecl:
+ case NodeTypeFnDef:
+ {
+ fprintf(stderr, "%s\n", node_type_str(node->type));
+ AstNode *child = node->data.fn_def.fn_proto;
+ ast_print(child, indent + 2);
+ ast_print(node->data.fn_def.body, indent + 2);
+ break;
+ }
+ case NodeTypeFnProto:
{
- Buf *name_buf = &node->data.fn_decl.name;
+ Buf *name_buf = &node->data.fn_proto.name;
fprintf(stderr, "%s '%s'\n", node_type_str(node->type), buf_ptr(name_buf));
- for (int i = 0; i < node->data.fn_decl.params.length; i += 1) {
- AstNode *child = node->data.fn_decl.params.at(i);
+ for (int i = 0; i < node->data.fn_proto.params.length; i += 1) {
+ AstNode *child = node->data.fn_proto.params.at(i);
ast_print(child, indent + 2);
}
- ast_print(node->data.fn_decl.return_type, indent + 2);
-
- ast_print(node->data.fn_decl.body, indent + 2);
+ ast_print(node->data.fn_proto.return_type, indent + 2);
break;
}
@@ -115,6 +127,19 @@ void ast_print(AstNode *node, int indent) {
break;
}
break;
+ case NodeTypeExternBlock:
+ {
+ fprintf(stderr, "%s\n", node_type_str(node->type));
+ for (int i = 0; i < node->data.extern_block.fn_decls.length; i += 1) {
+ AstNode *child = node->data.extern_block.fn_decls.at(i);
+ ast_print(child, indent + 2);
+ }
+ break;
+ }
+ case NodeTypeFnDecl:
+ fprintf(stderr, "%s\n", node_type_str(node->type));
+ ast_print(node->data.fn_decl.fn_proto, indent + 2);
+ break;
default:
fprintf(stderr, "%s\n", node_type_str(node->type));
break;
@@ -135,10 +160,52 @@ static AstNode *ast_create_node(NodeType type, Token *first_token) {
return node;
}
+static AstNode *ast_create_node_with_node(NodeType type, AstNode *other_node) {
+ AstNode *node = allocate<AstNode>(1);
+ node->type = type;
+ node->line = other_node->line;
+ node->column = other_node->column;
+ return node;
+}
+
static void ast_buf_from_token(ParseContext *pc, Token *token, Buf *buf) {
buf_init_from_mem(buf, buf_ptr(pc->buf) + token->start_pos, token->end_pos - token->start_pos);
}
+static void parse_string_literal(ParseContext *pc, Token *token, Buf *buf) {
+ // skip the double quotes at beginning and end
+ // convert escape sequences
+ bool escape = false;
+ for (int i = token->start_pos; i < token->end_pos - 1; i += 1) {
+ uint8_t c = *((uint8_t*)buf_ptr(pc->buf) + i);
+ if (escape) {
+ switch (c) {
+ case '\\':
+ buf_append_char(buf, '\\');
+ break;
+ case 'r':
+ buf_append_char(buf, '\r');
+ break;
+ case 'n':
+ buf_append_char(buf, '\n');
+ break;
+ case 't':
+ buf_append_char(buf, '\t');
+ break;
+ case '"':
+ buf_append_char(buf, '"');
+ break;
+ }
+ escape = false;
+ } else if (c == '\\') {
+ escape = true;
+ } else {
+ buf_append_char(buf, c);
+ }
+ }
+ assert(!escape);
+}
+
static void ast_invalid_token_error(ParseContext *pc, Token *token) {
Buf token_value = {0};
ast_buf_from_token(pc, token, &token_value);
@@ -304,7 +371,7 @@ static AstNode *ast_parse_expression(ParseContext *pc, int token_index, int *new
token_index += 1;
} else if (token->id == TokenIdStringLiteral) {
node->data.expression.type = AstNodeExpressionTypeString;
- ast_buf_from_token(pc, token, &node->data.expression.data.string);
+ parse_string_literal(pc, token, &node->data.expression.data.string);
token_index += 1;
} else {
ast_invalid_token_error(pc, token);
@@ -381,50 +448,111 @@ static AstNode *ast_parse_block(ParseContext *pc, int token_index, int *new_toke
}
/*
-FnDecl : token(Fn) token(Symbol) ParamDeclList option(token(Arrow) Type) Block;
+FnProto : token(Fn) token(Symbol) ParamDeclList option(token(Arrow) Type)
*/
-static AstNode *ast_parse_fn_decl(ParseContext *pc, int token_index, int *new_token_index) {
+static AstNode *ast_parse_fn_proto(ParseContext *pc, int token_index, int *new_token_index) {
Token *fn_token = &pc->tokens->at(token_index);
token_index += 1;
ast_expect_token(pc, fn_token, TokenIdKeywordFn);
- AstNode *node = ast_create_node(NodeTypeFnDecl, fn_token);
+ AstNode *node = ast_create_node(NodeTypeFnProto, fn_token);
Token *fn_name = &pc->tokens->at(token_index);
token_index += 1;
ast_expect_token(pc, fn_name, TokenIdSymbol);
- ast_buf_from_token(pc, fn_name, &node->data.fn_decl.name);
+ ast_buf_from_token(pc, fn_name, &node->data.fn_proto.name);
- ast_parse_param_decl_list(pc, token_index, &token_index, &node->data.fn_decl.params);
+ ast_parse_param_decl_list(pc, token_index, &token_index, &node->data.fn_proto.params);
Token *arrow = &pc->tokens->at(token_index);
token_index += 1;
if (arrow->id == TokenIdArrow) {
- node->data.fn_decl.return_type = ast_parse_type(pc, token_index, &token_index);
+ node->data.fn_proto.return_type = ast_parse_type(pc, token_index, &token_index);
} else if (arrow->id == TokenIdLBrace) {
- node->data.fn_decl.return_type = nullptr;
+ node->data.fn_proto.return_type = nullptr;
} else {
ast_invalid_token_error(pc, arrow);
}
- node->data.fn_decl.body = ast_parse_block(pc, token_index, &token_index);
+ *new_token_index = token_index;
+ return node;
+}
+
+/*
+FnDef : FnProto Block
+*/
+static AstNode *ast_parse_fn_def(ParseContext *pc, int token_index, int *new_token_index) {
+ AstNode *fn_proto = ast_parse_fn_proto(pc, token_index, &token_index);
+ AstNode *node = ast_create_node_with_node(NodeTypeFnDef, fn_proto);
+
+ node->data.fn_def.fn_proto = fn_proto;
+ node->data.fn_def.body = ast_parse_block(pc, token_index, &token_index);
+
+ *new_token_index = token_index;
+ return node;
+}
+
+/*
+FnDecl : FnProto token(Semicolon)
+*/
+static AstNode *ast_parse_fn_decl(ParseContext *pc, int token_index, int *new_token_index) {
+ AstNode *fn_proto = ast_parse_fn_proto(pc, token_index, &token_index);
+ AstNode *node = ast_create_node_with_node(NodeTypeFnDecl, fn_proto);
+
+ node->data.fn_decl.fn_proto = fn_proto;
+
+ Token *semicolon = &pc->tokens->at(token_index);
+ token_index += 1;
+ ast_expect_token(pc, semicolon, TokenIdSemicolon);
*new_token_index = token_index;
return node;
}
+/*
+ExternBlock : token(Extern) token(LBrace) many(FnProtoDecl) token(RBrace)
+*/
+static AstNode *ast_parse_extern_block(ParseContext *pc, int token_index, int *new_token_index) {
+ Token *extern_kw = &pc->tokens->at(token_index);
+ token_index += 1;
+ ast_expect_token(pc, extern_kw, TokenIdKeywordExtern);
+
+ AstNode *node = ast_create_node(NodeTypeExternBlock, extern_kw);
+
+ Token *l_brace = &pc->tokens->at(token_index);
+ token_index += 1;
+ ast_expect_token(pc, l_brace, TokenIdLBrace);
+
+ for (;;) {
+ Token *token = &pc->tokens->at(token_index);
+ if (token->id == TokenIdRBrace) {
+ token_index += 1;
+ *new_token_index = token_index;
+ return node;
+ } else {
+ AstNode *child = ast_parse_fn_decl(pc, token_index, &token_index);
+ node->data.extern_block.fn_decls.append(child);
+ }
+ }
+
+
+ zig_unreachable();
+}
-static void ast_parse_fn_decl_list(ParseContext *pc, int token_index, ZigList<AstNode *> *fn_decls,
- int *new_token_index)
+static void ast_parse_top_level_decls(ParseContext *pc, int token_index, int *new_token_index,
+ ZigList<AstNode *> *top_level_decls)
{
for (;;) {
Token *token = &pc->tokens->at(token_index);
if (token->id == TokenIdKeywordFn) {
- AstNode *fn_decl_node = ast_parse_fn_decl(pc, token_index, &token_index);
- fn_decls->append(fn_decl_node);
+ AstNode *fn_decl_node = ast_parse_fn_def(pc, token_index, &token_index);
+ top_level_decls->append(fn_decl_node);
+ } else if (token->id == TokenIdKeywordExtern) {
+ AstNode *extern_node = ast_parse_extern_block(pc, token_index, &token_index);
+ top_level_decls->append(extern_node);
} else {
*new_token_index = token_index;
return;
@@ -440,7 +568,7 @@ AstNode *ast_parse(Buf *buf, ZigList<Token> *tokens) {
pc.tokens = tokens;
int new_token_index;
- ast_parse_fn_decl_list(&pc, 0, &pc.root->data.root.fn_decls, &new_token_index);
+ ast_parse_top_level_decls(&pc, 0, &new_token_index, &pc.root->data.root.top_level_decls);
if (new_token_index != tokens->length - 1) {
ast_invalid_token_error(&pc, &tokens->at(new_token_index));