1use super::ast::{
38 BinaryOp, ContractNode, Expression, MethodNode, ParamNode, PrimitiveTypeName, PropertyNode,
39 SourceLocation, Statement, TypeNode, UnaryOp, Visibility,
40};
41use super::parser::ParseResult;
42
43pub fn parse_python(source: &str, file_name: Option<&str>) -> ParseResult {
49 let file = file_name.unwrap_or("contract.runar.py");
50 let mut errors: Vec<String> = Vec::new();
51
52 let tokens = tokenize(source);
53 let mut parser = PyParser::new(tokens, file, &mut errors);
54
55 let contract = parser.parse_contract();
56
57 ParseResult { contract, errors }
58}
59
60fn snake_to_camel(name: &str) -> String {
67 let n = if name.ends_with('_') && name != "_" {
69 &name[..name.len() - 1]
70 } else {
71 name
72 };
73
74 let mut result = String::new();
75 let mut capitalize_next = false;
76
77 for ch in n.chars() {
78 if ch == '_' {
79 capitalize_next = true;
80 } else if capitalize_next {
81 result.push(ch.to_ascii_uppercase());
82 capitalize_next = false;
83 } else {
84 result.push(ch);
85 }
86 }
87
88 result
89}
90
91fn map_builtin_name(name: &str) -> String {
93 match name {
95 "assert_" => return "assert".to_string(),
96 "verify_wots" => return "verifyWOTS".to_string(),
97 "verify_slh_dsa_sha2_128s" => return "verifySLHDSA_SHA2_128s".to_string(),
98 "verify_slh_dsa_sha2_128f" => return "verifySLHDSA_SHA2_128f".to_string(),
99 "verify_slh_dsa_sha2_192s" => return "verifySLHDSA_SHA2_192s".to_string(),
100 "verify_slh_dsa_sha2_192f" => return "verifySLHDSA_SHA2_192f".to_string(),
101 "verify_slh_dsa_sha2_256s" => return "verifySLHDSA_SHA2_256s".to_string(),
102 "verify_slh_dsa_sha2_256f" => return "verifySLHDSA_SHA2_256f".to_string(),
103 "verify_rabin_sig" => return "verifyRabinSig".to_string(),
104 "check_sig" => return "checkSig".to_string(),
105 "check_multi_sig" => return "checkMultiSig".to_string(),
106 "check_preimage" => return "checkPreimage".to_string(),
107 "hash160" => return "hash160".to_string(),
108 "hash256" => return "hash256".to_string(),
109 "sha256" => return "sha256".to_string(),
110 "ripemd160" => return "ripemd160".to_string(),
111 "num2bin" => return "num2bin".to_string(),
112 "reverse_bytes" => return "reverseBytes".to_string(),
113 "extract_locktime" => return "extractLocktime".to_string(),
114 "extract_output_hash" => return "extractOutputHash".to_string(),
115 "extract_amount" => return "extractAmount".to_string(),
116 "extract_version" => return "extractVersion".to_string(),
117 "extract_sequence" => return "extractSequence".to_string(),
118 "ec_add" => return "ecAdd".to_string(),
119 "ec_mul" => return "ecMul".to_string(),
120 "ec_mul_gen" => return "ecMulGen".to_string(),
121 "ec_negate" => return "ecNegate".to_string(),
122 "ec_on_curve" => return "ecOnCurve".to_string(),
123 "ec_mod_reduce" => return "ecModReduce".to_string(),
124 "ec_encode_compressed" => return "ecEncodeCompressed".to_string(),
125 "ec_make_point" => return "ecMakePoint".to_string(),
126 "ec_point_x" => return "ecPointX".to_string(),
127 "ec_point_y" => return "ecPointY".to_string(),
128 "mul_div" => return "mulDiv".to_string(),
129 "percent_of" => return "percentOf".to_string(),
130 "add_output" => return "addOutput".to_string(),
131 "get_state_script" => return "getStateScript".to_string(),
132 _ => {}
133 }
134
135 match name {
137 "bool" | "abs" | "min" | "max" | "len" | "pow" | "cat" | "within" | "safediv"
138 | "safemod" | "clamp" | "sign" | "sqrt" | "gcd" | "divmod" | "log2" | "substr" => {
139 return name.to_string();
140 }
141 _ => {}
142 }
143
144 snake_to_camel(name)
146}
147
148fn map_py_type(name: &str) -> &str {
150 match name {
151 "Bigint" | "int" | "Int" => "bigint",
152 "bool" => "boolean",
153 "ByteString" | "bytes" => "ByteString",
154 "PubKey" => "PubKey",
155 "Sig" => "Sig",
156 "Addr" => "Addr",
157 "Sha256" => "Sha256",
158 "Ripemd160" => "Ripemd160",
159 "SigHashPreimage" => "SigHashPreimage",
160 "RabinSig" => "RabinSig",
161 "RabinPubKey" => "RabinPubKey",
162 "Point" => "Point",
163 _ => name,
164 }
165}
166
167#[derive(Debug, Clone, PartialEq)]
172enum Token {
173 Class,
175 Def,
176 If,
177 Elif,
178 Else,
179 For,
180 In,
181 Range,
182 Return,
183 Pass,
184 TrueLit,
185 FalseLit,
186 NoneLit,
187 And,
188 Or,
189 Not,
190 SelfKw,
191 Super,
192 From,
193 Import,
194 Assert,
195
196 Ident(String),
198 NumberLit(i64),
199 HexStringLit(String),
200 StringLit(String),
201
202 At,
204
205 Plus,
207 Minus,
208 Star,
209 Slash,
210 IntDiv, Percent,
212 DoubleStar, EqEq, NotEq, Lt,
216 Le,
217 Gt,
218 Ge,
219 LShift, RShift, BitAnd, BitOr, BitXor, Tilde, Bang, Eq, PlusEq, MinusEq, StarEq, SlashEq, IntDivEq, PercentEq, Arrow, LParen,
237 RParen,
238 LBracket,
239 RBracket,
240 Colon,
241 Comma,
242 Dot,
243
244 Indent,
246 Dedent,
247 Newline,
248
249 Eof,
251}
252
253fn tokenize(source: &str) -> Vec<Token> {
254 let mut tokens = Vec::new();
255 let lines: Vec<&str> = source.split('\n').collect();
256 let mut indent_stack: Vec<usize> = vec![0];
257 let mut paren_depth: usize = 0;
258
259 for raw_line in &lines {
260 let line = if raw_line.ends_with('\r') {
262 &raw_line[..raw_line.len() - 1]
263 } else {
264 raw_line
265 };
266
267 let stripped = line.trim_start();
269 if stripped.is_empty() || stripped.starts_with('#') {
270 continue;
271 }
272
273 let chars: Vec<char> = line.chars().collect();
274
275 if paren_depth == 0 {
277 let mut indent = 0usize;
278 for &ch in &chars {
279 if ch == ' ' {
280 indent += 1;
281 } else if ch == '\t' {
282 indent += 4;
283 } else {
284 break;
285 }
286 }
287
288 let current_indent = *indent_stack.last().unwrap();
289 if indent > current_indent {
290 indent_stack.push(indent);
291 tokens.push(Token::Indent);
292 } else if indent < current_indent {
293 while indent_stack.len() > 1 && *indent_stack.last().unwrap() > indent {
294 indent_stack.pop();
295 tokens.push(Token::Dedent);
296 }
297 }
298 }
299
300 let start_offset = chars.len() - stripped.len();
302 let mut pos = start_offset;
303
304 while pos < chars.len() {
305 let ch = chars[pos];
306
307 if ch == ' ' || ch == '\t' {
309 pos += 1;
310 continue;
311 }
312
313 if ch == '#' {
315 break; }
317
318 if ch == '@' {
320 pos += 1;
321 tokens.push(Token::At);
322 continue;
323 }
324
325 if ch == '/'
327 && pos + 2 < chars.len()
328 && chars[pos + 1] == '/'
329 && chars[pos + 2] == '='
330 {
331 tokens.push(Token::IntDivEq);
332 pos += 3;
333 continue;
334 }
335
336 if ch == '*' && pos + 1 < chars.len() && chars[pos + 1] == '*' {
338 tokens.push(Token::DoubleStar);
339 pos += 2;
340 continue;
341 }
342 if ch == '/' && pos + 1 < chars.len() && chars[pos + 1] == '/' {
343 tokens.push(Token::IntDiv);
344 pos += 2;
345 continue;
346 }
347 if ch == '=' && pos + 1 < chars.len() && chars[pos + 1] == '=' {
348 tokens.push(Token::EqEq);
349 pos += 2;
350 continue;
351 }
352 if ch == '!' && pos + 1 < chars.len() && chars[pos + 1] == '=' {
353 tokens.push(Token::NotEq);
354 pos += 2;
355 continue;
356 }
357 if ch == '<' && pos + 1 < chars.len() && chars[pos + 1] == '=' {
358 tokens.push(Token::Le);
359 pos += 2;
360 continue;
361 }
362 if ch == '>' && pos + 1 < chars.len() && chars[pos + 1] == '=' {
363 tokens.push(Token::Ge);
364 pos += 2;
365 continue;
366 }
367 if ch == '<' && pos + 1 < chars.len() && chars[pos + 1] == '<' {
368 tokens.push(Token::LShift);
369 pos += 2;
370 continue;
371 }
372 if ch == '>' && pos + 1 < chars.len() && chars[pos + 1] == '>' {
373 tokens.push(Token::RShift);
374 pos += 2;
375 continue;
376 }
377 if ch == '+' && pos + 1 < chars.len() && chars[pos + 1] == '=' {
378 tokens.push(Token::PlusEq);
379 pos += 2;
380 continue;
381 }
382 if ch == '-' && pos + 1 < chars.len() && chars[pos + 1] == '=' {
383 tokens.push(Token::MinusEq);
384 pos += 2;
385 continue;
386 }
387 if ch == '*' && pos + 1 < chars.len() && chars[pos + 1] == '=' {
388 tokens.push(Token::StarEq);
389 pos += 2;
390 continue;
391 }
392 if ch == '/' && pos + 1 < chars.len() && chars[pos + 1] == '=' {
393 tokens.push(Token::SlashEq);
394 pos += 2;
395 continue;
396 }
397 if ch == '%' && pos + 1 < chars.len() && chars[pos + 1] == '=' {
398 tokens.push(Token::PercentEq);
399 pos += 2;
400 continue;
401 }
402 if ch == '-' && pos + 1 < chars.len() && chars[pos + 1] == '>' {
403 tokens.push(Token::Arrow);
404 pos += 2;
405 continue;
406 }
407
408 if ch == '(' {
410 paren_depth += 1;
411 tokens.push(Token::LParen);
412 pos += 1;
413 continue;
414 }
415 if ch == ')' {
416 if paren_depth > 0 {
417 paren_depth -= 1;
418 }
419 tokens.push(Token::RParen);
420 pos += 1;
421 continue;
422 }
423 if ch == '[' {
424 paren_depth += 1;
425 tokens.push(Token::LBracket);
426 pos += 1;
427 continue;
428 }
429 if ch == ']' {
430 if paren_depth > 0 {
431 paren_depth -= 1;
432 }
433 tokens.push(Token::RBracket);
434 pos += 1;
435 continue;
436 }
437
438 match ch {
440 '+' => {
441 tokens.push(Token::Plus);
442 pos += 1;
443 continue;
444 }
445 '-' => {
446 tokens.push(Token::Minus);
447 pos += 1;
448 continue;
449 }
450 '*' => {
451 tokens.push(Token::Star);
452 pos += 1;
453 continue;
454 }
455 '/' => {
456 tokens.push(Token::Slash);
457 pos += 1;
458 continue;
459 }
460 '%' => {
461 tokens.push(Token::Percent);
462 pos += 1;
463 continue;
464 }
465 '<' => {
466 tokens.push(Token::Lt);
467 pos += 1;
468 continue;
469 }
470 '>' => {
471 tokens.push(Token::Gt);
472 pos += 1;
473 continue;
474 }
475 '!' => {
476 tokens.push(Token::Bang);
477 pos += 1;
478 continue;
479 }
480 '~' => {
481 tokens.push(Token::Tilde);
482 pos += 1;
483 continue;
484 }
485 '&' => {
486 tokens.push(Token::BitAnd);
487 pos += 1;
488 continue;
489 }
490 '|' => {
491 tokens.push(Token::BitOr);
492 pos += 1;
493 continue;
494 }
495 '^' => {
496 tokens.push(Token::BitXor);
497 pos += 1;
498 continue;
499 }
500 '=' => {
501 tokens.push(Token::Eq);
502 pos += 1;
503 continue;
504 }
505 ':' => {
506 tokens.push(Token::Colon);
507 pos += 1;
508 continue;
509 }
510 ',' => {
511 tokens.push(Token::Comma);
512 pos += 1;
513 continue;
514 }
515 '.' => {
516 tokens.push(Token::Dot);
517 pos += 1;
518 continue;
519 }
520 _ => {}
521 }
522
523 if ch == 'b'
525 && pos + 1 < chars.len()
526 && (chars[pos + 1] == '\'' || chars[pos + 1] == '"')
527 {
528 let quote = chars[pos + 1];
529 pos += 2; let mut hex = String::new();
531 while pos < chars.len() && chars[pos] != quote {
532 if chars[pos] == '\\'
533 && pos + 1 < chars.len()
534 && chars[pos + 1] == 'x'
535 && pos + 3 < chars.len()
536 {
537 hex.push(chars[pos + 2]);
539 hex.push(chars[pos + 3]);
540 pos += 4;
541 } else {
542 let byte = chars[pos] as u32;
544 hex.push_str(&format!("{:02x}", byte));
545 pos += 1;
546 }
547 }
548 if pos < chars.len() {
549 pos += 1; }
551 tokens.push(Token::HexStringLit(hex));
552 continue;
553 }
554
555 if ch == '\'' || ch == '"' {
557 let quote = ch;
558 pos += 1;
559 let mut val = String::new();
560 while pos < chars.len() && chars[pos] != quote {
561 if chars[pos] == '\\' && pos + 1 < chars.len() {
562 pos += 1; val.push(chars[pos]);
564 pos += 1;
565 } else {
566 val.push(chars[pos]);
567 pos += 1;
568 }
569 }
570 if pos < chars.len() {
571 pos += 1; }
573 tokens.push(Token::StringLit(val));
574 continue;
575 }
576
577 if ch.is_ascii_digit() {
579 let mut num_str = String::new();
580 if ch == '0'
581 && pos + 1 < chars.len()
582 && (chars[pos + 1] == 'x' || chars[pos + 1] == 'X')
583 {
584 num_str.push_str("0x");
586 pos += 2;
587 while pos < chars.len()
588 && (chars[pos].is_ascii_hexdigit() || chars[pos] == '_')
589 {
590 if chars[pos] != '_' {
591 num_str.push(chars[pos]);
592 }
593 pos += 1;
594 }
595 } else {
596 while pos < chars.len()
597 && (chars[pos].is_ascii_digit() || chars[pos] == '_')
598 {
599 if chars[pos] != '_' {
600 num_str.push(chars[pos]);
601 }
602 pos += 1;
603 }
604 }
605 let val = if num_str.starts_with("0x") || num_str.starts_with("0X") {
606 i64::from_str_radix(&num_str[2..], 16).unwrap_or(0)
607 } else {
608 num_str.parse::<i64>().unwrap_or(0)
609 };
610 tokens.push(Token::NumberLit(val));
611 continue;
612 }
613
614 if ch.is_ascii_alphabetic() || ch == '_' {
616 let start = pos;
617 while pos < chars.len() && (chars[pos].is_ascii_alphanumeric() || chars[pos] == '_')
618 {
619 pos += 1;
620 }
621 let word: String = chars[start..pos].iter().collect();
622 let tok = match word.as_str() {
623 "class" => Token::Class,
624 "def" => Token::Def,
625 "if" => Token::If,
626 "elif" => Token::Elif,
627 "else" => Token::Else,
628 "for" => Token::For,
629 "in" => Token::In,
630 "range" => Token::Range,
631 "return" => Token::Return,
632 "pass" => Token::Pass,
633 "True" => Token::TrueLit,
634 "False" => Token::FalseLit,
635 "None" => Token::NoneLit,
636 "and" => Token::And,
637 "or" => Token::Or,
638 "not" => Token::Not,
639 "self" => Token::SelfKw,
640 "super" => Token::Super,
641 "from" => Token::From,
642 "import" => Token::Import,
643 "assert" => Token::Assert,
644 _ => Token::Ident(word),
645 };
646 tokens.push(tok);
647 continue;
648 }
649
650 pos += 1;
652 }
653
654 if paren_depth == 0 {
656 tokens.push(Token::Newline);
657 }
658 }
659
660 while indent_stack.len() > 1 {
662 indent_stack.pop();
663 tokens.push(Token::Dedent);
664 }
665
666 tokens.push(Token::Eof);
667 tokens
668}
669
670struct PyParser<'a> {
675 tokens: Vec<Token>,
676 pos: usize,
677 file: &'a str,
678 errors: &'a mut Vec<String>,
679}
680
681impl<'a> PyParser<'a> {
682 fn new(tokens: Vec<Token>, file: &'a str, errors: &'a mut Vec<String>) -> Self {
683 Self {
684 tokens,
685 pos: 0,
686 file,
687 errors,
688 }
689 }
690
691 fn peek(&self) -> &Token {
692 self.tokens.get(self.pos).unwrap_or(&Token::Eof)
693 }
694
695 fn advance(&mut self) -> Token {
696 let t = self.tokens.get(self.pos).cloned().unwrap_or(Token::Eof);
697 self.pos += 1;
698 t
699 }
700
701 fn expect(&mut self, expected: &Token) -> bool {
702 if std::mem::discriminant(self.peek()) == std::mem::discriminant(expected) {
703 self.advance();
704 true
705 } else {
706 self.errors.push(format!(
707 "Expected {:?}, got {:?}",
708 expected,
709 self.peek()
710 ));
711 false
712 }
713 }
714
715 fn match_tok(&mut self, expected: &Token) -> bool {
716 if std::mem::discriminant(self.peek()) == std::mem::discriminant(expected) {
717 self.advance();
718 true
719 } else {
720 false
721 }
722 }
723
724 fn expect_ident(&mut self) -> String {
725 match self.advance() {
726 Token::Ident(name) => name,
727 other => {
728 self.errors
729 .push(format!("Expected identifier, got {:?}", other));
730 "_error".to_string()
731 }
732 }
733 }
734
735 fn loc(&self) -> SourceLocation {
736 SourceLocation {
737 file: self.file.to_string(),
738 line: 1,
739 column: 0,
740 }
741 }
742
743 fn skip_newlines(&mut self) {
745 while *self.peek() == Token::Newline {
746 self.advance();
747 }
748 }
749
750 fn parse_contract(&mut self) -> Option<ContractNode> {
755 self.skip_newlines();
756
757 while *self.peek() == Token::From || *self.peek() == Token::Import {
759 self.parse_import_line();
760 self.skip_newlines();
761 }
762
763 self.skip_newlines();
764
765 if *self.peek() != Token::Class {
766 self.errors
767 .push("Expected 'class' declaration".to_string());
768 return None;
769 }
770
771 self.advance(); let contract_name = self.expect_ident();
773 self.expect(&Token::LParen);
774 let parent_class = self.expect_ident();
775 self.expect(&Token::RParen);
776 self.expect(&Token::Colon);
777 self.skip_newlines();
778 self.expect(&Token::Indent);
779 self.skip_newlines();
780
781 if parent_class != "SmartContract" && parent_class != "StatefulSmartContract" {
782 self.errors.push(format!(
783 "Unknown parent class: {}",
784 parent_class
785 ));
786 return None;
787 }
788
789 let mut properties = Vec::new();
790 let mut methods = Vec::new();
791 let mut constructor: Option<MethodNode> = None;
792
793 while *self.peek() != Token::Dedent && *self.peek() != Token::Eof {
794 self.skip_newlines();
795 if *self.peek() == Token::Dedent || *self.peek() == Token::Eof {
796 break;
797 }
798
799 let mut decorators: Vec<String> = Vec::new();
801 while *self.peek() == Token::At {
802 self.advance(); let dec_name = match self.advance() {
804 Token::Ident(name) => name,
805 other => {
806 self.errors
807 .push(format!("Expected decorator name, got {:?}", other));
808 String::new()
809 }
810 };
811 decorators.push(dec_name);
812 self.skip_newlines();
813 }
814
815 if *self.peek() == Token::Def {
817 let method = self.parse_method_def(&decorators);
818 if method.name == "constructor" {
819 constructor = Some(method);
820 } else {
821 methods.push(method);
822 }
823 self.skip_newlines();
824 continue;
825 }
826
827 if let Token::Ident(_) = self.peek().clone() {
829 if let Some(prop) = self.parse_property(&parent_class) {
830 properties.push(prop);
831 }
832 self.skip_newlines();
833 continue;
834 }
835
836 self.advance();
838 }
839
840 self.match_tok(&Token::Dedent);
841
842 let constructor = constructor
844 .unwrap_or_else(|| build_constructor(&properties, self.file));
845
846 Some(ContractNode {
847 name: contract_name,
848 parent_class,
849 properties,
850 constructor,
851 methods,
852 source_file: self.file.to_string(),
853 })
854 }
855
856 fn parse_import_line(&mut self) {
857 if *self.peek() == Token::From {
860 self.advance(); while *self.peek() != Token::Import
863 && *self.peek() != Token::Newline
864 && *self.peek() != Token::Eof
865 {
866 self.advance();
867 }
868 if self.match_tok(&Token::Import) {
869 while *self.peek() != Token::Newline && *self.peek() != Token::Eof {
871 self.advance();
872 }
873 }
874 } else if *self.peek() == Token::Import {
875 self.advance();
876 while *self.peek() != Token::Newline && *self.peek() != Token::Eof {
877 self.advance();
878 }
879 }
880 self.skip_newlines();
881 }
882
883 fn parse_property(&mut self, parent_class: &str) -> Option<PropertyNode> {
888 let raw_name = self.expect_ident();
889
890 if *self.peek() != Token::Colon {
891 while *self.peek() != Token::Newline && *self.peek() != Token::Eof {
893 self.advance();
894 }
895 return None;
896 }
897 self.advance(); let mut is_readonly = false;
901 let type_node;
902
903 if let Token::Ident(ref name) = *self.peek() {
904 if name == "Readonly" {
905 is_readonly = true;
906 self.advance(); self.expect(&Token::LBracket);
908 type_node = self.parse_type();
909 self.expect(&Token::RBracket);
910 } else {
911 type_node = self.parse_type();
912 }
913 } else {
914 type_node = self.parse_type();
915 }
916
917 if parent_class == "SmartContract" {
919 is_readonly = true;
920 }
921
922 let initializer = if *self.peek() == Token::Eq {
924 self.advance(); Some(self.parse_expression())
926 } else {
927 None
928 };
929
930 while *self.peek() != Token::Newline
932 && *self.peek() != Token::Eof
933 && *self.peek() != Token::Dedent
934 {
935 self.advance();
936 }
937
938 Some(PropertyNode {
939 name: snake_to_camel(&raw_name),
940 prop_type: type_node,
941 readonly: is_readonly,
942 initializer,
943 source_location: self.loc(),
944 })
945 }
946
947 fn parse_type(&mut self) -> TypeNode {
952 let raw_name = self.expect_ident();
953
954 if raw_name == "FixedArray" && *self.peek() == Token::LBracket {
956 self.advance(); let element = self.parse_type();
958 self.expect(&Token::Comma);
959 let length = match self.advance() {
960 Token::NumberLit(n) => n as usize,
961 _ => {
962 self.errors
963 .push("FixedArray requires numeric length".to_string());
964 0
965 }
966 };
967 self.expect(&Token::RBracket);
968 return TypeNode::FixedArray {
969 element: Box::new(element),
970 length,
971 };
972 }
973
974 let mapped = map_py_type(&raw_name);
975 if let Some(prim) = PrimitiveTypeName::from_str(mapped) {
976 TypeNode::Primitive(prim)
977 } else {
978 TypeNode::Custom(mapped.to_string())
979 }
980 }
981
982 fn parse_method_def(&mut self, decorators: &[String]) -> MethodNode {
987 self.expect(&Token::Def);
988
989 let raw_name = match self.advance() {
990 Token::Ident(name) => name,
991 other => {
992 self.errors
993 .push(format!("Expected method name, got {:?}", other));
994 "_error".to_string()
995 }
996 };
997
998 self.expect(&Token::LParen);
999 let params = self.parse_params();
1000 self.expect(&Token::RParen);
1001
1002 if self.match_tok(&Token::Arrow) {
1004 self.parse_type(); }
1006
1007 self.expect(&Token::Colon);
1008 self.skip_newlines();
1009 self.expect(&Token::Indent);
1010
1011 let body = self.parse_statements();
1012
1013 self.match_tok(&Token::Dedent);
1014
1015 if raw_name == "__init__" {
1017 return MethodNode {
1018 name: "constructor".to_string(),
1019 params,
1020 body,
1021 visibility: Visibility::Public,
1022 source_location: self.loc(),
1023 };
1024 }
1025
1026 let is_public = decorators.contains(&"public".to_string());
1027 let method_name = snake_to_camel(&raw_name);
1028
1029 MethodNode {
1030 name: method_name,
1031 params,
1032 body,
1033 visibility: if is_public {
1034 Visibility::Public
1035 } else {
1036 Visibility::Private
1037 },
1038 source_location: self.loc(),
1039 }
1040 }
1041
1042 fn parse_params(&mut self) -> Vec<ParamNode> {
1043 let mut params = Vec::new();
1044
1045 while *self.peek() != Token::RParen && *self.peek() != Token::Eof {
1046 if *self.peek() == Token::SelfKw {
1048 self.advance();
1049 if *self.peek() == Token::Comma {
1050 self.advance();
1051 }
1052 continue;
1053 }
1054
1055 let raw_name = self.expect_ident();
1056
1057 let param_type = if self.match_tok(&Token::Colon) {
1058 self.parse_type()
1059 } else {
1060 TypeNode::Custom("unknown".to_string())
1061 };
1062
1063 params.push(ParamNode {
1064 name: snake_to_camel(&raw_name),
1065 param_type,
1066 });
1067
1068 if !self.match_tok(&Token::Comma) {
1069 break;
1070 }
1071 }
1072
1073 params
1074 }
1075
1076 fn parse_statements(&mut self) -> Vec<Statement> {
1081 let mut stmts = Vec::new();
1082
1083 while *self.peek() != Token::Dedent && *self.peek() != Token::Eof {
1084 self.skip_newlines();
1085 if *self.peek() == Token::Dedent || *self.peek() == Token::Eof {
1086 break;
1087 }
1088
1089 if let Some(stmt) = self.parse_statement() {
1090 stmts.push(stmt);
1091 }
1092 self.skip_newlines();
1093 }
1094
1095 stmts
1096 }
1097
1098 fn parse_statement(&mut self) -> Option<Statement> {
1099 match self.peek().clone() {
1100 Token::Assert => Some(self.parse_assert_statement()),
1102
1103 Token::If => Some(self.parse_if_statement()),
1105
1106 Token::For => Some(self.parse_for_statement()),
1108
1109 Token::Return => Some(self.parse_return_statement()),
1111
1112 Token::Pass => {
1114 self.advance();
1115 None
1116 }
1117
1118 Token::Super => Some(self.parse_super_call()),
1120
1121 Token::SelfKw => Some(self.parse_self_statement()),
1123
1124 Token::Ident(_) => Some(self.parse_ident_statement()),
1126
1127 _ => {
1128 self.advance();
1129 None
1130 }
1131 }
1132 }
1133
1134 fn parse_assert_statement(&mut self) -> Statement {
1135 self.advance(); let expr = self.parse_expression();
1137 Statement::ExpressionStatement {
1138 expression: Expression::CallExpr {
1139 callee: Box::new(Expression::Identifier {
1140 name: "assert".to_string(),
1141 }),
1142 args: vec![expr],
1143 },
1144 source_location: self.loc(),
1145 }
1146 }
1147
1148 fn parse_if_statement(&mut self) -> Statement {
1149 self.advance(); let condition = self.parse_expression();
1151 self.expect(&Token::Colon);
1152 self.skip_newlines();
1153 self.expect(&Token::Indent);
1154 let then_branch = self.parse_statements();
1155 self.match_tok(&Token::Dedent);
1156 self.skip_newlines();
1157
1158 let else_branch = if *self.peek() == Token::Elif {
1159 Some(vec![self.parse_elif_statement()])
1161 } else if *self.peek() == Token::Else {
1162 self.advance(); self.expect(&Token::Colon);
1164 self.skip_newlines();
1165 self.expect(&Token::Indent);
1166 let stmts = self.parse_statements();
1167 self.match_tok(&Token::Dedent);
1168 Some(stmts)
1169 } else {
1170 None
1171 };
1172
1173 Statement::IfStatement {
1174 condition,
1175 then_branch,
1176 else_branch,
1177 source_location: self.loc(),
1178 }
1179 }
1180
1181 fn parse_elif_statement(&mut self) -> Statement {
1182 self.advance(); let condition = self.parse_expression();
1184 self.expect(&Token::Colon);
1185 self.skip_newlines();
1186 self.expect(&Token::Indent);
1187 let then_branch = self.parse_statements();
1188 self.match_tok(&Token::Dedent);
1189 self.skip_newlines();
1190
1191 let else_branch = if *self.peek() == Token::Elif {
1192 Some(vec![self.parse_elif_statement()])
1193 } else if *self.peek() == Token::Else {
1194 self.advance();
1195 self.expect(&Token::Colon);
1196 self.skip_newlines();
1197 self.expect(&Token::Indent);
1198 let stmts = self.parse_statements();
1199 self.match_tok(&Token::Dedent);
1200 Some(stmts)
1201 } else {
1202 None
1203 };
1204
1205 Statement::IfStatement {
1206 condition,
1207 then_branch,
1208 else_branch,
1209 source_location: self.loc(),
1210 }
1211 }
1212
1213 fn parse_for_statement(&mut self) -> Statement {
1214 self.advance(); let raw_var = self.expect_ident();
1217 let var_name = snake_to_camel(&raw_var);
1218
1219 self.expect(&Token::In);
1220 self.expect(&Token::Range);
1221 self.expect(&Token::LParen);
1222
1223 let first_arg = self.parse_expression();
1225 let (start_expr, end_expr) = if self.match_tok(&Token::Comma) {
1226 let second_arg = self.parse_expression();
1227 (first_arg, second_arg)
1228 } else {
1229 (Expression::BigIntLiteral { value: 0 }, first_arg)
1230 };
1231
1232 self.expect(&Token::RParen);
1233 self.expect(&Token::Colon);
1234 self.skip_newlines();
1235 self.expect(&Token::Indent);
1236 let body = self.parse_statements();
1237 self.match_tok(&Token::Dedent);
1238
1239 let init = Statement::VariableDecl {
1242 name: var_name.clone(),
1243 var_type: Some(TypeNode::Primitive(PrimitiveTypeName::Bigint)),
1244 mutable: true,
1245 init: start_expr,
1246 source_location: self.loc(),
1247 };
1248
1249 let condition = Expression::BinaryExpr {
1250 op: BinaryOp::Lt,
1251 left: Box::new(Expression::Identifier {
1252 name: var_name.clone(),
1253 }),
1254 right: Box::new(end_expr),
1255 };
1256
1257 let update = Statement::ExpressionStatement {
1258 expression: Expression::IncrementExpr {
1259 operand: Box::new(Expression::Identifier { name: var_name }),
1260 prefix: false,
1261 },
1262 source_location: self.loc(),
1263 };
1264
1265 Statement::ForStatement {
1266 init: Box::new(init),
1267 condition,
1268 update: Box::new(update),
1269 body,
1270 source_location: self.loc(),
1271 }
1272 }
1273
1274 fn parse_return_statement(&mut self) -> Statement {
1275 self.advance(); let value = if *self.peek() != Token::Newline
1277 && *self.peek() != Token::Dedent
1278 && *self.peek() != Token::Eof
1279 {
1280 Some(self.parse_expression())
1281 } else {
1282 None
1283 };
1284 Statement::ReturnStatement {
1285 value,
1286 source_location: self.loc(),
1287 }
1288 }
1289
1290 fn parse_super_call(&mut self) -> Statement {
1291 self.advance(); self.expect(&Token::LParen);
1294 self.expect(&Token::RParen);
1295 self.expect(&Token::Dot);
1296
1297 let method_name = self.expect_ident();
1299 if method_name != "__init__" {
1300 self.errors.push(format!(
1301 "Expected __init__ after super(), got '{}'",
1302 method_name
1303 ));
1304 }
1305
1306 self.expect(&Token::LParen);
1307 let mut args = Vec::new();
1308 while *self.peek() != Token::RParen && *self.peek() != Token::Eof {
1309 args.push(self.parse_expression());
1310 if !self.match_tok(&Token::Comma) {
1311 break;
1312 }
1313 }
1314 self.expect(&Token::RParen);
1315
1316 Statement::ExpressionStatement {
1317 expression: Expression::CallExpr {
1318 callee: Box::new(Expression::Identifier {
1319 name: "super".to_string(),
1320 }),
1321 args,
1322 },
1323 source_location: self.loc(),
1324 }
1325 }
1326
1327 fn parse_self_statement(&mut self) -> Statement {
1328 let expr = self.parse_expression();
1330
1331 if self.match_tok(&Token::Eq) {
1333 let value = self.parse_expression();
1334 return Statement::Assignment {
1335 target: expr,
1336 value,
1337 source_location: self.loc(),
1338 };
1339 }
1340
1341 if *self.peek() == Token::PlusEq {
1343 self.advance();
1344 let rhs = self.parse_expression();
1345 let value = Expression::BinaryExpr {
1346 op: BinaryOp::Add,
1347 left: Box::new(expr.clone()),
1348 right: Box::new(rhs),
1349 };
1350 return Statement::Assignment {
1351 target: expr,
1352 value,
1353 source_location: self.loc(),
1354 };
1355 }
1356 if *self.peek() == Token::MinusEq {
1357 self.advance();
1358 let rhs = self.parse_expression();
1359 let value = Expression::BinaryExpr {
1360 op: BinaryOp::Sub,
1361 left: Box::new(expr.clone()),
1362 right: Box::new(rhs),
1363 };
1364 return Statement::Assignment {
1365 target: expr,
1366 value,
1367 source_location: self.loc(),
1368 };
1369 }
1370 if *self.peek() == Token::StarEq {
1371 self.advance();
1372 let rhs = self.parse_expression();
1373 let value = Expression::BinaryExpr {
1374 op: BinaryOp::Mul,
1375 left: Box::new(expr.clone()),
1376 right: Box::new(rhs),
1377 };
1378 return Statement::Assignment {
1379 target: expr,
1380 value,
1381 source_location: self.loc(),
1382 };
1383 }
1384 if *self.peek() == Token::SlashEq || *self.peek() == Token::IntDivEq {
1385 self.advance();
1386 let rhs = self.parse_expression();
1387 let value = Expression::BinaryExpr {
1388 op: BinaryOp::Div,
1389 left: Box::new(expr.clone()),
1390 right: Box::new(rhs),
1391 };
1392 return Statement::Assignment {
1393 target: expr,
1394 value,
1395 source_location: self.loc(),
1396 };
1397 }
1398 if *self.peek() == Token::PercentEq {
1399 self.advance();
1400 let rhs = self.parse_expression();
1401 let value = Expression::BinaryExpr {
1402 op: BinaryOp::Mod,
1403 left: Box::new(expr.clone()),
1404 right: Box::new(rhs),
1405 };
1406 return Statement::Assignment {
1407 target: expr,
1408 value,
1409 source_location: self.loc(),
1410 };
1411 }
1412
1413 Statement::ExpressionStatement {
1415 expression: expr,
1416 source_location: self.loc(),
1417 }
1418 }
1419
1420 fn parse_ident_statement(&mut self) -> Statement {
1421 let raw_name = match self.peek().clone() {
1428 Token::Ident(ref name) => name.clone(),
1429 _ => "_error".to_string(),
1430 };
1431
1432 if self.tokens.get(self.pos + 1).map_or(false, |t| *t == Token::Colon) {
1434 self.advance(); self.advance(); let type_node = self.parse_type();
1440
1441 let init = if self.match_tok(&Token::Eq) {
1442 self.parse_expression()
1443 } else {
1444 Expression::BigIntLiteral { value: 0 }
1445 };
1446
1447 return Statement::VariableDecl {
1448 name: snake_to_camel(&raw_name),
1449 var_type: Some(type_node),
1450 mutable: true,
1451 init,
1452 source_location: self.loc(),
1453 };
1454 }
1455
1456 if self.tokens.get(self.pos + 1).map_or(false, |t| *t == Token::Eq) {
1458 self.advance(); self.advance(); let value = self.parse_expression();
1461 return Statement::VariableDecl {
1462 name: snake_to_camel(&raw_name),
1463 var_type: None,
1464 mutable: true,
1465 init: value,
1466 source_location: self.loc(),
1467 };
1468 }
1469
1470 let expr = self.parse_expression();
1472
1473 if self.match_tok(&Token::Eq) {
1475 let value = self.parse_expression();
1476 return Statement::Assignment {
1477 target: expr,
1478 value,
1479 source_location: self.loc(),
1480 };
1481 }
1482
1483 if *self.peek() == Token::PlusEq {
1485 self.advance();
1486 let rhs = self.parse_expression();
1487 let value = Expression::BinaryExpr {
1488 op: BinaryOp::Add,
1489 left: Box::new(expr.clone()),
1490 right: Box::new(rhs),
1491 };
1492 return Statement::Assignment {
1493 target: expr,
1494 value,
1495 source_location: self.loc(),
1496 };
1497 }
1498 if *self.peek() == Token::MinusEq {
1499 self.advance();
1500 let rhs = self.parse_expression();
1501 let value = Expression::BinaryExpr {
1502 op: BinaryOp::Sub,
1503 left: Box::new(expr.clone()),
1504 right: Box::new(rhs),
1505 };
1506 return Statement::Assignment {
1507 target: expr,
1508 value,
1509 source_location: self.loc(),
1510 };
1511 }
1512 if *self.peek() == Token::StarEq {
1513 self.advance();
1514 let rhs = self.parse_expression();
1515 let value = Expression::BinaryExpr {
1516 op: BinaryOp::Mul,
1517 left: Box::new(expr.clone()),
1518 right: Box::new(rhs),
1519 };
1520 return Statement::Assignment {
1521 target: expr,
1522 value,
1523 source_location: self.loc(),
1524 };
1525 }
1526 if *self.peek() == Token::SlashEq || *self.peek() == Token::IntDivEq {
1527 self.advance();
1528 let rhs = self.parse_expression();
1529 let value = Expression::BinaryExpr {
1530 op: BinaryOp::Div,
1531 left: Box::new(expr.clone()),
1532 right: Box::new(rhs),
1533 };
1534 return Statement::Assignment {
1535 target: expr,
1536 value,
1537 source_location: self.loc(),
1538 };
1539 }
1540 if *self.peek() == Token::PercentEq {
1541 self.advance();
1542 let rhs = self.parse_expression();
1543 let value = Expression::BinaryExpr {
1544 op: BinaryOp::Mod,
1545 left: Box::new(expr.clone()),
1546 right: Box::new(rhs),
1547 };
1548 return Statement::Assignment {
1549 target: expr,
1550 value,
1551 source_location: self.loc(),
1552 };
1553 }
1554
1555 Statement::ExpressionStatement {
1557 expression: expr,
1558 source_location: self.loc(),
1559 }
1560 }
1561
1562 fn parse_expression(&mut self) -> Expression {
1567 self.parse_ternary()
1568 }
1569
1570 fn parse_ternary(&mut self) -> Expression {
1573 let expr = self.parse_or();
1574
1575 if *self.peek() == Token::If {
1576 self.advance(); let condition = self.parse_or();
1578 self.expect(&Token::Else);
1579 let alternate = self.parse_ternary();
1580 Expression::TernaryExpr {
1581 condition: Box::new(condition),
1582 consequent: Box::new(expr),
1583 alternate: Box::new(alternate),
1584 }
1585 } else {
1586 expr
1587 }
1588 }
1589
1590 fn parse_or(&mut self) -> Expression {
1591 let mut left = self.parse_and();
1592 while *self.peek() == Token::Or {
1593 self.advance();
1594 let right = self.parse_and();
1595 left = Expression::BinaryExpr {
1596 op: BinaryOp::Or,
1597 left: Box::new(left),
1598 right: Box::new(right),
1599 };
1600 }
1601 left
1602 }
1603
1604 fn parse_and(&mut self) -> Expression {
1605 let mut left = self.parse_not();
1606 while *self.peek() == Token::And {
1607 self.advance();
1608 let right = self.parse_not();
1609 left = Expression::BinaryExpr {
1610 op: BinaryOp::And,
1611 left: Box::new(left),
1612 right: Box::new(right),
1613 };
1614 }
1615 left
1616 }
1617
1618 fn parse_not(&mut self) -> Expression {
1619 if *self.peek() == Token::Not {
1620 self.advance();
1621 let operand = self.parse_not();
1622 Expression::UnaryExpr {
1623 op: UnaryOp::Not,
1624 operand: Box::new(operand),
1625 }
1626 } else {
1627 self.parse_bit_or()
1628 }
1629 }
1630
1631 fn parse_bit_or(&mut self) -> Expression {
1632 let mut left = self.parse_bit_xor();
1633 while *self.peek() == Token::BitOr {
1634 self.advance();
1635 let right = self.parse_bit_xor();
1636 left = Expression::BinaryExpr {
1637 op: BinaryOp::BitOr,
1638 left: Box::new(left),
1639 right: Box::new(right),
1640 };
1641 }
1642 left
1643 }
1644
1645 fn parse_bit_xor(&mut self) -> Expression {
1646 let mut left = self.parse_bit_and();
1647 while *self.peek() == Token::BitXor {
1648 self.advance();
1649 let right = self.parse_bit_and();
1650 left = Expression::BinaryExpr {
1651 op: BinaryOp::BitXor,
1652 left: Box::new(left),
1653 right: Box::new(right),
1654 };
1655 }
1656 left
1657 }
1658
1659 fn parse_bit_and(&mut self) -> Expression {
1660 let mut left = self.parse_equality();
1661 while *self.peek() == Token::BitAnd {
1662 self.advance();
1663 let right = self.parse_equality();
1664 left = Expression::BinaryExpr {
1665 op: BinaryOp::BitAnd,
1666 left: Box::new(left),
1667 right: Box::new(right),
1668 };
1669 }
1670 left
1671 }
1672
1673 fn parse_equality(&mut self) -> Expression {
1674 let mut left = self.parse_comparison();
1675 loop {
1676 match self.peek() {
1677 Token::EqEq => {
1678 self.advance();
1679 let right = self.parse_comparison();
1680 left = Expression::BinaryExpr {
1682 op: BinaryOp::StrictEq,
1683 left: Box::new(left),
1684 right: Box::new(right),
1685 };
1686 }
1687 Token::NotEq => {
1688 self.advance();
1689 let right = self.parse_comparison();
1690 left = Expression::BinaryExpr {
1692 op: BinaryOp::StrictNe,
1693 left: Box::new(left),
1694 right: Box::new(right),
1695 };
1696 }
1697 _ => break,
1698 }
1699 }
1700 left
1701 }
1702
1703 fn parse_comparison(&mut self) -> Expression {
1704 let mut left = self.parse_shift();
1705 loop {
1706 match self.peek() {
1707 Token::Lt => {
1708 self.advance();
1709 let right = self.parse_shift();
1710 left = Expression::BinaryExpr {
1711 op: BinaryOp::Lt,
1712 left: Box::new(left),
1713 right: Box::new(right),
1714 };
1715 }
1716 Token::Le => {
1717 self.advance();
1718 let right = self.parse_shift();
1719 left = Expression::BinaryExpr {
1720 op: BinaryOp::Le,
1721 left: Box::new(left),
1722 right: Box::new(right),
1723 };
1724 }
1725 Token::Gt => {
1726 self.advance();
1727 let right = self.parse_shift();
1728 left = Expression::BinaryExpr {
1729 op: BinaryOp::Gt,
1730 left: Box::new(left),
1731 right: Box::new(right),
1732 };
1733 }
1734 Token::Ge => {
1735 self.advance();
1736 let right = self.parse_shift();
1737 left = Expression::BinaryExpr {
1738 op: BinaryOp::Ge,
1739 left: Box::new(left),
1740 right: Box::new(right),
1741 };
1742 }
1743 _ => break,
1744 }
1745 }
1746 left
1747 }
1748
1749 fn parse_shift(&mut self) -> Expression {
1750 let mut left = self.parse_additive();
1751 loop {
1752 match self.peek() {
1753 Token::LShift => {
1754 self.advance();
1755 let right = self.parse_additive();
1756 left = Expression::BinaryExpr {
1757 op: BinaryOp::Shl,
1758 left: Box::new(left),
1759 right: Box::new(right),
1760 };
1761 }
1762 Token::RShift => {
1763 self.advance();
1764 let right = self.parse_additive();
1765 left = Expression::BinaryExpr {
1766 op: BinaryOp::Shr,
1767 left: Box::new(left),
1768 right: Box::new(right),
1769 };
1770 }
1771 _ => break,
1772 }
1773 }
1774 left
1775 }
1776
1777 fn parse_additive(&mut self) -> Expression {
1778 let mut left = self.parse_multiplicative();
1779 loop {
1780 match self.peek() {
1781 Token::Plus => {
1782 self.advance();
1783 let right = self.parse_multiplicative();
1784 left = Expression::BinaryExpr {
1785 op: BinaryOp::Add,
1786 left: Box::new(left),
1787 right: Box::new(right),
1788 };
1789 }
1790 Token::Minus => {
1791 self.advance();
1792 let right = self.parse_multiplicative();
1793 left = Expression::BinaryExpr {
1794 op: BinaryOp::Sub,
1795 left: Box::new(left),
1796 right: Box::new(right),
1797 };
1798 }
1799 _ => break,
1800 }
1801 }
1802 left
1803 }
1804
1805 fn parse_multiplicative(&mut self) -> Expression {
1806 let mut left = self.parse_unary();
1807 loop {
1808 match self.peek() {
1809 Token::Star => {
1810 self.advance();
1811 let right = self.parse_unary();
1812 left = Expression::BinaryExpr {
1813 op: BinaryOp::Mul,
1814 left: Box::new(left),
1815 right: Box::new(right),
1816 };
1817 }
1818 Token::IntDiv => {
1819 self.advance();
1821 let right = self.parse_unary();
1822 left = Expression::BinaryExpr {
1823 op: BinaryOp::Div,
1824 left: Box::new(left),
1825 right: Box::new(right),
1826 };
1827 }
1828 Token::Slash => {
1829 self.advance();
1830 let right = self.parse_unary();
1831 left = Expression::BinaryExpr {
1832 op: BinaryOp::Div,
1833 left: Box::new(left),
1834 right: Box::new(right),
1835 };
1836 }
1837 Token::Percent => {
1838 self.advance();
1839 let right = self.parse_unary();
1840 left = Expression::BinaryExpr {
1841 op: BinaryOp::Mod,
1842 left: Box::new(left),
1843 right: Box::new(right),
1844 };
1845 }
1846 _ => break,
1847 }
1848 }
1849 left
1850 }
1851
1852 fn parse_unary(&mut self) -> Expression {
1853 match self.peek() {
1854 Token::Minus => {
1855 self.advance();
1856 let operand = self.parse_unary();
1857 Expression::UnaryExpr {
1858 op: UnaryOp::Neg,
1859 operand: Box::new(operand),
1860 }
1861 }
1862 Token::Tilde => {
1863 self.advance();
1864 let operand = self.parse_unary();
1865 Expression::UnaryExpr {
1866 op: UnaryOp::BitNot,
1867 operand: Box::new(operand),
1868 }
1869 }
1870 Token::Bang => {
1871 self.advance();
1872 let operand = self.parse_unary();
1873 Expression::UnaryExpr {
1874 op: UnaryOp::Not,
1875 operand: Box::new(operand),
1876 }
1877 }
1878 _ => self.parse_postfix(),
1879 }
1880 }
1881
1882 fn parse_postfix(&mut self) -> Expression {
1883 let mut expr = self.parse_primary();
1884
1885 loop {
1886 match self.peek().clone() {
1887 Token::Dot => {
1888 self.advance(); let raw_prop = self.expect_ident();
1890 let prop = snake_to_camel(&raw_prop);
1891
1892 if *self.peek() == Token::LParen {
1894 let args = self.parse_call_args();
1895 if matches!(&expr, Expression::Identifier { name } if name == "this") {
1897 expr = Expression::CallExpr {
1898 callee: Box::new(Expression::MemberExpr {
1899 object: Box::new(Expression::Identifier {
1900 name: "this".to_string(),
1901 }),
1902 property: prop,
1903 }),
1904 args,
1905 };
1906 } else {
1907 expr = Expression::CallExpr {
1908 callee: Box::new(Expression::MemberExpr {
1909 object: Box::new(expr),
1910 property: prop,
1911 }),
1912 args,
1913 };
1914 }
1915 } else {
1916 if matches!(&expr, Expression::Identifier { name } if name == "this") {
1918 expr = Expression::PropertyAccess { property: prop };
1919 } else {
1920 expr = Expression::MemberExpr {
1921 object: Box::new(expr),
1922 property: prop,
1923 };
1924 }
1925 }
1926 }
1927 Token::LParen => {
1928 let args = self.parse_call_args();
1929 expr = Expression::CallExpr {
1930 callee: Box::new(expr),
1931 args,
1932 };
1933 }
1934 Token::LBracket => {
1935 self.advance();
1936 let index = self.parse_expression();
1937 self.expect(&Token::RBracket);
1938 expr = Expression::IndexAccess {
1939 object: Box::new(expr),
1940 index: Box::new(index),
1941 };
1942 }
1943 _ => break,
1944 }
1945 }
1946
1947 expr
1948 }
1949
1950 fn parse_primary(&mut self) -> Expression {
1951 match self.advance() {
1952 Token::NumberLit(v) => Expression::BigIntLiteral { value: v },
1953 Token::TrueLit => Expression::BoolLiteral { value: true },
1954 Token::FalseLit => Expression::BoolLiteral { value: false },
1955 Token::NoneLit => Expression::BigIntLiteral { value: 0 },
1956 Token::HexStringLit(v) => Expression::ByteStringLiteral { value: v },
1957 Token::StringLit(v) => Expression::ByteStringLiteral { value: v },
1958 Token::SelfKw => {
1959 Expression::Identifier {
1961 name: "this".to_string(),
1962 }
1963 }
1964 Token::Ident(name) => {
1965 if name == "bytes" && *self.peek() == Token::Dot {
1967 if let Some(Token::Ident(ref next_name)) = self.tokens.get(self.pos + 1) {
1968 if next_name == "fromhex" {
1969 self.advance(); self.advance(); self.expect(&Token::LParen);
1972 let val = match self.advance() {
1973 Token::StringLit(s) => s,
1974 _ => {
1975 self.errors
1976 .push("Expected string in bytes.fromhex()".to_string());
1977 String::new()
1978 }
1979 };
1980 self.expect(&Token::RParen);
1981 return Expression::ByteStringLiteral { value: val };
1982 }
1983 }
1984 }
1985
1986 let mapped = map_builtin_name(&name);
1987 Expression::Identifier { name: mapped }
1988 }
1989 Token::Assert => {
1990 Expression::Identifier {
1994 name: "assert".to_string(),
1995 }
1996 }
1997 Token::LParen => {
1998 let expr = self.parse_expression();
1999 self.expect(&Token::RParen);
2000 expr
2001 }
2002 other => {
2003 self.errors
2004 .push(format!("Unexpected token in expression: {:?}", other));
2005 Expression::BigIntLiteral { value: 0 }
2006 }
2007 }
2008 }
2009
2010 fn parse_call_args(&mut self) -> Vec<Expression> {
2011 self.expect(&Token::LParen);
2012 let mut args = Vec::new();
2013 while *self.peek() != Token::RParen && *self.peek() != Token::Eof {
2014 args.push(self.parse_expression());
2015 if !self.match_tok(&Token::Comma) {
2016 break;
2017 }
2018 }
2019 self.expect(&Token::RParen);
2020 args
2021 }
2022}
2023
2024fn build_constructor(properties: &[PropertyNode], file: &str) -> MethodNode {
2029 let uninit_props: Vec<&PropertyNode> = properties
2031 .iter()
2032 .filter(|p| p.initializer.is_none())
2033 .collect();
2034
2035 let params: Vec<ParamNode> = uninit_props
2036 .iter()
2037 .map(|p| ParamNode {
2038 name: p.name.clone(),
2039 param_type: p.prop_type.clone(),
2040 })
2041 .collect();
2042
2043 let mut body: Vec<Statement> = Vec::new();
2044
2045 let super_args: Vec<Expression> = uninit_props
2047 .iter()
2048 .map(|p| Expression::Identifier {
2049 name: p.name.clone(),
2050 })
2051 .collect();
2052 body.push(Statement::ExpressionStatement {
2053 expression: Expression::CallExpr {
2054 callee: Box::new(Expression::Identifier {
2055 name: "super".to_string(),
2056 }),
2057 args: super_args,
2058 },
2059 source_location: SourceLocation {
2060 file: file.to_string(),
2061 line: 1,
2062 column: 0,
2063 },
2064 });
2065
2066 for p in &uninit_props {
2068 body.push(Statement::Assignment {
2069 target: Expression::PropertyAccess {
2070 property: p.name.clone(),
2071 },
2072 value: Expression::Identifier {
2073 name: p.name.clone(),
2074 },
2075 source_location: SourceLocation {
2076 file: file.to_string(),
2077 line: 1,
2078 column: 0,
2079 },
2080 });
2081 }
2082
2083 MethodNode {
2084 name: "constructor".to_string(),
2085 params,
2086 body,
2087 visibility: Visibility::Public,
2088 source_location: SourceLocation {
2089 file: file.to_string(),
2090 line: 1,
2091 column: 0,
2092 },
2093 }
2094}
2095
2096#[cfg(test)]
2101mod tests {
2102 use super::*;
2103
2104 #[test]
2105 fn test_snake_to_camel() {
2106 assert_eq!(snake_to_camel("hello_world"), "helloWorld");
2107 assert_eq!(snake_to_camel("check_sig"), "checkSig");
2108 assert_eq!(snake_to_camel("already"), "already");
2109 assert_eq!(snake_to_camel("a_b_c"), "aBC");
2110 assert_eq!(snake_to_camel("pub_key_hash"), "pubKeyHash");
2111 assert_eq!(snake_to_camel("sum_"), "sum");
2112 assert_eq!(snake_to_camel("assert_"), "assert");
2113 }
2114
2115 #[test]
2116 fn test_builtin_name_mapping() {
2117 assert_eq!(map_builtin_name("assert_"), "assert");
2118 assert_eq!(map_builtin_name("check_sig"), "checkSig");
2119 assert_eq!(map_builtin_name("hash160"), "hash160");
2120 assert_eq!(map_builtin_name("verify_wots"), "verifyWOTS");
2121 assert_eq!(
2122 map_builtin_name("verify_slh_dsa_sha2_128s"),
2123 "verifySLHDSA_SHA2_128s"
2124 );
2125 assert_eq!(map_builtin_name("ec_add"), "ecAdd");
2126 assert_eq!(map_builtin_name("add_output"), "addOutput");
2127 assert_eq!(map_builtin_name("abs"), "abs");
2128 assert_eq!(map_builtin_name("some_func"), "someFunc");
2129 }
2130
2131 #[test]
2132 fn test_parse_simple_python_contract() {
2133 let source = r#"
2134from runar import SmartContract, Addr, Sig, PubKey, public, assert_, hash160, check_sig
2135
2136class P2PKH(SmartContract):
2137 pub_key_hash: Addr
2138
2139 def __init__(self, pub_key_hash: Addr):
2140 super().__init__(pub_key_hash)
2141 self.pub_key_hash = pub_key_hash
2142
2143 @public
2144 def unlock(self, sig: Sig, pub_key: PubKey):
2145 assert_(hash160(pub_key) == self.pub_key_hash)
2146 assert_(check_sig(sig, pub_key))
2147"#;
2148
2149 let result = parse_python(source, Some("P2PKH.runar.py"));
2150 assert!(result.errors.is_empty(), "errors: {:?}", result.errors);
2151 let contract = result.contract.unwrap();
2152 assert_eq!(contract.name, "P2PKH");
2153 assert_eq!(contract.parent_class, "SmartContract");
2154 assert_eq!(contract.properties.len(), 1);
2155 assert_eq!(contract.properties[0].name, "pubKeyHash");
2156 assert!(contract.properties[0].readonly);
2157 assert_eq!(contract.methods.len(), 1);
2158 assert_eq!(contract.methods[0].name, "unlock");
2159 assert_eq!(contract.methods[0].visibility, Visibility::Public);
2160 assert_eq!(contract.methods[0].params.len(), 2);
2162 assert_eq!(contract.methods[0].params[0].name, "sig");
2163 assert_eq!(contract.methods[0].params[1].name, "pubKey");
2164 }
2165
2166 #[test]
2167 fn test_parse_stateful_python_contract() {
2168 let source = r#"
2169from runar import StatefulSmartContract, Bigint, Readonly, public, assert_
2170
2171class Stateful(StatefulSmartContract):
2172 count: Bigint
2173 max_count: Readonly[Bigint]
2174
2175 def __init__(self, count: Bigint, max_count: Bigint):
2176 super().__init__(count, max_count)
2177 self.count = count
2178 self.max_count = max_count
2179
2180 @public
2181 def increment(self, amount: Bigint):
2182 self.count = self.count + amount
2183 assert_(self.count <= self.max_count)
2184
2185 @public
2186 def reset(self):
2187 self.count = 0
2188"#;
2189
2190 let result = parse_python(source, Some("Stateful.runar.py"));
2191 assert!(result.errors.is_empty(), "errors: {:?}", result.errors);
2192 let contract = result.contract.unwrap();
2193 assert_eq!(contract.name, "Stateful");
2194 assert_eq!(contract.parent_class, "StatefulSmartContract");
2195 assert_eq!(contract.properties.len(), 2);
2196 assert_eq!(contract.properties[0].name, "count");
2197 assert!(!contract.properties[0].readonly);
2198 assert_eq!(contract.properties[1].name, "maxCount");
2199 assert!(contract.properties[1].readonly);
2200 assert_eq!(contract.methods.len(), 2);
2201 }
2202
2203 #[test]
2204 fn test_parse_for_loop() {
2205 let source = r#"
2206from runar import SmartContract, Bigint, public, assert_
2207
2208class BoundedLoop(SmartContract):
2209 expected_sum: Bigint
2210
2211 def __init__(self, expected_sum: Bigint):
2212 super().__init__(expected_sum)
2213 self.expected_sum = expected_sum
2214
2215 @public
2216 def verify(self, start: Bigint):
2217 sum_: Bigint = 0
2218 for i in range(5):
2219 sum_ = sum_ + start + i
2220 assert_(sum_ == self.expected_sum)
2221"#;
2222
2223 let result = parse_python(source, Some("BoundedLoop.runar.py"));
2224 assert!(result.errors.is_empty(), "errors: {:?}", result.errors);
2225 let contract = result.contract.unwrap();
2226 assert_eq!(contract.methods[0].name, "verify");
2227 assert_eq!(contract.methods[0].body.len(), 3);
2229 }
2230
2231 #[test]
2232 fn test_parse_if_else() {
2233 let source = r#"
2234from runar import SmartContract, Bigint, public, assert_
2235
2236class IfElse(SmartContract):
2237 limit: Bigint
2238
2239 def __init__(self, limit: Bigint):
2240 super().__init__(limit)
2241 self.limit = limit
2242
2243 @public
2244 def check(self, value: Bigint, mode: bool):
2245 result: Bigint = 0
2246 if mode:
2247 result = value + self.limit
2248 else:
2249 result = value - self.limit
2250 assert_(result > 0)
2251"#;
2252
2253 let result = parse_python(source, Some("IfElse.runar.py"));
2254 assert!(result.errors.is_empty(), "errors: {:?}", result.errors);
2255 let contract = result.contract.unwrap();
2256 assert_eq!(contract.methods[0].body.len(), 3); }
2258
2259 #[test]
2260 fn test_eq_maps_to_strict_eq() {
2261 let source = r#"
2262from runar import SmartContract, Bigint, public, assert_
2263
2264class Test(SmartContract):
2265 x: Bigint
2266
2267 @public
2268 def check(self, y: Bigint):
2269 assert_(self.x == y)
2270 assert_(self.x != y)
2271"#;
2272
2273 let result = parse_python(source, Some("Test.runar.py"));
2274 assert!(result.errors.is_empty(), "errors: {:?}", result.errors);
2275 let contract = result.contract.unwrap();
2276 let body = &contract.methods[0].body;
2277 assert_eq!(body.len(), 2);
2278
2279 if let Statement::ExpressionStatement { expression, .. } = &body[0] {
2281 if let Expression::CallExpr { args, .. } = expression {
2282 if let Expression::BinaryExpr { op, .. } = &args[0] {
2283 assert_eq!(*op, BinaryOp::StrictEq);
2284 } else {
2285 panic!("Expected BinaryExpr inside assert");
2286 }
2287 } else {
2288 panic!("Expected CallExpr for assert");
2289 }
2290 }
2291
2292 if let Statement::ExpressionStatement { expression, .. } = &body[1] {
2294 if let Expression::CallExpr { args, .. } = expression {
2295 if let Expression::BinaryExpr { op, .. } = &args[0] {
2296 assert_eq!(*op, BinaryOp::StrictNe);
2297 } else {
2298 panic!("Expected BinaryExpr inside assert");
2299 }
2300 }
2301 }
2302 }
2303
2304 #[test]
2305 fn test_self_to_this_conversion() {
2306 let source = r#"
2307from runar import StatefulSmartContract, Bigint, public
2308
2309class Example(StatefulSmartContract):
2310 value: Bigint
2311
2312 @public
2313 def set_value(self, new_value: Bigint):
2314 self.value = new_value
2315"#;
2316
2317 let result = parse_python(source, Some("Example.runar.py"));
2318 assert!(result.errors.is_empty(), "errors: {:?}", result.errors);
2319 let contract = result.contract.unwrap();
2320 let body = &contract.methods[0].body;
2321 assert_eq!(body.len(), 1);
2322
2323 if let Statement::Assignment { target, .. } = &body[0] {
2325 match target {
2326 Expression::PropertyAccess { property } => {
2327 assert_eq!(property, "value");
2328 }
2329 _ => panic!("Expected PropertyAccess, got {:?}", target),
2330 }
2331 }
2332 assert_eq!(contract.methods[0].name, "setValue");
2334 assert_eq!(contract.methods[0].params[0].name, "newValue");
2335 }
2336
2337 #[test]
2338 fn test_constructor_auto_generated() {
2339 let source = r#"
2340from runar import SmartContract, Bigint, PubKey, public, assert_
2341
2342class Test(SmartContract):
2343 a: Bigint
2344 b: PubKey
2345
2346 @public
2347 def check(self):
2348 assert_(self.a > 0)
2349"#;
2350
2351 let result = parse_python(source, None);
2352 assert!(result.errors.is_empty(), "errors: {:?}", result.errors);
2353 let contract = result.contract.unwrap();
2354 assert_eq!(contract.constructor.params.len(), 2);
2356 assert_eq!(contract.constructor.body.len(), 3);
2358 }
2359
2360 #[test]
2361 fn test_python_integer_division() {
2362 let source = r#"
2363from runar import SmartContract, Bigint, public, assert_
2364
2365class DivTest(SmartContract):
2366 x: Bigint
2367
2368 @public
2369 def check(self, y: Bigint):
2370 result: Bigint = self.x // y
2371 assert_(result > 0)
2372"#;
2373
2374 let result = parse_python(source, Some("DivTest.runar.py"));
2375 assert!(result.errors.is_empty(), "errors: {:?}", result.errors);
2376 let contract = result.contract.unwrap();
2377 let body = &contract.methods[0].body;
2378
2379 if let Statement::VariableDecl { init, .. } = &body[0] {
2381 if let Expression::BinaryExpr { op, .. } = init {
2382 assert_eq!(*op, BinaryOp::Div);
2383 } else {
2384 panic!("Expected BinaryExpr Div, got {:?}", init);
2385 }
2386 }
2387 }
2388
2389 #[test]
2390 fn test_ternary_expression() {
2391 let source = r#"
2392from runar import SmartContract, Bigint, public, assert_
2393
2394class TernTest(SmartContract):
2395 x: Bigint
2396
2397 @public
2398 def check(self, cond: bool):
2399 result: Bigint = 1 if cond else 0
2400 assert_(result == self.x)
2401"#;
2402
2403 let result = parse_python(source, Some("TernTest.runar.py"));
2404 assert!(result.errors.is_empty(), "errors: {:?}", result.errors);
2405 let contract = result.contract.unwrap();
2406 let body = &contract.methods[0].body;
2407
2408 if let Statement::VariableDecl { init, .. } = &body[0] {
2410 match init {
2411 Expression::TernaryExpr { .. } => {} _ => panic!("Expected TernaryExpr, got {:?}", init),
2413 }
2414 }
2415 }
2416
2417 #[test]
2418 fn test_assert_keyword_as_statement() {
2419 let source = r#"
2420from runar import SmartContract, Bigint, public
2421
2422class AssertTest(SmartContract):
2423 x: Bigint
2424
2425 @public
2426 def check(self, y: Bigint):
2427 assert self.x == y
2428"#;
2429
2430 let result = parse_python(source, Some("AssertTest.runar.py"));
2431 assert!(result.errors.is_empty(), "errors: {:?}", result.errors);
2432 let contract = result.contract.unwrap();
2433 let body = &contract.methods[0].body;
2434 assert_eq!(body.len(), 1);
2435
2436 if let Statement::ExpressionStatement { expression, .. } = &body[0] {
2437 if let Expression::CallExpr { callee, .. } = expression {
2438 if let Expression::Identifier { name } = callee.as_ref() {
2439 assert_eq!(name, "assert");
2440 }
2441 }
2442 }
2443 }
2444
2445 #[test]
2446 fn test_hex_byte_string() {
2447 let source = r#"
2448from runar import SmartContract, ByteString, public, assert_
2449
2450class HexTest(SmartContract):
2451 data: ByteString
2452
2453 @public
2454 def check(self):
2455 val: ByteString = b'\xde\xad'
2456 assert_(val == self.data)
2457"#;
2458
2459 let result = parse_python(source, Some("HexTest.runar.py"));
2460 assert!(result.errors.is_empty(), "errors: {:?}", result.errors);
2461 let contract = result.contract.unwrap();
2462 let body = &contract.methods[0].body;
2463
2464 if let Statement::VariableDecl { init, .. } = &body[0] {
2465 if let Expression::ByteStringLiteral { value } = init {
2466 assert_eq!(value, "dead");
2467 } else {
2468 panic!("Expected ByteStringLiteral, got {:?}", init);
2469 }
2470 }
2471 }
2472
2473 #[test]
2474 fn test_shift_operators() {
2475 let source = r#"
2476from runar import SmartContract, Bigint, public, assert_
2477
2478class ShiftTest(SmartContract):
2479 x: Bigint
2480
2481 @public
2482 def check(self, n: Bigint):
2483 a: Bigint = self.x << n
2484 b: Bigint = self.x >> n
2485 assert_(a + b > 0)
2486"#;
2487
2488 let result = parse_python(source, Some("ShiftTest.runar.py"));
2489 assert!(result.errors.is_empty(), "errors: {:?}", result.errors);
2490 let contract = result.contract.unwrap();
2491 let body = &contract.methods[0].body;
2492
2493 if let Statement::VariableDecl { init, .. } = &body[0] {
2495 if let Expression::BinaryExpr { op, .. } = init {
2496 assert_eq!(*op, BinaryOp::Shl);
2497 }
2498 }
2499 if let Statement::VariableDecl { init, .. } = &body[1] {
2501 if let Expression::BinaryExpr { op, .. } = init {
2502 assert_eq!(*op, BinaryOp::Shr);
2503 }
2504 }
2505 }
2506}