| 1074 | } |
| 1075 | |
| 1076 | Expect<void> Validator::validateCanonOptions( |
| 1077 | ComponentCanonOpCode Code, |
| 1078 | Span<const AST::Component::CanonOpt> Opts) noexcept { |
| 1079 | using OptCode = ComponentCanonOptCode; |
| 1080 | using CanonOp = ComponentCanonOpCode; |
| 1081 | |
| 1082 | // Only canon lift/lower accept canonical options. Any other built-in |
| 1083 | // (resource.new/rep/drop, drop_async, ...) must be invoked without options. |
| 1084 | if (Code != CanonOp::Lift && Code != CanonOp::Lower && !Opts.empty()) { |
| 1085 | spdlog::error(ErrCode::Value::InvalidCanonOption); |
| 1086 | spdlog::error( |
| 1087 | " canonical options are not allowed for this canon built-in"sv); |
| 1088 | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Canonical)); |
| 1089 | return Unexpect(ErrCode::Value::InvalidCanonOption); |
| 1090 | } |
| 1091 | |
| 1092 | bool HasEncoding = false; |
| 1093 | bool HasMemory = false; |
| 1094 | bool HasRealloc = false; |
| 1095 | bool HasPostReturn = false; |
| 1096 | bool HasAsync = false; |
| 1097 | bool HasCallback = false; |
| 1098 | bool HasAlwaysTaskReturn = false; |
| 1099 | uint32_t ReallocIdx = 0; |
| 1100 | uint32_t CallbackIdx = 0; |
| 1101 | uint32_t PostReturnIdx = 0; |
| 1102 | uint32_t MemoryIdx = 0; |
| 1103 | |
| 1104 | auto RejectDup = [&](const char *Name) -> Expect<void> { |
| 1105 | spdlog::error(ErrCode::Value::InvalidCanonOption); |
| 1106 | spdlog::error(" canonical option '{}' appears more than once"sv, Name); |
| 1107 | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Canonical)); |
| 1108 | return Unexpect(ErrCode::Value::InvalidCanonOption); |
| 1109 | }; |
| 1110 | auto RejectSite = [&](const char *Name) -> Expect<void> { |
| 1111 | spdlog::error(ErrCode::Value::InvalidCanonOption); |
| 1112 | spdlog::error( |
| 1113 | " canonical option '{}' is not allowed in this canon built-in"sv, |
| 1114 | Name); |
| 1115 | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Canonical)); |
| 1116 | return Unexpect(ErrCode::Value::InvalidCanonOption); |
| 1117 | }; |
| 1118 | |
| 1119 | for (const auto &Opt : Opts) { |
| 1120 | switch (Opt.getCode()) { |
| 1121 | case OptCode::Encode_UTF8: |
| 1122 | case OptCode::Encode_UTF16: |
| 1123 | case OptCode::Encode_Latin1: |
| 1124 | if (HasEncoding) { |
| 1125 | return RejectDup("string-encoding"); |
| 1126 | } |
| 1127 | HasEncoding = true; |
| 1128 | break; |
| 1129 | case OptCode::Memory: |
| 1130 | if (HasMemory) { |
| 1131 | return RejectDup("memory"); |
| 1132 | } |
| 1133 | HasMemory = true; |