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}