handle_literal.cpp 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. // Part of the Carbon Language project, under the Apache License v2.0 with LLVM
  2. // Exceptions. See /LICENSE for license information.
  3. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. #include "toolchain/check/call.h"
  5. #include "toolchain/check/context.h"
  6. #include "toolchain/check/handle.h"
  7. #include "toolchain/diagnostics/format_providers.h"
  8. #include "toolchain/sem_ir/typed_insts.h"
  9. namespace Carbon::Check {
  10. auto HandleParseNode(Context& context, Parse::BoolLiteralFalseId node_id)
  11. -> bool {
  12. context.AddInstAndPush<SemIR::BoolLiteral>(
  13. node_id,
  14. {.type_id = context.GetBuiltinType(SemIR::BuiltinInstKind::BoolType),
  15. .value = SemIR::BoolValue::False});
  16. return true;
  17. }
  18. auto HandleParseNode(Context& context, Parse::BoolLiteralTrueId node_id)
  19. -> bool {
  20. context.AddInstAndPush<SemIR::BoolLiteral>(
  21. node_id,
  22. {.type_id = context.GetBuiltinType(SemIR::BuiltinInstKind::BoolType),
  23. .value = SemIR::BoolValue::True});
  24. return true;
  25. }
  26. // Forms an IntValue instruction with type `IntLiteral` for a given literal
  27. // integer value, which is assumed to be unsigned.
  28. static auto MakeIntLiteral(Context& context, Parse::NodeId node_id,
  29. IntId int_id) -> SemIR::InstId {
  30. return context.AddInst<SemIR::IntValue>(
  31. node_id, {.type_id = context.GetBuiltinType(
  32. SemIR::BuiltinInstKind::IntLiteralType),
  33. .int_id = int_id});
  34. }
  35. auto HandleParseNode(Context& context, Parse::IntLiteralId node_id) -> bool {
  36. auto int_literal_id = MakeIntLiteral(
  37. context, node_id,
  38. context.tokens().GetIntLiteral(context.parse_tree().node_token(node_id)));
  39. context.node_stack().Push(node_id, int_literal_id);
  40. return true;
  41. }
  42. auto HandleParseNode(Context& context, Parse::RealLiteralId node_id) -> bool {
  43. // Convert the real literal to an llvm::APFloat and add it to the floats
  44. // ValueStore. In the future this would use an arbitrary precision Rational
  45. // type.
  46. //
  47. // TODO: Implement Carbon's actual implicit conversion rules for
  48. // floating-point constants, as per the design
  49. // docs/design/expressions/implicit_conversions.md
  50. auto real_id =
  51. context.tokens().GetRealLiteral(context.parse_tree().node_token(node_id));
  52. auto real_value = context.sem_ir().reals().Get(real_id);
  53. if (real_value.mantissa.getActiveBits() > 64) {
  54. CARBON_DIAGNOSTIC(RealMantissaTooLargeForI64, Error,
  55. "real mantissa with value {0} does not fit in i64",
  56. llvm::APSInt);
  57. context.emitter().Emit(node_id, RealMantissaTooLargeForI64,
  58. llvm::APSInt(real_value.mantissa, true));
  59. context.node_stack().Push(node_id, SemIR::InstId::BuiltinErrorInst);
  60. return true;
  61. }
  62. if (real_value.exponent.getSignificantBits() > 64) {
  63. CARBON_DIAGNOSTIC(RealExponentTooLargeForI64, Error,
  64. "real exponent with value {0} does not fit in i64",
  65. llvm::APSInt);
  66. context.emitter().Emit(node_id, RealExponentTooLargeForI64,
  67. llvm::APSInt(real_value.exponent, false));
  68. context.node_stack().Push(node_id, SemIR::InstId::BuiltinErrorInst);
  69. return true;
  70. }
  71. double double_val = real_value.mantissa.getZExtValue() *
  72. std::pow((real_value.is_decimal ? 10 : 2),
  73. real_value.exponent.getSExtValue());
  74. auto float_id = context.sem_ir().floats().Add(llvm::APFloat(double_val));
  75. context.AddInstAndPush<SemIR::FloatLiteral>(
  76. node_id, {.type_id = context.GetBuiltinType(
  77. SemIR::BuiltinInstKind::LegacyFloatType),
  78. .float_id = float_id});
  79. return true;
  80. }
  81. auto HandleParseNode(Context& context, Parse::StringLiteralId node_id) -> bool {
  82. context.AddInstAndPush<SemIR::StringLiteral>(
  83. node_id,
  84. {.type_id = context.GetBuiltinType(SemIR::BuiltinInstKind::StringType),
  85. .string_literal_id = context.tokens().GetStringLiteralValue(
  86. context.parse_tree().node_token(node_id))});
  87. return true;
  88. }
  89. auto HandleParseNode(Context& context, Parse::BoolTypeLiteralId node_id)
  90. -> bool {
  91. auto fn_inst_id = context.LookupNameInCore(node_id, "Bool");
  92. auto type_inst_id = PerformCall(context, node_id, fn_inst_id, {});
  93. context.node_stack().Push(node_id, type_inst_id);
  94. return true;
  95. }
  96. // Shared implementation for handling `iN` and `uN` literals.
  97. static auto HandleIntOrUnsignedIntTypeLiteral(Context& context,
  98. Parse::NodeId node_id,
  99. SemIR::IntKind int_kind,
  100. IntId size_id) -> bool {
  101. if (!(context.ints().Get(size_id) & 3).isZero()) {
  102. CARBON_DIAGNOSTIC(IntWidthNotMultipleOf8, Error,
  103. "bit width of integer type literal must be a multiple of "
  104. "8; use `Core.{0:Int|UInt}({1})` instead",
  105. BoolAsSelect, llvm::APSInt);
  106. context.emitter().Emit(
  107. node_id, IntWidthNotMultipleOf8, int_kind.is_signed(),
  108. llvm::APSInt(context.ints().Get(size_id), /*isUnsigned=*/true));
  109. }
  110. auto width_id = MakeIntLiteral(context, node_id, size_id);
  111. auto fn_inst_id = context.LookupNameInCore(
  112. node_id, int_kind == SemIR::IntKind::Signed ? "Int" : "UInt");
  113. auto type_inst_id = PerformCall(context, node_id, fn_inst_id, {width_id});
  114. context.node_stack().Push(node_id, type_inst_id);
  115. return true;
  116. }
  117. auto HandleParseNode(Context& context, Parse::IntTypeLiteralId node_id)
  118. -> bool {
  119. auto tok_id = context.parse_tree().node_token(node_id);
  120. auto size_id = context.tokens().GetTypeLiteralSize(tok_id);
  121. return HandleIntOrUnsignedIntTypeLiteral(context, node_id,
  122. SemIR::IntKind::Signed, size_id);
  123. }
  124. auto HandleParseNode(Context& context, Parse::UnsignedIntTypeLiteralId node_id)
  125. -> bool {
  126. auto tok_id = context.parse_tree().node_token(node_id);
  127. auto size_id = context.tokens().GetTypeLiteralSize(tok_id);
  128. return HandleIntOrUnsignedIntTypeLiteral(context, node_id,
  129. SemIR::IntKind::Unsigned, size_id);
  130. }
  131. auto HandleParseNode(Context& context, Parse::FloatTypeLiteralId node_id)
  132. -> bool {
  133. auto text =
  134. context.tokens().GetTokenText(context.parse_tree().node_token(node_id));
  135. if (text != "f64") {
  136. return context.TODO(node_id, "Currently only f64 is allowed");
  137. }
  138. auto tok_id = context.parse_tree().node_token(node_id);
  139. auto size_id = context.tokens().GetTypeLiteralSize(tok_id);
  140. auto width_id = MakeIntLiteral(context, node_id, size_id);
  141. auto fn_inst_id = context.LookupNameInCore(node_id, "Float");
  142. auto type_inst_id = PerformCall(context, node_id, fn_inst_id, {width_id});
  143. context.node_stack().Push(node_id, type_inst_id);
  144. return true;
  145. }
  146. auto HandleParseNode(Context& context, Parse::StringTypeLiteralId node_id)
  147. -> bool {
  148. context.node_stack().Push(node_id, SemIR::InstId::BuiltinStringType);
  149. return true;
  150. }
  151. auto HandleParseNode(Context& context, Parse::TypeTypeLiteralId node_id)
  152. -> bool {
  153. context.node_stack().Push(node_id, SemIR::InstId::BuiltinTypeType);
  154. return true;
  155. }
  156. auto HandleParseNode(Context& context, Parse::AutoTypeLiteralId node_id)
  157. -> bool {
  158. return context.TODO(node_id, "HandleAutoTypeLiteral");
  159. }
  160. } // namespace Carbon::Check