lib_ruby_parser/lexer/
parse_gvar.rs

1use crate::lexer::*;
2use crate::maybe_byte::*;
3use crate::source::buffer::*;
4use crate::DiagnosticMessage;
5use crate::{lex_states::*, LexState};
6
7impl Lexer {
8    pub(crate) fn parse_gvar(&mut self, last_state: LexState) -> i32 {
9        let ptr = self.buffer.pcur;
10
11        self.lex_state.set(EXPR_END);
12        self.buffer.ptok = ptr - 1; // from '$'
13        self.newtok();
14        let mut c = self.nextc();
15        match c.as_option() {
16            Some(b'_') => { /* $_: last read line string */
17                c = self.nextc();
18                if self.is_identchar() {
19                    self.tokadd(b'$');
20                    self.tokadd(b'_');
21                } else {
22                    self.buffer.pushback(c);
23                    c = MaybeByte::new(b'_');
24                    self.tokadd(b'$');
25                    self.tokadd(c);
26                    return Self::tGVAR;
27                }
28            },
29            Some(b'~')          /* $~: match-data */
30            | Some(b'*')        /* $*: argv */
31            | Some(b'$')        /* $$: pid */
32            | Some(b'?')        /* $?: last status */
33            | Some(b'!')        /* $!: error string */
34            | Some(b'@')        /* $@: error position */
35            | Some(b'/')        /* $/: input record separator */
36            | Some(b'\\')       /* $\: output record separator */
37            | Some(b';')        /* $;: field separator */
38            | Some(b',')        /* $,: output field separator */
39            | Some(b'.')        /* $.: last read line number */
40            | Some(b'=')        /* $=: ignorecase */
41            | Some(b':')        /* $:: load path */
42            | Some(b'<')        /* $<: reading filename */
43            | Some(b'>')        /* $>: default output handle */
44            | Some(b'\"') => {  /* $": already loaded files */
45                self.tokadd(b'$');
46                self.tokadd(c);
47                return Self::tGVAR;
48            },
49            Some(b'-') => {
50                self.tokadd(b'$');
51                self.tokadd(c);
52                c = self.nextc();
53                if self.is_identchar() {
54                    if self.tokadd_mbchar(c).is_err() { return Self::END_OF_INPUT }
55                } else {
56                    self.buffer.pushback(c);
57                    self.buffer.pushback(b'-');
58                    return Self::tCHAR;
59                }
60                return Self::tGVAR;
61            },
62            Some(b'&')         /* $&: last match */
63            | Some(b'`')       /* $`: string before last match */
64            | Some(b'\'')      /* $': string after last match */
65            | Some(b'+') => {  /* $+: string matches last paren. */
66                if last_state.is_some(EXPR_FNAME) {
67                    self.tokadd(b'$');
68                    self.tokadd(c);
69                    return Self::tGVAR
70                }
71                return Self::tBACK_REF;
72            },
73            Some(b'1')
74            | Some(b'2')
75            | Some(b'3')
76            | Some(b'4')
77            | Some(b'5')
78            | Some(b'6')
79            | Some(b'7')
80            | Some(b'8')
81            | Some(b'9') => {
82                self.tokadd(b'$');
83                loop {
84                    self.tokadd(c);
85                    c = self.nextc();
86
87                    if c.is_eof() || !c.is_digit() {
88                        break;
89                    }
90                }
91                self.buffer.pushback(c);
92                if last_state.is_some(EXPR_FNAME) {
93                    return Self::tGVAR
94                }
95                self.tokfix();
96                return Self::tNTH_REF;
97            }
98            _ => {
99                if !self.is_identchar() {
100                    match c.as_option() {
101                        None | Some(b' ') => self.compile_error(DiagnosticMessage::GvarWithoutId {}, self.current_loc()),
102                        Some(name) => {
103                            // The following line comes from MRI, but it seems to be a bug
104                            // self.buffer.pushback(c);
105                            self.compile_error(DiagnosticMessage::InvalidGvarName { c: name }, self.current_loc());
106                        }
107                    }
108                    return Self::tGVAR
109                }
110
111                self.tokadd(b'$');
112            }
113        }
114
115        if self.tokadd_ident(c) {
116            return Self::END_OF_INPUT;
117        }
118        self.lex_state.set(EXPR_END);
119        self.tokenize_ident();
120        Self::tGVAR
121    }
122}