| // This file is part of GCC. |
| |
| // GCC is free software; you can redistribute it and/or modify it under |
| // the terms of the GNU General Public License as published by the Free |
| // Software Foundation; either version 3, or (at your option) any later |
| // version. |
| |
| // GCC is distributed in the hope that it will be useful, but WITHOUT ANY |
| // WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| // for more details. |
| |
| // You should have received a copy of the GNU General Public License |
| // along with GCC; see the file COPYING3. If not see |
| // <http://www.gnu.org/licenses/>. |
| |
| #include "rust-lex.h" |
| #include "rust-token-converter.h" |
| #include "bi-map.h" |
| #include "line-map.h" |
| #include "rust-system.h" |
| |
| namespace Rust { |
| |
| static const BiMap<PrimitiveCoreType, std::string> suffixes |
| = {{{CORETYPE_F32, "f32"}, |
| {CORETYPE_F64, "f64"}, |
| {CORETYPE_U8, "u8"}, |
| {CORETYPE_U16, "u16"}, |
| {CORETYPE_U32, "u32"}, |
| {CORETYPE_U64, "u64"}, |
| {CORETYPE_U128, "u128"}, |
| {CORETYPE_I8, "i8"}, |
| {CORETYPE_I16, "i16"}, |
| {CORETYPE_I32, "i32"}, |
| {CORETYPE_I64, "i64"}, |
| {CORETYPE_I128, "i128"}, |
| {CORETYPE_ISIZE, "isize"}, |
| {CORETYPE_USIZE, "usize"}}}; |
| |
| static void |
| pop_group (std::vector<ProcMacro::TokenStream> &streams, |
| ProcMacro::Delimiter delim) |
| { |
| auto g = ProcMacro::Group::make_group (streams.back (), delim); |
| streams.pop_back (); |
| auto tt = ProcMacro::TokenTree::make_tokentree (g); |
| |
| streams.back ().push (tt); |
| } |
| |
| static ProcMacro::Span |
| convert (location_t location) |
| { |
| return ProcMacro::Span::make_span (location, 0); |
| } |
| |
| static location_t |
| convert (ProcMacro::Span span) |
| { |
| return span.start; |
| } |
| |
| static ProcMacro::Literal |
| handle_suffix (const const_TokenPtr &token, ProcMacro::LitKind kind) |
| { |
| auto str = token->as_string (); |
| auto lookup = suffixes.lookup (token->get_type_hint ()); |
| auto suffix = lookup.value_or (""); |
| return ProcMacro::Literal::make_literal (kind, convert (token->get_locus ()), |
| str, suffix); |
| } |
| |
| ProcMacro::Literal |
| convert_literal (const_TokenPtr lit) |
| { |
| auto loc = convert (lit->get_locus ()); |
| switch (lit->get_id ()) |
| { |
| case FLOAT_LITERAL: |
| return handle_suffix (lit, ProcMacro::LitKind::make_float ()); |
| case INT_LITERAL: |
| return handle_suffix (lit, ProcMacro::LitKind::make_integer ()); |
| case CHAR_LITERAL: |
| return ProcMacro::Literal::make_literal (ProcMacro::LitKind::make_char (), |
| loc, lit->as_string ()); |
| case STRING_LITERAL: |
| return ProcMacro::Literal::make_literal (ProcMacro::LitKind::make_str (), |
| loc, lit->as_string ()); |
| case BYTE_CHAR_LITERAL: |
| return ProcMacro::Literal::make_literal (ProcMacro::LitKind::make_byte (), |
| loc, lit->as_string ()); |
| case BYTE_STRING_LITERAL: |
| return ProcMacro::Literal::make_literal ( |
| ProcMacro::LitKind::make_byte_str (), loc, lit->as_string ()); |
| default: |
| rust_unreachable (); |
| } |
| } |
| |
| ProcMacro::TokenStream |
| convert (const std::vector<const_TokenPtr> &tokens) |
| { |
| std::vector<ProcMacro::TokenStream> trees; |
| trees.push_back (ProcMacro::TokenStream::make_tokenstream ()); |
| for (auto &token : tokens) |
| { |
| auto loc = convert (token->get_locus ()); |
| switch (token->get_id ()) |
| { |
| // Literals |
| case FLOAT_LITERAL: |
| case INT_LITERAL: |
| case CHAR_LITERAL: |
| case STRING_LITERAL: |
| case BYTE_CHAR_LITERAL: |
| case BYTE_STRING_LITERAL: |
| trees.back ().push ( |
| ProcMacro::TokenTree::make_tokentree (convert_literal (token))); |
| break; |
| // Ident |
| case IDENTIFIER: |
| case ABSTRACT: |
| case AS: |
| case ASYNC: |
| case AUTO: |
| case BECOME: |
| case BOX: |
| case BREAK: |
| case CONST: |
| case CONTINUE: |
| case CRATE: |
| case DO: |
| case DYN: |
| case ELSE: |
| case ENUM_KW: |
| case EXTERN_KW: |
| case FINAL_KW: |
| case FN_KW: |
| case FOR: |
| case IF: |
| case IMPL: |
| case IN: |
| case LET: |
| case LOOP: |
| case MACRO: |
| case MATCH_KW: |
| case MOD: |
| case MOVE: |
| case MUT: |
| case OVERRIDE_KW: |
| case PRIV: |
| case PUB: |
| case REF: |
| case RETURN_KW: |
| case SELF_ALIAS: |
| case SELF: |
| case STATIC_KW: |
| case STRUCT_KW: |
| case SUPER: |
| case TRAIT: |
| case TRY: |
| case TYPE: |
| case TYPEOF: |
| case UNSAFE: |
| case UNSIZED: |
| case USE: |
| case VIRTUAL: |
| case WHERE: |
| case WHILE: |
| case YIELD: |
| // Underscore is not a Punct, considered as an Ident |
| case UNDERSCORE: |
| // True and false are idents, not literals |
| // (https://doc.rust-lang.org/proc_macro/struct.Literal.html) |
| case FALSE_LITERAL: |
| case TRUE_LITERAL: |
| trees.back ().push (ProcMacro::TokenTree::make_tokentree ( |
| ProcMacro::Ident::make_ident (token->as_string (), loc))); |
| break; |
| // Joint punct |
| case OR: |
| case PIPE_EQ: |
| case CARET_EQ: |
| case RIGHT_SHIFT_EQ: |
| case RIGHT_SHIFT: |
| case GREATER_OR_EQUAL: |
| case MATCH_ARROW: |
| case LESS_OR_EQUAL: |
| case LEFT_SHIFT_EQ: |
| case LEFT_SHIFT: |
| case DIV_EQ: |
| case ELLIPSIS: |
| case DOT_DOT_EQ: |
| case DOT_DOT: |
| case RETURN_TYPE: |
| case MINUS_EQ: |
| case PLUS_EQ: |
| case ASTERISK_EQ: |
| case LOGICAL_AND: |
| case AMP_EQ: |
| case PERCENT_EQ: |
| case SCOPE_RESOLUTION: |
| case NOT_EQUAL: |
| case EQUAL_EQUAL: |
| { |
| auto str = token->as_string (); |
| auto it = str.cbegin (); |
| for (; it != str.cend () - 1; it++) |
| trees.back ().push (ProcMacro::TokenTree::make_tokentree ( |
| ProcMacro::Punct::make_punct (*it, loc, ProcMacro::JOINT))); |
| trees.back ().push (ProcMacro::TokenTree::make_tokentree ( |
| ProcMacro::Punct::make_punct (*it, loc, ProcMacro::ALONE))); |
| } |
| break; |
| // Alone punct tokens |
| case EQUAL: |
| case RIGHT_ANGLE: |
| case LEFT_ANGLE: |
| case EXCLAM: |
| case TILDE: |
| case PLUS: |
| case MINUS: |
| case ASTERISK: |
| case DIV: |
| case PERCENT: |
| case CARET: |
| case AMP: |
| case PIPE: |
| case PATTERN_BIND: |
| case DOT: |
| case COMMA: |
| case SEMICOLON: |
| case COLON: |
| case HASH: |
| case DOLLAR_SIGN: |
| case QUESTION_MARK: |
| case SINGLE_QUOTE: |
| trees.back ().push (ProcMacro::TokenTree::make_tokentree ( |
| ProcMacro::Punct::make_punct (token->as_string ()[0], loc, |
| ProcMacro::ALONE))); |
| break; |
| case RIGHT_PAREN: |
| pop_group (trees, ProcMacro::PARENTHESIS); |
| break; |
| case RIGHT_CURLY: |
| pop_group (trees, ProcMacro::BRACE); |
| break; |
| case RIGHT_SQUARE: |
| pop_group (trees, ProcMacro::BRACKET); |
| break; |
| case LEFT_SQUARE: |
| case LEFT_CURLY: |
| case LEFT_PAREN: |
| trees.push_back (ProcMacro::TokenStream::make_tokenstream ()); |
| break; |
| default: |
| rust_unreachable (); |
| } |
| } |
| return trees.back (); |
| } |
| |
| static void from_tokenstream (const ProcMacro::TokenStream &ts, |
| std::vector<const_TokenPtr> &result); |
| |
| /** |
| * Append the token corresponding to a given Ident to a vector. |
| * |
| * @param literal Reference to the Ident to convert. |
| * @param result Reference to the output vector. |
| */ |
| static void |
| from_ident (const ProcMacro::Ident &ident, std::vector<const_TokenPtr> &result) |
| { |
| std::string value (ident.value.to_string ()); |
| if (ident.is_raw) |
| value = "r#" + value; |
| |
| Lexer lexer (value, nullptr); |
| auto token = lexer.build_token (); |
| token->set_locus (convert (ident.span)); |
| result.push_back (token); |
| } |
| |
| /** |
| * Append the token corresponding to a given Literal to a vector. |
| * |
| * @param literal Reference to the Literal to convert. |
| * @param result Reference to the vector tokens should be appended to. |
| */ |
| static void |
| from_literal (const ProcMacro::Literal &literal, |
| std::vector<const_TokenPtr> &result) |
| { |
| auto lookup = suffixes.lookup (literal.suffix.to_string ()); |
| auto loc = convert (literal.span); |
| auto suffix = lookup.value_or (CORETYPE_UNKNOWN); |
| // FIXME: Add spans instead of empty locations |
| switch (literal.kind.tag) |
| { |
| case ProcMacro::BYTE: |
| result.push_back ( |
| Token::make_byte_char (loc, literal.text.to_string ()[0])); |
| break; |
| case ProcMacro::CHAR: |
| result.push_back (Token::make_char (loc, literal.text.to_string ()[0])); |
| break; |
| case ProcMacro::INTEGER: |
| result.push_back ( |
| Token::make_int (loc, literal.text.to_string (), suffix)); |
| break; |
| case ProcMacro::FLOAT: |
| result.push_back ( |
| Token::make_float (loc, literal.text.to_string (), suffix)); |
| break; |
| case ProcMacro::STR: |
| result.push_back (Token::make_string (loc, literal.text.to_string ())); |
| break; |
| case ProcMacro::BYTE_STR: |
| result.push_back ( |
| Token::make_byte_string (loc, literal.text.to_string ())); |
| break; |
| // FIXME: Handle raw string |
| case ProcMacro::STR_RAW: |
| case ProcMacro::BYTE_STR_RAW: |
| default: |
| rust_unreachable (); |
| } |
| } |
| |
| /** |
| * Accumulate through successive calls multiple Punct until one is tagged |
| * "Alone", then append the formed token to a given result vector. |
| * |
| * @param punct Reference to the Punct to convert. |
| * @param acc Reference to an accumulator for joined Punct. |
| * @param result Reference to the output token vector. |
| */ |
| static void |
| from_punct (const ProcMacro::Punct &punct, std::vector<std::uint32_t> &acc, |
| std::vector<const_TokenPtr> &result) |
| { |
| acc.push_back (punct.ch); |
| if (ProcMacro::ALONE == punct.spacing) /* Last punct of a chain */ |
| { |
| // TODO: UTF-8 string |
| std::string whole (acc.begin (), acc.end ()); |
| auto lexer = Lexer (whole, nullptr); |
| auto token = lexer.build_token (); |
| token->set_locus (convert (punct.span)); |
| result.push_back (token); |
| acc.clear (); |
| } |
| } |
| |
| /** |
| * Iterate over a Group and append all inner tokens to a vector enclosed by its |
| * delimiters. |
| * |
| * @param g Reference to the Group to convert. |
| * @param result Reference to the vector tokens should be appended to. |
| */ |
| static void |
| from_group (const ProcMacro::Group &g, std::vector<const_TokenPtr> &result) |
| { |
| auto loc = convert (g.span); |
| switch (g.delimiter) |
| { |
| case ProcMacro::PARENTHESIS: |
| result.push_back (Token::make (LEFT_PAREN, loc)); |
| from_tokenstream (g.stream, result); |
| result.push_back (Token::make (RIGHT_PAREN, loc)); |
| break; |
| case ProcMacro::BRACE: |
| result.push_back (Token::make (LEFT_CURLY, loc)); |
| from_tokenstream (g.stream, result); |
| result.push_back (Token::make (RIGHT_CURLY, loc)); |
| break; |
| case ProcMacro::BRACKET: |
| result.push_back (Token::make (LEFT_SQUARE, loc)); |
| from_tokenstream (g.stream, result); |
| result.push_back (Token::make (RIGHT_SQUARE, loc)); |
| break; |
| case ProcMacro::NONE: |
| from_tokenstream (g.stream, result); |
| break; |
| default: |
| rust_unreachable (); |
| } |
| } |
| |
| /** |
| * Dispatch TokenTree's conversion to its inner type depending on its tag. |
| * |
| * @param tt Reference to the TokenTree. |
| * @param punct_accumulator Reference to an accumulator for joined Punct. |
| * @param result Reference to the vector tokens should be appended to. |
| */ |
| static void |
| from_tokentree (const ProcMacro::TokenTree &tt, |
| std::vector<std::uint32_t> &punct_accumulator, |
| std::vector<const_TokenPtr> &result) |
| { |
| switch (tt.tag) |
| { |
| case ProcMacro::GROUP: |
| from_group (tt.payload.group, result); |
| break; |
| case ProcMacro::IDENT: |
| from_ident (tt.payload.ident, result); |
| break; |
| case ProcMacro::PUNCT: |
| from_punct (tt.payload.punct, punct_accumulator, result); |
| break; |
| case ProcMacro::LITERAL: |
| from_literal (tt.payload.literal, result); |
| break; |
| default: |
| rust_unreachable (); |
| } |
| } |
| |
| /** |
| * Iterate over a TokenStream and append all inner tokens to a vector. |
| * |
| * @param ts Reference to the TokenStream. |
| * @param result Reference to the vector tokens should be appended to. |
| */ |
| static void |
| from_tokenstream (const ProcMacro::TokenStream &ts, |
| std::vector<const_TokenPtr> &result) |
| { |
| std::vector<std::uint32_t> punct_accumulator; |
| for (std::uint64_t i = 0; i < ts.size; i++) |
| { |
| from_tokentree (ts.data[i], punct_accumulator, result); |
| } |
| } |
| |
| std::vector<const_TokenPtr> |
| convert (const ProcMacro::TokenStream &ts) |
| { |
| std::vector<const_TokenPtr> result; |
| from_tokenstream (ts, result); |
| return result; |
| } |
| |
| } // namespace Rust |