lib_ruby_parser/lexer/
parse_ident.rs

1use crate::lex_states::*;
2use crate::lexer::*;
3use crate::maybe_byte::*;
4use crate::reserved_word;
5use crate::source::buffer::*;
6use crate::DiagnosticMessage;
7
8fn is_var_name(ident: &str) -> bool {
9    if let Some(first_char) = ident.chars().next() {
10        return !first_char.is_uppercase();
11    }
12    false
13}
14
15impl Lexer {
16    pub(crate) fn is_identchar(&self) -> bool {
17        !self.buffer.eofp
18            && self
19                .buffer
20                .is_identchar(self.buffer.pcur - 1, self.buffer.pend)
21    }
22
23    pub(crate) fn tokenize_ident(&mut self) -> Option<String> {
24        self.set_yylval_name();
25        self.tokenbuf.borrow_string().map(|s| s.to_string()).ok()
26    }
27
28    pub(crate) fn parse_ident(&mut self, mut c: MaybeByte, cmd_state: bool) -> i32 {
29        let mut result: i32;
30        let last_state = self.lex_state;
31
32        loop {
33            if !c.is_ascii() { /* mb = ENC_CODERANGE_UNKNOWN */ }
34            if self.tokadd_mbchar(c).is_err() {
35                return Self::END_OF_INPUT;
36            }
37            c = self.nextc();
38
39            if !self.is_identchar() {
40                break;
41            }
42        }
43
44        if (c == b'!' || c == b'?') && !self.buffer.peek(b'=') {
45            result = Self::tFID;
46            self.tokadd(c);
47        } else if c == b'='
48            && self.lex_state.is_some(EXPR_FNAME)
49            && (!self.buffer.peek(b'~')
50                && !self.buffer.peek(b'>')
51                && (!self.buffer.peek(b'=') || (self.buffer.peek_n(b'>', 1))))
52        {
53            result = Self::tIDENTIFIER;
54            self.tokadd(c)
55        } else {
56            result = Self::tCONSTANT; /* assume provisionally */
57            self.buffer.pushback(c)
58        }
59        self.tokfix();
60
61        if self.lex_state.is_label_possible(cmd_state) && self.is_label_suffix(0) {
62            self.lex_state.set(EXPR_ARG | EXPR_LABELED);
63            self.nextc();
64            self.set_yylval_name();
65            return Self::tLABEL;
66        }
67        if !self.lex_state.is_some(EXPR_DOT) {
68            if let Some(kw) = reserved_word(self.tokenbuf.bytes.as_raw()) {
69                let state = self.lex_state;
70                if state.is_some(EXPR_FNAME) {
71                    self.lex_state.set(EXPR_ENDFN);
72                    self.set_yylval_name();
73                    return kw.id;
74                }
75                self.lex_state.set(kw.state);
76                if self.lex_state.is_some(EXPR_BEG) {
77                    self.command_start = true
78                }
79                if kw.id == Self::kDO {
80                    if self.is_lambda_beginning() {
81                        self.lpar_beg = -1; /* make lambda_beginning_p() == FALSE in the body of "-> do ... end" */
82                        return Self::kDO_LAMBDA;
83                    }
84                    if self.cond.is_active() {
85                        return Self::kDO_COND;
86                    }
87                    if self.cmdarg.is_active() && !state.is_some(EXPR_CMDARG) {
88                        return Self::kDO_BLOCK;
89                    }
90                    return Self::kDO;
91                }
92                if state.is_some(EXPR_BEG | EXPR_LABELED) {
93                    return kw.id;
94                } else {
95                    if kw.id != kw.modifier_id {
96                        self.lex_state.set(EXPR_BEG | EXPR_LABEL)
97                    }
98                    return kw.modifier_id;
99                }
100            }
101        }
102
103        if self
104            .lex_state
105            .is_some(EXPR_BEG_ANY | EXPR_ARG_ANY | EXPR_DOT)
106        {
107            if cmd_state {
108                self.lex_state.set(EXPR_CMDARG);
109            } else {
110                self.lex_state.set(EXPR_ARG);
111            }
112        } else if self.lex_state.is(EXPR_FNAME) {
113            self.lex_state.set(EXPR_ENDFN)
114        } else {
115            self.lex_state.set(EXPR_END)
116        }
117
118        let ident = match self.tokenize_ident() {
119            Some(ident) => ident,
120            None => {
121                self.yyerror0(DiagnosticMessage::InvalidMultibyteChar {});
122                return Self::END_OF_INPUT;
123            }
124        };
125        if result == Self::tCONSTANT && is_var_name(&ident) {
126            result = Self::tIDENTIFIER
127        }
128        if !last_state.is_some(EXPR_DOT|EXPR_FNAME) &&
129            result == Self::tIDENTIFIER && /* not EXPR_FNAME, not attrasgn */
130            self.is_lvar_defined(&ident)
131        {
132            self.lex_state.set(EXPR_END | EXPR_LABEL);
133        }
134
135        result
136    }
137}