| /* |
| * Copyright 2023 WebAssembly Community Group participants |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include <cstddef> |
| #include <cstdint> |
| #include <cstring> |
| #include <iterator> |
| #include <optional> |
| #include <ostream> |
| #include <string_view> |
| #include <variant> |
| |
| #include "support/name.h" |
| #include "support/result.h" |
| #include "support/string.h" |
| |
| #ifndef parser_lexer_h |
| #define parser_lexer_h |
| |
| namespace wasm::WATParser { |
| |
| struct TextPos { |
| size_t line; |
| size_t col; |
| |
| bool operator==(const TextPos& other) const; |
| bool operator!=(const TextPos& other) const { return !(*this == other); } |
| |
| friend std::ostream& operator<<(std::ostream& os, const TextPos& pos); |
| }; |
| |
| // =========== |
| // Annotations |
| // =========== |
| |
| struct Annotation { |
| Name kind; |
| std::string_view contents; |
| }; |
| |
| extern Name srcAnnotationKind; |
| |
| // ===== |
| // Lexer |
| // ===== |
| |
| struct Lexer { |
| private: |
| size_t pos = 0; |
| std::vector<Annotation> annotations; |
| std::optional<std::string> file; |
| |
| public: |
| std::string_view buffer; |
| |
| Lexer(std::string_view buffer, std::optional<std::string> file = std::nullopt) |
| : file(file), buffer(buffer) { |
| setPos(0); |
| } |
| |
| size_t getPos() const { return pos; } |
| |
| void setPos(size_t i) { |
| pos = i; |
| advance(); |
| } |
| |
| bool takeLParen(); |
| |
| bool peekLParen() { return Lexer(*this).takeLParen(); } |
| |
| bool takeRParen(); |
| |
| bool peekRParen() { return Lexer(*this).takeRParen(); } |
| |
| bool takeUntilParen() { |
| while (true) { |
| if (empty()) { |
| return false; |
| } |
| if (peekLParen() || peekRParen()) { |
| return true; |
| } |
| // Do not count the parentheses in strings. |
| if (takeString()) { |
| continue; |
| } |
| ++pos; |
| advance(); |
| } |
| } |
| |
| std::optional<Name> takeID(); |
| |
| std::optional<std::string_view> takeKeyword(); |
| bool takeKeyword(std::string_view expected); |
| |
| std::optional<std::string_view> peekKeyword() { |
| return Lexer(*this).takeKeyword(); |
| } |
| |
| std::optional<uint64_t> takeOffset(); |
| std::optional<uint32_t> takeAlign(); |
| |
| std::optional<uint64_t> takeU64() { return takeU<uint64_t>(); } |
| std::optional<uint64_t> takeI64() { return takeI<uint64_t>(); } |
| std::optional<uint32_t> takeU32() { return takeU<uint32_t>(); } |
| std::optional<uint32_t> takeI32() { return takeI<uint32_t>(); } |
| std::optional<uint16_t> takeI16() { return takeI<uint16_t>(); } |
| std::optional<uint8_t> takeU8() { return takeU<uint8_t>(); } |
| std::optional<uint8_t> takeI8() { return takeI<uint8_t>(); } |
| |
| std::optional<double> takeF64(); |
| std::optional<float> takeF32(); |
| |
| std::optional<std::string> takeString(); |
| |
| std::optional<Name> takeName() { |
| auto str = takeString(); |
| if (!str || !String::isUTF8(*str)) { |
| return std::nullopt; |
| } |
| return Name(*str); |
| } |
| |
| bool takeSExprStart(std::string_view expected) { |
| auto original = *this; |
| if (takeLParen() && takeKeyword(expected)) { |
| return true; |
| } |
| *this = original; |
| return false; |
| } |
| |
| bool peekSExprStart(std::string_view expected) { |
| auto original = *this; |
| if (!takeLParen()) { |
| return false; |
| } |
| bool ret = takeKeyword(expected); |
| *this = original; |
| return ret; |
| } |
| |
| std::string_view next() const { return buffer.substr(pos); } |
| |
| void advance() { |
| annotations.clear(); |
| skipSpace(); |
| } |
| |
| bool empty() const { return pos == buffer.size(); } |
| |
| TextPos position(const char* c) const; |
| TextPos position(size_t i) const { return position(buffer.data() + i); } |
| TextPos position(std::string_view span) const { |
| return position(span.data()); |
| } |
| TextPos position() const { return position(getPos()); } |
| |
| [[nodiscard]] Err err(size_t pos, std::string reason) { |
| std::stringstream msg; |
| if (file) { |
| msg << *file << ":"; |
| } |
| msg << position(pos) << ": error: " << reason; |
| return Err{msg.str()}; |
| } |
| |
| [[nodiscard]] Err err(std::string reason) { return err(getPos(), reason); } |
| |
| const std::vector<Annotation> getAnnotations() { return annotations; } |
| std::vector<Annotation> takeAnnotations() { return std::move(annotations); } |
| |
| void setAnnotations(std::vector<Annotation>&& annotations) { |
| this->annotations = std::move(annotations); |
| } |
| |
| private: |
| template<typename T> std::optional<T> takeU(); |
| template<typename T> std::optional<T> takeS(); |
| template<typename T> std::optional<T> takeI(); |
| |
| void skipSpace(); |
| }; |
| |
| } // namespace wasm::WATParser |
| |
| #endif // parser_lexer_h |