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 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 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 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 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 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 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 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 return None;
564 }
565 let expression_l = self.loc(®exp_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 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 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 continue;
859 };
860 let key2 = if let Node::Pair(Pair { key, .. }) = &pairs[j] {
861 &**key
862 } else {
863 continue;
865 };
866
867 fn keys_are_equal(left: &Node, right: &Node) -> bool {
868 match (left, right) {
869 (
871 Node::Sym(Sym { name: name1, .. }),
872 Node::Sym(Sym { name: name2, .. }),
873 ) if name1 == name2 => true,
874
875 (
877 Node::Str(Str { value: value1, .. }),
878 Node::Str(Str { value: value2, .. }),
879 ) if value1 == value2 => true,
880
881 (
883 Node::Int(Int { value: value1, .. }),
884 Node::Int(Int { value: value2, .. }),
885 ) if value1 == value2 => true,
886
887 (
889 Node::Float(Float { value: value1, .. }),
890 Node::Float(Float { value: value2, .. }),
891 ) if value1 == value2 => true,
892
893 (
895 Node::Rational(Rational { value: value1, .. }),
896 Node::Rational(Rational { value: value2, .. }),
897 ) if value1 == value2 => true,
898
899 (
901 Node::Complex(Complex { value: value1, .. }),
902 Node::Complex(Complex { value: value2, .. }),
903 ) if value1 == value2 => true,
904
905 (
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 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 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 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 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 }
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 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(<_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 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 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(&er_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 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 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(&er_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(¬_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(¬_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(¬_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 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 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 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 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 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 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 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 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 *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 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 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 Box::new(Node::KwBegin(KwBegin {
3161 statements: vec![],
3162 begin_l,
3163 end_l,
3164 expression_l,
3165 }))
3166 }
3167 }
3168
3169 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 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 }
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 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 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 raw_max_numparam_stack.pop();
4256
4257 for outer_scope in raw_max_numparam_stack.iter().rev() {
4258 if outer_scope.is_static {
4259 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 }
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}