| ... | ... | @@ -41,7 +41,7 @@ const char *node_type_str(NodeType node_type) { |
| 41 | 41 | case NodeTypeFnCall: |
| 42 | 42 | return "FnCall"; |
| 43 | 43 | } |
| 44 | | zig_panic("unreachable"); |
| 44 | zig_unreachable(); |
| 45 | 45 | } |
| 46 | 46 | |
| 47 | 47 | void ast_print(AstNode *node, int indent) { |
| ... | ... | @@ -82,28 +82,321 @@ void ast_print(AstNode *node, int indent) { |
| 82 | 82 | struct ParseContext { |
| 83 | 83 | Buf *buf; |
| 84 | 84 | AstNode *root; |
| 85 | ZigList<Token> *tokens; |
| 85 | 86 | }; |
| 86 | 87 | |
| 87 | | AstNode *ast_create_root(void) { |
| 88 | | zig_panic("TODO create root"); |
| 88 | static AstNode *ast_create_node(NodeType type) { |
| 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 | 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 | 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) { |
| 98 | | zig_panic("TODO parse fn decls"); |
| 104 | static AstNode *ast_parse_expression(ParseContext *pc, int token_index, int *new_token_index); |
| 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 | 388 | AstNode *ast_parse(Buf *buf, ZigList<Token> *tokens) { |
| 102 | 389 | ParseContext pc = {0}; |
| 103 | 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 | 401 | return pc.root; |
| 109 | 402 | } |