| ... | @@ -13,8 +13,8 @@ | ... | @@ -13,8 +13,8 @@ |
| 13 | | 13 | |
| 14 | static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context, | 14 | static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 15 | TypeTableEntry *expected_type, AstNode *node); | 15 | TypeTableEntry *expected_type, AstNode *node); |
| 16 | static TypeTableEntry *eval_const_expr(CodeGen *g, BlockContext *context, | 16 | static void eval_const_expr(CodeGen *g, BlockContext *context, |
| 17 | AstNode *node, AstNodeNumberLiteral *out_number_literal); | 17 | AstNode *node, ConstExprValue *out_val); |
| 18 | static VariableTableEntry *analyze_variable_declaration(CodeGen *g, ImportTableEntry *import, | 18 | static VariableTableEntry *analyze_variable_declaration(CodeGen *g, ImportTableEntry *import, |
| 19 | BlockContext *context, TypeTableEntry *expected_type, AstNode *node); | 19 | BlockContext *context, TypeTableEntry *expected_type, AstNode *node); |
| 20 | static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableEntry *struct_type); | 20 | static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableEntry *struct_type); |
| ... | @@ -32,8 +32,6 @@ static AstNode *first_executing_node(AstNode *node) { | ... | @@ -32,8 +32,6 @@ static AstNode *first_executing_node(AstNode *node) { |
| 32 | return first_executing_node(node->data.slice_expr.array_ref_expr); | 32 | return first_executing_node(node->data.slice_expr.array_ref_expr); |
| 33 | case NodeTypeFieldAccessExpr: | 33 | case NodeTypeFieldAccessExpr: |
| 34 | return first_executing_node(node->data.field_access_expr.struct_expr); | 34 | return first_executing_node(node->data.field_access_expr.struct_expr); |
| 35 | case NodeTypeCastExpr: | | |
| 36 | return first_executing_node(node->data.cast_expr.expr); | | |
| 37 | case NodeTypeRoot: | 35 | case NodeTypeRoot: |
| 38 | case NodeTypeRootExportDecl: | 36 | case NodeTypeRootExportDecl: |
| 39 | case NodeTypeFnProto: | 37 | case NodeTypeFnProto: |
| ... | @@ -125,6 +123,7 @@ TypeTableEntry *new_type_table_entry(TypeTableEntryId id) { | ... | @@ -125,6 +123,7 @@ TypeTableEntry *new_type_table_entry(TypeTableEntryId id) { |
| 125 | case TypeTableEntryIdArray: | 123 | case TypeTableEntryIdArray: |
| 126 | case TypeTableEntryIdNumberLiteral: | 124 | case TypeTableEntryIdNumberLiteral: |
| 127 | case TypeTableEntryIdMaybe: | 125 | case TypeTableEntryIdMaybe: |
| | 126 | case TypeTableEntryIdFn: |
| 128 | // nothing to init | 127 | // nothing to init |
| 129 | break; | 128 | break; |
| 130 | case TypeTableEntryIdStruct: | 129 | case TypeTableEntryIdStruct: |
| ... | @@ -357,63 +356,74 @@ static TypeTableEntry *analyze_type_expr(CodeGen *g, ImportTableEntry *import, B | ... | @@ -357,63 +356,74 @@ static TypeTableEntry *analyze_type_expr(CodeGen *g, ImportTableEntry *import, B |
| 357 | } | 356 | } |
| 358 | } | 357 | } |
| 359 | | 358 | |
| 360 | | 359 | static void eval_const_expr_bin_op(CodeGen *g, BlockContext *context, |
| 361 | static TypeTableEntry *eval_const_expr_bin_op(CodeGen *g, BlockContext *context, | 360 | AstNode *node, ConstExprValue *out_val) |
| 362 | AstNode *node, AstNodeNumberLiteral *out_number_literal) | | |
| 363 | { | 361 | { |
| 364 | AstNodeNumberLiteral op1_lit; | 362 | AstNode *op1_node = node->data.bin_op_expr.op1; |
| 365 | AstNodeNumberLiteral op2_lit; | 363 | AstNode *op2_node = node->data.bin_op_expr.op2; |
| 366 | TypeTableEntry *op1_type = eval_const_expr(g, context, node->data.bin_op_expr.op1, &op1_lit); | 364 | ConstExprValue op1_val = {0}; |
| 367 | TypeTableEntry *op2_type = eval_const_expr(g, context, node->data.bin_op_expr.op1, &op2_lit); | 365 | ConstExprValue op2_val = {0}; |
| 368 | | 366 | eval_const_expr(g, context, op1_node, &op1_val); |
| 369 | if (op1_type->id == TypeTableEntryIdInvalid || | 367 | eval_const_expr(g, context, op2_node, &op2_val); |
| 370 | op2_type->id == TypeTableEntryIdInvalid) | 368 | |
| 371 | { | 369 | if (!op1_val.ok || !op2_val.ok) { |
| 372 | return g->builtin_types.entry_invalid; | 370 | return; |
| 373 | } | 371 | } |
| 374 | | 372 | |
| | 373 | TypeTableEntry *op1_type = get_resolved_expr(op1_node)->type_entry; |
| | 374 | TypeTableEntry *op2_type = get_resolved_expr(op2_node)->type_entry; |
| | 375 | |
| 375 | // TODO complete more of this function instead of returning invalid | 376 | // TODO complete more of this function instead of returning invalid |
| 376 | // returning invalid makes the "unable to evaluate constant expression" error | 377 | // returning invalid makes the "unable to evaluate constant expression" error |
| 377 | | 378 | |
| 378 | switch (node->data.bin_op_expr.bin_op) { | 379 | switch (node->data.bin_op_expr.bin_op) { |
| 379 | case BinOpTypeCmpNotEq: | 380 | case BinOpTypeCmpNotEq: |
| 380 | { | 381 | { |
| 381 | if (is_num_lit_unsigned(op1_lit.kind) && | 382 | if (op1_type->id == TypeTableEntryIdInt && |
| 382 | is_num_lit_unsigned(op2_lit.kind)) | 383 | op2_type->id == TypeTableEntryIdInt) |
| 383 | { | 384 | { |
| 384 | out_number_literal->kind = NumLitU8; | 385 | out_val->data.x_bool = (op1_val.data.x_uint == op2_val.data.x_uint); |
| 385 | out_number_literal->overflow = false; | 386 | out_val->ok = true; |
| 386 | out_number_literal->data.x_uint = (op1_lit.data.x_uint != op2_lit.data.x_uint); | | |
| 387 | return get_resolved_expr(node)->type_entry; | | |
| 388 | } else { | | |
| 389 | return g->builtin_types.entry_invalid; | | |
| 390 | } | 387 | } |
| | 388 | break; |
| 391 | } | 389 | } |
| 392 | case BinOpTypeCmpLessThan: | 390 | case BinOpTypeCmpLessThan: |
| 393 | { | 391 | { |
| 394 | if (is_num_lit_unsigned(op1_lit.kind) && | 392 | if (op1_type->id == TypeTableEntryIdInt && |
| 395 | is_num_lit_unsigned(op2_lit.kind)) | 393 | op2_type->id == TypeTableEntryIdInt) |
| 396 | { | 394 | { |
| 397 | out_number_literal->kind = NumLitU8; | 395 | if (op1_type->data.integral.is_signed && |
| 398 | out_number_literal->overflow = false; | 396 | op2_type->data.integral.is_signed) |
| 399 | out_number_literal->data.x_uint = (op1_lit.data.x_uint < op2_lit.data.x_uint); | 397 | { |
| 400 | return get_resolved_expr(node)->type_entry; | 398 | out_val->data.x_bool = (op1_val.data.x_int < op2_val.data.x_int); |
| 401 | } else { | 399 | out_val->ok = true; |
| 402 | return g->builtin_types.entry_invalid; | 400 | } else if (!op1_type->data.integral.is_signed && |
| | 401 | !op2_type->data.integral.is_signed) |
| | 402 | { |
| | 403 | out_val->data.x_bool = (op1_val.data.x_uint < op2_val.data.x_uint); |
| | 404 | out_val->ok = true; |
| | 405 | } |
| 403 | } | 406 | } |
| | 407 | break; |
| 404 | } | 408 | } |
| 405 | case BinOpTypeMod: | 409 | case BinOpTypeMod: |
| 406 | { | 410 | { |
| 407 | if (is_num_lit_unsigned(op1_lit.kind) && | 411 | if (op1_type->id == TypeTableEntryIdInt && |
| 408 | is_num_lit_unsigned(op2_lit.kind)) | 412 | op2_type->id == TypeTableEntryIdInt) |
| 409 | { | 413 | { |
| 410 | out_number_literal->kind = NumLitU64; | 414 | if (op1_type->data.integral.is_signed && |
| 411 | out_number_literal->overflow = false; | 415 | op2_type->data.integral.is_signed) |
| 412 | out_number_literal->data.x_uint = (op1_lit.data.x_uint % op2_lit.data.x_uint); | 416 | { |
| 413 | return get_resolved_expr(node)->type_entry; | 417 | out_val->data.x_int = op1_val.data.x_int % op2_val.data.x_int; |
| 414 | } else { | 418 | out_val->ok = true; |
| 415 | return g->builtin_types.entry_invalid; | 419 | } else if (!op1_type->data.integral.is_signed && |
| | 420 | !op2_type->data.integral.is_signed) |
| | 421 | { |
| | 422 | out_val->data.x_uint = op1_val.data.x_uint % op2_val.data.x_uint; |
| | 423 | out_val->ok = true; |
| | 424 | } |
| 416 | } | 425 | } |
| | 426 | break; |
| 417 | } | 427 | } |
| 418 | case BinOpTypeBoolOr: | 428 | case BinOpTypeBoolOr: |
| 419 | case BinOpTypeBoolAnd: | 429 | case BinOpTypeBoolAnd: |
| ... | @@ -431,7 +441,7 @@ static TypeTableEntry *eval_const_expr_bin_op(CodeGen *g, BlockContext *context, | ... | @@ -431,7 +441,7 @@ static TypeTableEntry *eval_const_expr_bin_op(CodeGen *g, BlockContext *context, |
| 431 | case BinOpTypeMult: | 441 | case BinOpTypeMult: |
| 432 | case BinOpTypeDiv: | 442 | case BinOpTypeDiv: |
| 433 | case BinOpTypeUnwrapMaybe: | 443 | case BinOpTypeUnwrapMaybe: |
| 434 | return g->builtin_types.entry_invalid; | 444 | break; |
| 435 | case BinOpTypeInvalid: | 445 | case BinOpTypeInvalid: |
| 436 | case BinOpTypeAssign: | 446 | case BinOpTypeAssign: |
| 437 | case BinOpTypeAssignTimes: | 447 | case BinOpTypeAssignTimes: |
| ... | @@ -448,31 +458,23 @@ static TypeTableEntry *eval_const_expr_bin_op(CodeGen *g, BlockContext *context, | ... | @@ -448,31 +458,23 @@ static TypeTableEntry *eval_const_expr_bin_op(CodeGen *g, BlockContext *context, |
| 448 | case BinOpTypeAssignBoolOr: | 458 | case BinOpTypeAssignBoolOr: |
| 449 | zig_unreachable(); | 459 | zig_unreachable(); |
| 450 | } | 460 | } |
| 451 | zig_unreachable(); | | |
| 452 | } | 461 | } |
| 453 | | 462 | |
| 454 | static TypeTableEntry *eval_const_expr_fn_call(CodeGen *g, BlockContext *context, | 463 | static void eval_const_expr_builtin(CodeGen *g, BlockContext *context, AstNode *node, ConstExprValue *out_val) { |
| 455 | AstNode *node, AstNodeNumberLiteral *out_number_literal) | | |
| 456 | { | | |
| 457 | if (!node->data.fn_call_expr.is_builtin) { | | |
| 458 | return g->builtin_types.entry_invalid; | | |
| 459 | } | | |
| 460 | | | |
| 461 | switch (node->data.fn_call_expr.builtin_fn->id) { | 464 | switch (node->data.fn_call_expr.builtin_fn->id) { |
| 462 | case BuiltinFnIdInvalid: | 465 | case BuiltinFnIdInvalid: |
| 463 | zig_unreachable(); | 466 | zig_unreachable(); |
| 464 | case BuiltinFnIdArithmeticWithOverflow: | 467 | case BuiltinFnIdArithmeticWithOverflow: |
| 465 | case BuiltinFnIdMemcpy: | 468 | case BuiltinFnIdMemcpy: |
| 466 | case BuiltinFnIdMemset: | 469 | case BuiltinFnIdMemset: |
| 467 | return g->builtin_types.entry_invalid; | 470 | break; |
| 468 | case BuiltinFnIdSizeof: | 471 | case BuiltinFnIdSizeof: |
| 469 | { | 472 | { |
| 470 | AstNode *type_node = node->data.fn_call_expr.params.at(0); | 473 | AstNode *type_node = node->data.fn_call_expr.params.at(0); |
| 471 | TypeTableEntry *target_type = unwrapped_node_type(type_node); | 474 | TypeTableEntry *target_type = unwrapped_node_type(type_node); |
| 472 | out_number_literal->overflow = false; | 475 | out_val->data.x_uint = target_type->size_in_bits / 8; |
| 473 | out_number_literal->data.x_uint = target_type->size_in_bits / 8; | 476 | out_val->ok = true; |
| 474 | out_number_literal->kind = get_number_literal_kind_unsigned(out_number_literal->data.x_uint); | 477 | break; |
| 475 | return get_resolved_expr(node)->type_entry; | | |
| 476 | } | 478 | } |
| 477 | case BuiltinFnIdMaxValue: | 479 | case BuiltinFnIdMaxValue: |
| 478 | case BuiltinFnIdMinValue: | 480 | case BuiltinFnIdMinValue: |
| ... | @@ -480,43 +482,154 @@ static TypeTableEntry *eval_const_expr_fn_call(CodeGen *g, BlockContext *context | ... | @@ -480,43 +482,154 @@ static TypeTableEntry *eval_const_expr_fn_call(CodeGen *g, BlockContext *context |
| 480 | case BuiltinFnIdValueCount: | 482 | case BuiltinFnIdValueCount: |
| 481 | zig_panic("TODO eval_const_expr_fn_call value_count"); | 483 | zig_panic("TODO eval_const_expr_fn_call value_count"); |
| 482 | case BuiltinFnIdTypeof: | 484 | case BuiltinFnIdTypeof: |
| 483 | return get_resolved_expr(node)->type_entry; | 485 | // TODO |
| | 486 | out_val->ok = true; |
| | 487 | break; |
| 484 | } | 488 | } |
| 485 | zig_unreachable(); | | |
| 486 | } | 489 | } |
| 487 | | 490 | |
| 488 | static TypeTableEntry *eval_const_expr(CodeGen *g, BlockContext *context, | 491 | static void eval_const_expr_fn_call_known(CodeGen *g, BlockContext *context, |
| 489 | AstNode *node, AstNodeNumberLiteral *out_number_literal) | 492 | AstNode *node, ConstExprValue *out_val) |
| | 493 | { |
| | 494 | // currently no functions can be constant expression evaluated, |
| | 495 | // so we do nothing |
| | 496 | } |
| | 497 | |
| | 498 | static void eval_const_expr_fn_call_cast(CodeGen *g, BlockContext *context, |
| | 499 | AstNode *node, ConstExprValue *out_val) |
| | 500 | { |
| | 501 | assert(node->type == NodeTypeFnCallExpr); |
| | 502 | AstNode *expr_node = node->data.fn_call_expr.params.at(0); |
| | 503 | Cast *cast = &node->data.fn_call_expr.cast; |
| | 504 | switch (cast->op) { |
| | 505 | case CastOpNothing: |
| | 506 | case CastOpPtrToInt: |
| | 507 | case CastOpPointerReinterpret: |
| | 508 | case CastOpIntWidenOrShorten: |
| | 509 | { |
| | 510 | eval_const_expr(g, context, expr_node, out_val); |
| | 511 | break; |
| | 512 | } |
| | 513 | case CastOpMaybeWrap: |
| | 514 | { |
| | 515 | ConstExprValue *child_val = allocate<ConstExprValue>(1); |
| | 516 | eval_const_expr(g, context, expr_node, child_val); |
| | 517 | if (!child_val->ok) { |
| | 518 | return; |
| | 519 | } |
| | 520 | out_val->data.x_maybe.child_val = child_val; |
| | 521 | out_val->data.x_maybe.is_null = false; |
| | 522 | out_val->ok = true; |
| | 523 | break; |
| | 524 | } |
| | 525 | case CastOpToUnknownSizeArray: |
| | 526 | zig_panic("TODO eval_const_expr CastOpToUnknownSizeArray"); |
| | 527 | } |
| | 528 | } |
| | 529 | |
| | 530 | static void eval_const_expr_fn_call(CodeGen *g, BlockContext *context, |
| | 531 | AstNode *node, ConstExprValue *out_val) |
| | 532 | { |
| | 533 | if (node->data.fn_call_expr.is_builtin) { |
| | 534 | return eval_const_expr_builtin(g, context, node, out_val); |
| | 535 | } |
| | 536 | if (node->data.fn_call_expr.fn_entry) { |
| | 537 | return eval_const_expr_fn_call_known(g, context, node, out_val); |
| | 538 | } |
| | 539 | return eval_const_expr_fn_call_cast(g, context, node, out_val); |
| | 540 | } |
| | 541 | |
| | 542 | static void eval_const_expr_prefix_op_expr(CodeGen *g, BlockContext *context, AstNode *node, |
| | 543 | ConstExprValue *out_val) |
| 490 | { | 544 | { |
| | 545 | AstNode *expr_node = node->data.prefix_op_expr.primary_expr; |
| | 546 | switch (node->data.prefix_op_expr.prefix_op) { |
| | 547 | case PrefixOpInvalid: |
| | 548 | zig_unreachable(); |
| | 549 | case PrefixOpBoolNot: |
| | 550 | { |
| | 551 | eval_const_expr(g, context, expr_node, out_val); |
| | 552 | if (out_val->ok) { |
| | 553 | out_val->data.x_bool = !out_val->data.x_bool; |
| | 554 | } |
| | 555 | break; |
| | 556 | } |
| | 557 | case PrefixOpBinNot: |
| | 558 | break; |
| | 559 | case PrefixOpNegation: |
| | 560 | break; |
| | 561 | case PrefixOpAddressOf: |
| | 562 | { |
| | 563 | if (get_resolved_expr(node)->type_entry->id == TypeTableEntryIdMetaType) { |
| | 564 | eval_const_expr(g, context, expr_node, out_val); |
| | 565 | } |
| | 566 | break; |
| | 567 | } |
| | 568 | case PrefixOpConstAddressOf: |
| | 569 | break; |
| | 570 | case PrefixOpDereference: |
| | 571 | break; |
| | 572 | case PrefixOpMaybe: |
| | 573 | break; |
| | 574 | } |
| | 575 | } |
| | 576 | |
| | 577 | static void eval_const_expr(CodeGen *g, BlockContext *context, AstNode *node, ConstExprValue *out_val) { |
| 491 | switch (node->type) { | 578 | switch (node->type) { |
| 492 | case NodeTypeNumberLiteral: | 579 | case NodeTypeNumberLiteral: |
| 493 | *out_number_literal = node->data.number_literal; | 580 | { |
| 494 | return get_resolved_expr(node)->type_entry; | 581 | if (is_num_lit_unsigned(node->data.number_literal.kind)) { |
| | 582 | out_val->data.x_uint = node->data.number_literal.data.x_uint; |
| | 583 | out_val->ok = true; |
| | 584 | } else if (is_num_lit_float(node->data.number_literal.kind)) { |
| | 585 | out_val->data.x_uint = node->data.number_literal.data.x_float; |
| | 586 | out_val->ok = true; |
| | 587 | } |
| | 588 | break; |
| | 589 | } |
| 495 | case NodeTypeBoolLiteral: | 590 | case NodeTypeBoolLiteral: |
| 496 | out_number_literal->data.x_uint = node->data.bool_literal.value ? 1 : 0; | 591 | out_val->data.x_uint = node->data.bool_literal.value ? 1 : 0; |
| 497 | return get_resolved_expr(node)->type_entry; | 592 | out_val->ok = true; |
| | 593 | break; |
| 498 | case NodeTypeNullLiteral: | 594 | case NodeTypeNullLiteral: |
| 499 | return get_resolved_expr(node)->type_entry; | 595 | out_val->data.x_maybe.is_null = true; |
| | 596 | out_val->ok = true; |
| | 597 | break; |
| 500 | case NodeTypeBinOpExpr: | 598 | case NodeTypeBinOpExpr: |
| 501 | return eval_const_expr_bin_op(g, context, node, out_number_literal); | 599 | eval_const_expr_bin_op(g, context, node, out_val); |
| | 600 | break; |
| 502 | case NodeTypeSymbol: | 601 | case NodeTypeSymbol: |
| 503 | { | 602 | { |
| 504 | VariableTableEntry *var = find_variable(context, &node->data.symbol_expr.symbol); | 603 | VariableTableEntry *var = node->data.symbol_expr.variable; |
| 505 | assert(var); | 604 | if (var) { |
| 506 | AstNode *decl_node = var->decl_node; | 605 | if (var->is_const) { |
| 507 | AstNode *expr_node = decl_node->data.variable_declaration.expr; | 606 | AstNode *decl_node = var->decl_node; |
| 508 | if (expr_node) { | 607 | if (decl_node->type == NodeTypeVariableDeclaration) { |
| 509 | BlockContext *next_context = get_resolved_expr(expr_node)->block_context; | 608 | AstNode *expr_node = decl_node->data.variable_declaration.expr; |
| 510 | return eval_const_expr(g, next_context, expr_node, out_number_literal); | 609 | if (expr_node) { |
| | 610 | BlockContext *next_context = get_resolved_expr(expr_node)->block_context; |
| | 611 | eval_const_expr(g, next_context, expr_node, out_val); |
| | 612 | } |
| | 613 | } |
| | 614 | } |
| | 615 | } else if (node->data.symbol_expr.meta_type) { |
| | 616 | out_val->ok = true; |
| | 617 | } else if (node->data.symbol_expr.fn_entry) { |
| | 618 | out_val->ok = true; |
| | 619 | out_val->data.x_fn = node->data.symbol_expr.fn_entry; |
| 511 | } else { | 620 | } else { |
| 512 | // can't eval it | 621 | zig_unreachable(); |
| 513 | return g->builtin_types.entry_invalid; | | |
| 514 | } | 622 | } |
| | 623 | break; |
| 515 | } | 624 | } |
| 516 | case NodeTypeFnCallExpr: | 625 | case NodeTypeFnCallExpr: |
| 517 | return eval_const_expr_fn_call(g, context, node, out_number_literal); | 626 | eval_const_expr_fn_call(g, context, node, out_val); |
| | 627 | break; |
| | 628 | case NodeTypePrefixOpExpr: |
| | 629 | eval_const_expr_prefix_op_expr(g, context, node, out_val); |
| | 630 | break; |
| 518 | default: | 631 | default: |
| 519 | return g->builtin_types.entry_invalid; | 632 | break; |
| 520 | } | 633 | } |
| 521 | } | 634 | } |
| 522 | | 635 | |
| ... | @@ -550,11 +663,30 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t | ... | @@ -550,11 +663,30 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t |
| 550 | } | 663 | } |
| 551 | } | 664 | } |
| 552 | | 665 | |
| 553 | for (int i = 0; i < node->data.fn_proto.params.length; i += 1) { | 666 | int param_count = node->data.fn_proto.params.length; |
| | 667 | |
| | 668 | TypeTableEntry *fn_type = new_type_table_entry(TypeTableEntryIdFn); |
| | 669 | fn_type->data.fn.param_count = param_count; |
| | 670 | fn_type->data.fn.param_types = allocate<TypeTableEntry*>(param_count); |
| | 671 | |
| | 672 | fn_table_entry->type_entry = fn_type; |
| | 673 | |
| | 674 | Buf *name = &node->data.fn_proto.name; |
| | 675 | buf_resize(&fn_type->name, 0); |
| | 676 | buf_appendf(&fn_type->name, "fn %s(", buf_ptr(name)); |
| | 677 | for (int i = 0; i < param_count; i += 1) { |
| 554 | AstNode *child = node->data.fn_proto.params.at(i); | 678 | AstNode *child = node->data.fn_proto.params.at(i); |
| 555 | assert(child->type == NodeTypeParamDecl); | 679 | assert(child->type == NodeTypeParamDecl); |
| 556 | TypeTableEntry *type_entry = analyze_type_expr(g, import, import->block_context, | 680 | TypeTableEntry *type_entry = analyze_type_expr(g, import, import->block_context, |
| 557 | child->data.param_decl.type); | 681 | child->data.param_decl.type); |
| | 682 | fn_table_entry->type_entry->data.fn.param_types[i] = type_entry; |
| | 683 | |
| | 684 | buf_appendf(&fn_type->name, "%s : %s", |
| | 685 | buf_ptr(&child->data.param_decl.name), buf_ptr(&type_entry->name)); |
| | 686 | |
| | 687 | if (i + 1 < param_count) { |
| | 688 | buf_appendf(&fn_type->name, ", "); |
| | 689 | } |
| 558 | | 690 | |
| 559 | if (type_entry->id == TypeTableEntryIdUnreachable) { | 691 | if (type_entry->id == TypeTableEntryIdUnreachable) { |
| 560 | add_node_error(g, child->data.param_decl.type, | 692 | add_node_error(g, child->data.param_decl.type, |
| ... | @@ -567,7 +699,14 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t | ... | @@ -567,7 +699,14 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t |
| 567 | } | 699 | } |
| 568 | } | 700 | } |
| 569 | | 701 | |
| 570 | analyze_type_expr(g, import, import->block_context, node->data.fn_proto.return_type); | 702 | TypeTableEntry *return_type = analyze_type_expr(g, import, import->block_context, |
| | 703 | node->data.fn_proto.return_type); |
| | 704 | fn_table_entry->type_entry->data.fn.return_type = return_type; |
| | 705 | |
| | 706 | buf_appendf(&fn_type->name, ")"); |
| | 707 | if (return_type->id != TypeTableEntryIdVoid) { |
| | 708 | buf_appendf(&fn_type->name, " %s", buf_ptr(&return_type->name)); |
| | 709 | } |
| 571 | } | 710 | } |
| 572 | | 711 | |
| 573 | static void preview_function_labels(CodeGen *g, AstNode *node, FnTableEntry *fn_table_entry) { | 712 | static void preview_function_labels(CodeGen *g, AstNode *node, FnTableEntry *fn_table_entry) { |
| ... | @@ -1058,7 +1197,6 @@ static void resolve_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode | ... | @@ -1058,7 +1197,6 @@ static void resolve_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode |
| 1058 | case NodeTypeBoolLiteral: | 1197 | case NodeTypeBoolLiteral: |
| 1059 | case NodeTypeNullLiteral: | 1198 | case NodeTypeNullLiteral: |
| 1060 | case NodeTypeSymbol: | 1199 | case NodeTypeSymbol: |
| 1061 | case NodeTypeCastExpr: | | |
| 1062 | case NodeTypePrefixOpExpr: | 1200 | case NodeTypePrefixOpExpr: |
| 1063 | case NodeTypeIfBoolExpr: | 1201 | case NodeTypeIfBoolExpr: |
| 1064 | case NodeTypeIfVarExpr: | 1202 | case NodeTypeIfVarExpr: |
| ... | @@ -1116,6 +1254,7 @@ static bool num_lit_fits_in_other_type(CodeGen *g, TypeTableEntry *literal_type, | ... | @@ -1116,6 +1254,7 @@ static bool num_lit_fits_in_other_type(CodeGen *g, TypeTableEntry *literal_type, |
| 1116 | case TypeTableEntryIdStruct: | 1254 | case TypeTableEntryIdStruct: |
| 1117 | case TypeTableEntryIdEnum: | 1255 | case TypeTableEntryIdEnum: |
| 1118 | case TypeTableEntryIdMetaType: | 1256 | case TypeTableEntryIdMetaType: |
| | 1257 | case TypeTableEntryIdFn: |
| 1119 | return false; | 1258 | return false; |
| 1120 | case TypeTableEntryIdInt: | 1259 | case TypeTableEntryIdInt: |
| 1121 | if (is_num_lit_unsigned(num_lit)) { | 1260 | if (is_num_lit_unsigned(num_lit)) { |
| ... | @@ -1703,17 +1842,28 @@ static TypeTableEntry *analyze_symbol_expr(CodeGen *g, ImportTableEntry *import, | ... | @@ -1703,17 +1842,28 @@ static TypeTableEntry *analyze_symbol_expr(CodeGen *g, ImportTableEntry *import, |
| 1703 | | 1842 | |
| 1704 | auto primitive_table_entry = g->primitive_type_table.maybe_get(variable_name); | 1843 | auto primitive_table_entry = g->primitive_type_table.maybe_get(variable_name); |
| 1705 | if (primitive_table_entry) { | 1844 | if (primitive_table_entry) { |
| 1706 | return get_meta_type(g, primitive_table_entry->value); | 1845 | TypeTableEntry *meta_type = get_meta_type(g, primitive_table_entry->value); |
| | 1846 | node->data.symbol_expr.meta_type = meta_type; |
| | 1847 | return meta_type; |
| 1707 | } | 1848 | } |
| 1708 | | 1849 | |
| 1709 | VariableTableEntry *var = find_variable(context, variable_name); | 1850 | VariableTableEntry *var = find_variable(context, variable_name); |
| 1710 | if (var) { | 1851 | if (var) { |
| | 1852 | node->data.symbol_expr.variable = var; |
| 1711 | return var->type; | 1853 | return var->type; |
| 1712 | } | 1854 | } |
| 1713 | | 1855 | |
| 1714 | TypeTableEntry *container_type = find_container(context, variable_name); | 1856 | TypeTableEntry *container_type = find_container(context, variable_name); |
| 1715 | if (container_type) { | 1857 | if (container_type) { |
| 1716 | return get_meta_type(g, container_type); | 1858 | TypeTableEntry *meta_type = get_meta_type(g, container_type); |
| | 1859 | node->data.symbol_expr.meta_type = meta_type; |
| | 1860 | return meta_type; |
| | 1861 | } |
| | 1862 | |
| | 1863 | auto fn_table_entry = import->fn_table.maybe_get(variable_name); |
| | 1864 | if (fn_table_entry) { |
| | 1865 | node->data.symbol_expr.fn_entry = fn_table_entry->value; |
| | 1866 | return node->data.symbol_expr.fn_entry->type_entry; |
| 1717 | } | 1867 | } |
| 1718 | | 1868 | |
| 1719 | add_node_error(g, node, buf_sprintf("use of undeclared identifier '%s'", buf_ptr(variable_name))); | 1869 | add_node_error(g, node, buf_sprintf("use of undeclared identifier '%s'", buf_ptr(variable_name))); |
| ... | @@ -1781,65 +1931,6 @@ static bool is_op_allowed(TypeTableEntry *type, BinOpType op) { | ... | @@ -1781,65 +1931,6 @@ static bool is_op_allowed(TypeTableEntry *type, BinOpType op) { |
| 1781 | zig_unreachable(); | 1931 | zig_unreachable(); |
| 1782 | } | 1932 | } |
| 1783 | | 1933 | |
| 1784 | static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, | | |
| 1785 | TypeTableEntry *expected_type, AstNode *node) | | |
| 1786 | { | | |
| 1787 | assert(node->type == NodeTypeCastExpr); | | |
| 1788 | | | |
| 1789 | TypeTableEntry *wanted_type = analyze_type_expr(g, import, context, node->data.cast_expr.type); | | |
| 1790 | TypeTableEntry *actual_type = analyze_expression(g, import, context, nullptr, node->data.cast_expr.expr); | | |
| 1791 | | | |
| 1792 | if (wanted_type->id == TypeTableEntryIdInvalid || | | |
| 1793 | actual_type->id == TypeTableEntryIdInvalid) | | |
| 1794 | { | | |
| 1795 | return g->builtin_types.entry_invalid; | | |
| 1796 | } | | |
| 1797 | | | |
| 1798 | Cast *cast = &node->data.cast_expr.cast; | | |
| 1799 | cast->source_node = node; | | |
| 1800 | cast->after_type = wanted_type; | | |
| 1801 | | | |
| 1802 | if ((wanted_type == g->builtin_types.entry_isize || wanted_type == g->builtin_types.entry_usize) && | | |
| 1803 | actual_type->id == TypeTableEntryIdPointer) | | |
| 1804 | { | | |
| 1805 | cast->op = CastOpPtrToInt; | | |
| 1806 | return wanted_type; | | |
| 1807 | } else if (wanted_type->id == TypeTableEntryIdInt && | | |
| 1808 | actual_type->id == TypeTableEntryIdInt) | | |
| 1809 | { | | |
| 1810 | cast->op = CastOpIntWidenOrShorten; | | |
| 1811 | return wanted_type; | | |
| 1812 | } else if (wanted_type->id == TypeTableEntryIdStruct && | | |
| 1813 | wanted_type->data.structure.is_unknown_size_array && | | |
| 1814 | actual_type->id == TypeTableEntryIdArray && | | |
| 1815 | actual_type->data.array.child_type == wanted_type->data.structure.fields[0].type_entry) | | |
| 1816 | { | | |
| 1817 | cast->op = CastOpToUnknownSizeArray; | | |
| 1818 | context->cast_expr_alloca_list.append(cast); | | |
| 1819 | return wanted_type; | | |
| 1820 | } else if (actual_type->id == TypeTableEntryIdNumberLiteral && | | |
| 1821 | num_lit_fits_in_other_type(g, actual_type, wanted_type)) | | |
| 1822 | { | | |
| 1823 | AstNode *literal_node = node->data.cast_expr.expr; | | |
| 1824 | NumLitCodeGen *codegen_num_lit = get_resolved_num_lit(literal_node); | | |
| 1825 | assert(!codegen_num_lit->resolved_type); | | |
| 1826 | codegen_num_lit->resolved_type = wanted_type; | | |
| 1827 | cast->op = CastOpNothing; | | |
| 1828 | return wanted_type; | | |
| 1829 | } else if (actual_type->id == TypeTableEntryIdPointer && | | |
| 1830 | wanted_type->id == TypeTableEntryIdPointer) | | |
| 1831 | { | | |
| 1832 | cast->op = CastOpPointerReinterpret; | | |
| 1833 | return wanted_type; | | |
| 1834 | } else { | | |
| 1835 | add_node_error(g, node, | | |
| 1836 | buf_sprintf("invalid cast from type '%s' to '%s'", | | |
| 1837 | buf_ptr(&actual_type->name), | | |
| 1838 | buf_ptr(&wanted_type->name))); | | |
| 1839 | return g->builtin_types.entry_invalid; | | |
| 1840 | } | | |
| 1841 | } | | |
| 1842 | | | |
| 1843 | enum LValPurpose { | 1934 | enum LValPurpose { |
| 1844 | LValPurposeAssign, | 1935 | LValPurposeAssign, |
| 1845 | LValPurposeAddressOf, | 1936 | LValPurposeAddressOf, |
| ... | @@ -2153,17 +2244,11 @@ static TypeTableEntry *analyze_array_type(CodeGen *g, ImportTableEntry *import, | ... | @@ -2153,17 +2244,11 @@ static TypeTableEntry *analyze_array_type(CodeGen *g, ImportTableEntry *import, |
| 2153 | return g->builtin_types.entry_invalid; | 2244 | return g->builtin_types.entry_invalid; |
| 2154 | } | 2245 | } |
| 2155 | | 2246 | |
| 2156 | AstNodeNumberLiteral number_literal; | 2247 | ConstExprValue const_val = {0}; |
| 2157 | TypeTableEntry *resolved_type = eval_const_expr(g, context, size_node, &number_literal); | 2248 | eval_const_expr(g, context, size_node, &const_val); |
| 2158 | | 2249 | |
| 2159 | if (resolved_type->id == TypeTableEntryIdInt) { | 2250 | if (const_val.ok) { |
| 2160 | if (resolved_type->data.integral.is_signed) { | 2251 | return get_meta_type(g, get_array_type(g, import, child_type, const_val.data.x_uint)); |
| 2161 | add_node_error(g, size_node, | | |
| 2162 | buf_create_from_str("array size must be unsigned integer")); | | |
| 2163 | return g->builtin_types.entry_invalid; | | |
| 2164 | } else { | | |
| 2165 | return get_meta_type(g, get_array_type(g, import, child_type, number_literal.data.x_uint)); | | |
| 2166 | } | | |
| 2167 | } else { | 2252 | } else { |
| 2168 | add_node_error(g, size_node, | 2253 | add_node_error(g, size_node, |
| 2169 | buf_create_from_str("unable to resolve constant expression")); | 2254 | buf_create_from_str("unable to resolve constant expression")); |
| ... | @@ -2195,12 +2280,11 @@ static TypeTableEntry *analyze_while_expr(CodeGen *g, ImportTableEntry *import, | ... | @@ -2195,12 +2280,11 @@ static TypeTableEntry *analyze_while_expr(CodeGen *g, ImportTableEntry *import, |
| 2195 | } else { | 2280 | } else { |
| 2196 | // if the condition is a simple constant expression and there are no break statements | 2281 | // if the condition is a simple constant expression and there are no break statements |
| 2197 | // then the return type is unreachable | 2282 | // then the return type is unreachable |
| 2198 | AstNodeNumberLiteral number_literal; | 2283 | ConstExprValue const_val = {0}; |
| 2199 | TypeTableEntry *resolved_type = eval_const_expr(g, context, condition_node, &number_literal); | 2284 | eval_const_expr(g, context, condition_node, &const_val); |
| 2200 | if (resolved_type->id != TypeTableEntryIdInvalid) { | 2285 | |
| 2201 | assert(resolved_type->id == TypeTableEntryIdBool); | 2286 | if (const_val.ok) { |
| 2202 | bool constant_cond_value = number_literal.data.x_uint; | 2287 | if (const_val.data.x_bool) { |
| 2203 | if (constant_cond_value) { | | |
| 2204 | node->data.while_expr.condition_always_true = true; | 2288 | node->data.while_expr.condition_always_true = true; |
| 2205 | if (!node->data.while_expr.contains_break) { | 2289 | if (!node->data.while_expr.contains_break) { |
| 2206 | expr_return_type = g->builtin_types.entry_unreachable; | 2290 | expr_return_type = g->builtin_types.entry_unreachable; |
| ... | @@ -2305,6 +2389,73 @@ static TypeTableEntry *analyze_min_max_value(CodeGen *g, ImportTableEntry *impor | ... | @@ -2305,6 +2389,73 @@ static TypeTableEntry *analyze_min_max_value(CodeGen *g, ImportTableEntry *impor |
| 2305 | } | 2389 | } |
| 2306 | } | 2390 | } |
| 2307 | | 2391 | |
| | 2392 | static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| | 2393 | AstNode *node, TypeTableEntry *invoke_type_entry) |
| | 2394 | { |
| | 2395 | assert(node->type == NodeTypeFnCallExpr); |
| | 2396 | |
| | 2397 | AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr; |
| | 2398 | int actual_param_count = node->data.fn_call_expr.params.length; |
| | 2399 | |
| | 2400 | if (actual_param_count != 1) { |
| | 2401 | add_node_error(g, fn_ref_expr, buf_sprintf("cast expression expects exactly one parameter")); |
| | 2402 | return g->builtin_types.entry_invalid; |
| | 2403 | } |
| | 2404 | |
| | 2405 | AstNode *expr_node = node->data.fn_call_expr.params.at(0); |
| | 2406 | TypeTableEntry *wanted_type = invoke_type_entry->data.meta_type.child_type; |
| | 2407 | TypeTableEntry *actual_type = analyze_expression(g, import, context, nullptr, expr_node); |
| | 2408 | |
| | 2409 | if (wanted_type->id == TypeTableEntryIdInvalid || |
| | 2410 | actual_type->id == TypeTableEntryIdInvalid) |
| | 2411 | { |
| | 2412 | return g->builtin_types.entry_invalid; |
| | 2413 | } |
| | 2414 | |
| | 2415 | Cast *cast = &node->data.fn_call_expr.cast; |
| | 2416 | cast->source_node = node; |
| | 2417 | cast->after_type = wanted_type; |
| | 2418 | |
| | 2419 | if ((wanted_type == g->builtin_types.entry_isize || wanted_type == g->builtin_types.entry_usize) && |
| | 2420 | actual_type->id == TypeTableEntryIdPointer) |
| | 2421 | { |
| | 2422 | cast->op = CastOpPtrToInt; |
| | 2423 | return wanted_type; |
| | 2424 | } else if (wanted_type->id == TypeTableEntryIdInt && |
| | 2425 | actual_type->id == TypeTableEntryIdInt) |
| | 2426 | { |
| | 2427 | cast->op = CastOpIntWidenOrShorten; |
| | 2428 | return wanted_type; |
| | 2429 | } else if (wanted_type->id == TypeTableEntryIdStruct && |
| | 2430 | wanted_type->data.structure.is_unknown_size_array && |
| | 2431 | actual_type->id == TypeTableEntryIdArray && |
| | 2432 | actual_type->data.array.child_type == wanted_type->data.structure.fields[0].type_entry) |
| | 2433 | { |
| | 2434 | cast->op = CastOpToUnknownSizeArray; |
| | 2435 | context->cast_expr_alloca_list.append(cast); |
| | 2436 | return wanted_type; |
| | 2437 | } else if (actual_type->id == TypeTableEntryIdNumberLiteral && |
| | 2438 | num_lit_fits_in_other_type(g, actual_type, wanted_type)) |
| | 2439 | { |
| | 2440 | NumLitCodeGen *codegen_num_lit = get_resolved_num_lit(expr_node); |
| | 2441 | assert(!codegen_num_lit->resolved_type); |
| | 2442 | codegen_num_lit->resolved_type = wanted_type; |
| | 2443 | cast->op = CastOpNothing; |
| | 2444 | return wanted_type; |
| | 2445 | } else if (actual_type->id == TypeTableEntryIdPointer && |
| | 2446 | wanted_type->id == TypeTableEntryIdPointer) |
| | 2447 | { |
| | 2448 | cast->op = CastOpPointerReinterpret; |
| | 2449 | return wanted_type; |
| | 2450 | } else { |
| | 2451 | add_node_error(g, node, |
| | 2452 | buf_sprintf("invalid cast from type '%s' to '%s'", |
| | 2453 | buf_ptr(&actual_type->name), |
| | 2454 | buf_ptr(&wanted_type->name))); |
| | 2455 | return g->builtin_types.entry_invalid; |
| | 2456 | } |
| | 2457 | } |
| | 2458 | |
| 2308 | static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, | 2459 | static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 2309 | TypeTableEntry *expected_type, AstNode *node) | 2460 | TypeTableEntry *expected_type, AstNode *node) |
| 2310 | { | 2461 | { |
| ... | @@ -2458,25 +2609,93 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry | ... | @@ -2458,25 +2609,93 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry |
| 2458 | } | 2609 | } |
| 2459 | } | 2610 | } |
| 2460 | | 2611 | |
| | 2612 | static TypeTableEntry *analyze_fn_call_raw(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| | 2613 | TypeTableEntry *expected_type, AstNode *node, FnTableEntry *fn_table_entry, TypeTableEntry *struct_type) |
| | 2614 | { |
| | 2615 | assert(node->type == NodeTypeFnCallExpr); |
| | 2616 | |
| | 2617 | node->data.fn_call_expr.fn_entry = fn_table_entry; |
| | 2618 | assert(fn_table_entry->proto_node->type == NodeTypeFnProto); |
| | 2619 | AstNodeFnProto *fn_proto = &fn_table_entry->proto_node->data.fn_proto; |
| | 2620 | |
| | 2621 | // count parameters |
| | 2622 | int expected_param_count = fn_proto->params.length; |
| | 2623 | int actual_param_count = node->data.fn_call_expr.params.length; |
| | 2624 | |
| | 2625 | if (struct_type) { |
| | 2626 | actual_param_count += 1; |
| | 2627 | } |
| | 2628 | |
| | 2629 | if (fn_proto->is_var_args) { |
| | 2630 | if (actual_param_count < expected_param_count) { |
| | 2631 | add_node_error(g, node, |
| | 2632 | buf_sprintf("expected at least %d arguments, got %d", |
| | 2633 | expected_param_count, actual_param_count)); |
| | 2634 | } |
| | 2635 | } else if (expected_param_count != actual_param_count) { |
| | 2636 | add_node_error(g, node, |
| | 2637 | buf_sprintf("expected %d arguments, got %d", |
| | 2638 | expected_param_count, actual_param_count)); |
| | 2639 | } |
| | 2640 | |
| | 2641 | // analyze each parameter. in the case of a method, we already analyzed the |
| | 2642 | // first parameter in order to figure out which struct we were calling a method on. |
| | 2643 | for (int i = 0; i < node->data.fn_call_expr.params.length; i += 1) { |
| | 2644 | AstNode *child = node->data.fn_call_expr.params.at(i); |
| | 2645 | // determine the expected type for each parameter |
| | 2646 | TypeTableEntry *expected_param_type = nullptr; |
| | 2647 | int fn_proto_i = i + (struct_type ? 1 : 0); |
| | 2648 | if (fn_proto_i < fn_proto->params.length) { |
| | 2649 | AstNode *param_decl_node = fn_proto->params.at(fn_proto_i); |
| | 2650 | assert(param_decl_node->type == NodeTypeParamDecl); |
| | 2651 | AstNode *param_type_node = param_decl_node->data.param_decl.type; |
| | 2652 | TypeTableEntry *param_type_entry = get_resolved_expr(param_type_node)->type_entry; |
| | 2653 | if (param_type_entry) { |
| | 2654 | expected_param_type = unwrapped_node_type(param_type_node); |
| | 2655 | } |
| | 2656 | } |
| | 2657 | analyze_expression(g, import, context, expected_param_type, child); |
| | 2658 | } |
| | 2659 | |
| | 2660 | return unwrapped_node_type(fn_proto->return_type); |
| | 2661 | } |
| | 2662 | |
| 2461 | static TypeTableEntry *analyze_fn_call_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, | 2663 | static TypeTableEntry *analyze_fn_call_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 2462 | TypeTableEntry *expected_type, AstNode *node) | 2664 | TypeTableEntry *expected_type, AstNode *node) |
| 2463 | { | 2665 | { |
| 2464 | AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr; | 2666 | AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr; |
| 2465 | TypeTableEntry *struct_type = nullptr; | 2667 | |
| 2466 | HashMap<Buf *, FnTableEntry *, buf_hash, buf_eql_buf> *fn_table = &import->fn_table; | 2668 | if (node->data.fn_call_expr.is_builtin) { |
| 2467 | AstNode *first_param_expr = nullptr; | 2669 | return analyze_builtin_fn_call_expr(g, import, context, expected_type, node); |
| 2468 | Buf *name; | 2670 | } |
| 2469 | | 2671 | |
| 2470 | if (fn_ref_expr->type == NodeTypeFieldAccessExpr) { | 2672 | if (fn_ref_expr->type == NodeTypeFieldAccessExpr) { |
| 2471 | first_param_expr = fn_ref_expr->data.field_access_expr.struct_expr; | 2673 | AstNode *first_param_expr = fn_ref_expr->data.field_access_expr.struct_expr; |
| 2472 | struct_type = analyze_expression(g, import, context, nullptr, first_param_expr); | 2674 | TypeTableEntry *struct_type = analyze_expression(g, import, context, nullptr, first_param_expr); |
| 2473 | name = &fn_ref_expr->data.field_access_expr.field_name; | 2675 | Buf *name = &fn_ref_expr->data.field_access_expr.field_name; |
| 2474 | if (struct_type->id == TypeTableEntryIdStruct) { | 2676 | if (struct_type->id == TypeTableEntryIdStruct || |
| 2475 | fn_table = &struct_type->data.structure.fn_table; | 2677 | (struct_type->id == TypeTableEntryIdPointer && |
| 2476 | } else if (struct_type->id == TypeTableEntryIdPointer && | 2678 | struct_type->data.pointer.child_type->id == TypeTableEntryIdStruct)) |
| 2477 | struct_type->data.pointer.child_type->id == TypeTableEntryIdStruct) | | |
| 2478 | { | 2679 | { |
| 2479 | fn_table = &struct_type->data.pointer.child_type->data.structure.fn_table; | 2680 | TypeTableEntry *bare_struct_type = (struct_type->id == TypeTableEntryIdStruct) ? |
| | 2681 | struct_type : struct_type->data.pointer.child_type; |
| | 2682 | |
| | 2683 | auto table_entry = bare_struct_type->data.structure.fn_table.maybe_get(name); |
| | 2684 | if (table_entry) { |
| | 2685 | return analyze_fn_call_raw(g, import, context, expected_type, node, |
| | 2686 | table_entry->value, bare_struct_type); |
| | 2687 | } else { |
| | 2688 | add_node_error(g, fn_ref_expr, |
| | 2689 | buf_sprintf("no function named '%s' in '%s'", |
| | 2690 | buf_ptr(name), buf_ptr(&bare_struct_type->name))); |
| | 2691 | // still analyze the parameters, even though we don't know what to expect |
| | 2692 | for (int i = 0; i < node->data.fn_call_expr.params.length; i += 1) { |
| | 2693 | AstNode *child = node->data.fn_call_expr.params.at(i); |
| | 2694 | analyze_expression(g, import, context, nullptr, child); |
| | 2695 | } |
| | 2696 | |
| | 2697 | return g->builtin_types.entry_invalid; |
| | 2698 | } |
| 2480 | } else if (struct_type->id == TypeTableEntryIdInvalid) { | 2699 | } else if (struct_type->id == TypeTableEntryIdInvalid) { |
| 2481 | return struct_type; | 2700 | return struct_type; |
| 2482 | } else if (struct_type->id == TypeTableEntryIdMetaType && | 2701 | } else if (struct_type->id == TypeTableEntryIdMetaType && |
| ... | @@ -2505,74 +2724,31 @@ static TypeTableEntry *analyze_fn_call_expr(CodeGen *g, ImportTableEntry *import | ... | @@ -2505,74 +2724,31 @@ static TypeTableEntry *analyze_fn_call_expr(CodeGen *g, ImportTableEntry *import |
| 2505 | buf_sprintf("member reference base type not struct or enum")); | 2724 | buf_sprintf("member reference base type not struct or enum")); |
| 2506 | return g->builtin_types.entry_invalid; | 2725 | return g->builtin_types.entry_invalid; |
| 2507 | } | 2726 | } |
| 2508 | } else if (fn_ref_expr->type == NodeTypeSymbol) { | | |
| 2509 | if (node->data.fn_call_expr.is_builtin) { | | |
| 2510 | return analyze_builtin_fn_call_expr(g, import, context, expected_type, node); | | |
| 2511 | } | | |
| 2512 | name = &fn_ref_expr->data.symbol_expr.symbol; | | |
| 2513 | } else { | | |
| 2514 | add_node_error(g, node, | | |
| 2515 | buf_sprintf("function pointers not yet supported")); | | |
| 2516 | return g->builtin_types.entry_invalid; | | |
| 2517 | } | 2727 | } |
| 2518 | | 2728 | |
| 2519 | auto entry = fn_table->maybe_get(name); | 2729 | TypeTableEntry *invoke_type_entry = analyze_expression(g, import, context, nullptr, fn_ref_expr); |
| 2520 | | 2730 | if (invoke_type_entry->id == TypeTableEntryIdInvalid) { |
| 2521 | if (!entry) { | | |
| 2522 | add_node_error(g, fn_ref_expr, | | |
| 2523 | buf_sprintf("undefined function: '%s'", buf_ptr(name))); | | |
| 2524 | // still analyze the parameters, even though we don't know what to expect | | |
| 2525 | for (int i = 0; i < node->data.fn_call_expr.params.length; i += 1) { | | |
| 2526 | AstNode *child = node->data.fn_call_expr.params.at(i); | | |
| 2527 | analyze_expression(g, import, context, nullptr, child); | | |
| 2528 | } | | |
| 2529 | | | |
| 2530 | return g->builtin_types.entry_invalid; | 2731 | return g->builtin_types.entry_invalid; |
| 2531 | } else { | 2732 | } |
| 2532 | FnTableEntry *fn_table_entry = entry->value; | | |
| 2533 | assert(fn_table_entry->proto_node->type == NodeTypeFnProto); | | |
| 2534 | AstNodeFnProto *fn_proto = &fn_table_entry->proto_node->data.fn_proto; | | |
| 2535 | | | |
| 2536 | // count parameters | | |
| 2537 | int expected_param_count = fn_proto->params.length; | | |
| 2538 | int actual_param_count = node->data.fn_call_expr.params.length; | | |
| 2539 | | | |
| 2540 | if (struct_type) { | | |
| 2541 | actual_param_count += 1; | | |
| 2542 | } | | |
| 2543 | | 2733 | |
| 2544 | if (fn_proto->is_var_args) { | 2734 | // use constant expression evaluator to figure out the function at compile time. |
| 2545 | if (actual_param_count < expected_param_count) { | 2735 | // otherwise we treat this as a function pointer. |
| 2546 | add_node_error(g, node, | 2736 | ConstExprValue const_val = {0}; |
| 2547 | buf_sprintf("expected at least %d arguments, got %d", | 2737 | eval_const_expr(g, context, fn_ref_expr, &const_val); |
| 2548 | expected_param_count, actual_param_count)); | | |
| 2549 | } | | |
| 2550 | } else if (expected_param_count != actual_param_count) { | | |
| 2551 | add_node_error(g, node, | | |
| 2552 | buf_sprintf("expected %d arguments, got %d", | | |
| 2553 | expected_param_count, actual_param_count)); | | |
| 2554 | } | | |
| 2555 | | 2738 | |
| 2556 | // analyze each parameter. in the case of a method, we already analyzed the | 2739 | if (!const_val.ok) { |
| 2557 | // first parameter in order to figure out which struct we were calling a method on. | 2740 | add_node_error(g, node, buf_sprintf("function pointers not yet supported")); |
| 2558 | for (int i = 0; i < node->data.fn_call_expr.params.length; i += 1) { | 2741 | return g->builtin_types.entry_invalid; |
| 2559 | AstNode *child = node->data.fn_call_expr.params.at(i); | 2742 | } |
| 2560 | // determine the expected type for each parameter | | |
| 2561 | TypeTableEntry *expected_param_type = nullptr; | | |
| 2562 | int fn_proto_i = i + (struct_type ? 1 : 0); | | |
| 2563 | if (fn_proto_i < fn_proto->params.length) { | | |
| 2564 | AstNode *param_decl_node = fn_proto->params.at(fn_proto_i); | | |
| 2565 | assert(param_decl_node->type == NodeTypeParamDecl); | | |
| 2566 | AstNode *param_type_node = param_decl_node->data.param_decl.type; | | |
| 2567 | TypeTableEntry *param_type_entry = get_resolved_expr(param_type_node)->type_entry; | | |
| 2568 | if (param_type_entry) { | | |
| 2569 | expected_param_type = unwrapped_node_type(param_type_node); | | |
| 2570 | } | | |
| 2571 | } | | |
| 2572 | analyze_expression(g, import, context, expected_param_type, child); | | |
| 2573 | } | | |
| 2574 | | 2743 | |
| 2575 | return unwrapped_node_type(fn_proto->return_type); | 2744 | if (invoke_type_entry->id == TypeTableEntryIdMetaType) { |
| | 2745 | return analyze_cast_expr(g, import, context, node, invoke_type_entry); |
| | 2746 | } else if (invoke_type_entry->id == TypeTableEntryIdFn) { |
| | 2747 | return analyze_fn_call_raw(g, import, context, expected_type, node, const_val.data.x_fn, nullptr); |
| | 2748 | } else { |
| | 2749 | add_node_error(g, fn_ref_expr, |
| | 2750 | buf_sprintf("type '%s' not a function", buf_ptr(&invoke_type_entry->name))); |
| | 2751 | return g->builtin_types.entry_invalid; |
| 2576 | } | 2752 | } |
| 2577 | } | 2753 | } |
| 2578 | | 2754 | |
| ... | @@ -2847,9 +3023,6 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, | ... | @@ -2847,9 +3023,6 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, |
| 2847 | case NodeTypeSymbol: | 3023 | case NodeTypeSymbol: |
| 2848 | return_type = analyze_symbol_expr(g, import, context, expected_type, node); | 3024 | return_type = analyze_symbol_expr(g, import, context, expected_type, node); |
| 2849 | break; | 3025 | break; |
| 2850 | case NodeTypeCastExpr: | | |
| 2851 | return_type = analyze_cast_expr(g, import, context, expected_type, node); | | |
| 2852 | break; | | |
| 2853 | case NodeTypePrefixOpExpr: | 3026 | case NodeTypePrefixOpExpr: |
| 2854 | return_type = analyze_prefix_op_expr(g, import, context, expected_type, node); | 3027 | return_type = analyze_prefix_op_expr(g, import, context, expected_type, node); |
| 2855 | break; | 3028 | break; |
| ... | @@ -3008,7 +3181,6 @@ static void analyze_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode | ... | @@ -3008,7 +3181,6 @@ static void analyze_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode |
| 3008 | case NodeTypeBoolLiteral: | 3181 | case NodeTypeBoolLiteral: |
| 3009 | case NodeTypeNullLiteral: | 3182 | case NodeTypeNullLiteral: |
| 3010 | case NodeTypeSymbol: | 3183 | case NodeTypeSymbol: |
| 3011 | case NodeTypeCastExpr: | | |
| 3012 | case NodeTypePrefixOpExpr: | 3184 | case NodeTypePrefixOpExpr: |
| 3013 | case NodeTypeIfBoolExpr: | 3185 | case NodeTypeIfBoolExpr: |
| 3014 | case NodeTypeIfVarExpr: | 3186 | case NodeTypeIfVarExpr: |
| ... | @@ -3060,10 +3232,6 @@ static void collect_expr_decl_deps(CodeGen *g, ImportTableEntry *import, AstNode | ... | @@ -3060,10 +3232,6 @@ static void collect_expr_decl_deps(CodeGen *g, ImportTableEntry *import, AstNode |
| 3060 | case NodeTypeReturnExpr: | 3232 | case NodeTypeReturnExpr: |
| 3061 | collect_expr_decl_deps(g, import, node->data.return_expr.expr, decl_node); | 3233 | collect_expr_decl_deps(g, import, node->data.return_expr.expr, decl_node); |
| 3062 | break; | 3234 | break; |
| 3063 | case NodeTypeCastExpr: | | |
| 3064 | collect_expr_decl_deps(g, import, node->data.cast_expr.expr, decl_node); | | |
| 3065 | collect_expr_decl_deps(g, import, node->data.cast_expr.type, decl_node); | | |
| 3066 | break; | | |
| 3067 | case NodeTypePrefixOpExpr: | 3235 | case NodeTypePrefixOpExpr: |
| 3068 | collect_expr_decl_deps(g, import, node->data.prefix_op_expr.primary_expr, decl_node); | 3236 | collect_expr_decl_deps(g, import, node->data.prefix_op_expr.primary_expr, decl_node); |
| 3069 | break; | 3237 | break; |
| ... | @@ -3331,7 +3499,6 @@ static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, Ast | ... | @@ -3331,7 +3499,6 @@ static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, Ast |
| 3331 | case NodeTypeBoolLiteral: | 3499 | case NodeTypeBoolLiteral: |
| 3332 | case NodeTypeNullLiteral: | 3500 | case NodeTypeNullLiteral: |
| 3333 | case NodeTypeSymbol: | 3501 | case NodeTypeSymbol: |
| 3334 | case NodeTypeCastExpr: | | |
| 3335 | case NodeTypePrefixOpExpr: | 3502 | case NodeTypePrefixOpExpr: |
| 3336 | case NodeTypeIfBoolExpr: | 3503 | case NodeTypeIfBoolExpr: |
| 3337 | case NodeTypeIfVarExpr: | 3504 | case NodeTypeIfVarExpr: |
| ... | @@ -3504,8 +3671,6 @@ Expr *get_resolved_expr(AstNode *node) { | ... | @@ -3504,8 +3671,6 @@ Expr *get_resolved_expr(AstNode *node) { |
| 3504 | return &node->data.return_expr.resolved_expr; | 3671 | return &node->data.return_expr.resolved_expr; |
| 3505 | case NodeTypeBinOpExpr: | 3672 | case NodeTypeBinOpExpr: |
| 3506 | return &node->data.bin_op_expr.resolved_expr; | 3673 | return &node->data.bin_op_expr.resolved_expr; |
| 3507 | case NodeTypeCastExpr: | | |
| 3508 | return &node->data.cast_expr.resolved_expr; | | |
| 3509 | case NodeTypePrefixOpExpr: | 3674 | case NodeTypePrefixOpExpr: |
| 3510 | return &node->data.prefix_op_expr.resolved_expr; | 3675 | return &node->data.prefix_op_expr.resolved_expr; |
| 3511 | case NodeTypeFnCallExpr: | 3676 | case NodeTypeFnCallExpr: |
| ... | @@ -3577,7 +3742,6 @@ NumLitCodeGen *get_resolved_num_lit(AstNode *node) { | ... | @@ -3577,7 +3742,6 @@ NumLitCodeGen *get_resolved_num_lit(AstNode *node) { |
| 3577 | return &node->data.fn_call_expr.resolved_num_lit; | 3742 | return &node->data.fn_call_expr.resolved_num_lit; |
| 3578 | case NodeTypeReturnExpr: | 3743 | case NodeTypeReturnExpr: |
| 3579 | case NodeTypeBinOpExpr: | 3744 | case NodeTypeBinOpExpr: |
| 3580 | case NodeTypeCastExpr: | | |
| 3581 | case NodeTypePrefixOpExpr: | 3745 | case NodeTypePrefixOpExpr: |
| 3582 | case NodeTypeArrayAccessExpr: | 3746 | case NodeTypeArrayAccessExpr: |
| 3583 | case NodeTypeSliceExpr: | 3747 | case NodeTypeSliceExpr: |
| ... | @@ -3627,7 +3791,6 @@ TopLevelDecl *get_resolved_top_level_decl(AstNode *node) { | ... | @@ -3627,7 +3791,6 @@ TopLevelDecl *get_resolved_top_level_decl(AstNode *node) { |
| 3627 | case NodeTypeNumberLiteral: | 3791 | case NodeTypeNumberLiteral: |
| 3628 | case NodeTypeReturnExpr: | 3792 | case NodeTypeReturnExpr: |
| 3629 | case NodeTypeBinOpExpr: | 3793 | case NodeTypeBinOpExpr: |
| 3630 | case NodeTypeCastExpr: | | |
| 3631 | case NodeTypePrefixOpExpr: | 3794 | case NodeTypePrefixOpExpr: |
| 3632 | case NodeTypeFnCallExpr: | 3795 | case NodeTypeFnCallExpr: |
| 3633 | case NodeTypeArrayAccessExpr: | 3796 | case NodeTypeArrayAccessExpr: |