lib_ruby_parser/
builder.rs

1#[cfg(feature = "onig")]
2use onig::{Regex, RegexOptions};
3
4use std::collections::HashMap;
5use std::convert::TryInto;
6
7use alloc_from_pool::{Factory as PoolFactory, PoolValue};
8
9use crate::error::Diagnostics;
10#[allow(unused_imports)]
11use crate::nodes::*;
12use crate::Loc;
13use crate::{
14    Bytes, CurrentArgStack, Lexer, MaxNumparamStack, Node, SharedContext, StaticEnvironment, Token,
15    VariablesStack,
16};
17use crate::{Diagnostic, DiagnosticMessage, ErrorLevel};
18
19#[derive(Debug, PartialEq)]
20pub(crate) enum LoopType {
21    While,
22    Until,
23}
24
25#[derive(Debug, PartialEq)]
26pub(crate) enum KeywordCmd {
27    Break,
28    Defined,
29    Next,
30    Redo,
31    Retry,
32    Return,
33    Super,
34    Yield,
35    Zsuper,
36}
37
38enum MethodCallType {
39    Send,
40    CSend,
41}
42
43#[derive(Debug, PartialEq)]
44pub(crate) enum LogicalOp {
45    And,
46    Or,
47}
48
49#[derive(Debug, Clone)]
50pub(crate) enum PKwLabel {
51    PlainLabel(PoolValue<Token>),
52    QuotedLabel((PoolValue<Token>, Vec<Node>, PoolValue<Token>)),
53}
54
55#[derive(Debug, Clone)]
56pub(crate) enum ArgsType {
57    Args(Option<Box<Node>>),
58    Numargs(u8),
59}
60
61#[derive(Debug)]
62pub(crate) struct Builder {
63    static_env: StaticEnvironment,
64    context: SharedContext,
65    current_arg_stack: CurrentArgStack,
66    max_numparam_stack: MaxNumparamStack,
67    pattern_variables: VariablesStack,
68    pattern_hash_keys: VariablesStack,
69    diagnostics: Diagnostics,
70    pool_factory: PoolFactory<Token>,
71}
72
73impl Builder {
74    pub(crate) fn new(
75        static_env: StaticEnvironment,
76        context: SharedContext,
77        current_arg_stack: CurrentArgStack,
78        max_numparam_stack: MaxNumparamStack,
79        pattern_variables: VariablesStack,
80        pattern_hash_keys: VariablesStack,
81        diagnostics: Diagnostics,
82        pool_factory: PoolFactory<Token>,
83    ) -> Self {
84        Self {
85            static_env,
86            context,
87            current_arg_stack,
88            max_numparam_stack,
89            pattern_variables,
90            pattern_hash_keys,
91            diagnostics,
92            pool_factory,
93        }
94    }
95
96    //
97    // Literals
98    //
99
100    // Singletons
101
102    pub(crate) fn nil(&self, nil_t: PoolValue<Token>) -> Box<Node> {
103        Box::new(Node::Nil(Nil {
104            expression_l: self.loc(&nil_t),
105        }))
106    }
107
108    pub(crate) fn true_(&self, true_t: PoolValue<Token>) -> Box<Node> {
109        Box::new(Node::True(True {
110            expression_l: self.loc(&true_t),
111        }))
112    }
113
114    pub(crate) fn false_(&self, false_t: PoolValue<Token>) -> Box<Node> {
115        Box::new(Node::False(False {
116            expression_l: self.loc(&false_t),
117        }))
118    }
119
120    // Numerics
121
122    pub(crate) fn integer(&self, integer_t: PoolValue<Token>) -> Box<Node> {
123        let expression_l = self.loc(&integer_t);
124        Box::new(Node::Int(Int {
125            value: value(integer_t),
126            operator_l: None,
127            expression_l,
128        }))
129    }
130
131    pub(crate) fn float(&self, float_t: PoolValue<Token>) -> Box<Node> {
132        let expression_l = self.loc(&float_t);
133        Box::new(Node::Float(Float {
134            value: value(float_t),
135            operator_l: None,
136            expression_l,
137        }))
138    }
139
140    pub(crate) fn rational(&self, rational_t: PoolValue<Token>) -> Box<Node> {
141        let expression_l = self.loc(&rational_t);
142        Box::new(Node::Rational(Rational {
143            value: value(rational_t),
144            operator_l: None,
145            expression_l,
146        }))
147    }
148
149    pub(crate) fn complex(&self, complex_t: PoolValue<Token>) -> Box<Node> {
150        let expression_l = self.loc(&complex_t);
151        Box::new(Node::Complex(Complex {
152            value: value(complex_t),
153            operator_l: None,
154            expression_l,
155        }))
156    }
157
158    pub(crate) fn unary_num(&self, unary_t: PoolValue<Token>, mut numeric: Box<Node>) -> Box<Node> {
159        let new_operator_l = self.loc(&unary_t);
160        let sign = value(unary_t);
161
162        match &mut *numeric {
163            Node::Int(Int {
164                value,
165                expression_l,
166                operator_l,
167            })
168            | Node::Float(Float {
169                value,
170                expression_l,
171                operator_l,
172            })
173            | Node::Rational(Rational {
174                value,
175                operator_l,
176                expression_l,
177            })
178            | Node::Complex(Complex {
179                value,
180                operator_l,
181                expression_l,
182            }) => {
183                *value = format!("{}{}", sign, value);
184                *expression_l = new_operator_l.join(expression_l);
185                *operator_l = Some(new_operator_l);
186            }
187            _ => unreachable!(),
188        }
189
190        numeric
191    }
192
193    pub(crate) fn __line__(&self, line_t: PoolValue<Token>) -> Box<Node> {
194        Box::new(Node::Line(Line {
195            expression_l: self.loc(&line_t),
196        }))
197    }
198
199    // Strings
200
201    pub(crate) fn str_node(
202        &self,
203        begin_t: Option<PoolValue<Token>>,
204        value: Bytes,
205        parts: Vec<Node>,
206        end_t: Option<PoolValue<Token>>,
207    ) -> Box<Node> {
208        if self.is_heredoc(&begin_t) {
209            let HeredocMap {
210                heredoc_body_l,
211                heredoc_end_l,
212                expression_l,
213            } = self.heredoc_map(&begin_t, &parts, &end_t);
214
215            Box::new(Node::Heredoc(Heredoc {
216                parts,
217                heredoc_body_l,
218                heredoc_end_l,
219                expression_l,
220            }))
221        } else {
222            let CollectionMap {
223                begin_l,
224                end_l,
225                expression_l,
226            } = self.collection_map(&begin_t, &parts, &end_t);
227
228            Box::new(Node::Str(Str {
229                value,
230                begin_l,
231                end_l,
232                expression_l,
233            }))
234        }
235    }
236
237    pub(crate) fn string_internal(&self, mut string_t: PoolValue<Token>) -> Box<Node> {
238        let expression_l = self.loc(&string_t);
239        let value = string_t.take_value().token_value;
240        Box::new(Node::Str(Str {
241            value,
242            begin_l: None,
243            end_l: None,
244            expression_l,
245        }))
246    }
247
248    pub(crate) fn string_compose(
249        &self,
250        begin_t: Option<PoolValue<Token>>,
251        parts: Vec<Node>,
252        end_t: Option<PoolValue<Token>>,
253    ) -> Box<Node> {
254        match &parts[..] {
255            [] => {
256                return self.str_node(begin_t, Bytes::empty(), parts, end_t);
257            }
258            [Node::Str(_) | Node::Dstr(_) | Node::Heredoc(_)]
259                if begin_t.is_none() && end_t.is_none() =>
260            {
261                return Box::new(
262                    parts
263                        .into_iter()
264                        .next()
265                        .expect("expected at least 1 element"),
266                );
267            }
268
269            [Node::Str(Str { value, .. })] => {
270                return self.str_node(begin_t, value.clone(), parts, end_t);
271            }
272
273            [Node::Dstr(_) | Node::Heredoc(_)] => {
274                unreachable!()
275            }
276            _ => {}
277        }
278
279        if self.is_heredoc(&begin_t) {
280            let HeredocMap {
281                heredoc_body_l,
282                heredoc_end_l,
283                expression_l,
284            } = self.heredoc_map(&begin_t, &parts, &end_t);
285
286            Box::new(Node::Heredoc(Heredoc {
287                parts,
288                heredoc_body_l,
289                heredoc_end_l,
290                expression_l,
291            }))
292        } else {
293            let CollectionMap {
294                begin_l,
295                end_l,
296                expression_l,
297            } = self.collection_map(&begin_t, &parts, &end_t);
298
299            Box::new(Node::Dstr(Dstr {
300                parts,
301                begin_l,
302                end_l,
303                expression_l,
304            }))
305        }
306    }
307
308    pub(crate) fn character(&self, mut char_t: PoolValue<Token>) -> Box<Node> {
309        let str_loc = self.loc(&char_t);
310
311        let begin_l = Some(str_loc.with_end(str_loc.begin + 1));
312        let end_l = None;
313        let expression_l = str_loc;
314
315        let value = char_t.take_value().token_value;
316        Box::new(Node::Str(Str {
317            value,
318            begin_l,
319            end_l,
320            expression_l,
321        }))
322    }
323
324    pub(crate) fn __file__(&self, file_t: PoolValue<Token>) -> Box<Node> {
325        Box::new(Node::File(File {
326            expression_l: self.loc(&file_t),
327        }))
328    }
329
330    // Symbols
331
332    fn validate_sym_value(&self, value: &Bytes, loc: &Loc) {
333        if !value.is_valid_utf8() {
334            self.error(
335                DiagnosticMessage::InvalidSymbol {
336                    symbol: String::from("UTF-8"),
337                },
338                loc,
339            )
340        }
341    }
342
343    pub(crate) fn symbol(
344        &self,
345        start_t: PoolValue<Token>,
346        mut value_t: PoolValue<Token>,
347    ) -> Box<Node> {
348        let expression_l = self.loc(&start_t).join(&self.loc(&value_t));
349        let begin_l = Some(self.loc(&start_t));
350        let value = value_t.take_value().token_value;
351        self.validate_sym_value(&value, &expression_l);
352        Box::new(Node::Sym(Sym {
353            name: value,
354            begin_l,
355            end_l: None,
356            expression_l,
357        }))
358    }
359
360    pub(crate) fn symbol_internal(&self, mut symbol_t: PoolValue<Token>) -> Box<Node> {
361        let expression_l = self.loc(&symbol_t);
362        let value = symbol_t.take_value().token_value;
363        self.validate_sym_value(&value, &expression_l);
364        Box::new(Node::Sym(Sym {
365            name: value,
366            begin_l: None,
367            end_l: None,
368            expression_l,
369        }))
370    }
371
372    pub(crate) fn symbol_compose(
373        &self,
374        begin_t: PoolValue<Token>,
375        parts: Vec<Node>,
376        end_t: PoolValue<Token>,
377    ) -> Box<Node> {
378        if parts.len() == 1 && matches!(&parts[0], Node::Str(_)) {
379            match parts.into_iter().next().unwrap() {
380                Node::Str(Str { value, .. }) => {
381                    let CollectionMap {
382                        begin_l,
383                        end_l,
384                        expression_l,
385                    } = self.collection_map(&Some(begin_t), &[], &Some(end_t));
386
387                    self.validate_sym_value(&value, &expression_l);
388
389                    return Box::new(Node::Sym(Sym {
390                        name: value,
391                        begin_l,
392                        end_l,
393                        expression_l,
394                    }));
395                }
396                _ => unreachable!(),
397            }
398        }
399
400        let CollectionMap {
401            begin_l,
402            end_l,
403            expression_l,
404        } = self.collection_map(&Some(begin_t), &parts, &Some(end_t));
405        Box::new(Node::Dsym(Dsym {
406            parts,
407            begin_l,
408            end_l,
409            expression_l,
410        }))
411    }
412
413    // Executable strings
414
415    pub(crate) fn xstring_compose(
416        &self,
417        begin_t: PoolValue<Token>,
418        parts: Vec<Node>,
419        end_t: PoolValue<Token>,
420    ) -> Box<Node> {
421        let begin_l = self.loc(&begin_t);
422
423        let begin = &begin_t.token_value;
424        if begin.len() >= 2 && begin[0] == b'<' && begin[1] == b'<' {
425            let heredoc_body_l = collection_expr(&parts).unwrap_or_else(|| self.loc(&end_t));
426            let heredoc_end_l = self.loc(&end_t);
427            let expression_l = begin_l;
428
429            Box::new(Node::XHeredoc(XHeredoc {
430                parts,
431                heredoc_body_l,
432                heredoc_end_l,
433                expression_l,
434            }))
435        } else {
436            let end_l = self.loc(&end_t);
437            let expression_l = begin_l.join(&end_l);
438
439            Box::new(Node::Xstr(Xstr {
440                parts,
441                begin_l,
442                end_l,
443                expression_l,
444            }))
445        }
446    }
447
448    // Indented (interpolated, noninterpolated, executable) strings
449
450    pub(crate) fn heredoc_dedent(&self, node: Box<Node>, dedent_level: i32) -> Box<Node> {
451        if dedent_level == 0 {
452            return node;
453        }
454
455        let dedent_level: usize = dedent_level
456            .try_into()
457            .expect("dedent_level must be positive");
458
459        let dedent_heredoc_parts = |parts: Vec<Node>| -> Vec<Node> {
460            parts
461                .into_iter()
462                .filter_map(|part| match part {
463                    Node::Str(Str {
464                        value,
465                        begin_l,
466                        end_l,
467                        expression_l,
468                    }) => {
469                        let value = Self::dedent_string(value, dedent_level);
470                        if value.is_empty() {
471                            None
472                        } else {
473                            Some(Node::Str(Str {
474                                value,
475                                begin_l,
476                                end_l,
477                                expression_l,
478                            }))
479                        }
480                    }
481                    Node::Begin(_)
482                    | Node::Gvar(_)
483                    | Node::BackRef(_)
484                    | Node::NthRef(_)
485                    | Node::Ivar(_)
486                    | Node::Cvar(_) => Some(part),
487                    other => {
488                        unreachable!("unsupported heredoc child {}", other.str_type())
489                    }
490                })
491                .collect::<Vec<_>>()
492        };
493
494        match *node {
495            Node::Heredoc(Heredoc {
496                parts,
497                heredoc_body_l,
498                heredoc_end_l,
499                expression_l,
500            }) => {
501                let parts = dedent_heredoc_parts(parts);
502                Box::new(Node::Heredoc(Heredoc {
503                    parts,
504                    heredoc_body_l,
505                    heredoc_end_l,
506                    expression_l,
507                }))
508            }
509            Node::XHeredoc(XHeredoc {
510                parts,
511                heredoc_body_l,
512                heredoc_end_l,
513                expression_l,
514            }) => {
515                let parts = dedent_heredoc_parts(parts);
516                Box::new(Node::XHeredoc(XHeredoc {
517                    parts,
518                    heredoc_body_l,
519                    heredoc_end_l,
520                    expression_l,
521                }))
522            }
523            _ => {
524                unreachable!("unsupported heredoc_dedent argument {}", node.str_type())
525            }
526        }
527    }
528
529    const TAB_WIDTH: usize = 8;
530
531    pub(crate) fn dedent_string(s: Bytes, width: usize) -> Bytes {
532        let mut col: usize = 0;
533        let mut i: usize = 0;
534
535        loop {
536            if !(i < s.len() && col < width) {
537                break;
538            }
539
540            if s[i] == b' ' {
541                col += 1;
542            } else if s[i] == b'\t' {
543                let n = Self::TAB_WIDTH * (col / Self::TAB_WIDTH + 1);
544                if n > Self::TAB_WIDTH {
545                    break;
546                }
547                col = n;
548            } else {
549                break;
550            }
551
552            i += 1;
553        }
554
555        Bytes::new(Vec::from(&s.as_raw()[i..]))
556    }
557
558    // Regular expressions
559
560    pub(crate) fn regexp_options(&self, regexp_end_t: PoolValue<Token>) -> Option<Box<Node>> {
561        if regexp_end_t.loc.end - regexp_end_t.loc.begin == 1 {
562            // no regexp options, only trailing "/"
563            return None;
564        }
565        let expression_l = self.loc(&regexp_end_t).adjust_begin(1);
566        let options = value(regexp_end_t);
567        let mut options = options.as_str().chars().skip(1).collect::<Vec<_>>();
568        options.sort_unstable();
569        options.dedup();
570        let options = if options.is_empty() {
571            None
572        } else {
573            Some(options.into_iter().collect::<String>())
574        };
575
576        Some(Box::new(Node::RegOpt(RegOpt {
577            options,
578            expression_l,
579        })))
580    }
581
582    pub(crate) fn regexp_compose(
583        &self,
584        begin_t: PoolValue<Token>,
585        parts: Vec<Node>,
586        end_t: PoolValue<Token>,
587        options: Option<Box<Node>>,
588    ) -> Box<Node> {
589        let begin_l = self.loc(&begin_t);
590        let end_l = self.loc(&end_t).resize(1);
591        let expression_l =
592            begin_l.join(&maybe_boxed_node_expr(&options).unwrap_or_else(|| self.loc(&end_t)));
593
594        match options.as_deref() {
595            Some(Node::RegOpt(RegOpt {
596                options,
597                expression_l,
598            })) => self.validate_static_regexp(&parts, options, expression_l),
599            None => self.validate_static_regexp(&parts, &None, &expression_l),
600            _ => unreachable!("must be Option<RegOpt>"),
601        }
602
603        Box::new(Node::Regexp(Regexp {
604            parts,
605            options,
606            begin_l,
607            end_l,
608            expression_l,
609        }))
610    }
611
612    // Arrays
613
614    pub(crate) fn array(
615        &self,
616        begin_t: Option<PoolValue<Token>>,
617        elements: Vec<Node>,
618        end_t: Option<PoolValue<Token>>,
619    ) -> Box<Node> {
620        let CollectionMap {
621            begin_l,
622            end_l,
623            expression_l,
624        } = self.collection_map(&begin_t, &elements, &end_t);
625
626        Box::new(Node::Array(Array {
627            elements,
628            begin_l,
629            end_l,
630            expression_l,
631        }))
632    }
633
634    pub(crate) fn splat(&self, star_t: PoolValue<Token>, value: Option<Box<Node>>) -> Box<Node> {
635        let operator_l = self.loc(&star_t);
636        let expression_l = operator_l.maybe_join(&maybe_boxed_node_expr(&value));
637
638        Box::new(Node::Splat(Splat {
639            value,
640            operator_l,
641            expression_l,
642        }))
643    }
644
645    pub(crate) fn word(&self, parts: Vec<Node>) -> Box<Node> {
646        if parts.len() == 1 && matches!(&parts[0], Node::Str(_) | Node::Dstr(_)) {
647            let part = parts
648                .into_iter()
649                .next()
650                .expect("parts is supposed to have exactly 1 element");
651            return Box::new(part);
652        }
653
654        let CollectionMap {
655            begin_l,
656            end_l,
657            expression_l,
658        } = self.collection_map(&None, &parts, &None);
659
660        Box::new(Node::Dstr(Dstr {
661            parts,
662            begin_l,
663            end_l,
664            expression_l,
665        }))
666    }
667
668    pub(crate) fn words_compose(
669        &self,
670        begin_t: PoolValue<Token>,
671        elements: Vec<Node>,
672        end_t: PoolValue<Token>,
673    ) -> Box<Node> {
674        let begin_l = self.loc(&begin_t);
675        let end_l = self.loc(&end_t);
676        let expression_l = begin_l.join(&end_l);
677        Box::new(Node::Array(Array {
678            elements,
679            begin_l: Some(begin_l),
680            end_l: Some(end_l),
681            expression_l,
682        }))
683    }
684
685    pub(crate) fn symbols_compose(
686        &self,
687        begin_t: PoolValue<Token>,
688        parts: Vec<Node>,
689        end_t: PoolValue<Token>,
690    ) -> Box<Node> {
691        let parts = parts
692            .into_iter()
693            .map(|part| match part {
694                Node::Str(Str {
695                    value,
696                    begin_l,
697                    end_l,
698                    expression_l,
699                }) => {
700                    self.validate_sym_value(&value, &expression_l);
701                    Node::Sym(Sym {
702                        name: value,
703                        begin_l,
704                        end_l,
705                        expression_l,
706                    })
707                }
708                Node::Dstr(Dstr {
709                    parts,
710                    begin_l,
711                    end_l,
712                    expression_l,
713                }) => Node::Dsym(Dsym {
714                    parts,
715                    begin_l,
716                    end_l,
717                    expression_l,
718                }),
719                other => other,
720            })
721            .collect::<Vec<_>>();
722
723        let begin_l = self.loc(&begin_t);
724        let end_l = self.loc(&end_t);
725        let expression_l = begin_l.join(&end_l);
726        Box::new(Node::Array(Array {
727            elements: parts,
728            begin_l: Some(begin_l),
729            end_l: Some(end_l),
730            expression_l,
731        }))
732    }
733
734    // Hashes
735
736    pub(crate) fn pair(
737        &self,
738        key: Box<Node>,
739        assoc_t: PoolValue<Token>,
740        value: Box<Node>,
741    ) -> Box<Node> {
742        let operator_l = self.loc(&assoc_t);
743        let expression_l = join_exprs(&key, &value);
744
745        Box::new(Node::Pair(Pair {
746            key,
747            value,
748            operator_l,
749            expression_l,
750        }))
751    }
752
753    pub(crate) fn pair_keyword(&self, mut key_t: PoolValue<Token>, value: Box<Node>) -> Box<Node> {
754        let key_loc = self.loc(&key_t);
755        let key_l = key_loc.adjust_end(-1);
756        let colon_l = key_loc.with_begin(key_loc.end - 1);
757        let expression_l = key_loc.join(value.expression());
758
759        let key = key_t.take_value().token_value;
760        self.validate_sym_value(&key, &key_l);
761
762        Box::new(Node::Pair(Pair {
763            key: Box::new(Node::Sym(Sym {
764                name: key,
765                begin_l: None,
766                end_l: None,
767                expression_l: key_l,
768            })),
769            value,
770            operator_l: colon_l,
771            expression_l,
772        }))
773    }
774
775    pub(crate) fn pair_quoted(
776        &self,
777        begin_t: PoolValue<Token>,
778        parts: Vec<Node>,
779        end_t: PoolValue<Token>,
780        value: Box<Node>,
781    ) -> Box<Node> {
782        let end_l = self.loc(&end_t);
783
784        let quote_loc = Loc {
785            begin: end_l.end - 2,
786            end: end_l.end - 1,
787        };
788
789        let colon_l = end_l.with_begin(end_l.end - 1);
790
791        let mut end_t = end_t;
792        let end_t: PoolValue<Token> = self.pool_factory.alloc(Token {
793            token_type: end_t.token_type,
794            token_value: end_t.take_value().token_value,
795            loc: quote_loc,
796        });
797        let expression_l = self.loc(&begin_t).join(value.expression());
798
799        Box::new(Node::Pair(Pair {
800            key: self.symbol_compose(begin_t, parts, end_t),
801            value,
802            operator_l: colon_l,
803            expression_l,
804        }))
805    }
806
807    pub(crate) fn pair_label(&self, key_t: PoolValue<Token>) -> Box<Node> {
808        let key_l = self.loc(&key_t);
809        let value_l = key_l.adjust_end(-1);
810
811        let label = value(key_t.clone());
812        let value = if label
813            .chars()
814            .next()
815            .expect("bug: label can't be empty")
816            .is_lowercase()
817        {
818            Box::new(Node::Lvar(Lvar {
819                name: label,
820                expression_l: value_l,
821            }))
822        } else {
823            Box::new(Node::Const(Const {
824                scope: None,
825                name: label,
826                double_colon_l: None,
827                name_l: value_l,
828                expression_l: value_l,
829            }))
830        };
831
832        self.pair_keyword(key_t, self.accessible(value))
833    }
834
835    pub(crate) fn kwsplat(&self, dstar_t: PoolValue<Token>, value: Box<Node>) -> Box<Node> {
836        let operator_l = self.loc(&dstar_t);
837        let expression_l = value.expression().join(&operator_l);
838
839        Box::new(Node::Kwsplat(Kwsplat {
840            value,
841            operator_l,
842            expression_l,
843        }))
844    }
845
846    pub(crate) fn associate(
847        &self,
848        begin_t: Option<PoolValue<Token>>,
849        pairs: Vec<Node>,
850        end_t: Option<PoolValue<Token>>,
851    ) -> Box<Node> {
852        for i in 0..pairs.len() {
853            for j in i + 1..pairs.len() {
854                let key1 = if let Node::Pair(Pair { key, .. }) = &pairs[i] {
855                    &**key
856                } else {
857                    // kwsplat
858                    continue;
859                };
860                let key2 = if let Node::Pair(Pair { key, .. }) = &pairs[j] {
861                    &**key
862                } else {
863                    // kwsplat
864                    continue;
865                };
866
867                fn keys_are_equal(left: &Node, right: &Node) -> bool {
868                    match (left, right) {
869                        // sym
870                        (
871                            Node::Sym(Sym { name: name1, .. }),
872                            Node::Sym(Sym { name: name2, .. }),
873                        ) if name1 == name2 => true,
874
875                        // str
876                        (
877                            Node::Str(Str { value: value1, .. }),
878                            Node::Str(Str { value: value2, .. }),
879                        ) if value1 == value2 => true,
880
881                        // int
882                        (
883                            Node::Int(Int { value: value1, .. }),
884                            Node::Int(Int { value: value2, .. }),
885                        ) if value1 == value2 => true,
886
887                        // float
888                        (
889                            Node::Float(Float { value: value1, .. }),
890                            Node::Float(Float { value: value2, .. }),
891                        ) if value1 == value2 => true,
892
893                        // rational
894                        (
895                            Node::Rational(Rational { value: value1, .. }),
896                            Node::Rational(Rational { value: value2, .. }),
897                        ) if value1 == value2 => true,
898
899                        // complex
900                        (
901                            Node::Complex(Complex { value: value1, .. }),
902                            Node::Complex(Complex { value: value2, .. }),
903                        ) if value1 == value2 => true,
904
905                        // regexp
906                        (
907                            Node::Regexp(Regexp {
908                                parts: parts1,
909                                options: options1,
910                                ..
911                            }),
912                            Node::Regexp(Regexp {
913                                parts: parts2,
914                                options: options2,
915                                ..
916                            }),
917                        ) if options1 == options2 => {
918                            parts1.len() == parts2.len()
919                                && parts1
920                                    .iter()
921                                    .zip(parts2.iter())
922                                    .all(|(child1, child2)| keys_are_equal(child1, child2))
923                        }
924
925                        _ => false,
926                    }
927                }
928
929                let do_warn = keys_are_equal(key1, key2);
930
931                if do_warn {
932                    self.warn(DiagnosticMessage::DuplicateHashKey {}, key2.expression());
933                }
934            }
935        }
936
937        let CollectionMap {
938            begin_l,
939            end_l,
940            expression_l,
941        } = self.collection_map(&begin_t, &pairs, &end_t);
942
943        Box::new(Node::Hash(Hash {
944            pairs,
945            begin_l,
946            end_l,
947            expression_l,
948        }))
949    }
950
951    // Ranges
952
953    pub(crate) fn range_inclusive(
954        &self,
955        left: Option<Box<Node>>,
956        dot2_t: PoolValue<Token>,
957        right: Option<Box<Node>>,
958    ) -> Box<Node> {
959        let operator_l = self.loc(&dot2_t);
960        let expression_l = operator_l
961            .maybe_join(&maybe_boxed_node_expr(&left))
962            .maybe_join(&maybe_boxed_node_expr(&right));
963
964        Box::new(Node::Irange(Irange {
965            left,
966            right,
967            operator_l,
968            expression_l,
969        }))
970    }
971
972    pub(crate) fn range_exclusive(
973        &self,
974        left: Option<Box<Node>>,
975        dot3_t: PoolValue<Token>,
976        right: Option<Box<Node>>,
977    ) -> Box<Node> {
978        let operator_l = self.loc(&dot3_t);
979        let expression_l = operator_l
980            .maybe_join(&maybe_boxed_node_expr(&left))
981            .maybe_join(&maybe_boxed_node_expr(&right));
982
983        Box::new(Node::Erange(Erange {
984            left,
985            right,
986            operator_l,
987            expression_l,
988        }))
989    }
990
991    //
992    // Access
993    //
994
995    pub(crate) fn self_(&self, token: PoolValue<Token>) -> Box<Node> {
996        Box::new(Node::Self_(Self_ {
997            expression_l: self.loc(&token),
998        }))
999    }
1000
1001    pub(crate) fn lvar(&self, token: PoolValue<Token>) -> Box<Node> {
1002        let expression_l = self.loc(&token);
1003        Box::new(Node::Lvar(Lvar {
1004            name: value(token),
1005            expression_l,
1006        }))
1007    }
1008
1009    pub(crate) fn ivar(&self, token: PoolValue<Token>) -> Box<Node> {
1010        let expression_l = self.loc(&token);
1011        Box::new(Node::Ivar(Ivar {
1012            name: value(token),
1013            expression_l,
1014        }))
1015    }
1016
1017    pub(crate) fn gvar(&self, token: PoolValue<Token>) -> Box<Node> {
1018        let expression_l = self.loc(&token);
1019        Box::new(Node::Gvar(Gvar {
1020            name: value(token),
1021            expression_l,
1022        }))
1023    }
1024
1025    pub(crate) fn cvar(&self, token: PoolValue<Token>) -> Box<Node> {
1026        let expression_l = self.loc(&token);
1027        Box::new(Node::Cvar(Cvar {
1028            name: value(token),
1029            expression_l,
1030        }))
1031    }
1032
1033    pub(crate) fn back_ref(&self, token: PoolValue<Token>) -> Box<Node> {
1034        let expression_l = self.loc(&token);
1035        Box::new(Node::BackRef(BackRef {
1036            name: value(token),
1037            expression_l,
1038        }))
1039    }
1040
1041    const MAX_NTH_REF: usize = 0b111111111111111111111111111111;
1042
1043    pub(crate) fn nth_ref(&self, token: PoolValue<Token>) -> Box<Node> {
1044        let expression_l = self.loc(&token);
1045        let name = value(token);
1046        let name = &name.as_str()[1..];
1047        let parsed = name.parse::<usize>();
1048        let name = String::from(name);
1049
1050        if parsed.is_err() || parsed.map(|n| n > Self::MAX_NTH_REF) == Ok(true) {
1051            self.warn(
1052                DiagnosticMessage::NthRefIsTooBig {
1053                    nth_ref: name.clone(),
1054                },
1055                &expression_l,
1056            )
1057        }
1058
1059        Box::new(Node::NthRef(NthRef { name, expression_l }))
1060    }
1061    pub(crate) fn accessible(&self, node: Box<Node>) -> Box<Node> {
1062        if matches!(&*node, Node::Lvar(_)) {
1063            match *node {
1064                Node::Lvar(Lvar { name, expression_l }) => {
1065                    let name_s = name.as_str();
1066
1067                    if name_s.ends_with('?') || name_s.ends_with('!') {
1068                        self.error(
1069                            DiagnosticMessage::InvalidIdToGet {
1070                                identifier: name_s.to_string(),
1071                            },
1072                            &expression_l,
1073                        );
1074                    }
1075
1076                    // Numbered parameters are not declared anywhere,
1077                    // so they take precedence over method calls in numblock contexts
1078                    if self.try_declare_numparam(name_s, &expression_l) {
1079                        return Box::new(Node::Lvar(Lvar { name, expression_l }));
1080                    }
1081
1082                    if !self.static_env.is_declared(name_s) {
1083                        return Box::new(Node::Send(Send {
1084                            recv: None,
1085                            method_name: name,
1086                            args: vec![],
1087                            dot_l: None,
1088                            selector_l: Some(expression_l),
1089                            begin_l: None,
1090                            end_l: None,
1091                            operator_l: None,
1092                            expression_l,
1093                        }));
1094                    }
1095
1096                    if let Some(current_arg) = self.current_arg_stack.top() {
1097                        if current_arg == name_s {
1098                            self.error(
1099                                DiagnosticMessage::CircularArgumentReference {
1100                                    arg_name: name.clone(),
1101                                },
1102                                &expression_l,
1103                            );
1104                        }
1105                    }
1106
1107                    Box::new(Node::Lvar(Lvar { name, expression_l }))
1108                }
1109                _ => unreachable!(),
1110            }
1111        } else {
1112            node
1113        }
1114    }
1115
1116    pub(crate) fn const_(&self, name_t: PoolValue<Token>) -> Box<Node> {
1117        let name_l = self.loc(&name_t);
1118        let expression_l = name_l;
1119
1120        Box::new(Node::Const(Const {
1121            scope: None,
1122            name: value(name_t),
1123            double_colon_l: None,
1124            name_l,
1125            expression_l,
1126        }))
1127    }
1128
1129    pub(crate) fn const_global(
1130        &self,
1131        t_colon3: PoolValue<Token>,
1132        name_t: PoolValue<Token>,
1133    ) -> Box<Node> {
1134        let scope = Box::new(Node::Cbase(Cbase {
1135            expression_l: self.loc(&t_colon3),
1136        }));
1137
1138        let name_l = self.loc(&name_t);
1139        let expression_l = scope.expression().join(&name_l);
1140        let double_colon_l = self.loc(&t_colon3);
1141
1142        Box::new(Node::Const(Const {
1143            scope: Some(scope),
1144            name: value(name_t),
1145            double_colon_l: Some(double_colon_l),
1146            name_l,
1147            expression_l,
1148        }))
1149    }
1150
1151    pub(crate) fn const_fetch(
1152        &self,
1153        scope: Box<Node>,
1154        t_colon2: PoolValue<Token>,
1155        name_t: PoolValue<Token>,
1156    ) -> Box<Node> {
1157        let scope: Box<Node> = scope;
1158        let name_l = self.loc(&name_t);
1159        let expression_l = scope.expression().join(&name_l);
1160        let double_colon_l = self.loc(&t_colon2);
1161
1162        Box::new(Node::Const(Const {
1163            scope: Some(scope),
1164            name: value(name_t),
1165            double_colon_l: Some(double_colon_l),
1166            name_l,
1167            expression_l,
1168        }))
1169    }
1170
1171    pub(crate) fn __encoding__(&self, encoding_t: PoolValue<Token>) -> Box<Node> {
1172        Box::new(Node::Encoding(Encoding {
1173            expression_l: self.loc(&encoding_t),
1174        }))
1175    }
1176
1177    //
1178    // Assignments
1179    //
1180
1181    pub(crate) fn assignable(&self, node: Box<Node>) -> Result<Box<Node>, ()> {
1182        let node = match *node {
1183            Node::Cvar(Cvar { name, expression_l }) => Node::Cvasgn(Cvasgn {
1184                name,
1185                value: None,
1186                name_l: expression_l,
1187                operator_l: None,
1188                expression_l,
1189            }),
1190            Node::Ivar(Ivar { name, expression_l }) => Node::Ivasgn(Ivasgn {
1191                name,
1192                value: None,
1193                name_l: expression_l,
1194                operator_l: None,
1195                expression_l,
1196            }),
1197            Node::Gvar(Gvar { name, expression_l }) => Node::Gvasgn(Gvasgn {
1198                name,
1199                value: None,
1200                name_l: expression_l,
1201                operator_l: None,
1202                expression_l,
1203            }),
1204            Node::Const(Const {
1205                scope,
1206                name,
1207                double_colon_l,
1208                name_l,
1209                expression_l,
1210            }) => {
1211                if self.context.in_def() {
1212                    self.error(
1213                        DiagnosticMessage::DynamicConstantAssignment {},
1214                        &expression_l,
1215                    );
1216                    return Err(());
1217                }
1218                Node::Casgn(Casgn {
1219                    scope,
1220                    name,
1221                    value: None,
1222                    double_colon_l,
1223                    name_l,
1224                    operator_l: None,
1225                    expression_l,
1226                })
1227            }
1228            Node::Lvar(Lvar { name, expression_l }) => {
1229                let name_s = name.as_str();
1230                self.check_assignment_to_numparam(name_s, &expression_l)?;
1231                self.check_reserved_for_numparam(name_s, &expression_l)?;
1232
1233                self.static_env.declare(name_s);
1234
1235                Node::Lvasgn(Lvasgn {
1236                    name,
1237                    value: None,
1238                    name_l: expression_l,
1239                    operator_l: None,
1240                    expression_l,
1241                })
1242            }
1243            Node::MatchVar(MatchVar {
1244                name,
1245                name_l,
1246                expression_l,
1247            }) => {
1248                let name_s = name.as_str();
1249                self.check_assignment_to_numparam(name_s, &name_l)?;
1250                self.check_reserved_for_numparam(name_s, &name_l)?;
1251
1252                Node::MatchVar(MatchVar {
1253                    name,
1254                    name_l,
1255                    expression_l,
1256                })
1257            }
1258            Node::Self_(Self_ { expression_l }) => {
1259                self.error(DiagnosticMessage::CantAssignToSelf {}, &expression_l);
1260                return Err(());
1261            }
1262            Node::Nil(Nil { expression_l }) => {
1263                self.error(DiagnosticMessage::CantAssignToNil {}, &expression_l);
1264                return Err(());
1265            }
1266            Node::True(True { expression_l }) => {
1267                self.error(DiagnosticMessage::CantAssignToTrue {}, &expression_l);
1268                return Err(());
1269            }
1270            Node::False(False { expression_l }) => {
1271                self.error(DiagnosticMessage::CantAssignToFalse {}, &expression_l);
1272                return Err(());
1273            }
1274            Node::File(File { expression_l }) => {
1275                self.error(DiagnosticMessage::CantAssignToFile {}, &expression_l);
1276                return Err(());
1277            }
1278            Node::Line(Line { expression_l }) => {
1279                self.error(DiagnosticMessage::CantAssignToLine {}, &expression_l);
1280                return Err(());
1281            }
1282            Node::Encoding(Encoding { expression_l }) => {
1283                self.error(DiagnosticMessage::CantAssignToEncoding {}, &expression_l);
1284                return Err(());
1285            }
1286            Node::BackRef(BackRef { name, expression_l }) => {
1287                self.error(
1288                    DiagnosticMessage::CantSetVariable { var_name: name },
1289                    &expression_l,
1290                );
1291                return Err(());
1292            }
1293            Node::NthRef(NthRef { name, expression_l }) => {
1294                self.error(
1295                    DiagnosticMessage::CantSetVariable {
1296                        var_name: format!("${}", name),
1297                    },
1298                    &expression_l,
1299                );
1300                return Err(());
1301            }
1302            other => unreachable!("{:?} can't be used in assignment", other),
1303        };
1304
1305        Ok(Box::new(node))
1306    }
1307
1308    pub(crate) fn const_op_assignable(&self, node: Box<Node>) -> Box<Node> {
1309        match *node {
1310            Node::Const(Const {
1311                scope,
1312                name,
1313                double_colon_l,
1314                name_l,
1315                expression_l,
1316            }) => Box::new(Node::Casgn(Casgn {
1317                scope,
1318                name,
1319                value: None,
1320                double_colon_l,
1321                name_l,
1322                operator_l: None,
1323                expression_l,
1324            })),
1325            other => {
1326                unreachable!("unsupported const_op_assignable argument: {:?}", other)
1327            }
1328        }
1329    }
1330
1331    pub(crate) fn assign(
1332        &self,
1333        mut lhs: Box<Node>,
1334        eql_t: PoolValue<Token>,
1335        new_rhs: Box<Node>,
1336    ) -> Box<Node> {
1337        let op_l = Some(self.loc(&eql_t));
1338        let expr_l = join_exprs(&lhs, &new_rhs);
1339
1340        match &mut *lhs {
1341            Node::Cvasgn(Cvasgn {
1342                expression_l,
1343                operator_l,
1344                value,
1345                ..
1346            })
1347            | Node::Ivasgn(Ivasgn {
1348                expression_l,
1349                operator_l,
1350                value,
1351                ..
1352            })
1353            | Node::Gvasgn(Gvasgn {
1354                expression_l,
1355                operator_l,
1356                value,
1357                ..
1358            })
1359            | Node::Lvasgn(Lvasgn {
1360                expression_l,
1361                operator_l,
1362                value,
1363                ..
1364            })
1365            | Node::Casgn(Casgn {
1366                expression_l,
1367                operator_l,
1368                value,
1369                ..
1370            })
1371            | Node::IndexAsgn(IndexAsgn {
1372                expression_l,
1373                operator_l,
1374                value,
1375                ..
1376            }) => {
1377                *expression_l = expr_l;
1378                *operator_l = op_l;
1379                *value = Some(new_rhs);
1380            }
1381            Node::Send(Send {
1382                expression_l,
1383                operator_l,
1384                args,
1385                ..
1386            })
1387            | Node::CSend(CSend {
1388                expression_l,
1389                operator_l,
1390                args,
1391                ..
1392            }) => {
1393                *expression_l = expr_l;
1394                *operator_l = op_l;
1395                if args.is_empty() {
1396                    *args = vec![*new_rhs];
1397                } else {
1398                    unreachable!("can't assign to method call with args")
1399                }
1400            }
1401            other => unreachable!("{:?} can't be used in assignment", other),
1402        }
1403
1404        lhs
1405    }
1406
1407    pub(crate) fn op_assign(
1408        &self,
1409        mut lhs: Box<Node>,
1410        op_t: PoolValue<Token>,
1411        rhs: Box<Node>,
1412    ) -> Result<Box<Node>, ()> {
1413        let operator_l = self.loc(&op_t);
1414        let mut operator = value(op_t);
1415        operator.pop();
1416        let expression_l = join_exprs(&lhs, &rhs);
1417
1418        match &*lhs {
1419            Node::Gvasgn(_)
1420            | Node::Ivasgn(_)
1421            | Node::Lvasgn(_)
1422            | Node::Cvasgn(_)
1423            | Node::Casgn(_)
1424            | Node::Send(_)
1425            | Node::CSend(_) => {
1426                // ignore
1427            }
1428            Node::Index(_) => match *lhs {
1429                Node::Index(Index {
1430                    recv,
1431                    indexes,
1432                    begin_l,
1433                    end_l,
1434                    expression_l,
1435                }) => {
1436                    lhs = Box::new(Node::IndexAsgn(IndexAsgn {
1437                        recv,
1438                        indexes,
1439                        value: None,
1440                        begin_l,
1441                        end_l,
1442                        operator_l: None,
1443                        expression_l,
1444                    }));
1445                }
1446                _ => unreachable!(),
1447            },
1448            Node::BackRef(BackRef { name, expression_l }) => {
1449                self.error(
1450                    DiagnosticMessage::CantSetVariable {
1451                        var_name: name.clone(),
1452                    },
1453                    expression_l,
1454                );
1455                return Err(());
1456            }
1457            Node::NthRef(NthRef { name, expression_l }) => {
1458                self.error(
1459                    DiagnosticMessage::CantSetVariable {
1460                        var_name: format!("${}", name),
1461                    },
1462                    expression_l,
1463                );
1464                return Err(());
1465            }
1466            _ => unreachable!("unsupported op_assign lhs {:?}", lhs),
1467        }
1468
1469        let recv: Box<Node> = lhs;
1470        let value: Box<Node> = rhs;
1471
1472        let result = match &operator[..] {
1473            "&&" => Node::AndAsgn(AndAsgn {
1474                recv,
1475                value,
1476                operator_l,
1477                expression_l,
1478            }),
1479            "||" => Node::OrAsgn(OrAsgn {
1480                recv,
1481                value,
1482                operator_l,
1483                expression_l,
1484            }),
1485            _ => Node::OpAsgn(OpAsgn {
1486                recv,
1487                operator,
1488                value,
1489                operator_l,
1490                expression_l,
1491            }),
1492        };
1493
1494        Ok(Box::new(result))
1495    }
1496
1497    pub(crate) fn multi_lhs(
1498        &self,
1499        begin_t: Option<PoolValue<Token>>,
1500        items: Vec<Node>,
1501        end_t: Option<PoolValue<Token>>,
1502    ) -> Box<Node> {
1503        let CollectionMap {
1504            begin_l,
1505            end_l,
1506            expression_l,
1507        } = self.collection_map(&begin_t, &items, &end_t);
1508
1509        Box::new(Node::Mlhs(Mlhs {
1510            items,
1511            begin_l,
1512            end_l,
1513            expression_l,
1514        }))
1515    }
1516
1517    pub(crate) fn multi_assign(
1518        &self,
1519        lhs: Box<Node>,
1520        eql_t: PoolValue<Token>,
1521        rhs: Box<Node>,
1522    ) -> Box<Node> {
1523        let operator_l = self.loc(&eql_t);
1524        let expression_l = join_exprs(&lhs, &rhs);
1525
1526        Box::new(Node::Masgn(Masgn {
1527            lhs,
1528            rhs,
1529            operator_l,
1530            expression_l,
1531        }))
1532    }
1533
1534    //
1535    // Class and module definition
1536    //
1537
1538    pub(crate) fn def_class(
1539        &self,
1540        class_t: PoolValue<Token>,
1541        name: Box<Node>,
1542        lt_t: Option<PoolValue<Token>>,
1543        superclass: Option<Box<Node>>,
1544        body: Option<Box<Node>>,
1545        end_t: PoolValue<Token>,
1546    ) -> Box<Node> {
1547        let keyword_l = self.loc(&class_t);
1548        let end_l = self.loc(&end_t);
1549        let operator_l = self.maybe_loc(&lt_t);
1550        let expression_l = keyword_l.join(&end_l);
1551
1552        Box::new(Node::Class(Class {
1553            name,
1554            superclass,
1555            body,
1556            keyword_l,
1557            operator_l,
1558            end_l,
1559            expression_l,
1560        }))
1561    }
1562
1563    pub(crate) fn def_sclass(
1564        &self,
1565        class_t: PoolValue<Token>,
1566        lshift_t: PoolValue<Token>,
1567        expr: Box<Node>,
1568        body: Option<Box<Node>>,
1569        end_t: PoolValue<Token>,
1570    ) -> Box<Node> {
1571        let keyword_l = self.loc(&class_t);
1572        let end_l = self.loc(&end_t);
1573        let operator_l = self.loc(&lshift_t);
1574        let expression_l = keyword_l.join(&end_l);
1575
1576        Box::new(Node::SClass(SClass {
1577            expr,
1578            body,
1579            keyword_l,
1580            operator_l,
1581            end_l,
1582            expression_l,
1583        }))
1584    }
1585
1586    pub(crate) fn def_module(
1587        &self,
1588        module_t: PoolValue<Token>,
1589        name: Box<Node>,
1590        body: Option<Box<Node>>,
1591        end_t: PoolValue<Token>,
1592    ) -> Box<Node> {
1593        let keyword_l = self.loc(&module_t);
1594        let end_l = self.loc(&end_t);
1595        let expression_l = keyword_l.join(&end_l);
1596
1597        Box::new(Node::Module(Module {
1598            name,
1599            body,
1600            keyword_l,
1601            end_l,
1602            expression_l,
1603        }))
1604    }
1605
1606    //
1607    // Method (un)definition
1608    //
1609
1610    pub(crate) fn def_method(
1611        &self,
1612        def_t: PoolValue<Token>,
1613        name_t: PoolValue<Token>,
1614        args: Option<Box<Node>>,
1615        body: Option<Box<Node>>,
1616        end_t: PoolValue<Token>,
1617    ) -> Result<Box<Node>, ()> {
1618        let name_l = self.loc(&name_t);
1619        let keyword_l = self.loc(&def_t);
1620        let end_l = self.loc(&end_t);
1621        let expression_l = keyword_l.join(&end_l);
1622
1623        let name = value(name_t);
1624        self.check_reserved_for_numparam(name.as_str(), &name_l)?;
1625
1626        Ok(Box::new(Node::Def(Def {
1627            name,
1628            args,
1629            body,
1630            keyword_l,
1631            name_l,
1632            end_l: Some(end_l),
1633            assignment_l: None,
1634            expression_l,
1635        })))
1636    }
1637
1638    pub(crate) fn def_endless_method(
1639        &self,
1640        def_t: PoolValue<Token>,
1641        name_t: PoolValue<Token>,
1642        args: Option<Box<Node>>,
1643        assignment_t: PoolValue<Token>,
1644        body: Option<Box<Node>>,
1645    ) -> Result<Box<Node>, ()> {
1646        let body_l = maybe_boxed_node_expr(&body)
1647            .unwrap_or_else(|| unreachable!("endless method always has a body"));
1648
1649        let keyword_l = self.loc(&def_t);
1650        let expression_l = keyword_l.join(&body_l);
1651        let name_l = self.loc(&name_t);
1652        let assignment_l = self.loc(&assignment_t);
1653
1654        let name = value(name_t);
1655        self.check_reserved_for_numparam(name.as_str(), &name_l)?;
1656
1657        Ok(Box::new(Node::Def(Def {
1658            name,
1659            args,
1660            body,
1661            keyword_l,
1662            name_l,
1663            end_l: None,
1664            assignment_l: Some(assignment_l),
1665            expression_l,
1666        })))
1667    }
1668
1669    pub(crate) fn def_singleton(
1670        &self,
1671        def_t: PoolValue<Token>,
1672        definee: Box<Node>,
1673        dot_t: PoolValue<Token>,
1674        name_t: PoolValue<Token>,
1675        args: Option<Box<Node>>,
1676        body: Option<Box<Node>>,
1677        end_t: PoolValue<Token>,
1678    ) -> Result<Box<Node>, ()> {
1679        let keyword_l = self.loc(&def_t);
1680        let operator_l = self.loc(&dot_t);
1681        let name_l = self.loc(&name_t);
1682        let end_l = self.loc(&end_t);
1683        let expression_l = keyword_l.join(&end_l);
1684
1685        let name = value(name_t);
1686        self.check_reserved_for_numparam(name.as_str(), &name_l)?;
1687
1688        Ok(Box::new(Node::Defs(Defs {
1689            definee,
1690            name,
1691            args,
1692            body,
1693            keyword_l,
1694            operator_l,
1695            name_l,
1696            assignment_l: None,
1697            end_l: Some(end_l),
1698            expression_l,
1699        })))
1700    }
1701
1702    pub(crate) fn def_endless_singleton(
1703        &self,
1704        def_t: PoolValue<Token>,
1705        definee: Box<Node>,
1706        dot_t: PoolValue<Token>,
1707        name_t: PoolValue<Token>,
1708        args: Option<Box<Node>>,
1709        assignment_t: PoolValue<Token>,
1710        body: Option<Box<Node>>,
1711    ) -> Result<Box<Node>, ()> {
1712        let body_l = maybe_boxed_node_expr(&body)
1713            .unwrap_or_else(|| unreachable!("endless method always has body"));
1714
1715        let keyword_l = self.loc(&def_t);
1716        let operator_l = self.loc(&dot_t);
1717        let name_l = self.loc(&name_t);
1718        let assignment_l = self.loc(&assignment_t);
1719        let expression_l = keyword_l.join(&body_l);
1720
1721        let name = value(name_t);
1722        self.check_reserved_for_numparam(name.as_str(), &name_l)?;
1723
1724        Ok(Box::new(Node::Defs(Defs {
1725            definee,
1726            name,
1727            args,
1728            body,
1729            keyword_l,
1730            operator_l,
1731            name_l,
1732            assignment_l: Some(assignment_l),
1733            end_l: None,
1734            expression_l,
1735        })))
1736    }
1737
1738    pub(crate) fn undef_method(&self, undef_t: PoolValue<Token>, names: Vec<Node>) -> Box<Node> {
1739        let keyword_l = self.loc(&undef_t);
1740        let expression_l = keyword_l.maybe_join(&collection_expr(&names));
1741        Box::new(Node::Undef(Undef {
1742            names,
1743            keyword_l,
1744            expression_l,
1745        }))
1746    }
1747
1748    pub(crate) fn alias(
1749        &self,
1750        alias_t: PoolValue<Token>,
1751        to: Box<Node>,
1752        from: Box<Node>,
1753    ) -> Box<Node> {
1754        let keyword_l = self.loc(&alias_t);
1755        let expression_l = keyword_l.join(from.expression());
1756        Box::new(Node::Alias(Alias {
1757            to,
1758            from,
1759            keyword_l,
1760            expression_l,
1761        }))
1762    }
1763
1764    //
1765    // Formal arguments
1766    //
1767
1768    pub(crate) fn args(
1769        &self,
1770        begin_t: Option<PoolValue<Token>>,
1771        args: Vec<Node>,
1772        end_t: Option<PoolValue<Token>>,
1773    ) -> Option<Box<Node>> {
1774        self.check_duplicate_args(&args, &mut HashMap::new());
1775        self.validate_no_forward_arg_after_restarg(&args);
1776
1777        if begin_t.is_none() && args.is_empty() && end_t.is_none() {
1778            return None;
1779        }
1780
1781        let CollectionMap {
1782            begin_l,
1783            end_l,
1784            expression_l,
1785        } = self.collection_map(&begin_t, &args, &end_t);
1786
1787        Some(Box::new(Node::Args(Args {
1788            args,
1789            expression_l,
1790            begin_l,
1791            end_l,
1792        })))
1793    }
1794
1795    pub(crate) fn forward_arg(&self, dots_t: PoolValue<Token>) -> Box<Node> {
1796        Box::new(Node::ForwardArg(ForwardArg {
1797            expression_l: self.loc(&dots_t),
1798        }))
1799    }
1800
1801    pub(crate) fn arg(&self, name_t: PoolValue<Token>) -> Result<Box<Node>, ()> {
1802        let name_l = self.loc(&name_t);
1803        let name = value(name_t);
1804
1805        self.check_reserved_for_numparam(name.as_str(), &name_l)?;
1806
1807        Ok(Box::new(Node::Arg(Arg {
1808            name,
1809            expression_l: name_l,
1810        })))
1811    }
1812
1813    pub(crate) fn optarg(
1814        &self,
1815        name_t: PoolValue<Token>,
1816        eql_t: PoolValue<Token>,
1817        default: Box<Node>,
1818    ) -> Result<Box<Node>, ()> {
1819        let operator_l = self.loc(&eql_t);
1820        let name_l = self.loc(&name_t);
1821        let expression_l = self.loc(&name_t).join(default.expression());
1822
1823        let name = value(name_t);
1824        self.check_reserved_for_numparam(name.as_str(), &name_l)?;
1825
1826        Ok(Box::new(Node::Optarg(Optarg {
1827            name,
1828            default,
1829            name_l,
1830            operator_l,
1831            expression_l,
1832        })))
1833    }
1834
1835    pub(crate) fn restarg(
1836        &self,
1837        star_t: PoolValue<Token>,
1838        name_t: Option<PoolValue<Token>>,
1839    ) -> Result<Box<Node>, ()> {
1840        let (name, name_l) = if let Some(name_t) = name_t {
1841            let name_l = self.loc(&name_t);
1842            let name = value(name_t);
1843            self.check_reserved_for_numparam(name.as_str(), &name_l)?;
1844            (Some(name), Some(name_l))
1845        } else {
1846            (None, None)
1847        };
1848
1849        let operator_l = self.loc(&star_t);
1850        let expression_l = operator_l.maybe_join(&name_l);
1851
1852        Ok(Box::new(Node::Restarg(Restarg {
1853            name,
1854            operator_l,
1855            name_l,
1856            expression_l,
1857        })))
1858    }
1859
1860    pub(crate) fn kwarg(&self, name_t: PoolValue<Token>) -> Result<Box<Node>, ()> {
1861        let name_l = self.loc(&name_t);
1862        let name = value(name_t);
1863        self.check_reserved_for_numparam(name.as_str(), &name_l)?;
1864
1865        let expression_l = name_l;
1866        let name_l = expression_l.adjust_end(-1);
1867
1868        Ok(Box::new(Node::Kwarg(Kwarg {
1869            name,
1870            name_l,
1871            expression_l,
1872        })))
1873    }
1874
1875    pub(crate) fn kwoptarg(
1876        &self,
1877        name_t: PoolValue<Token>,
1878        default: Box<Node>,
1879    ) -> Result<Box<Node>, ()> {
1880        let name_l = self.loc(&name_t);
1881        let name = value(name_t);
1882        self.check_reserved_for_numparam(name.as_str(), &name_l)?;
1883
1884        let label_l = name_l;
1885        let name_l = label_l.adjust_end(-1);
1886        let expression_l = default.expression().join(&label_l);
1887
1888        Ok(Box::new(Node::Kwoptarg(Kwoptarg {
1889            name,
1890            default,
1891            name_l,
1892            expression_l,
1893        })))
1894    }
1895
1896    pub(crate) fn kwrestarg(
1897        &self,
1898        dstar_t: PoolValue<Token>,
1899        name_t: Option<PoolValue<Token>>,
1900    ) -> Result<Box<Node>, ()> {
1901        let (name, name_l) = if let Some(name_t) = name_t {
1902            let name_l = self.loc(&name_t);
1903            let name = value(name_t);
1904            self.check_reserved_for_numparam(name.as_str(), &name_l)?;
1905            (Some(name), Some(name_l))
1906        } else {
1907            (None, None)
1908        };
1909
1910        let operator_l = self.loc(&dstar_t);
1911        let expression_l = operator_l.maybe_join(&name_l);
1912
1913        Ok(Box::new(Node::Kwrestarg(Kwrestarg {
1914            name,
1915            operator_l,
1916            name_l,
1917            expression_l,
1918        })))
1919    }
1920
1921    pub(crate) fn kwnilarg(&self, dstar_t: PoolValue<Token>, nil_t: PoolValue<Token>) -> Box<Node> {
1922        let dstar_l = self.loc(&dstar_t);
1923        let nil_l = self.loc(&nil_t);
1924        let expression_l = dstar_l.join(&nil_l);
1925        Box::new(Node::Kwnilarg(Kwnilarg {
1926            name_l: nil_l,
1927            expression_l,
1928        }))
1929    }
1930
1931    pub(crate) fn shadowarg(&self, name_t: PoolValue<Token>) -> Result<Box<Node>, ()> {
1932        let name_l = self.loc(&name_t);
1933        let name = value(name_t);
1934        self.check_reserved_for_numparam(name.as_str(), &name_l)?;
1935
1936        Ok(Box::new(Node::Shadowarg(Shadowarg {
1937            name,
1938            expression_l: name_l,
1939        })))
1940    }
1941
1942    pub(crate) fn blockarg(
1943        &self,
1944        amper_t: PoolValue<Token>,
1945        name_t: Option<PoolValue<Token>>,
1946    ) -> Result<Box<Node>, ()> {
1947        let name_l = self.maybe_loc(&name_t);
1948        let name = maybe_value(name_t);
1949        if let (Some(name_l), Some(name)) = (name_l.as_ref(), name.as_ref()) {
1950            self.check_reserved_for_numparam(name, name_l)?;
1951        }
1952
1953        let operator_l = self.loc(&amper_t);
1954        let expression_l = operator_l.maybe_join(&name_l);
1955
1956        Ok(Box::new(Node::Blockarg(Blockarg {
1957            name,
1958            operator_l,
1959            name_l,
1960            expression_l,
1961        })))
1962    }
1963
1964    pub(crate) fn procarg0(&self, arg: Box<Node>) -> Box<Node> {
1965        match *arg {
1966            Node::Mlhs(Mlhs {
1967                items,
1968                begin_l,
1969                end_l,
1970                expression_l,
1971            }) => Box::new(Node::Procarg0(Procarg0 {
1972                args: items,
1973                begin_l,
1974                end_l,
1975                expression_l,
1976            })),
1977            Node::Arg(Arg { name, expression_l }) => Box::new(Node::Procarg0(Procarg0 {
1978                args: vec![Node::Arg(Arg { name, expression_l })],
1979                begin_l: None,
1980                end_l: None,
1981                expression_l,
1982            })),
1983            other => {
1984                unreachable!("unsupported procarg0 child {:?}", other)
1985            }
1986        }
1987    }
1988
1989    //
1990    // Method calls
1991    //
1992
1993    fn call_type_for_dot(&self, dot_t: &Option<PoolValue<Token>>) -> MethodCallType {
1994        match dot_t.as_ref() {
1995            Some(token) if token.token_type == Lexer::tANDDOT => MethodCallType::CSend,
1996            _ => MethodCallType::Send,
1997        }
1998    }
1999
2000    pub(crate) fn forwarded_args(&self, dots_t: PoolValue<Token>) -> Box<Node> {
2001        Box::new(Node::ForwardedArgs(ForwardedArgs {
2002            expression_l: self.loc(&dots_t),
2003        }))
2004    }
2005
2006    pub(crate) fn call_method(
2007        &self,
2008        receiver: Option<Box<Node>>,
2009        dot_t: Option<PoolValue<Token>>,
2010        selector_t: Option<PoolValue<Token>>,
2011        lparen_t: Option<PoolValue<Token>>,
2012        mut args: Vec<Node>,
2013        rparen_t: Option<PoolValue<Token>>,
2014    ) -> Box<Node> {
2015        let begin_l = maybe_boxed_node_expr(&receiver)
2016            .or_else(|| self.maybe_loc(&selector_t))
2017            .unwrap_or_else(|| unreachable!("can't compute begin_l"));
2018        let end_l = self
2019            .maybe_loc(&rparen_t)
2020            .or_else(|| maybe_node_expr(&args.last()))
2021            .or_else(|| self.maybe_loc(&selector_t))
2022            .unwrap_or_else(|| unreachable!("can't compute end_l"));
2023
2024        let expression_l = begin_l.join(&end_l);
2025
2026        let dot_l = self.maybe_loc(&dot_t);
2027        let selector_l = self.maybe_loc(&selector_t);
2028        let begin_l = self.maybe_loc(&lparen_t);
2029        let end_l = self.maybe_loc(&rparen_t);
2030
2031        let method_name = maybe_value(selector_t);
2032        let method_name = method_name.unwrap_or_else(|| String::from("call"));
2033
2034        self.rewrite_hash_args_to_kwargs(&mut args);
2035
2036        match self.call_type_for_dot(&dot_t) {
2037            MethodCallType::Send => Box::new(Node::Send(Send {
2038                recv: receiver,
2039                method_name,
2040                args,
2041                dot_l,
2042                selector_l,
2043                begin_l,
2044                end_l,
2045                operator_l: None,
2046                expression_l,
2047            })),
2048
2049            MethodCallType::CSend => Box::new(Node::CSend(CSend {
2050                recv: receiver.expect("csend node must have a receiver"),
2051                method_name,
2052                args,
2053                dot_l: dot_l.expect("csend node must have &."),
2054                selector_l,
2055                begin_l,
2056                end_l,
2057                operator_l: None,
2058                expression_l,
2059            })),
2060        }
2061    }
2062
2063    pub(crate) fn call_lambda(&self, lambda_t: PoolValue<Token>) -> Box<Node> {
2064        Box::new(Node::Lambda(Lambda {
2065            expression_l: self.loc(&lambda_t),
2066        }))
2067    }
2068
2069    pub(crate) fn block(
2070        &self,
2071        method_call: Box<Node>,
2072        begin_t: PoolValue<Token>,
2073        block_args: ArgsType,
2074        body: Option<Box<Node>>,
2075        end_t: PoolValue<Token>,
2076    ) -> Result<Box<Node>, ()> {
2077        let block_body = body;
2078
2079        let validate_block_and_block_arg = |args: &Vec<Node>| {
2080            if let Some(last_arg) = args.last() {
2081                match last_arg {
2082                    Node::BlockPass(_) | Node::ForwardedArgs(_) => {
2083                        self.error(
2084                            DiagnosticMessage::BlockAndBlockArgGiven {},
2085                            last_arg.expression(),
2086                        );
2087                        Err(())
2088                    }
2089                    _ => Ok(()),
2090                }
2091            } else {
2092                Ok(())
2093            }
2094        };
2095
2096        match &*method_call {
2097            Node::Yield(Yield { keyword_l, .. }) => {
2098                self.error(DiagnosticMessage::BlockGivenToYield {}, keyword_l);
2099                return Err(());
2100            }
2101            Node::Send(Send { args, .. }) => {
2102                validate_block_and_block_arg(args)?;
2103            }
2104            Node::CSend(CSend { args, .. }) => {
2105                validate_block_and_block_arg(args)?;
2106            }
2107            _ => {}
2108        }
2109
2110        let rewrite_args_and_loc =
2111            |method_args: Vec<Node>,
2112             keyword_expression_l: Loc,
2113             block_args: ArgsType,
2114             block_body: Option<Box<Node>>| {
2115                // Code like "return foo 1 do end" is reduced in a weird sequence.
2116                // Here, method_call is actually (return).
2117                let actual_send = method_args.into_iter().next().unwrap();
2118
2119                let begin_l = self.loc(&begin_t);
2120                let end_l = self.loc(&end_t);
2121                let expression_l = actual_send.expression().join(&end_l);
2122
2123                let block = match block_args {
2124                    ArgsType::Args(args) => Node::Block(Block {
2125                        call: Box::new(actual_send),
2126                        args,
2127                        body: block_body,
2128                        begin_l,
2129                        end_l,
2130                        expression_l,
2131                    }),
2132                    ArgsType::Numargs(numargs) => Node::Numblock(Numblock {
2133                        call: Box::new(actual_send),
2134                        numargs,
2135                        body: block_body.unwrap_or_else(|| {
2136                            Box::new(Node::Nil(Nil {
2137                                expression_l: Loc { begin: 0, end: 0 },
2138                            }))
2139                        }),
2140                        begin_l,
2141                        end_l,
2142                        expression_l,
2143                    }),
2144                };
2145
2146                let expr_l = keyword_expression_l.join(block.expression());
2147
2148                (vec![block], expr_l)
2149            };
2150
2151        match &*method_call {
2152            Node::Send(_)
2153            | Node::CSend(_)
2154            | Node::Index(_)
2155            | Node::Super(_)
2156            | Node::ZSuper(_)
2157            | Node::Lambda(_) => {
2158                let begin_l = self.loc(&begin_t);
2159                let end_l = self.loc(&end_t);
2160                let expression_l = method_call.expression().join(&end_l);
2161
2162                let result = match block_args {
2163                    ArgsType::Args(args) => Node::Block(Block {
2164                        call: method_call,
2165                        args,
2166                        body: block_body,
2167                        begin_l,
2168                        end_l,
2169                        expression_l,
2170                    }),
2171                    ArgsType::Numargs(numargs) => Node::Numblock(Numblock {
2172                        call: method_call,
2173                        numargs,
2174                        body: block_body.unwrap_or_else(|| {
2175                            Box::new(Node::Nil(Nil {
2176                                expression_l: Loc { begin: 0, end: 0 },
2177                            }))
2178                        }),
2179                        begin_l,
2180                        end_l,
2181                        expression_l,
2182                    }),
2183                };
2184                return Ok(Box::new(result));
2185            }
2186            _ => {}
2187        }
2188
2189        let method_call = method_call;
2190        let result = match *method_call {
2191            Node::Return(Return {
2192                args,
2193                keyword_l,
2194                expression_l,
2195            }) => {
2196                let (args, expression_l) =
2197                    rewrite_args_and_loc(args, expression_l, block_args, block_body);
2198                Node::Return(Return {
2199                    args,
2200                    keyword_l,
2201                    expression_l,
2202                })
2203            }
2204            Node::Next(Next {
2205                args,
2206                keyword_l,
2207                expression_l,
2208            }) => {
2209                let (args, expression_l) =
2210                    rewrite_args_and_loc(args, expression_l, block_args, block_body);
2211                Node::Next(Next {
2212                    args,
2213                    keyword_l,
2214                    expression_l,
2215                })
2216            }
2217            Node::Break(Break {
2218                args,
2219                keyword_l,
2220                expression_l,
2221            }) => {
2222                let (args, expression_l) =
2223                    rewrite_args_and_loc(args, expression_l, block_args, block_body);
2224                Node::Break(Break {
2225                    args,
2226                    keyword_l,
2227                    expression_l,
2228                })
2229            }
2230            other => {
2231                unreachable!("unsupported method call {:?}", other)
2232            }
2233        };
2234
2235        Ok(Box::new(result))
2236    }
2237    pub(crate) fn block_pass(
2238        &self,
2239        amper_t: PoolValue<Token>,
2240        value: Option<Box<Node>>,
2241    ) -> Box<Node> {
2242        let amper_l = self.loc(&amper_t);
2243        let expression_l = amper_l.maybe_join(&value.as_ref().map(|node| *node.expression()));
2244
2245        Box::new(Node::BlockPass(BlockPass {
2246            value,
2247            operator_l: amper_l,
2248            expression_l,
2249        }))
2250    }
2251
2252    pub(crate) fn attr_asgn(
2253        &self,
2254        receiver: Box<Node>,
2255        dot_t: PoolValue<Token>,
2256        selector_t: PoolValue<Token>,
2257    ) -> Box<Node> {
2258        let dot_l = self.loc(&dot_t);
2259        let selector_l = self.loc(&selector_t);
2260        let expression_l = receiver.expression().join(&selector_l);
2261        let receiver: Box<Node> = receiver;
2262
2263        let method_name = value(selector_t) + "=";
2264
2265        match self.call_type_for_dot(&Some(dot_t)) {
2266            MethodCallType::Send => Box::new(Node::Send(Send {
2267                recv: Some(receiver),
2268                method_name,
2269                args: vec![],
2270                dot_l: Some(dot_l),
2271                selector_l: Some(selector_l),
2272                begin_l: None,
2273                end_l: None,
2274                operator_l: None,
2275                expression_l,
2276            })),
2277
2278            MethodCallType::CSend => Box::new(Node::CSend(CSend {
2279                recv: receiver,
2280                method_name,
2281                args: vec![],
2282                dot_l,
2283                selector_l: Some(selector_l),
2284                begin_l: None,
2285                end_l: None,
2286                operator_l: None,
2287                expression_l,
2288            })),
2289        }
2290    }
2291
2292    pub(crate) fn index(
2293        &self,
2294        recv: Box<Node>,
2295        lbrack_t: PoolValue<Token>,
2296        mut indexes: Vec<Node>,
2297        rbrack_t: PoolValue<Token>,
2298    ) -> Box<Node> {
2299        let begin_l = self.loc(&lbrack_t);
2300        let end_l = self.loc(&rbrack_t);
2301        let expression_l = recv.expression().join(&end_l);
2302
2303        self.rewrite_hash_args_to_kwargs(&mut indexes);
2304
2305        Box::new(Node::Index(Index {
2306            recv,
2307            indexes,
2308            begin_l,
2309            end_l,
2310            expression_l,
2311        }))
2312    }
2313
2314    pub(crate) fn index_asgn(
2315        &self,
2316        recv: Box<Node>,
2317        lbrack_t: PoolValue<Token>,
2318        indexes: Vec<Node>,
2319        rbrack_t: PoolValue<Token>,
2320    ) -> Box<Node> {
2321        let begin_l = self.loc(&lbrack_t);
2322        let end_l = self.loc(&rbrack_t);
2323        let expression_l = recv.expression().join(&end_l);
2324
2325        Box::new(Node::IndexAsgn(IndexAsgn {
2326            recv,
2327            indexes,
2328            value: None,
2329            begin_l,
2330            end_l,
2331            operator_l: None,
2332            expression_l,
2333        }))
2334    }
2335
2336    pub(crate) fn binary_op(
2337        &self,
2338        receiver: Box<Node>,
2339        operator_t: PoolValue<Token>,
2340        arg: Box<Node>,
2341    ) -> Result<Box<Node>, ()> {
2342        self.value_expr(&receiver)?;
2343        self.value_expr(&arg)?;
2344
2345        let selector_l = Some(self.loc(&operator_t));
2346        let expression_l = join_exprs(&receiver, &arg);
2347
2348        Ok(Box::new(Node::Send(Send {
2349            recv: Some(receiver),
2350            method_name: value(operator_t),
2351            args: vec![*arg],
2352            dot_l: None,
2353            selector_l,
2354            begin_l: None,
2355            end_l: None,
2356            operator_l: None,
2357            expression_l,
2358        })))
2359    }
2360
2361    pub(crate) fn match_op(
2362        &self,
2363        receiver: Box<Node>,
2364        match_t: PoolValue<Token>,
2365        arg: Box<Node>,
2366    ) -> Result<Box<Node>, ()> {
2367        self.value_expr(&receiver)?;
2368        self.value_expr(&arg)?;
2369
2370        let selector_l = self.loc(&match_t);
2371        let expression_l = join_exprs(&receiver, &arg);
2372
2373        let result = match self.static_regexp_captures(&receiver) {
2374            Some(captures) => {
2375                for capture in captures {
2376                    self.static_env.declare(&capture);
2377                }
2378
2379                Node::MatchWithLvasgn(MatchWithLvasgn {
2380                    re: receiver,
2381                    value: arg,
2382                    operator_l: selector_l,
2383                    expression_l,
2384                })
2385            }
2386            None => Node::Send(Send {
2387                recv: Some(receiver),
2388                method_name: String::from("=~"),
2389                args: vec![*arg],
2390                dot_l: None,
2391                selector_l: Some(selector_l),
2392                begin_l: None,
2393                end_l: None,
2394                operator_l: None,
2395                expression_l,
2396            }),
2397        };
2398
2399        Ok(Box::new(result))
2400    }
2401
2402    pub(crate) fn unary_op(
2403        &self,
2404        op_t: PoolValue<Token>,
2405        receiver: Box<Node>,
2406    ) -> Result<Box<Node>, ()> {
2407        self.value_expr(&receiver)?;
2408
2409        let selector_l = self.loc(&op_t);
2410        let expression_l = receiver.expression().join(&selector_l);
2411
2412        let op = value(op_t);
2413        let method_name = if op == "+" || op == "-" { op + "@" } else { op };
2414        Ok(Box::new(Node::Send(Send {
2415            recv: Some(receiver),
2416            method_name,
2417            args: vec![],
2418            dot_l: None,
2419            selector_l: Some(selector_l),
2420            begin_l: None,
2421            end_l: None,
2422            operator_l: None,
2423            expression_l,
2424        })))
2425    }
2426
2427    pub(crate) fn not_op(
2428        &self,
2429        not_t: PoolValue<Token>,
2430        begin_t: Option<PoolValue<Token>>,
2431        receiver: Option<Box<Node>>,
2432        end_t: Option<PoolValue<Token>>,
2433    ) -> Result<Box<Node>, ()> {
2434        if let Some(receiver) = receiver {
2435            let receiver = receiver;
2436            self.value_expr(&receiver)?;
2437
2438            let begin_l = self.loc(&not_t);
2439            let end_l = self
2440                .maybe_loc(&end_t)
2441                .unwrap_or_else(|| *receiver.expression());
2442
2443            let expression_l = begin_l.join(&end_l);
2444
2445            let selector_l = self.loc(&not_t);
2446            let begin_l = self.maybe_loc(&begin_t);
2447            let end_l = self.maybe_loc(&end_t);
2448
2449            Ok(Box::new(Node::Send(Send {
2450                recv: Some(Self::check_condition(receiver)),
2451                method_name: String::from("!"),
2452                args: vec![],
2453                dot_l: None,
2454                selector_l: Some(selector_l),
2455                begin_l,
2456                end_l,
2457                operator_l: None,
2458                expression_l,
2459            })))
2460        } else {
2461            let CollectionMap {
2462                begin_l,
2463                end_l,
2464                expression_l,
2465            } = self.collection_map(&begin_t, &[], &end_t);
2466
2467            let nil_node = Box::new(Node::Begin(Begin {
2468                statements: vec![],
2469                begin_l,
2470                end_l,
2471                expression_l,
2472            }));
2473
2474            let selector_l = self.loc(&not_t);
2475            let expression_l = nil_node.expression().join(&selector_l);
2476            Ok(Box::new(Node::Send(Send {
2477                recv: Some(nil_node),
2478                method_name: String::from("!"),
2479                args: vec![],
2480                dot_l: None,
2481                selector_l: Some(selector_l),
2482                begin_l: None,
2483                end_l: None,
2484                operator_l: None,
2485                expression_l,
2486            })))
2487        }
2488    }
2489
2490    //
2491    // Control flow
2492    //
2493
2494    // Logical operations: and, or
2495
2496    pub(crate) fn logical_op(
2497        &self,
2498        type_: LogicalOp,
2499        lhs: Box<Node>,
2500        op_t: PoolValue<Token>,
2501        rhs: Box<Node>,
2502    ) -> Result<Box<Node>, ()> {
2503        self.value_expr(&lhs)?;
2504
2505        let operator_l = self.loc(&op_t);
2506        let expression_l = join_exprs(&lhs, &rhs);
2507        let lhs: Box<Node> = lhs;
2508        let rhs: Box<Node> = rhs;
2509
2510        let result = match type_ {
2511            LogicalOp::And => Node::And(And {
2512                lhs,
2513                rhs,
2514                operator_l,
2515                expression_l,
2516            }),
2517            LogicalOp::Or => Node::Or(Or {
2518                lhs,
2519                rhs,
2520                operator_l,
2521                expression_l,
2522            }),
2523        };
2524        Ok(Box::new(result))
2525    }
2526
2527    // Conditionals
2528
2529    pub(crate) fn condition(
2530        &self,
2531        cond_t: PoolValue<Token>,
2532        cond: Box<Node>,
2533        then_t: PoolValue<Token>,
2534        if_true: Option<Box<Node>>,
2535        else_t: Option<PoolValue<Token>>,
2536        if_false: Option<Box<Node>>,
2537        end_t: Option<PoolValue<Token>>,
2538    ) -> Box<Node> {
2539        let end_l = self
2540            .maybe_loc(&end_t)
2541            .or_else(|| maybe_boxed_node_expr(&if_false))
2542            .or_else(|| self.maybe_loc(&else_t))
2543            .or_else(|| maybe_boxed_node_expr(&if_true))
2544            .unwrap_or_else(|| self.loc(&then_t));
2545
2546        let expression_l = self.loc(&cond_t).join(&end_l);
2547        let keyword_l = self.loc(&cond_t);
2548        let begin_l = self.loc(&then_t);
2549        let else_l = self.maybe_loc(&else_t);
2550        let end_l = self.maybe_loc(&end_t);
2551
2552        Box::new(Node::If(If {
2553            cond: Self::check_condition(cond),
2554            if_true,
2555            if_false,
2556            keyword_l,
2557            begin_l,
2558            else_l,
2559            end_l,
2560            expression_l,
2561        }))
2562    }
2563
2564    pub(crate) fn condition_mod(
2565        &self,
2566        if_true: Option<Box<Node>>,
2567        if_false: Option<Box<Node>>,
2568        cond_t: PoolValue<Token>,
2569        cond: Box<Node>,
2570    ) -> Box<Node> {
2571        let pre = match (if_true.as_ref(), if_false.as_ref()) {
2572            (None, None) => unreachable!("at least one of if_true/if_false is required"),
2573            (None, Some(if_false)) => if_false,
2574            (Some(if_true), None) => if_true,
2575            (Some(_), Some(_)) => unreachable!("only one of if_true/if_false is required"),
2576        };
2577
2578        let expression_l = pre.expression().join(cond.expression());
2579        let keyword_l = self.loc(&cond_t);
2580
2581        Box::new(Node::IfMod(IfMod {
2582            cond: Self::check_condition(cond),
2583            if_true,
2584            if_false,
2585            keyword_l,
2586            expression_l,
2587        }))
2588    }
2589
2590    pub(crate) fn ternary(
2591        &self,
2592        cond: Box<Node>,
2593        question_t: PoolValue<Token>,
2594        if_true: Box<Node>,
2595        colon_t: PoolValue<Token>,
2596        if_false: Box<Node>,
2597    ) -> Box<Node> {
2598        let expression_l = join_exprs(&cond, &if_false);
2599        let question_l = self.loc(&question_t);
2600        let colon_l = self.loc(&colon_t);
2601
2602        Box::new(Node::IfTernary(IfTernary {
2603            cond,
2604            if_true,
2605            if_false,
2606            question_l,
2607            colon_l,
2608            expression_l,
2609        }))
2610    }
2611
2612    // Case matching
2613
2614    pub(crate) fn when(
2615        &self,
2616        when_t: PoolValue<Token>,
2617        patterns: Vec<Node>,
2618        then_t: PoolValue<Token>,
2619        body: Option<Box<Node>>,
2620    ) -> Box<Node> {
2621        let begin_l = self.loc(&then_t);
2622
2623        let expr_end_l = maybe_boxed_node_expr(&body)
2624            .or_else(|| maybe_node_expr(&patterns.last()))
2625            .unwrap_or_else(|| self.loc(&when_t));
2626        let when_l = self.loc(&when_t);
2627        let expression_l = when_l.join(&expr_end_l);
2628
2629        Box::new(Node::When(When {
2630            patterns,
2631            body,
2632            keyword_l: when_l,
2633            begin_l,
2634            expression_l,
2635        }))
2636    }
2637
2638    pub(crate) fn case(
2639        &self,
2640        case_t: PoolValue<Token>,
2641        expr: Option<Box<Node>>,
2642        when_bodies: Vec<Node>,
2643        else_t: Option<PoolValue<Token>>,
2644        else_body: Option<Box<Node>>,
2645        end_t: PoolValue<Token>,
2646    ) -> Box<Node> {
2647        let keyword_l = self.loc(&case_t);
2648        let else_l = self.maybe_loc(&else_t);
2649        let end_l = self.loc(&end_t);
2650        let expression_l = keyword_l.join(&end_l);
2651
2652        Box::new(Node::Case(Case {
2653            expr,
2654            when_bodies,
2655            else_body,
2656            keyword_l,
2657            else_l,
2658            end_l,
2659            expression_l,
2660        }))
2661    }
2662
2663    // Loops
2664
2665    pub(crate) fn loop_(
2666        &self,
2667        loop_type: LoopType,
2668        keyword_t: PoolValue<Token>,
2669        cond: Box<Node>,
2670        do_t: PoolValue<Token>,
2671        body: Option<Box<Node>>,
2672        end_t: PoolValue<Token>,
2673    ) -> Box<Node> {
2674        let keyword_l = self.loc(&keyword_t);
2675        let begin_l = self.loc(&do_t);
2676        let end_l = self.loc(&end_t);
2677        let expression_l = self.loc(&keyword_t).join(&end_l);
2678
2679        let cond = Self::check_condition(cond);
2680
2681        match loop_type {
2682            LoopType::While => Box::new(Node::While(While {
2683                cond,
2684                body,
2685                keyword_l,
2686                begin_l: Some(begin_l),
2687                end_l: Some(end_l),
2688                expression_l,
2689            })),
2690            LoopType::Until => Box::new(Node::Until(Until {
2691                cond,
2692                body,
2693                keyword_l,
2694                begin_l: Some(begin_l),
2695                end_l: Some(end_l),
2696                expression_l,
2697            })),
2698        }
2699    }
2700
2701    pub(crate) fn loop_mod(
2702        &self,
2703        loop_type: LoopType,
2704        body: Box<Node>,
2705        keyword_t: PoolValue<Token>,
2706        cond: Box<Node>,
2707    ) -> Box<Node> {
2708        let expression_l = body.expression().join(cond.expression());
2709        let keyword_l = self.loc(&keyword_t);
2710
2711        let cond = Self::check_condition(cond);
2712
2713        match (loop_type, &*body) {
2714            (LoopType::While, Node::KwBegin(_)) => Box::new(Node::WhilePost(WhilePost {
2715                cond,
2716                body,
2717                keyword_l,
2718                expression_l,
2719            })),
2720            (LoopType::While, _) => Box::new(Node::While(While {
2721                cond,
2722                body: Some(body),
2723                keyword_l,
2724                begin_l: None,
2725                end_l: None,
2726                expression_l,
2727            })),
2728            (LoopType::Until, Node::KwBegin(_)) => Box::new(Node::UntilPost(UntilPost {
2729                cond,
2730                body,
2731                keyword_l,
2732                expression_l,
2733            })),
2734            (LoopType::Until, _) => Box::new(Node::Until(Until {
2735                cond,
2736                body: Some(body),
2737                keyword_l,
2738                begin_l: None,
2739                end_l: None,
2740                expression_l,
2741            })),
2742        }
2743    }
2744
2745    pub(crate) fn for_(
2746        &self,
2747        for_t: PoolValue<Token>,
2748        iterator: Box<Node>,
2749        in_t: PoolValue<Token>,
2750        iteratee: Box<Node>,
2751        do_t: PoolValue<Token>,
2752        body: Option<Box<Node>>,
2753        end_t: PoolValue<Token>,
2754    ) -> Box<Node> {
2755        let keyword_l = self.loc(&for_t);
2756        let operator_l = self.loc(&in_t);
2757        let begin_l = self.loc(&do_t);
2758        let end_l = self.loc(&end_t);
2759        let expression_l = keyword_l.join(&end_l);
2760
2761        Box::new(Node::For(For {
2762            iterator,
2763            iteratee,
2764            body,
2765            keyword_l,
2766            operator_l,
2767            begin_l,
2768            end_l,
2769            expression_l,
2770        }))
2771    }
2772
2773    // Keywords
2774
2775    pub(crate) fn keyword_cmd(
2776        &self,
2777        type_: KeywordCmd,
2778        keyword_t: PoolValue<Token>,
2779        lparen_t: Option<PoolValue<Token>>,
2780        mut args: Vec<Node>,
2781        rparen_t: Option<PoolValue<Token>>,
2782    ) -> Result<Box<Node>, ()> {
2783        let keyword_l = self.loc(&keyword_t);
2784
2785        if type_ == KeywordCmd::Yield && !args.is_empty() {
2786            if let Some(Node::BlockPass(_)) = args.last() {
2787                self.error(DiagnosticMessage::BlockGivenToYield {}, &keyword_l);
2788                return Err(());
2789            }
2790        }
2791
2792        match type_ {
2793            KeywordCmd::Yield | KeywordCmd::Super => {
2794                self.rewrite_hash_args_to_kwargs(&mut args);
2795            }
2796            _ => {}
2797        }
2798
2799        let begin_l = self.maybe_loc(&lparen_t);
2800        let end_l = self.maybe_loc(&rparen_t);
2801
2802        let expr_end_l = end_l
2803            .or_else(|| maybe_node_expr(&args.last()))
2804            .unwrap_or(keyword_l);
2805
2806        let expression_l = keyword_l.join(&expr_end_l);
2807
2808        let result = match type_ {
2809            KeywordCmd::Break => Node::Break(Break {
2810                args,
2811                keyword_l,
2812                expression_l,
2813            }),
2814            KeywordCmd::Defined => Node::Defined(Defined {
2815                value: Box::new(args.into_iter().next().unwrap()),
2816                keyword_l,
2817                begin_l,
2818                end_l,
2819                expression_l,
2820            }),
2821            KeywordCmd::Next => Node::Next(Next {
2822                args,
2823                keyword_l,
2824                expression_l,
2825            }),
2826            KeywordCmd::Redo => Node::Redo(Redo { expression_l }),
2827            KeywordCmd::Retry => Node::Retry(Retry { expression_l }),
2828            KeywordCmd::Return => Node::Return(Return {
2829                args,
2830                keyword_l,
2831                expression_l,
2832            }),
2833            KeywordCmd::Super => Node::Super(Super {
2834                args,
2835                keyword_l,
2836                begin_l,
2837                end_l,
2838                expression_l,
2839            }),
2840            KeywordCmd::Yield => Node::Yield(Yield {
2841                args,
2842                keyword_l,
2843                begin_l,
2844                end_l,
2845                expression_l,
2846            }),
2847            KeywordCmd::Zsuper => Node::ZSuper(ZSuper { expression_l }),
2848        };
2849
2850        Ok(Box::new(result))
2851    }
2852
2853    // BEGIN, END
2854
2855    pub(crate) fn preexe(
2856        &self,
2857        preexe_t: PoolValue<Token>,
2858        lbrace_t: PoolValue<Token>,
2859        body: Option<Box<Node>>,
2860        rbrace_t: PoolValue<Token>,
2861    ) -> Box<Node> {
2862        let keyword_l = self.loc(&preexe_t);
2863        let begin_l = self.loc(&lbrace_t);
2864        let end_l = self.loc(&rbrace_t);
2865        let expression_l = keyword_l.join(&end_l);
2866
2867        Box::new(Node::Preexe(Preexe {
2868            body,
2869            keyword_l,
2870            begin_l,
2871            end_l,
2872            expression_l,
2873        }))
2874    }
2875    pub(crate) fn postexe(
2876        &self,
2877        postexe_t: PoolValue<Token>,
2878        lbrace_t: PoolValue<Token>,
2879        body: Option<Box<Node>>,
2880        rbrace_t: PoolValue<Token>,
2881    ) -> Box<Node> {
2882        let keyword_l = self.loc(&postexe_t);
2883        let begin_l = self.loc(&lbrace_t);
2884        let end_l = self.loc(&rbrace_t);
2885        let expression_l = keyword_l.join(&end_l);
2886
2887        Box::new(Node::Postexe(Postexe {
2888            body,
2889            keyword_l,
2890            begin_l,
2891            end_l,
2892            expression_l,
2893        }))
2894    }
2895
2896    // Exception handling
2897
2898    pub(crate) fn rescue_body(
2899        &self,
2900        rescue_t: PoolValue<Token>,
2901        exc_list: Option<Box<Node>>,
2902        assoc_t: Option<PoolValue<Token>>,
2903        exc_var: Option<Box<Node>>,
2904        then_t: Option<PoolValue<Token>>,
2905        body: Option<Box<Node>>,
2906    ) -> Box<Node> {
2907        let end_l = maybe_boxed_node_expr(&body)
2908            .or_else(|| self.maybe_loc(&then_t))
2909            .or_else(|| maybe_boxed_node_expr(&exc_var))
2910            .or_else(|| maybe_boxed_node_expr(&exc_list))
2911            .unwrap_or_else(|| self.loc(&rescue_t));
2912
2913        let expression_l = self.loc(&rescue_t).join(&end_l);
2914        let keyword_l = self.loc(&rescue_t);
2915        let assoc_l = self.maybe_loc(&assoc_t);
2916        let begin_l = self.maybe_loc(&then_t);
2917
2918        Box::new(Node::RescueBody(RescueBody {
2919            exc_list,
2920            exc_var,
2921            body,
2922            keyword_l,
2923            assoc_l,
2924            begin_l,
2925            expression_l,
2926        }))
2927    }
2928
2929    pub(crate) fn begin_body(
2930        &self,
2931        compound_stmt: Option<Box<Node>>,
2932        rescue_bodies: Vec<Node>,
2933        else_: Option<(PoolValue<Token>, Option<Box<Node>>)>,
2934        ensure: Option<(PoolValue<Token>, Option<Box<Node>>)>,
2935    ) -> Option<Box<Node>> {
2936        let mut result: Option<Box<Node>>;
2937
2938        if !rescue_bodies.is_empty() {
2939            if let Some((else_t, else_)) = else_ {
2940                let begin_l = maybe_boxed_node_expr(&compound_stmt)
2941                    .or_else(|| maybe_node_expr(&rescue_bodies.first()))
2942                    .unwrap_or_else(|| unreachable!("can't compute begin_l"));
2943
2944                let end_l = maybe_boxed_node_expr(&else_).unwrap_or_else(|| self.loc(&else_t));
2945
2946                let expression_l = begin_l.join(&end_l);
2947                let else_l = self.loc(&else_t);
2948
2949                result = Some(Box::new(Node::Rescue(Rescue {
2950                    body: compound_stmt,
2951                    rescue_bodies,
2952                    else_,
2953                    else_l: Some(else_l),
2954                    expression_l,
2955                })))
2956            } else {
2957                let begin_l = maybe_boxed_node_expr(&compound_stmt)
2958                    .or_else(|| maybe_node_expr(&rescue_bodies.first()))
2959                    .unwrap_or_else(|| unreachable!("can't compute begin_l"));
2960
2961                let end_l = maybe_node_expr(&rescue_bodies.last())
2962                    .unwrap_or_else(|| unreachable!("can't compute end_l"));
2963
2964                let expression_l = begin_l.join(&end_l);
2965                let else_l = self.maybe_loc(&None);
2966
2967                result = Some(Box::new(Node::Rescue(Rescue {
2968                    body: compound_stmt,
2969                    rescue_bodies,
2970                    else_: None,
2971                    else_l,
2972                    expression_l,
2973                })))
2974            }
2975        } else if let Some((else_t, else_)) = else_ {
2976            let mut statements = vec![];
2977
2978            if let Some(compound_stmt) = compound_stmt {
2979                match *compound_stmt {
2980                    Node::Begin(Begin {
2981                        statements: stmts, ..
2982                    }) => statements = stmts,
2983                    other => statements.push(other),
2984                }
2985            }
2986
2987            let parts = if else_.is_some() {
2988                vec![*else_.unwrap()]
2989            } else {
2990                vec![]
2991            };
2992            let CollectionMap {
2993                begin_l,
2994                end_l,
2995                expression_l,
2996            } = self.collection_map(&Some(else_t), &parts, &None);
2997
2998            statements.push(Node::Begin(Begin {
2999                statements: parts,
3000                begin_l,
3001                end_l,
3002                expression_l,
3003            }));
3004
3005            let CollectionMap {
3006                begin_l,
3007                end_l,
3008                expression_l,
3009            } = self.collection_map(&None, &statements, &None);
3010
3011            result = Some(Box::new(Node::Begin(Begin {
3012                statements,
3013                begin_l,
3014                end_l,
3015                expression_l,
3016            })))
3017        } else {
3018            result = compound_stmt;
3019        }
3020
3021        if let Some((ensure_t, ensure)) = ensure {
3022            let ensure_body = ensure;
3023            let keyword_l = self.loc(&ensure_t);
3024
3025            let begin_l = maybe_boxed_node_expr(&result).unwrap_or_else(|| self.loc(&ensure_t));
3026
3027            let end_l = maybe_node_expr(&ensure_body.as_ref().map(|x| x.as_ref()))
3028                .unwrap_or_else(|| self.loc(&ensure_t));
3029
3030            let expression_l = begin_l.join(&end_l);
3031
3032            result = Some(Box::new(Node::Ensure(Ensure {
3033                body: result,
3034                ensure: ensure_body,
3035                keyword_l,
3036                expression_l,
3037            })))
3038        }
3039
3040        result
3041    }
3042
3043    //
3044    // Expression grouping
3045    //
3046
3047    pub(crate) fn compstmt(&self, statements: Vec<Node>) -> Option<Box<Node>> {
3048        match &statements[..] {
3049            [] => None,
3050            [_] => Some(Box::new(statements.into_iter().next().unwrap())),
3051            _ => {
3052                let CollectionMap {
3053                    begin_l,
3054                    end_l,
3055                    expression_l,
3056                } = self.collection_map(&None, &statements, &None);
3057
3058                Some(Box::new(Node::Begin(Begin {
3059                    statements,
3060                    begin_l,
3061                    end_l,
3062                    expression_l,
3063                })))
3064            }
3065        }
3066    }
3067
3068    pub(crate) fn begin(
3069        &self,
3070        begin_t: PoolValue<Token>,
3071        body: Option<Box<Node>>,
3072        end_t: PoolValue<Token>,
3073    ) -> Box<Node> {
3074        let new_begin_l = self.loc(&begin_t);
3075        let new_end_l = self.loc(&end_t);
3076        let new_expression_l = new_begin_l.join(&new_end_l);
3077
3078        let new_begin_l = Some(new_begin_l);
3079        let new_end_l = Some(new_end_l);
3080
3081        if let Some(body) = body {
3082            let mut body = *body;
3083            match &mut body {
3084                Node::Mlhs(Mlhs {
3085                    begin_l,
3086                    end_l,
3087                    expression_l,
3088                    ..
3089                }) => {
3090                    // Synthesized (begin) from compstmt "a; b" or (mlhs)
3091                    // from multi_lhs "(a, b) = *foo".
3092                    *begin_l = new_begin_l;
3093                    *end_l = new_end_l;
3094                    *expression_l = new_expression_l;
3095                    Box::new(body)
3096                }
3097                Node::Begin(Begin {
3098                    begin_l,
3099                    end_l,
3100                    expression_l,
3101                    ..
3102                }) if begin_l.is_none() && end_l.is_none() => {
3103                    *begin_l = new_begin_l;
3104                    *end_l = new_end_l;
3105                    *expression_l = new_expression_l;
3106                    Box::new(body)
3107                }
3108                _ => Box::new(Node::Begin(Begin {
3109                    statements: vec![body],
3110                    begin_l: new_begin_l,
3111                    end_l: new_end_l,
3112                    expression_l: new_expression_l,
3113                })),
3114            }
3115        } else {
3116            // A nil expression: `()'.
3117            Box::new(Node::Begin(Begin {
3118                statements: vec![],
3119                begin_l: new_begin_l,
3120                end_l: new_end_l,
3121                expression_l: new_expression_l,
3122            }))
3123        }
3124    }
3125
3126    pub(crate) fn begin_keyword(
3127        &self,
3128        begin_t: PoolValue<Token>,
3129        body: Option<Box<Node>>,
3130        end_t: PoolValue<Token>,
3131    ) -> Box<Node> {
3132        let begin_l = self.loc(&begin_t);
3133        let end_l = self.loc(&end_t);
3134        let expression_l = begin_l.join(&end_l);
3135
3136        let begin_l = Some(begin_l);
3137        let end_l = Some(end_l);
3138
3139        if let Some(body) = body {
3140            let body = *body;
3141            match body {
3142                Node::Begin(Begin { statements, .. }) => {
3143                    // Synthesized (begin) from compstmt "a; b".
3144                    Box::new(Node::KwBegin(KwBegin {
3145                        statements,
3146                        begin_l,
3147                        end_l,
3148                        expression_l,
3149                    }))
3150                }
3151                other => Box::new(Node::KwBegin(KwBegin {
3152                    statements: vec![other],
3153                    begin_l,
3154                    end_l,
3155                    expression_l,
3156                })),
3157            }
3158        } else {
3159            // A nil expression: `begin end'.
3160            Box::new(Node::KwBegin(KwBegin {
3161                statements: vec![],
3162                begin_l,
3163                end_l,
3164                expression_l,
3165            }))
3166        }
3167    }
3168
3169    //
3170    // Pattern matching
3171    //
3172
3173    pub(crate) fn case_match(
3174        &self,
3175        case_t: PoolValue<Token>,
3176        expr: Box<Node>,
3177        in_bodies: Vec<Node>,
3178        else_t: Option<PoolValue<Token>>,
3179        else_body: Option<Box<Node>>,
3180        end_t: PoolValue<Token>,
3181    ) -> Box<Node> {
3182        let else_body = match (else_t.as_ref(), else_body.as_ref()) {
3183            (Some(else_t), None) => Some(Box::new(Node::EmptyElse(EmptyElse {
3184                expression_l: self.loc(else_t),
3185            }))),
3186            _ => else_body,
3187        };
3188
3189        let keyword_l = self.loc(&case_t);
3190        let else_l = self.maybe_loc(&else_t);
3191        let end_l = self.loc(&end_t);
3192        let expression_l = self.loc(&case_t).join(&end_l);
3193
3194        Box::new(Node::CaseMatch(CaseMatch {
3195            expr,
3196            in_bodies,
3197            else_body,
3198            keyword_l,
3199            else_l,
3200            end_l,
3201            expression_l,
3202        }))
3203    }
3204
3205    pub(crate) fn match_pattern(
3206        &self,
3207        value: Box<Node>,
3208        assoc_t: PoolValue<Token>,
3209        pattern: Box<Node>,
3210    ) -> Box<Node> {
3211        let operator_l = self.loc(&assoc_t);
3212        let expression_l = join_exprs(&value, &pattern);
3213
3214        Box::new(Node::MatchPattern(MatchPattern {
3215            value,
3216            pattern,
3217            operator_l,
3218            expression_l,
3219        }))
3220    }
3221
3222    pub(crate) fn match_pattern_p(
3223        &self,
3224        value: Box<Node>,
3225        in_t: PoolValue<Token>,
3226        pattern: Box<Node>,
3227    ) -> Box<Node> {
3228        let operator_l = self.loc(&in_t);
3229        let expression_l = join_exprs(&value, &pattern);
3230
3231        Box::new(Node::MatchPatternP(MatchPatternP {
3232            value,
3233            pattern,
3234            operator_l,
3235            expression_l,
3236        }))
3237    }
3238
3239    pub(crate) fn in_pattern(
3240        &self,
3241        in_t: PoolValue<Token>,
3242        pattern: Box<Node>,
3243        guard: Option<Box<Node>>,
3244        then_t: PoolValue<Token>,
3245        body: Option<Box<Node>>,
3246    ) -> Box<Node> {
3247        let keyword_l = self.loc(&in_t);
3248        let begin_l = self.loc(&then_t);
3249
3250        let expression_l = maybe_boxed_node_expr(&body)
3251            .or_else(|| maybe_boxed_node_expr(&guard))
3252            .unwrap_or_else(|| *pattern.expression())
3253            .join(&keyword_l);
3254
3255        Box::new(Node::InPattern(InPattern {
3256            pattern,
3257            guard,
3258            body,
3259            keyword_l,
3260            begin_l,
3261            expression_l,
3262        }))
3263    }
3264
3265    pub(crate) fn if_guard(&self, if_t: PoolValue<Token>, cond: Box<Node>) -> Box<Node> {
3266        let keyword_l = self.loc(&if_t);
3267        let expression_l = keyword_l.join(cond.expression());
3268
3269        Box::new(Node::IfGuard(IfGuard {
3270            cond,
3271            keyword_l,
3272            expression_l,
3273        }))
3274    }
3275    pub(crate) fn unless_guard(&self, unless_t: PoolValue<Token>, cond: Box<Node>) -> Box<Node> {
3276        let keyword_l = self.loc(&unless_t);
3277        let expression_l = keyword_l.join(cond.expression());
3278
3279        Box::new(Node::UnlessGuard(UnlessGuard {
3280            cond,
3281            keyword_l,
3282            expression_l,
3283        }))
3284    }
3285
3286    pub(crate) fn match_var(&self, name_t: PoolValue<Token>) -> Result<Box<Node>, ()> {
3287        let name_l = self.loc(&name_t);
3288        let expression_l = name_l;
3289        let name = value(name_t);
3290
3291        self.check_lvar_name(name.as_str(), &name_l)?;
3292        self.check_duplicate_pattern_variable(name.as_str(), &name_l)?;
3293        self.static_env.declare(name.as_str());
3294
3295        Ok(Box::new(Node::MatchVar(MatchVar {
3296            name,
3297            name_l,
3298            expression_l,
3299        })))
3300    }
3301
3302    pub(crate) fn match_hash_var(&self, name_t: PoolValue<Token>) -> Result<Box<Node>, ()> {
3303        let expression_l = self.loc(&name_t);
3304        let name_l = expression_l.adjust_end(-1);
3305
3306        let name = value(name_t);
3307
3308        self.check_lvar_name(name.as_str(), &name_l)?;
3309        self.check_duplicate_pattern_variable(name.as_str(), &name_l)?;
3310        self.static_env.declare(name.as_str());
3311
3312        Ok(Box::new(Node::MatchVar(MatchVar {
3313            name,
3314            name_l,
3315            expression_l,
3316        })))
3317    }
3318    pub(crate) fn match_hash_var_from_str(
3319        &self,
3320        begin_t: PoolValue<Token>,
3321        mut strings: Vec<Node>,
3322        end_t: PoolValue<Token>,
3323    ) -> Result<Box<Node>, ()> {
3324        if strings.len() != 1 {
3325            self.error(
3326                DiagnosticMessage::SymbolLiteralWithInterpolation {},
3327                &self.loc(&begin_t).join(&self.loc(&end_t)),
3328            );
3329            return Err(());
3330        }
3331
3332        let string = strings.remove(0);
3333        let result = match string {
3334            Node::Str(Str {
3335                value,
3336                begin_l,
3337                end_l,
3338                expression_l,
3339            }) => {
3340                let name = value.to_string_lossy();
3341                let mut name_l = expression_l;
3342
3343                self.check_lvar_name(name.as_str(), &name_l)?;
3344                self.check_duplicate_pattern_variable(name.as_str(), &name_l)?;
3345
3346                self.static_env.declare(name.as_str());
3347
3348                if let Some(begin_l) = begin_l.as_ref() {
3349                    let begin_d: i32 = begin_l
3350                        .size()
3351                        .try_into()
3352                        .expect("failed to convert usize loc into i32, is it too big?");
3353                    name_l = name_l.adjust_begin(begin_d)
3354                }
3355
3356                if let Some(end_l) = end_l.as_ref() {
3357                    let end_d: i32 = end_l
3358                        .size()
3359                        .try_into()
3360                        .expect("failed to convert usize loc into i32, is it too big?");
3361                    name_l = name_l.adjust_end(-end_d)
3362                }
3363
3364                let expression_l = self
3365                    .loc(&begin_t)
3366                    .join(&expression_l)
3367                    .join(&self.loc(&end_t));
3368                Box::new(Node::MatchVar(MatchVar {
3369                    name,
3370                    name_l,
3371                    expression_l,
3372                }))
3373            }
3374            Node::Begin(Begin { statements, .. }) => {
3375                self.match_hash_var_from_str(begin_t, statements, end_t)?
3376            }
3377            _ => {
3378                self.error(
3379                    DiagnosticMessage::SymbolLiteralWithInterpolation {},
3380                    &self.loc(&begin_t).join(&self.loc(&end_t)),
3381                );
3382                return Err(());
3383            }
3384        };
3385
3386        Ok(result)
3387    }
3388
3389    pub(crate) fn match_rest(
3390        &self,
3391        star_t: PoolValue<Token>,
3392        name_t: Option<PoolValue<Token>>,
3393    ) -> Result<Box<Node>, ()> {
3394        let name = if let Some(name_t) = name_t {
3395            Some(self.match_var(name_t)?)
3396        } else {
3397            None
3398        };
3399
3400        let operator_l = self.loc(&star_t);
3401        let expression_l = operator_l.maybe_join(&maybe_boxed_node_expr(&name));
3402
3403        Ok(Box::new(Node::MatchRest(MatchRest {
3404            name,
3405            operator_l,
3406            expression_l,
3407        })))
3408    }
3409
3410    pub(crate) fn hash_pattern(
3411        &self,
3412        lbrace_t: Option<PoolValue<Token>>,
3413        kwargs: Vec<Node>,
3414        rbrace_t: Option<PoolValue<Token>>,
3415    ) -> Box<Node> {
3416        let CollectionMap {
3417            begin_l,
3418            end_l,
3419            expression_l,
3420        } = self.collection_map(&lbrace_t, &kwargs, &rbrace_t);
3421
3422        Box::new(Node::HashPattern(HashPattern {
3423            elements: kwargs,
3424            begin_l,
3425            end_l,
3426            expression_l,
3427        }))
3428    }
3429
3430    pub(crate) fn array_pattern(
3431        &self,
3432        lbrack_t: Option<PoolValue<Token>>,
3433        elements: Vec<Node>,
3434        trailing_comma: Option<PoolValue<Token>>,
3435        rbrack_t: Option<PoolValue<Token>>,
3436    ) -> Box<Node> {
3437        let CollectionMap {
3438            begin_l,
3439            end_l,
3440            expression_l,
3441        } = self.collection_map(&lbrack_t, &elements, &rbrack_t);
3442
3443        let expression_l = expression_l.maybe_join(&self.maybe_loc(&trailing_comma));
3444
3445        if elements.is_empty() {
3446            return Box::new(Node::ArrayPattern(ArrayPattern {
3447                elements: vec![],
3448                begin_l,
3449                end_l,
3450                expression_l,
3451            }));
3452        }
3453
3454        if trailing_comma.is_some() {
3455            Box::new(Node::ArrayPatternWithTail(ArrayPatternWithTail {
3456                elements,
3457                begin_l,
3458                end_l,
3459                expression_l,
3460            }))
3461        } else {
3462            Box::new(Node::ArrayPattern(ArrayPattern {
3463                elements,
3464                begin_l,
3465                end_l,
3466                expression_l,
3467            }))
3468        }
3469    }
3470
3471    pub(crate) fn find_pattern(
3472        &self,
3473        lbrack_t: Option<PoolValue<Token>>,
3474        elements: Vec<Node>,
3475        rbrack_t: Option<PoolValue<Token>>,
3476    ) -> Box<Node> {
3477        let CollectionMap {
3478            begin_l,
3479            end_l,
3480            expression_l,
3481        } = self.collection_map(&lbrack_t, &elements, &rbrack_t);
3482
3483        Box::new(Node::FindPattern(FindPattern {
3484            elements,
3485            begin_l,
3486            end_l,
3487            expression_l,
3488        }))
3489    }
3490
3491    pub(crate) fn const_pattern(
3492        &self,
3493        const_: Box<Node>,
3494        ldelim_t: PoolValue<Token>,
3495        pattern: Box<Node>,
3496        rdelim_t: PoolValue<Token>,
3497    ) -> Box<Node> {
3498        let begin_l = self.loc(&ldelim_t);
3499        let end_l = self.loc(&rdelim_t);
3500        let expression_l = const_.expression().join(&self.loc(&rdelim_t));
3501
3502        Box::new(Node::ConstPattern(ConstPattern {
3503            const_,
3504            pattern,
3505            begin_l,
3506            end_l,
3507            expression_l,
3508        }))
3509    }
3510
3511    pub(crate) fn pin(&self, pin_t: PoolValue<Token>, var: Box<Node>) -> Box<Node> {
3512        let operator_l = self.loc(&pin_t);
3513        let expression_l = var.expression().join(&operator_l);
3514
3515        Box::new(Node::Pin(Pin {
3516            var,
3517            selector_l: operator_l,
3518            expression_l,
3519        }))
3520    }
3521
3522    pub(crate) fn match_alt(
3523        &self,
3524        lhs: Box<Node>,
3525        pipe_t: PoolValue<Token>,
3526        rhs: Box<Node>,
3527    ) -> Box<Node> {
3528        let operator_l = self.loc(&pipe_t);
3529        let expression_l = join_exprs(&lhs, &rhs);
3530
3531        Box::new(Node::MatchAlt(MatchAlt {
3532            lhs,
3533            rhs,
3534            operator_l,
3535            expression_l,
3536        }))
3537    }
3538
3539    pub(crate) fn match_as(
3540        &self,
3541        value: Box<Node>,
3542        assoc_t: PoolValue<Token>,
3543        as_: Box<Node>,
3544    ) -> Box<Node> {
3545        let operator_l = self.loc(&assoc_t);
3546        let expression_l = join_exprs(&value, &as_);
3547
3548        Box::new(Node::MatchAs(MatchAs {
3549            value,
3550            as_,
3551            operator_l,
3552            expression_l,
3553        }))
3554    }
3555
3556    pub(crate) fn match_nil_pattern(
3557        &self,
3558        dstar_t: PoolValue<Token>,
3559        nil_t: PoolValue<Token>,
3560    ) -> Box<Node> {
3561        let operator_l = self.loc(&dstar_t);
3562        let name_l = self.loc(&nil_t);
3563        let expression_l = operator_l.join(&name_l);
3564
3565        Box::new(Node::MatchNilPattern(MatchNilPattern {
3566            operator_l,
3567            name_l,
3568            expression_l,
3569        }))
3570    }
3571
3572    pub(crate) fn match_pair(
3573        &self,
3574        p_kw_label: PKwLabel,
3575        value: Box<Node>,
3576    ) -> Result<Box<Node>, ()> {
3577        let result = match p_kw_label {
3578            PKwLabel::PlainLabel(label_t) => {
3579                self.check_duplicate_pattern_key(
3580                    clone_value(&label_t).as_str(),
3581                    &self.loc(&label_t),
3582                )?;
3583                self.pair_keyword(label_t, value)
3584            }
3585            PKwLabel::QuotedLabel((begin_t, parts, end_t)) => {
3586                let label_loc = self.loc(&begin_t).join(&self.loc(&end_t));
3587
3588                match Self::static_string(&parts) {
3589                    Some(var_name) => self.check_duplicate_pattern_key(&var_name, &label_loc)?,
3590                    _ => {
3591                        self.error(
3592                            DiagnosticMessage::SymbolLiteralWithInterpolation {},
3593                            &label_loc,
3594                        );
3595                        return Err(());
3596                    }
3597                }
3598
3599                self.pair_quoted(begin_t, parts, end_t, value)
3600            }
3601        };
3602        Ok(result)
3603    }
3604
3605    pub(crate) fn match_label(&self, p_kw_label: PKwLabel) -> Result<Box<Node>, ()> {
3606        match p_kw_label {
3607            PKwLabel::PlainLabel(label_t) => self.match_hash_var(label_t),
3608            PKwLabel::QuotedLabel((begin_t, parts, end_t)) => {
3609                self.match_hash_var_from_str(begin_t, parts, end_t)
3610            }
3611        }
3612    }
3613
3614    //
3615    // Verification
3616    //
3617
3618    pub(crate) fn check_condition(cond: Box<Node>) -> Box<Node> {
3619        let cond = cond;
3620
3621        match *cond {
3622            Node::Begin(Begin {
3623                statements,
3624                begin_l,
3625                end_l,
3626                expression_l,
3627            }) => {
3628                if statements.len() == 1 {
3629                    let stmt = statements.into_iter().next().unwrap();
3630                    let stmt = *Self::check_condition(Box::new(stmt));
3631                    Box::new(Node::Begin(Begin {
3632                        statements: vec![stmt],
3633                        begin_l,
3634                        end_l,
3635                        expression_l,
3636                    }))
3637                } else {
3638                    Box::new(Node::Begin(Begin {
3639                        statements,
3640                        begin_l,
3641                        end_l,
3642                        expression_l,
3643                    }))
3644                }
3645            }
3646            Node::And(And {
3647                lhs,
3648                rhs,
3649                operator_l,
3650                expression_l,
3651            }) => {
3652                let lhs = Self::check_condition(lhs);
3653                let rhs = Self::check_condition(rhs);
3654                Box::new(Node::And(And {
3655                    lhs,
3656                    rhs,
3657                    operator_l,
3658                    expression_l,
3659                }))
3660            }
3661            Node::Or(Or {
3662                lhs,
3663                rhs,
3664                operator_l,
3665                expression_l,
3666            }) => {
3667                let lhs = Self::check_condition(lhs);
3668                let rhs = Self::check_condition(rhs);
3669                Box::new(Node::Or(Or {
3670                    lhs,
3671                    rhs,
3672                    operator_l,
3673                    expression_l,
3674                }))
3675            }
3676            Node::Irange(Irange {
3677                left,
3678                right,
3679                operator_l,
3680                expression_l,
3681            }) => Box::new(Node::IFlipFlop(IFlipFlop {
3682                left: left.map(Self::check_condition),
3683                right: right.map(Self::check_condition),
3684                operator_l,
3685                expression_l,
3686            })),
3687            Node::Erange(Erange {
3688                left,
3689                right,
3690                operator_l,
3691                expression_l,
3692            }) => Box::new(Node::EFlipFlop(EFlipFlop {
3693                left: left.map(Self::check_condition),
3694                right: right.map(Self::check_condition),
3695                operator_l,
3696                expression_l,
3697            })),
3698            regexp if matches!(regexp, Node::Regexp(_)) => {
3699                let expression_l = *regexp.expression();
3700
3701                Box::new(Node::MatchCurrentLine(MatchCurrentLine {
3702                    re: Box::new(regexp),
3703                    expression_l,
3704                }))
3705            }
3706            other => Box::new(other),
3707        }
3708    }
3709
3710    pub(crate) fn check_duplicate_args<'a>(
3711        &self,
3712        args: &'a [Node],
3713        map: &mut HashMap<String, &'a Node>,
3714    ) {
3715        for arg in args {
3716            match arg {
3717                Node::Arg(_)
3718                | Node::Optarg(_)
3719                | Node::Restarg(_)
3720                | Node::Kwarg(_)
3721                | Node::Kwoptarg(_)
3722                | Node::Kwrestarg(_)
3723                | Node::Shadowarg(_)
3724                | Node::Blockarg(_) => {
3725                    self.check_duplicate_arg(arg, map);
3726                }
3727                Node::Mlhs(Mlhs { items, .. }) => {
3728                    self.check_duplicate_args(items, map);
3729                }
3730                Node::Procarg0(Procarg0 { args, .. }) => {
3731                    self.check_duplicate_args(args, map);
3732                }
3733                Node::ForwardArg(_) | Node::Kwnilarg(_) => {
3734                    // ignore
3735                }
3736                _ => {
3737                    unreachable!("unsupported arg type {:?}", arg)
3738                }
3739            }
3740        }
3741    }
3742
3743    fn arg_name<'a>(&self, node: &'a Node) -> Option<&'a str> {
3744        match node {
3745            Node::Arg(Arg { name, .. })
3746            | Node::Optarg(Optarg { name, .. })
3747            | Node::Kwarg(Kwarg { name, .. })
3748            | Node::Kwoptarg(Kwoptarg { name, .. })
3749            | Node::Shadowarg(Shadowarg { name, .. }) => Some(name.as_str()),
3750
3751            Node::Restarg(Restarg { name, .. })
3752            | Node::Kwrestarg(Kwrestarg { name, .. })
3753            | Node::Blockarg(Blockarg { name, .. }) => name.as_ref().map(|s| s.as_str()),
3754            _ => {
3755                unreachable!("unsupported arg {:?}", node)
3756            }
3757        }
3758    }
3759
3760    fn arg_name_loc<'a>(&self, node: &'a Node) -> &'a Loc {
3761        match node {
3762            Node::Arg(Arg {
3763                expression_l: output_l,
3764                ..
3765            })
3766            | Node::Optarg(Optarg {
3767                name_l: output_l, ..
3768            })
3769            | Node::Kwarg(Kwarg {
3770                name_l: output_l, ..
3771            })
3772            | Node::Kwoptarg(Kwoptarg {
3773                name_l: output_l, ..
3774            })
3775            | Node::Shadowarg(Shadowarg {
3776                expression_l: output_l,
3777                ..
3778            }) => output_l,
3779            Node::Blockarg(Blockarg {
3780                name_l,
3781                expression_l,
3782                ..
3783            })
3784            | Node::Restarg(Restarg {
3785                name_l,
3786                expression_l,
3787                ..
3788            })
3789            | Node::Kwrestarg(Kwrestarg {
3790                name_l,
3791                expression_l,
3792                ..
3793            }) => name_l.as_ref().unwrap_or(expression_l),
3794            _ => unreachable!("unsupported arg {:?}", node),
3795        }
3796    }
3797
3798    pub(crate) fn check_duplicate_arg<'a>(
3799        &self,
3800        this_arg: &'a Node,
3801        map: &mut HashMap<String, &'a Node>,
3802    ) {
3803        let this_name = match self.arg_name(this_arg) {
3804            Some(name) => name,
3805            None => return,
3806        };
3807
3808        let that_arg = map.get(this_name);
3809
3810        match that_arg {
3811            None => {
3812                map.insert(this_name.to_string(), this_arg);
3813            }
3814            Some(that_arg) => {
3815                let that_name = match self.arg_name(that_arg) {
3816                    Some(name) => name,
3817                    None => return,
3818                };
3819                if self.arg_name_collides(this_name, that_name) {
3820                    self.error(
3821                        DiagnosticMessage::DuplicatedArgumentName {},
3822                        self.arg_name_loc(this_arg),
3823                    )
3824                }
3825            }
3826        }
3827    }
3828
3829    pub(crate) fn check_assignment_to_numparam(&self, name: &str, loc: &Loc) -> Result<(), ()> {
3830        let assigning_to_numparam = self.context.is_in_dynamic_block()
3831            && matches!(
3832                name,
3833                "_1" | "_2" | "_3" | "_4" | "_5" | "_6" | "_7" | "_8" | "_9"
3834            )
3835            && self.max_numparam_stack.has_numparams();
3836
3837        if assigning_to_numparam {
3838            self.error(
3839                DiagnosticMessage::CantAssignToNumparam {
3840                    numparam: String::from(name),
3841                },
3842                loc,
3843            );
3844            return Err(());
3845        }
3846        Ok(())
3847    }
3848
3849    pub(crate) fn validate_no_forward_arg_after_restarg(&self, args: &[Node]) {
3850        let mut restarg = None;
3851        let mut forward_arg = None;
3852        for arg in args {
3853            match arg {
3854                Node::Restarg(_) => restarg = Some(arg),
3855                Node::ForwardArg(_) => forward_arg = Some(arg),
3856                _ => {}
3857            }
3858        }
3859
3860        if restarg.is_none() {
3861            return;
3862        }
3863
3864        if let Some(forward_arg) = forward_arg {
3865            self.error(
3866                DiagnosticMessage::ForwardArgAfterRestarg {},
3867                forward_arg.expression(),
3868            );
3869        }
3870    }
3871
3872    pub(crate) fn check_reserved_for_numparam(&self, name: &str, loc: &Loc) -> Result<(), ()> {
3873        match name {
3874            "_1" | "_2" | "_3" | "_4" | "_5" | "_6" | "_7" | "_8" | "_9" => {
3875                self.error(
3876                    DiagnosticMessage::ReservedForNumparam {
3877                        numparam: String::from(name),
3878                    },
3879                    loc,
3880                );
3881                Err(())
3882            }
3883            _ => Ok(()),
3884        }
3885    }
3886
3887    pub(crate) fn arg_name_collides(&self, this_name: &str, that_name: &str) -> bool {
3888        &this_name[0..1] != "_" && this_name == that_name
3889    }
3890
3891    pub(crate) fn check_lvar_name(&self, name: &str, loc: &Loc) -> Result<(), ()> {
3892        let mut all_chars = name.chars();
3893        let first = all_chars
3894            .next()
3895            .expect("local variable name can't be empty");
3896        let mut rest = all_chars;
3897
3898        if (first.is_lowercase() || first == '_') && rest.all(|c| c.is_alphanumeric() || c == '_') {
3899            Ok(())
3900        } else {
3901            self.error(DiagnosticMessage::KeyMustBeValidAsLocalVariable {}, loc);
3902            Err(())
3903        }
3904    }
3905
3906    pub(crate) fn check_duplicate_pattern_variable(&self, name: &str, loc: &Loc) -> Result<(), ()> {
3907        if name.starts_with('_') {
3908            return Ok(());
3909        }
3910
3911        if self.pattern_variables.is_declared(name) {
3912            self.error(DiagnosticMessage::DuplicateVariableName {}, loc);
3913            return Err(());
3914        }
3915
3916        self.pattern_variables.declare(name);
3917        Ok(())
3918    }
3919
3920    pub(crate) fn check_duplicate_pattern_key(&self, name: &str, loc: &Loc) -> Result<(), ()> {
3921        if self.pattern_hash_keys.is_declared(name) {
3922            self.error(DiagnosticMessage::DuplicateKeyName {}, loc);
3923            return Err(());
3924        }
3925
3926        self.pattern_hash_keys.declare(name);
3927        Ok(())
3928    }
3929
3930    //
3931    // Helpers
3932    //
3933
3934    pub(crate) fn static_string(nodes: &[Node]) -> Option<String> {
3935        let mut result = String::from("");
3936
3937        for node in nodes {
3938            match node {
3939                Node::Str(Str { value, .. }) => {
3940                    let value = value.to_string_lossy();
3941                    result.push_str(value.as_str())
3942                }
3943                Node::Begin(Begin { statements, .. }) => {
3944                    if let Some(s) = Self::static_string(statements) {
3945                        result.push_str(&s)
3946                    } else {
3947                        return None;
3948                    }
3949                }
3950                _ => {
3951                    return None;
3952                }
3953            }
3954        }
3955
3956        Some(result)
3957    }
3958
3959    #[cfg(feature = "onig")]
3960    pub(crate) fn build_static_regexp(
3961        &self,
3962        parts: &[Node],
3963        options: &Option<String>,
3964        loc: &Loc,
3965    ) -> Option<Regex> {
3966        let source = Self::static_string(parts)?;
3967        let mut reg_options = RegexOptions::REGEX_OPTION_NONE;
3968        reg_options |= RegexOptions::REGEX_OPTION_CAPTURE_GROUP;
3969        if let Some(options_s) = options.as_ref().map(|s| s.as_str()) {
3970            if options_s.as_bytes().contains(&b'x') {
3971                reg_options |= RegexOptions::REGEX_OPTION_EXTEND;
3972            }
3973        }
3974
3975        let bytes = onig::EncodedBytes::ascii(source.as_bytes());
3976
3977        match Regex::with_options_and_encoding(bytes, reg_options, onig::Syntax::ruby()) {
3978            Ok(regex) => Some(regex),
3979            Err(err) => {
3980                self.error(
3981                    DiagnosticMessage::RegexError {
3982                        error: String::from(err.description()),
3983                    },
3984                    loc,
3985                );
3986                None
3987            }
3988        }
3989    }
3990
3991    #[cfg(feature = "onig")]
3992    pub(crate) fn validate_static_regexp(
3993        &self,
3994        parts: &[Node],
3995        options: &Option<String>,
3996        loc: &Loc,
3997    ) {
3998        self.build_static_regexp(parts, options, loc);
3999    }
4000
4001    #[cfg(not(feature = "onig"))]
4002    pub(crate) fn validate_static_regexp(
4003        &self,
4004        _parts: &[Node],
4005        _options: &Option<String>,
4006        _loc: &Loc,
4007    ) {
4008    }
4009
4010    #[cfg(feature = "onig")]
4011    pub(crate) fn static_regexp_captures(&self, node: &Node) -> Option<Vec<String>> {
4012        if let Node::Regexp(Regexp {
4013            parts,
4014            options,
4015            expression_l,
4016            ..
4017        }) = node
4018        {
4019            let mut re_options = &None;
4020            if let Some(Node::RegOpt(RegOpt { options, .. })) = options.as_ref().map(|b| &**b) {
4021                re_options = options;
4022            };
4023            let regex = self.build_static_regexp(parts, re_options, expression_l)?;
4024
4025            let mut result: Vec<String> = vec![];
4026
4027            regex.foreach_name(|name, _| {
4028                result.push(name.to_string());
4029                true
4030            });
4031
4032            return Some(result);
4033        }
4034        None
4035    }
4036
4037    #[cfg(not(feature = "onig"))]
4038    pub(crate) fn static_regexp_captures(&self, _node: &Node) -> Option<Vec<String>> {
4039        None
4040    }
4041
4042    pub(crate) fn loc(&self, token: &Token) -> Loc {
4043        token.loc
4044    }
4045
4046    pub(crate) fn maybe_loc(&self, token: &Option<PoolValue<Token>>) -> Option<Loc> {
4047        token.as_deref().map(|token| self.loc(token))
4048    }
4049
4050    pub(crate) fn collection_map(
4051        &self,
4052        begin_t: &Option<PoolValue<Token>>,
4053        parts: &[Node],
4054        end_t: &Option<PoolValue<Token>>,
4055    ) -> CollectionMap {
4056        let begin_l = self.maybe_loc(begin_t);
4057        let end_l = self.maybe_loc(end_t);
4058
4059        let expression_l = collection_expr(parts);
4060        let expression_l = join_maybe_locs(&expression_l, &begin_l);
4061        let expression_l = join_maybe_locs(&expression_l, &end_l);
4062        let expression_l = expression_l.unwrap_or_else(|| {
4063            unreachable!("empty collection without begin_t/end_t, can't build source map")
4064        });
4065
4066        CollectionMap {
4067            begin_l,
4068            end_l,
4069            expression_l,
4070        }
4071    }
4072
4073    pub(crate) fn is_heredoc(&self, begin_t: &Option<PoolValue<Token>>) -> bool {
4074        if let Some(begin_t) = begin_t.as_ref() {
4075            let begin = &begin_t.token_value;
4076            if begin.len() >= 2 && begin[0] == b'<' && begin[1] == b'<' {
4077                return true;
4078            }
4079        }
4080        false
4081    }
4082
4083    pub(crate) fn heredoc_map(
4084        &self,
4085        begin_t: &Option<PoolValue<Token>>,
4086        parts: &[Node],
4087        end_t: &Option<PoolValue<Token>>,
4088    ) -> HeredocMap {
4089        let begin_t = begin_t.as_ref().expect("bug: begin_t must be Some");
4090        let end_t = end_t.as_ref().expect("heredoc must have end_t");
4091
4092        let heredoc_body_l = collection_expr(parts).unwrap_or_else(|| self.loc(end_t));
4093        let expression_l = self.loc(begin_t);
4094        let heredoc_end_l = self.loc(end_t);
4095
4096        HeredocMap {
4097            heredoc_body_l,
4098            heredoc_end_l,
4099            expression_l,
4100        }
4101    }
4102
4103    pub(crate) fn error(&self, message: DiagnosticMessage, loc: &Loc) {
4104        self.diagnostics.emit(Diagnostic {
4105            level: ErrorLevel::Error,
4106            message,
4107            loc: *loc,
4108        })
4109    }
4110
4111    pub(crate) fn warn(&self, message: DiagnosticMessage, loc: &Loc) {
4112        self.diagnostics.emit(Diagnostic {
4113            level: ErrorLevel::Warning,
4114            message,
4115            loc: *loc,
4116        })
4117    }
4118
4119    pub(crate) fn value_expr(&self, node: &Node) -> Result<(), ()> {
4120        if let Some(void_node) = Self::void_value(node) {
4121            self.error(
4122                DiagnosticMessage::VoidValueExpression {},
4123                void_node.expression(),
4124            );
4125            Err(())
4126        } else {
4127            Ok(())
4128        }
4129    }
4130
4131    fn void_value<'a>(node: &'a Node) -> Option<&'a Node> {
4132        let check_stmts = |statements: &'a Vec<Node>| {
4133            if let Some(last_stmt) = statements.last() {
4134                Self::void_value(last_stmt)
4135            } else {
4136                None
4137            }
4138        };
4139
4140        let check_condition = |if_true: &'a Node, if_false: &'a Node| {
4141            if Self::void_value(if_true).is_some() && Self::void_value(if_false).is_some() {
4142                Some(if_true)
4143            } else {
4144                None
4145            }
4146        };
4147
4148        let check_maybe_condition =
4149            |if_true: &'a Option<Box<Node>>, if_false: &'a Option<Box<Node>>| match (
4150                if_true.as_ref(),
4151                if_false.as_ref(),
4152            ) {
4153                (None, None) | (None, Some(_)) | (Some(_), None) => None,
4154                (Some(if_true), Some(if_false)) => check_condition(if_true, if_false),
4155            };
4156
4157        match node {
4158            Node::Return(_) | Node::Break(_) | Node::Next(_) | Node::Redo(_) | Node::Retry(_) => {
4159                Some(node)
4160            }
4161
4162            Node::MatchPattern(MatchPattern { value, .. })
4163            | Node::MatchPatternP(MatchPatternP { value, .. }) => Self::void_value(value),
4164
4165            Node::Begin(Begin { statements, .. }) | Node::KwBegin(KwBegin { statements, .. }) => {
4166                check_stmts(statements)
4167            }
4168
4169            Node::IfTernary(IfTernary {
4170                if_true, if_false, ..
4171            }) => check_condition(if_true, if_false),
4172
4173            Node::If(If {
4174                if_true, if_false, ..
4175            })
4176            | Node::IfMod(IfMod {
4177                if_true, if_false, ..
4178            }) => check_maybe_condition(if_true, if_false),
4179
4180            Node::And(And { lhs, .. }) | Node::Or(Or { lhs, .. }) => Self::void_value(lhs),
4181
4182            _ => None,
4183        }
4184    }
4185
4186    fn rewrite_hash_args_to_kwargs(&self, args: &mut Vec<Node>) {
4187        let len = args.len();
4188
4189        if !args.is_empty() && self.is_kwargs(&args[len - 1]) {
4190            match args.pop().unwrap() {
4191                Node::Hash(Hash {
4192                    pairs,
4193                    expression_l,
4194                    ..
4195                }) => {
4196                    let kwargs = Node::Kwargs(Kwargs {
4197                        pairs,
4198                        expression_l,
4199                    });
4200                    args.push(kwargs);
4201                }
4202                _ => unreachable!(),
4203            }
4204        } else if len > 1
4205            && matches!(args[len - 1], Node::BlockPass(_))
4206            && self.is_kwargs(&args[len - 2])
4207        {
4208            let block_pass = args.pop().unwrap();
4209            match args.pop().unwrap() {
4210                Node::Hash(Hash {
4211                    pairs,
4212                    expression_l,
4213                    ..
4214                }) => {
4215                    let kwargs = Node::Kwargs(Kwargs {
4216                        pairs,
4217                        expression_l,
4218                    });
4219                    args.push(kwargs);
4220                    args.push(block_pass);
4221                }
4222                _ => unreachable!(),
4223            }
4224        }
4225    }
4226
4227    fn is_kwargs(&self, node: &Node) -> bool {
4228        matches!(
4229            node,
4230            Node::Hash(Hash {
4231                begin_l: None,
4232                end_l: None,
4233                ..
4234            })
4235        )
4236    }
4237
4238    fn try_declare_numparam(&self, name: &str, loc: &Loc) -> bool {
4239        match name.as_bytes()[..] {
4240            [b'_', n]
4241                if (b'1'..=b'9').contains(&n)
4242                    && !self.static_env.is_declared(name)
4243                    && self.context.is_in_dynamic_block() =>
4244            {
4245                if true {
4246                    /* definitely an implicit param */
4247
4248                    if self.max_numparam_stack.has_ordinary_params() {
4249                        self.error(DiagnosticMessage::OrdinaryParamDefined {}, loc);
4250                    }
4251
4252                    let mut raw_max_numparam_stack = self.max_numparam_stack.inner_clone();
4253
4254                    /* ignore current block scope */
4255                    raw_max_numparam_stack.pop();
4256
4257                    for outer_scope in raw_max_numparam_stack.iter().rev() {
4258                        if outer_scope.is_static {
4259                            /* found an outer scope that can't have numparams
4260                            like def/class/etc */
4261                            break;
4262                        } else {
4263                            let outer_scope_has_numparams = outer_scope.value > 0;
4264
4265                            if outer_scope_has_numparams {
4266                                self.error(DiagnosticMessage::NumparamUsed {}, loc);
4267                            } else {
4268                                /* for now it's ok, but an outer scope can also be a block
4269                                like proc { _1; proc { proc { proc { _2 }} }}
4270                                with numparams, so we need to continue */
4271                            }
4272                        }
4273                    }
4274
4275                    self.static_env.declare(name);
4276                    self.max_numparam_stack.register((n - b'0') as i32);
4277
4278                    true
4279                } else {
4280                    false
4281                }
4282            }
4283            _ => false,
4284        }
4285    }
4286}
4287
4288pub(crate) fn maybe_node_expr(node: &Option<&Node>) -> Option<Loc> {
4289    node.map(|node| *node.expression())
4290}
4291
4292pub(crate) fn maybe_boxed_node_expr(node: &Option<Box<Node>>) -> Option<Loc> {
4293    node.as_deref().map(|node| *node.expression())
4294}
4295
4296pub(crate) fn collection_expr(nodes: &[Node]) -> Option<Loc> {
4297    join_maybe_exprs(&nodes.first(), &nodes.last())
4298}
4299
4300pub(crate) fn value(mut token: PoolValue<Token>) -> String {
4301    token.take_value().into_string().unwrap()
4302}
4303
4304pub(crate) fn clone_value(token: &Token) -> String {
4305    token.to_string_lossy()
4306}
4307
4308pub(crate) fn maybe_value(token: Option<PoolValue<Token>>) -> Option<String> {
4309    token.map(value)
4310}
4311
4312pub(crate) fn join_exprs(lhs: &Node, rhs: &Node) -> Loc {
4313    lhs.expression().join(rhs.expression())
4314}
4315
4316pub(crate) fn join_maybe_exprs(lhs: &Option<&Node>, rhs: &Option<&Node>) -> Option<Loc> {
4317    join_maybe_locs(&maybe_node_expr(lhs), &maybe_node_expr(rhs))
4318}
4319
4320pub(crate) fn join_maybe_locs(lhs: &Option<Loc>, rhs: &Option<Loc>) -> Option<Loc> {
4321    match (lhs.as_ref(), rhs.as_ref()) {
4322        (None, None) => None,
4323        (None, Some(rhs)) => Some(*rhs),
4324        (Some(lhs), None) => Some(*lhs),
4325        (Some(lhs), Some(rhs)) => Some(lhs.join(rhs)),
4326    }
4327}
4328
4329pub(crate) struct CollectionMap {
4330    begin_l: Option<Loc>,
4331    end_l: Option<Loc>,
4332    expression_l: Loc,
4333}
4334
4335pub(crate) struct HeredocMap {
4336    heredoc_body_l: Loc,
4337    heredoc_end_l: Loc,
4338    expression_l: Loc,
4339}