// Copyright (c) 2016-2021 Fabian Schuiki pub use self::DelimToken::*; pub use self::Token::*; use moore_common::name::*; use std; use std::fmt::{Display, Formatter, Result}; /// A primary token as emitted by the lexer. #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] pub enum Token { /// A basic or extended identifier. Ident(Name), /// A literal. Lit(Literal), /// An opening delimiter. OpenDelim(DelimToken), /// A closing delimiter. CloseDelim(DelimToken), /// A keyword. Keyword(Kw), Period, Comma, Colon, Semicolon, Apostrophe, Ampersand, Arrow, Condition, LtGt, VarAssign, Lshift, Rshift, Eq, Neq, Lt, Leq, Gt, Geq, MatchEq, MatchNeq, MatchLt, MatchLeq, MatchGt, MatchGeq, Add, Sub, Mul, Div, Pow, Pipe, Qmark, /// The end of the input file. Eof, } impl Token { pub fn as_str(self) -> &'static str { match self { Ident(_) => "identifier", Lit(l) => l.as_str(), OpenDelim(Paren) => "(", CloseDelim(Paren) => ")", OpenDelim(Brack) => "[", CloseDelim(Brack) => "]", Keyword(kw) => kw.as_str(), Period => ".", Comma => ",", Colon => ":", Semicolon => ";", Apostrophe => "'", Ampersand => "&", Arrow => "=>", Condition => "??", LtGt => "<>", VarAssign => ":=", Lshift => "<<", Rshift => ">>", Eq => "=", Neq => "/=", Lt => "<", Leq => "<=", Gt => ">", Geq => ">=", MatchEq => "?=", MatchNeq => "?/=", MatchLt => "?<", MatchLeq => "?<=", MatchGt => "?>", MatchGeq => "?>=", Add => "+", Sub => "-", Mul => "*", Div => "/", Pow => "**", Pipe => "|", Qmark => "?", Eof => "end of file", } } /// Checks if this token is a identifier. pub fn is_ident(self) -> bool { match self { Ident(_) => true, _ => false, } } } impl Display for Token { fn fmt(&self, f: &mut Formatter) -> Result { match *self { Ident(n) => write!(f, "identifier `{}`", n), Lit(l) => write!(f, "{}", l.as_str()), Keyword(kw) => write!(f, "keyword `{}`", kw.as_str()), tkn => write!(f, "`{}`", tkn.as_str()), } } } #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] pub enum Literal { Abstract( /// Base Option, /// Integer part Name, /// Fractional part Option, /// Exponent Option, ), BitString( /// Size Option, /// Base BitStringBase, /// Value Name, ), Char(char), String(Name), } impl Literal { pub fn as_str(self) -> &'static str { match self { Literal::Abstract(..) => "abstract literal", Literal::BitString(..) => "bit string literal", Literal::Char(..) => "character literal", Literal::String(..) => "string literal", } } } #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] pub enum DelimToken { Paren, Brack, } #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] pub struct Exponent( /// Sign pub ExponentSign, /// Value pub Name, ); #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] pub enum ExponentSign { Positive, Negative, } #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] pub enum BitStringBase { B, O, X, D, UB, UO, UX, SB, SO, SX, } /// Generates a `Kw` enum from a list of keywords. macro_rules! declare_keywords {( $( ($konst: ident, $string: expr) )* ) => { #[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Debug, Hash)] pub enum Kw { $($konst,)* } impl Kw { pub fn as_str(self) -> &'static str { match self { $(Kw::$konst => $string,)* } } } impl std::fmt::Display for Kw { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "{}", self.as_str()) } } pub fn find_keyword>(name: S) -> Option { use std::collections::HashMap; use once_cell::sync::Lazy; static TBL: Lazy> = Lazy::new(|| { let mut tbl = HashMap::new(); $( assert!($string.chars().all(|c| !c.is_uppercase())); tbl.insert($string, Kw::$konst); )* tbl }); TBL.get(name.as_ref().to_lowercase().as_str()).map(|kw| *kw) } }} declare_keywords! { // Keywords as per IEEE 1076-2008 section 15.10 (Abs, "abs") (Access, "access") (After, "after") (Alias, "alias") (All, "all") (And, "and") (Architecture, "architecture") (Array, "array") (Assert, "assert") (Assume, "assume") (AssumeGuarantee, "assume_guarantee") (Attribute, "attribute") (Begin, "begin") (Block, "block") (Body, "body") (Buffer, "buffer") (Bus, "bus") (Case, "case") (Component, "component") (Configuration, "configuration") (Constant, "constant") (Context, "context") (Cover, "cover") (Default, "default") (Disconnect, "disconnect") (Downto, "downto") (Else, "else") (Elsif, "elsif") (End, "end") (Entity, "entity") (Exit, "exit") (Fairness, "fairness") (File, "file") (For, "for") (Force, "force") (Function, "function") (Generate, "generate") (Generic, "generic") (Group, "group") (Guarded, "guarded") (If, "if") (Impure, "impure") (In, "in") (Inertial, "inertial") (Inout, "inout") (Is, "is") (Label, "label") (Library, "library") (Linkage, "linkage") (Literal, "literal") (Loop, "loop") (Map, "map") (Mod, "mod") (Nand, "nand") (New, "new") (Next, "next") (Nor, "nor") (Not, "not") (Null, "null") (Of, "of") (On, "on") (Open, "open") (Or, "or") (Others, "others") (Out, "out") (Package, "package") (Parameter, "parameter") (Port, "port") (Postponed, "postponed") (Procedure, "procedure") (Process, "process") (Property, "property") (Protected, "protected") (Pure, "pure") (Range, "range") (Record, "record") (Register, "register") (Reject, "reject") (Release, "release") (Rem, "rem") (Report, "report") (Restrict, "restrict") (RestrictGuarantee, "restrict_guarantee") (Return, "return") (Rol, "rol") (Ror, "ror") (Select, "select") (Sequence, "sequence") (Severity, "severity") (Shared, "shared") (Signal, "signal") (Sla, "sla") (Sll, "sll") (Sra, "sra") (Srl, "srl") (Strong, "strong") (Subtype, "subtype") (Then, "then") (To, "to") (Transport, "transport") (Type, "type") (Unaffected, "unaffected") (Units, "units") (Until, "until") (Use, "use") (Variable, "variable") (Vmode, "vmode") (Vprop, "vprop") (Vunit, "vunit") (Wait, "wait") (When, "when") (While, "while") (With, "with") (Xnor, "xnor") (Xor, "xor") }