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