| ... | @@ -41,7 +41,7 @@ const char *node_type_str(NodeType node_type) { | ... | @@ -41,7 +41,7 @@ const char *node_type_str(NodeType node_type) { |
| 41 | case NodeTypeFnCall: | 41 | case NodeTypeFnCall: |
| 42 | return "FnCall"; | 42 | return "FnCall"; |
| 43 | } | 43 | } |
| 44 | zig_panic("unreachable"); | 44 | zig_unreachable(); |
| 45 | } | 45 | } |
| 46 | | 46 | |
| 47 | void ast_print(AstNode *node, int indent) { | 47 | void ast_print(AstNode *node, int indent) { |
| ... | @@ -82,28 +82,321 @@ void ast_print(AstNode *node, int indent) { | ... | @@ -82,28 +82,321 @@ void ast_print(AstNode *node, int indent) { |
| 82 | struct ParseContext { | 82 | struct ParseContext { |
| 83 | Buf *buf; | 83 | Buf *buf; |
| 84 | AstNode *root; | 84 | AstNode *root; |
| | 85 | ZigList<Token> *tokens; |
| 85 | }; | 86 | }; |
| 86 | | 87 | |
| 87 | AstNode *ast_create_root(void) { | 88 | static AstNode *ast_create_node(NodeType type) { |
| 88 | zig_panic("TODO create root"); | 89 | AstNode *node = allocate<AstNode>(1); |
| | 90 | node->type = type; |
| | 91 | return node; |
| 89 | } | 92 | } |
| 90 | | 93 | |
| 91 | void ast_invalid_token_error(Buf *buf, Token *token) { | 94 | static void ast_buf_from_token(ParseContext *pc, Token *token, Buf *buf) { |
| | 95 | buf_init_from_mem(buf, buf_ptr(pc->buf) + token->start_pos, token->end_pos - token->start_pos); |
| | 96 | } |
| | 97 | |
| | 98 | static void ast_invalid_token_error(ParseContext *pc, Token *token) { |
| 92 | Buf token_value = {0}; | 99 | Buf token_value = {0}; |
| 93 | buf_init_from_mem(&token_value, buf_ptr(buf) + token->start_pos, token->end_pos - token->start_pos); | 100 | ast_buf_from_token(pc, token, &token_value); |
| 94 | ast_error(token, "invalid token: '%s'", buf_ptr(&token_value)); | 101 | ast_error(token, "invalid token: '%s'", buf_ptr(&token_value)); |
| 95 | } | 102 | } |
| 96 | | 103 | |
| 97 | void ast_parse_fn_decls(ParseContext *pc, ZigList<AstNode *> *fn_decls) { | 104 | static AstNode *ast_parse_expression(ParseContext *pc, int token_index, int *new_token_index); |
| 98 | zig_panic("TODO parse fn decls"); | 105 | |
| | 106 | |
| | 107 | static void ast_expect_token(ParseContext *pc, Token *token, TokenId token_id) { |
| | 108 | if (token->id != token_id) { |
| | 109 | ast_invalid_token_error(pc, token); |
| | 110 | } |
| | 111 | } |
| | 112 | |
| | 113 | /* |
| | 114 | Type : token(Symbol) | PointerType; |
| | 115 | PointerType : token(Star) token(Const) Type | token(Star) token(Mut) Type; |
| | 116 | */ |
| | 117 | static AstNode *ast_parse_type(ParseContext *pc, int token_index, int *new_token_index) { |
| | 118 | AstNode *node = ast_create_node(NodeTypeType); |
| | 119 | |
| | 120 | Token *token = &pc->tokens->at(token_index); |
| | 121 | token_index += 1; |
| | 122 | |
| | 123 | if (token->id == TokenIdSymbol) { |
| | 124 | node->data.type.type = AstNodeTypeTypePrimitive; |
| | 125 | ast_buf_from_token(pc, token, &node->data.type.primitive_name); |
| | 126 | } else if (token->id == TokenIdStar) { |
| | 127 | Token *const_or_mut = &pc->tokens->at(token_index); |
| | 128 | token_index += 1; |
| | 129 | if (const_or_mut->id == TokenIdKeywordMut) { |
| | 130 | node->data.type.is_const = false; |
| | 131 | } else if (const_or_mut->id == TokenIdKeywordConst) { |
| | 132 | node->data.type.is_const = true; |
| | 133 | } else { |
| | 134 | ast_invalid_token_error(pc, const_or_mut); |
| | 135 | } |
| | 136 | |
| | 137 | node->data.type.child_type = ast_parse_type(pc, token_index, &token_index); |
| | 138 | } else { |
| | 139 | ast_invalid_token_error(pc, token); |
| | 140 | } |
| | 141 | |
| | 142 | *new_token_index = token_index; |
| | 143 | return node; |
| | 144 | } |
| | 145 | |
| | 146 | /* |
| | 147 | ParamDecl<node> : token(Symbol) token(Colon) Type { |
| | 148 | }; |
| | 149 | */ |
| | 150 | static AstNode *ast_parse_param_decl(ParseContext *pc, int token_index, int *new_token_index) { |
| | 151 | AstNode *node = ast_create_node(NodeTypeParamDecl); |
| | 152 | |
| | 153 | Token *param_name = &pc->tokens->at(token_index); |
| | 154 | token_index += 1; |
| | 155 | ast_expect_token(pc, param_name, TokenIdSymbol); |
| | 156 | |
| | 157 | ast_buf_from_token(pc, param_name, &node->data.param_decl.name); |
| | 158 | |
| | 159 | Token *colon = &pc->tokens->at(token_index); |
| | 160 | token_index += 1; |
| | 161 | ast_expect_token(pc, colon, TokenIdColon); |
| | 162 | |
| | 163 | node->data.param_decl.type = ast_parse_type(pc, token_index, &token_index); |
| | 164 | |
| | 165 | *new_token_index = token_index; |
| | 166 | return node; |
| | 167 | } |
| | 168 | |
| | 169 | |
| | 170 | static void ast_parse_param_decl_list(ParseContext *pc, int token_index, int *new_token_index, |
| | 171 | ZigList<AstNode *> *params) |
| | 172 | { |
| | 173 | Token *l_paren = &pc->tokens->at(token_index); |
| | 174 | token_index += 1; |
| | 175 | ast_expect_token(pc, l_paren, TokenIdLParen); |
| | 176 | |
| | 177 | Token *token = &pc->tokens->at(token_index); |
| | 178 | if (token->id == TokenIdRParen) { |
| | 179 | token_index += 1; |
| | 180 | *new_token_index = token_index; |
| | 181 | return; |
| | 182 | } |
| | 183 | |
| | 184 | for (;;) { |
| | 185 | AstNode *param_decl_node = ast_parse_param_decl(pc, token_index, &token_index); |
| | 186 | params->append(param_decl_node); |
| | 187 | |
| | 188 | Token *token = &pc->tokens->at(token_index); |
| | 189 | token_index += 1; |
| | 190 | if (token->id == TokenIdRParen) { |
| | 191 | *new_token_index = token_index; |
| | 192 | return; |
| | 193 | } else { |
| | 194 | ast_expect_token(pc, token, TokenIdComma); |
| | 195 | } |
| | 196 | } |
| | 197 | zig_unreachable(); |
| | 198 | } |
| | 199 | |
| | 200 | static void ast_parse_fn_call_param_list(ParseContext *pc, int token_index, int *new_token_index, |
| | 201 | ZigList<AstNode*> *params) |
| | 202 | { |
| | 203 | Token *l_paren = &pc->tokens->at(token_index); |
| | 204 | token_index += 1; |
| | 205 | ast_expect_token(pc, l_paren, TokenIdLParen); |
| | 206 | |
| | 207 | Token *token = &pc->tokens->at(token_index); |
| | 208 | if (token->id == TokenIdRParen) { |
| | 209 | token_index += 1; |
| | 210 | *new_token_index = token_index; |
| | 211 | return; |
| | 212 | } |
| | 213 | |
| | 214 | for (;;) { |
| | 215 | AstNode *expr = ast_parse_expression(pc, token_index, &token_index); |
| | 216 | params->append(expr); |
| | 217 | |
| | 218 | Token *token = &pc->tokens->at(token_index); |
| | 219 | token_index += 1; |
| | 220 | if (token->id == TokenIdRParen) { |
| | 221 | *new_token_index = token_index; |
| | 222 | return; |
| | 223 | } else { |
| | 224 | ast_expect_token(pc, token, TokenIdComma); |
| | 225 | } |
| | 226 | } |
| | 227 | zig_unreachable(); |
| | 228 | } |
| | 229 | |
| | 230 | /* |
| | 231 | FnCall : token(Symbol) token(LParen) list(Expression, token(Comma)) token(RParen) ; |
| | 232 | */ |
| | 233 | static AstNode *ast_parse_fn_call(ParseContext *pc, int token_index, int *new_token_index) { |
| | 234 | AstNode *node = ast_create_node(NodeTypeFnCall); |
| | 235 | |
| | 236 | Token *fn_name = &pc->tokens->at(token_index); |
| | 237 | token_index += 1; |
| | 238 | ast_expect_token(pc, fn_name, TokenIdSymbol); |
| | 239 | |
| | 240 | ast_buf_from_token(pc, fn_name, &node->data.fn_call.name); |
| | 241 | |
| | 242 | ast_parse_fn_call_param_list(pc, token_index, &token_index, &node->data.fn_call.params); |
| | 243 | |
| | 244 | *new_token_index = token_index; |
| | 245 | return node; |
| | 246 | } |
| | 247 | |
| | 248 | static AstNode *ast_parse_expression(ParseContext *pc, int token_index, int *new_token_index) { |
| | 249 | AstNode *node = ast_create_node(NodeTypeExpression); |
| | 250 | |
| | 251 | Token *token = &pc->tokens->at(token_index); |
| | 252 | if (token->id == TokenIdSymbol) { |
| | 253 | node->data.expression.type = AstNodeExpressionTypeFnCall; |
| | 254 | node->data.expression.data.fn_call = ast_parse_fn_call(pc, token_index, &token_index); |
| | 255 | } else if (token->id == TokenIdNumberLiteral) { |
| | 256 | node->data.expression.type = AstNodeExpressionTypeNumber; |
| | 257 | ast_buf_from_token(pc, token, &node->data.expression.data.number); |
| | 258 | token_index += 1; |
| | 259 | } else if (token->id == TokenIdStringLiteral) { |
| | 260 | node->data.expression.type = AstNodeExpressionTypeString; |
| | 261 | ast_buf_from_token(pc, token, &node->data.expression.data.string); |
| | 262 | token_index += 1; |
| | 263 | } else { |
| | 264 | ast_invalid_token_error(pc, token); |
| | 265 | } |
| | 266 | |
| | 267 | *new_token_index = token_index; |
| | 268 | return node; |
| | 269 | } |
| | 270 | |
| | 271 | /* |
| | 272 | Statement : ExpressionStatement | ReturnStatement ; |
| | 273 | |
| | 274 | ExpressionStatement : Expression token(Semicolon) ; |
| | 275 | |
| | 276 | ReturnStatement : token(Return) Expression token(Semicolon) ; |
| | 277 | |
| | 278 | Expression : token(Number) | token(String) | FnCall ; |
| | 279 | |
| | 280 | FnCall : token(Symbol) token(LParen) list(Expression, token(Comma)) token(RParen) ; |
| | 281 | */ |
| | 282 | static AstNode *ast_parse_statement(ParseContext *pc, int token_index, int *new_token_index) { |
| | 283 | AstNode *node = ast_create_node(NodeTypeStatement); |
| | 284 | |
| | 285 | Token *token = &pc->tokens->at(token_index); |
| | 286 | if (token->id == TokenIdKeywordReturn) { |
| | 287 | token_index += 1; |
| | 288 | node->data.statement.type = AstNodeStatementTypeReturn; |
| | 289 | node->data.statement.data.retrn.expression = ast_parse_expression(pc, token_index, &token_index); |
| | 290 | |
| | 291 | Token *semicolon = &pc->tokens->at(token_index); |
| | 292 | token_index += 1; |
| | 293 | ast_expect_token(pc, semicolon, TokenIdSemicolon); |
| | 294 | } else if (token->id == TokenIdSymbol || |
| | 295 | token->id == TokenIdStringLiteral || |
| | 296 | token->id == TokenIdNumberLiteral) |
| | 297 | { |
| | 298 | node->data.statement.type = AstNodeStatementTypeExpression; |
| | 299 | node->data.statement.data.expr.expression = ast_parse_expression(pc, token_index, &token_index); |
| | 300 | |
| | 301 | Token *semicolon = &pc->tokens->at(token_index); |
| | 302 | token_index += 1; |
| | 303 | ast_expect_token(pc, semicolon, TokenIdSemicolon); |
| | 304 | } else { |
| | 305 | ast_invalid_token_error(pc, token); |
| | 306 | } |
| | 307 | |
| | 308 | *new_token_index = token_index; |
| | 309 | return node; |
| | 310 | } |
| | 311 | |
| | 312 | /* |
| | 313 | Block : token(LBrace) many(Statement) token(RBrace); |
| | 314 | */ |
| | 315 | static AstNode *ast_parse_block(ParseContext *pc, int token_index, int *new_token_index) { |
| | 316 | AstNode *node = ast_create_node(NodeTypeBlock); |
| | 317 | |
| | 318 | Token *l_brace = &pc->tokens->at(token_index); |
| | 319 | token_index += 1; |
| | 320 | ast_expect_token(pc, l_brace, TokenIdLBrace); |
| | 321 | |
| | 322 | for (;;) { |
| | 323 | Token *token = &pc->tokens->at(token_index); |
| | 324 | if (token->id == TokenIdRBrace) { |
| | 325 | token_index += 1; |
| | 326 | *new_token_index = token_index; |
| | 327 | return node; |
| | 328 | } else { |
| | 329 | AstNode *statement_node = ast_parse_statement(pc, token_index, &token_index); |
| | 330 | node->data.block.statements.append(statement_node); |
| | 331 | } |
| | 332 | } |
| | 333 | zig_unreachable(); |
| | 334 | } |
| | 335 | |
| | 336 | /* |
| | 337 | FnDecl : token(Fn) token(Symbol) ParamDeclList option(token(Arrow) Type) Block; |
| | 338 | */ |
| | 339 | static AstNode *ast_parse_fn_decl(ParseContext *pc, int token_index, int *new_token_index) { |
| | 340 | AstNode *node = ast_create_node(NodeTypeFnDecl); |
| | 341 | |
| | 342 | Token *fn_token = &pc->tokens->at(token_index); |
| | 343 | token_index += 1; |
| | 344 | ast_expect_token(pc, fn_token, TokenIdKeywordFn); |
| | 345 | |
| | 346 | Token *fn_name = &pc->tokens->at(token_index); |
| | 347 | token_index += 1; |
| | 348 | ast_expect_token(pc, fn_name, TokenIdSymbol); |
| | 349 | |
| | 350 | ast_buf_from_token(pc, fn_name, &node->data.fn_decl.name); |
| | 351 | |
| | 352 | |
| | 353 | ast_parse_param_decl_list(pc, token_index, &token_index, &node->data.fn_decl.params); |
| | 354 | |
| | 355 | Token *arrow = &pc->tokens->at(token_index); |
| | 356 | token_index += 1; |
| | 357 | if (arrow->id == TokenIdArrow) { |
| | 358 | node->data.fn_decl.return_type = ast_parse_type(pc, token_index, &token_index); |
| | 359 | } else if (arrow->id == TokenIdLBrace) { |
| | 360 | node->data.fn_decl.return_type = nullptr; |
| | 361 | } else { |
| | 362 | ast_invalid_token_error(pc, arrow); |
| | 363 | } |
| | 364 | |
| | 365 | node->data.fn_decl.body = ast_parse_block(pc, token_index, &token_index); |
| | 366 | |
| | 367 | *new_token_index = token_index; |
| | 368 | return node; |
| | 369 | } |
| | 370 | |
| | 371 | |
| | 372 | static void ast_parse_fn_decl_list(ParseContext *pc, int token_index, ZigList<AstNode *> *fn_decls, |
| | 373 | int *new_token_index) |
| | 374 | { |
| | 375 | for (;;) { |
| | 376 | Token *token = &pc->tokens->at(token_index); |
| | 377 | if (token->id == TokenIdKeywordFn) { |
| | 378 | AstNode *fn_decl_node = ast_parse_fn_decl(pc, token_index, &token_index); |
| | 379 | fn_decls->append(fn_decl_node); |
| | 380 | } else { |
| | 381 | *new_token_index = token_index; |
| | 382 | return; |
| | 383 | } |
| | 384 | } |
| | 385 | zig_unreachable(); |
| 99 | } | 386 | } |
| 100 | | 387 | |
| 101 | AstNode *ast_parse(Buf *buf, ZigList<Token> *tokens) { | 388 | AstNode *ast_parse(Buf *buf, ZigList<Token> *tokens) { |
| 102 | ParseContext pc = {0}; | 389 | ParseContext pc = {0}; |
| 103 | pc.buf = buf; | 390 | pc.buf = buf; |
| 104 | pc.root = ast_create_root(); | 391 | pc.root = ast_create_node(NodeTypeRoot); |
| | 392 | pc.tokens = tokens; |
| 105 | | 393 | |
| 106 | ast_parse_fn_decls(&pc, &pc.root->data.root.fn_decls); | 394 | int new_token_index; |
| | 395 | ast_parse_fn_decl_list(&pc, 0, &pc.root->data.root.fn_decls, &new_token_index); |
| | 396 | |
| | 397 | if (new_token_index != tokens->length - 1) { |
| | 398 | ast_invalid_token_error(&pc, &tokens->at(new_token_index)); |
| | 399 | } |
| 107 | | 400 | |
| 108 | return pc.root; | 401 | return pc.root; |
| 109 | } | 402 | } |