forked from softpano/pythonizer
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathPerlscan.pm
9926 lines (9495 loc) · 516 KB
/
Perlscan.pm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
package Perlscan;
## ABSTRACT: Lexical analysis module for Perl -- parses one line of Perl program (which should contain a complete statement) into tokens/lexems
## For alpha-testers only. Should be used with Pythoinizer testing suit
##
## Copyright Nikolai Bezroukov, 2019-2020.
## Licensed under Perl Artistic license
##
## REQURES
## pythonizer.pl
## Pythonizer.pm
## Softpano.pm
#--- Development History
#
# Ver Date Who Modification
# ==== ========== ======== ==============================================================
# 0.10 2019/10/09 BEZROUN Initial implementation
# 0.20 2019/11/13 BEZROUN Tail comment is now treated as a special case and does not produce a lexem
# 0.30 2019/11/14 BEZROUN Parsing of literals completly reorganized.
# 0.40 2019/11/14 BEZROUN For now double quoted string are translatied into concatenation of components
# 0.50 2019/11/15 BEZROUN Better parsing of Perl literals implemented
# 0.51 2019/11/19 BEZROUN Problem of translation of ` ` (and rx() is that it is Python version dependent
# 0.52 2019/11/20 BEZROUN Problem of translation of tr/abc/def/ solved
# 0.53 2019/12/20 BEZROUN Here strings are now processed
# 0.60 2020/02/03 BEZROUN Allow processing multiline statements
# 0.61 2020/02/03 BEZROUN If the line does not ends with ; ){ or } we assume that the statement is continued on the next line
# 0.62 2020/05/16 BEZROUN Nesting is performed from this module
# 0.63 2020/06/15 BEZROUN Tail comments are artifically made properties of the last token in the line
# 0.64 2020/08/06 BEZROUN gen_statement moved from pythonizer, ValCom became a local array
# 0.65 2020/08/08 BEZROUN Diamond operator (<> <HANDLE>) is treated now as identifier
# 0.66 2020/08/09 BEZROUN gen_chunk moved to Perlscan module. Pythoncode array made local
# 0.70 2020/08/10 BEZROUN Postfix statements accomodated
# 0.71 2020/08/11 BEZROUN scanning of regular expressions improved. / qr and 'm' are treated uniformly
# 0.72 2020/08/12 BEZROUN Perl_default_var is renamed to default_var
# 0.73 2020/08/14 BEZROUN Decoding of system variables in double quoted literals implemented
# 0.74 2020/08/18 BEZROUN f-strings are generated for double quoted literals for Python 3.8
# 0.75 2020/08/25 BEZROUN variable for other namespaces are recognized now
# 0.76 2020/08/27 BEZROUN Special subroutine for putting regex in quote created
# 0.80 2020/08/31 BEZROUN Handling of regex improved, keywords are added,
# 0.81 2020/08/31 BEZROUN Handling of % improved.
# 0.82 2020/09/01 BEZROUN my is eliminated, unless is the first token (for my $i...)
# 0.83 2020/09/02 BEZROUN if regex contains both single and double quotes use """. Same for tranlation of double quoted
# 0.90 2020/09/17 BEZROUN Adapted for detection of global identifiers.
# 0.91 2020/09/18 BEZROUN ValType array added and now used in pass 0: values set to 'X' for special variables
# 0.92 2020/10/12 BEZROUN Better special var handling. Many bug fixes
# 0.93 2021/11/21 SNOOPYJC See specific changes in main module
#==start=============================================================================================
use v5.10.1;
use warnings;
#use strict 'subs';
use feature 'state';
use Softpano qw(abend logme out);
#use Pythonizer qw(correct_nest getline prolog epilog output_line);
use Pyconfig; # issue 32
use Text::Balanced qw{extract_bracketed}; # issue 53
require Exporter;
use Data::Dumper; # issue 108
use Storable qw(dclone); # SNOOPYJC
use Carp qw(cluck); # SNOOPYJC
use charnames qw/:full :short/; # SNOOPYJC
use File::Basename; # SNOOPYJC
use File::Spec::Functions qw(file_name_is_absolute catfile); # SNOOPYJC
use Encode qw/find_encoding/; # issue s70
our ($VERSION, @ISA, @EXPORT, @EXPORT_OK, %EXPORT_TAGS);
@ISA = qw(Exporter);
@EXPORT = qw(gen_statement tokenize gen_chunk append replace destroy insert destroy autoincrement_fix @ValClass @ValPerl @ValPy @ValCom @ValType $TokenStr escape_keywords unescape_keywords %SPECIAL_FUNCTION_MAPPINGS save_code restore_code %token_precedence %SpecialVarsUsed @EndBlocks %SpecialVarR2L get_sub_vars_with_class %FileHandles add_package_to_mapped_name %FuncType %PyFuncType %UseRequireVars %UseRequireOptionsPassed %UseRequireOptionsDesired mapped_name %WHILE_MAGIC_FUNCTIONS %UseSwitch @BeginBlocks @InitBlocks @CheckBlocks @UnitCheckBlocks special_code_block_name ok_to_break_line handle_block_scope_pragma); # issue 41, issue 65, issue 74, issue 92, issue 93, issue 78, issue names, issue s40, issue s129, issue s155, issue s228, use integer, use English
#our (@ValClass, @ValPerl, @ValPy, $TokenStr); # those are from main::
$VERSION = '0.93';
#
# types of veriables detected during the first pass; to be implemented later
#
#%is_numeric=();
%SpecialVarsUsed=(); # SNOOPYJC: Keep track of special vars used so we can generate better code if you don't use some feature
%NameMap=(); # issue 92: Map names to python names (Original python name => {sigil => new python name, ...})
%ReverseNameMap=(); # issue s172: New python name => Original python name
@EndBlocks=(); # SNOOPYJC: List of END blocks with their unique names
@BeginBlocks=(); # issue s155: List of BEGIN blocks with their unique names
@InitBlocks=(); # issue s155: List of INIT blocks with their unique names
@CheckBlocks=(); # issue s155: List of CHECK blocks with their unique names
@UnitCheckBlocks=(); # issue s155: List of UNITCHECK blocks with their unique names
%SpecialVarR2L=(); # SNOOPYJC: Map from special var RHS to LHS
%FileHandles = (); # SNOOPYJC: Set of file handles used in this file
@UseLib=(); # SNOOPYJC: Paths added using "use lib"
%UseSwitch=(); # issue s129: use Switch: set of what's passed on the use statement like __ or fallthrough
$fullpy = undef; # SNOOPYJC: Path to python file of package ref
%UseRequireVars=(); # issue names: map from fullpath to setref of perl varnames
%UseRequireOptionsPassed=(); # issue names: map from fullpath to string of options that were sent to pythonizer
%UseRequireOptionsDesired=(); # issue names: map from fullpath to string of options we want passed to pythonizer
%BlockScopePragmas=(); # use integer, use English
%StatementStartingLno=(); # issue s275: Map from line number to statement_starting_lno
#
# List of Perl special variables
#
# NOTE: If you add more to this hash, update $specials in decode_scalar, defined below
%SPECIAL_VAR=(';'=>'PERL_SUBSCRIPT_SEPARATOR','>'=>'os.geteuid()','<'=>'os.getuid()',
'('=>"' '.join(map(str, [os.getgid()] + os.getgroups()))", # issue s335
')'=>"' '.join(map(str, [os.getegid()] + os.getgroups()))", # issue s335
'?'=>"$SUBPROCESS_RC",
#SNOOPYJC '!'=>'unix_diag_message',
'!'=>'OS_ERROR', # SNOOPYJC
# SNOOPYJC '$'=>'process_number',
'$'=>'os.getpid()', # SNOOPYJC
';'=>'subscript_separator,',
# SNOOPYJC ']'=>'perl_version',
']'=>"$PERL_VERSION", # SNOOPYJC
#SNOOPYJC '&'=>'last_successful_match',
'&'=>"$DEFAULT_MATCH.group(0)", # SNOOPYJC, issue 32
'@'=>'EVAL_ERROR', # SNOOPYC
'"'=>'LIST_SEPARATOR', # issue 46
'|'=>'OUTPUT_AUTOFLUSH', # SNOOPYJC
'`'=>"$DEFAULT_MATCH.string[:$DEFAULT_MATCH.start()]", # SNOOPYJC
"'"=>"$DEFAULT_MATCH.string[$DEFAULT_MATCH.end():]", # SNOOPYJC
'-'=>"$DEFAULT_MATCH.start", # SNOOPYJC: Needs fixing at end to change [...] to (...)
'+'=>"$DEFAULT_MATCH.end", # SNOOPYJC: Needs fixing at end to change [...] to (...)
'/'=>'INPUT_RECORD_SEPARATOR',','=>'OUTPUT_FIELD_SEPARATOR','\\'=>'OUTPUT_RECORD_SEPARATOR',
'%'=>'FORMAT_PAGE_NUMBER', '='=>'FORMAT_LINES_PER_PAGE', '~'=>'FORMAT_NAME', '^'=>'FORMAT_TOP_NAME', # SNOOPYJC
':'=>'FORMAT_LINE_BREAK_CHARACTERS',
'*'=>'MATCH_MULTIPLE_LINES', # issue s140
);
%SPECIAL_VAR2=('O'=>'_os_name', # SNOOPYJC: was os.name
'T'=>'OS_BASETIME', 'V'=>'sys.version[0]', 'X'=>'sys.executable', # $^O and friends
'L'=>'FORMAT_FORMFEED', # SNOOPYJC
'T'=>'BASETIME', # SNOOPYJC
'F'=>2, # SNOOPYJC
'S'=>'EXCEPTIONS_BEING_CAUGHT', # issue s282
'W'=>'WARNING'); # SNOOPYJC
%SPECIAL_VAR_FULL=(TAINT=>'False', SAFE_LOCALES=>'False', UNICODE=>'0', UTF8CACHE=>'True', UTF8LOCALE=>'True'); # issue s23
%SpecialVarType=('.'=>'I', '?'=>'S', '!'=>'I', '$'=>'I', ';'=>'S', ']'=>'F',
'0'=>'S', '@'=>'S', '"'=>'S', '|'=>'I', '/'=>'m', ','=>'S', # changed '/' to 'm' to distinguish undef from ''
'^O'=>'S', '^T'=>'S', '^V'=>'S', '^X'=>'S', '^W'=>'I',
'^TAINT'=>'I', '^SAFE_LOCALES'=>'I', '^UNICODE'=>'I', 'UTF8CACHE'=>'I', 'UTF8LOCALE'=>'I', # issue s23
'&'=>'S', '1'=>'S', '2'=>'S', '3'=>'S', '4'=>'S',
'5'=>'S', '6'=>'S', '7'=>'S', '8'=>'S', '9'=>'S',
'-'=>'I', '+'=>'I', '('=>'S', ')'=>'S', '>'=>'I', '<'=>'I',
'%'=>'I', '='=>'I', '~'=>'S', '^'=>'S', ':'=>'S',
'_'=>'s');
# issue s359 %SpecialArrayType=('ARGV'=>'a of S', '_'=>'a of m', 'INC'=>'a of S');
%SpecialArrayType=('ARGV'=>'a of m', '_'=>'a of m', 'INC'=>'a of S'); # issue s359: .get(...) a non-existent element needs to eq ''
%SpecialHashType=('ENV'=>'h of m'); # Not 'h of S' as when we pull a non-existant key we get None!
# NOTE: If you add to this, add the type of the scalar function to %SPECIAL_FUNCTION_TYPES below!!
# Map of functions to python where the mapping is different for scalar and list context
%SPECIAL_FUNCTION_MAPPINGS=('localtime'=>{scalar=>'tm_py.ctime', list=>'_localtime'}, # issue times
'gmtime'=>{scalar=>'_cgtime', list=>'_gmtime'}, # issue times
'splice'=>{scalar=>'_splice_s', list=>'_splice'}, # issue splice
'reverse'=>{list=>'[::-1]', scalar=>'_reverse_scalar'}, # issue 65
'grep'=>{list=>'filter', scalar=>'filter_s'}, # issue 37: Note: The "_s" gets removed when emitting the code
'map'=>{list=>'map', scalar=>'map_s'}, # issue 37: Note: The "_s" gets removed when emitting the code
'keys'=>{list=>'.keys()', scalar=>'.keys()_s'}, # issue s3: Note: The "_s" gets removed when emitting the code
'values'=>{list=>'.values()', scalar=>'.values()_s'}, # issue s3: Note: The "_s" gets removed when emitting the code
'chomp'=>{list=>'.rstrip("\n")', scalar=>'.rstrip("\n")_s'}, # issue s48: Note: The "_s" gets removed when emitting the code
'chop'=>{list=>'[0:-1]', scalar=>'[0:-1]_s'}, # issue s48: Note: The "_s" gets removed when emitting the code
'split'=>{list=>'_split', scalar=>'_split_s'}, # issue s52
'readdir'=>{list=>'_readdirs', scalar=>'_readdir'}, # issue s40
'readline'=>{list=>'.readlines()', scalar=>'_readline_full'}, # issue s40
'caller'=>{list=>'_caller', scalar=>'_caller_s'}, # issue s177
);
%SPECIAL_FUNCTION_TYPES=('tm_py.ctime'=>'I?:S', '_cgtime'=>'I?:S', '_splice_s'=>'aI?I?a?:s',
'.keys()_s'=>'h:I', '.values()_s'=>'h:I', # issue s3
'_readdir'=>'H:S', '_readline_full'=>'H:S', # issue s40
'.rstrip("\n")_s'=>'S:m', '[0:-1]_s'=>'S:m', # issue s48
'_split_s'=>'S?S?I?:I', # issue s52, issue s246: Add the '?' to everything
'_reverse_scalar'=>'a of S?:S', # test reverse
# issue s153 'filter_s'=>'Sa:I',
'filter_s'=>'sa:I', # issue s153
'caller_s'=>'I?:m', # issue s177
'map_s'=>'fa:I');
# issue s40:
# From the documentation: If the condition expression of a while statement is
# based on any of a group of iterative expression types then it gets some magic
# treatment. The affected iterative expression types are readline, the <FILEHANDLE>
# input operator, readdir, glob, the <PATTERN> globbing operator, and each. If the
# condition expression is one of these expression types, then the value yielded by
# the iterative operator will be implicitly assigned to $_. If the condition
# expression is one of these expression types or an explicit assignment of one of
# them to a scalar, then the condition actually tests for definedness of the
# expression's value, not for its regular truth value.
%WHILE_MAGIC_FUNCTIONS=('glob'=>1, 'readline'=>1, 'readdir'=>1,
# this one causes problems: 'each'=>1,
); # issue s40
%keyword_tr=('eq'=>'==','ne'=>'!=','lt'=>'<','gt'=>'>','le'=>'<=','ge'=>'>=',
'and'=>'and','or'=>'or','not'=>'not',
'x'=>' * ',
'abs'=>'abs', # SNOOPYJC
'alarm'=>'signal.alarm', # issue 81
'assert'=>'assert', # SNOOPYJC
'atan2'=>'math.atan2', # SNOOPYJC
'basename'=>'_basename', # SNOOPYJC
'binmode'=>'_dup', # SNOOPYJC
'bless'=>'_bless','BEGIN'=>'for _ in range(1):', # SNOOPYJC, issue s12
'UNITCHECK'=>'for _ in range(1):', 'CHECK'=>'for _ in range(1):', 'INIT'=>'for _ in range(1):', # SNOOPYJC, issue s12
# SNOOPYJC 'caller'=>q(['implementable_via_inspect',__file__,sys._getframe().f_lineno]),
'caller'=>'_caller', # issue s195
# issue 54 'chdir'=>'.os.chdir','chmod'=>'.os.chmod',
'carp'=>'_carp', 'confess'=>'_confess', 'croak'=>'_croak', 'cluck'=>'_cluck', # SNOOPYJC
'longmess'=>'_longmess', 'shortmess'=>'_shortmess', # SNOOPYJC
'chdir'=>'_chdir','chmod'=>'_chmod', # issue 54
'chomp'=>'.rstrip("\n")','chop'=>'[0:-1]','chr'=>'chr',
# issue close 'close'=>'.f.close',
'close'=>'_close_', # issue close, issue 72, issue test coverage
'cmp'=>'_cmp', # SNOOPYJC
'cos'=>'math.cos', # issue s3
# issue 42 'die'=>'sys.exit',
'die'=>'raise Die', # issue 42
'dirname'=>'_dirname', # SNOOPYJC
'defined'=>'unknown', 'delete'=>'.pop(','defined'=>'perl_defined',
'each'=>'_each', # SNOOPYJC
'END'=>'_END_', # SNOOPYJC
'exp'=>'math.exp', # issue s3
'__expand'=>"$DEFAULT_MATCH.expand", # issue s131
'for'=>'for','foreach'=>'for', # SNOOPYJC: remove space from each
'else'=>'else: ','elsif'=>'elif ',
# issue 42 'eval'=>'NoTrans!',
'eval'=>'try', # issue 42
'exec'=>'_exec', # issue s247
'exit'=>'sys.exit','exists'=> 'in', # if key in dictionary 'exists'=>'.has_key'
'fc'=>'.casefold()', # SNOOPYJC
'flock'=>'_flock', # issue flock
'fileno'=>'_fileno', # SNOOPYJC
'fileparse'=>'_fileparse', # SNOOPYJC
'fork'=>'os.fork', # SNOOPYJC
'glob'=>'glob.glob', # SNOOPYJC
'hex'=>'int', # SNOOPYJC
'if'=>'if ', 'index'=>'.find',
'int'=>'_int', # issue int
'isa'=>'_isa', # issue s54
'getopt'=>'getopt', 'getopts'=>'getopt', # issue s67
'GetOptions'=>'argparse', # issue 48
'gmtime'=>'_gmtime', # issue times
'grep'=>'filter', 'goto'=>'goto', 'getcwd'=>'os.getcwd',
'join'=>'.join(',
# issue 33 'keys'=>'.keys',
'keys'=>'.keys()', # issue 33
'kill'=>'_kill', # SNOOPYJC
'last'=>'break', 'local'=>'', 'lc'=>'.lower()',
'lcfirst'=>'_lcfirst', # SNOOPYJC
'length'=>'lens', # SNOOPYJC
# issue localtime 'localtime'=>'.localtime',
'localtime'=>'_localtime', # issue times
'log'=>'math.log', # issue s3
'lstat'=>'_lstat', # SNOOPYJC
'map'=>'map',
# issue mkdir 'mkdir'=>'os.mkdir',
'mkdir'=>'_mkdir', # issue mkdir
'my'=>'',
'next'=>'continue',
# SNOOPYJC 'no'=>'NoTrans!',
'no'=>'import', # SNOOPYJC: for "no autovivification;";
# SNOOPYJC 'own'=>'global',
# SNOOPYJC 'oct'=>'oct',
'oct'=>'int', # SNOOPYJC: oct is the reverse in python!
'ord'=>'ord',
'our'=>'', # SNOOPYJC
'pack'=>'_pack', # SNOOPYJC
'package'=>'package', 'pop'=>'.pop()', 'push'=>'.extend(',
'pos'=>'pos', # SNOOPYJC
# SNOOPYJC 'printf'=>'print',
'printf'=>'printf', # SNOOPYJC: Don't have the same python name for both print and printf so PyFuncType is distinct
'quotemeta'=>'_quotemeta', # SNOOPYJC, issue s28
'rename'=>'os.replace', # SNOOPYJC
'say'=>'print','scalar'=>'len', 'shift'=>'.pop(0)',
'sin'=>'math.sin', # issue s3
'splice'=>'_splice', # issue splice
# SNOOPYJC 'split'=>'re.split',
'split'=>'_split', # SNOOPYJC perl split has different semantics on empty matches at the end
'seek'=>'_seek', # SNOOPYJC
# issue 34 'sort'=>'sort',
'sleep'=>'tm_py.sleep', # SNOOPYJC
'sqrt'=>'math.sqrt', # SNOOPYJC
'sort'=>'sorted', # issue 34
'state'=>'global',
'rand'=>'_rand', # SNOOPYJC
'read'=>'.read', # issue 10
'readlink'=>'_readlink', # issue s128
'stat'=>'_stat','sysread'=>'.sysread',
'substr'=>'_substr','sub'=>'def','STDERR'=>'sys.stderr','STDIN'=>'sys.stdin', # issue bootstrap
# SNOOPYJC 'system'=>'os.system',
'system'=>'_system', # SNOOPYJC
'sprintf'=>'_sprintf',
'STDOUT'=>'sys.stdout', # issue 10
# SNOOPYJC 'sysseek'=>'perl_sysseek',
'sysseek'=>'_sysseek', # SNOOPYJC
'STDERR'=>'sys.stderr','STDIN'=>'sys.stdin', '__LINE__' =>'sys._getframe().f_lineno',
'__FILE__'=>'__file__', # SNOOPYJC
'__SUB__'=>'_sub', # SNOOPYJC
'reverse'=>'[::-1]', # issue 65
'rindex'=>'.rfind',
# SNOOPYJC 'ref'=>'type',
'ref'=>'_ref', # SNOOPYJC
# SNOOPYJC 'require'=>'NoTrans!',
'opendir'=>'_opendir', 'closedir'=>'_closedir',
'readdir'=>'_readdirs', # issue s40: Start with the list version
'seekdir'=>'_seekdir', 'telldir'=>'_telldir', 'rewinddir'=>'_rewinddir', # SNOOPYJC
'readline'=>'.readlines()', # issue s40
'redo'=>'continue', # SNOOPYJC
'require'=>'__import__', # SNOOPYJC
'return'=>'return', 'rmdir'=>'_rmdir',
'tell'=>'_tell', # SNOOPYJC
# issue s154 'tie'=>'NoTrans!',
'time'=>'_time', # SNOOPYJC
'timelocal'=>'_timelocal', # issue times
'timegm'=>'_timegm', # issue times
'truncate'=>'_truncate', # SNOOPYJC
'uc'=>'.upper()',
# issue s28 'ucfirst'=>'.capitalize()',
'ucfirst'=>'_ucfirst', # issue s28
'undef'=>'None', 'unless'=>'if not ',
# issue s94 'unlink'=>'os.unlink',
'unlink'=>'_unlink', # issue s94
'umask'=>'os.umask', # SNOOPYJC
'unshift'=>'.insert(0,',
# SNOOPYJC 'use'=>'NoTrans!',
'use'=>'import',
'unpack'=>'_unpack', # SNOOPYJC
'until'=>'while not ',
# issue s154 'untie'=>'NoTrans!',
'utime'=>'_utime', # issue s32
'values'=>'.values()', # SNOOPYJC
# issue s101 'warn'=>'print',
'warn'=>'_warn', # issue s101, issue s288
'wait'=>'_wait', # SNOOPYJC
'waitpid'=>'_waitpid', # SNOOPYJC
'xor'=>'_logical_xor', # issue s237
# issue s3 'wantarray'=>'True', # SNOOPYJC
);
#
# TOKENS TYPES:
# a => Array like @arr
# b
# c => Control like if, for, foreach, while, unless, until, ...
# d => Digits like 123 or 12.34 or .5
# e
# f => Built-in function like abs, atan2, basename, or chomp
# g => Glob like <*.c>
# h => Hashname like %hash
# i => BareWord like ABC or abc - could be a local sub name
# j => Diamond like <> or <$fh> or <FH>
# k => Special control like last, next, return, or sub
# l, m,
# n => not
# o => or, and, xor - lower precedence than || &&
# p => => Pattern match like =~ or !~ (issue s151: distinguish ~ from p)
# q => Pattern like m/.../, s/../.../, tr/../../, or wr, or /.../
# r => range (..)
# s => Scalar like $var
# t => Variable type like local, my, own, state
# u, v, w
# x => Executable in `...` or qx
# y => Extra python code we need to generate as is (used in multi_subscripts)
# z
# A => => (arrow)
# B
# C => More control like default, else, elsif
# D => -> (dot in python)
# E
# F => Named Unary Operators (not generated, but used in calls to next_lower_or_equal_precedent_token)
# G => TypeGlob *name
# H => Here doc <<
# I => >>
# J, K, L,
# M => ~~ (smartMatch)
# N, O
# P => :: (package reference)
# Q, R
# S => isa (as operator) # issue s287
# T..V
# W => Context manager (with)
# X..Z
# 0 => &&, ||
# ^ => ++ or --
# > => comparison like > < >= <= == eq ne lt gt le ge
# = => assignment like = += -= etc
# ? => ? (part of ? : )
# : => :
# . => . or ::
# * => *, **, or x
# ! => !
# +, -, /, % => Operators
# ~ => ~ (issue s151)
# " => Quoted string or q/abc/, qq(def), etc
%token_precedence=(
# Prec Assoc Token Desc
c=>26, C=>26, k=>26, W=>26,
# 25 left ashi terms and list operators (leftward)
a=>25, s=>25, h=>25, i=>25, '('=>25, ')'=>25, '"'=>25, q=>25, x=>25, f=>25, G=>25,
# 24 left D ->
D=>24,
# 23 nonassoc ^ ++ --
'^'=>23,
# 22 right * **
#'*'=>22,
# 21 right !~\+- ! ~ ~. \ and unary + and -
'!'=>21, '\\'=>21, '~'=>21, # issue s151
# 20 left p =~ !~
'p'=>20, # issue s151
# 19 left */% * / % x
'*'=>19, '/'=>19, '%'=>19,
# 18 left +-. + - .
'+'=>18, '-'=>18, '.'=>18,
# 17 left HI << >>
H=>17, I=>17,
# 16 nonassoc f named unary operators
F=>16, # Used in a call to next_lower_or_equal_precedent_token; issue s190: also used for weak functions
# 15 nonassoc N/A isa
S=>15, # issue s287
# 14 chained > < > <= >= lt gt le ge
'>'=>14,
# 13 chain/na > == != eq ne <=> cmp ~~
'M'=>13, # issue s251
# 12 left & & &.
'&'=>12,
# 11 left | | |. ^ ^.
'|'=>11,
# 10 left 0 &&
'0'=>10,
# 9 left 0 || //
# 8 nonassoc r .. ...
'r'=>8,
# 7 right ?: ?:
'?'=>7, ':'=>7,
# 6 right = = += -= *= etc. goto last next redo dump
'='=>6,
# 5 left ,A , =>
','=>5, A=>5,
# 4 nonassoc f list operators (rightward)
# 3 right n not
n=>3,
# 2 left o and
# 1 left o or xor
o=>1);
%TokenType=('eq'=>'>','ne'=>'>','lt'=>'>','gt'=>'>','le'=>'>','ge'=>'>',
'x'=>'*',
'y'=>'q', 'q'=>'q','qq'=>'q','qr'=>'q',
# issue 44 'wq'=>'q',
'qw'=>'q', # issue 44
'wr'=>'q','qx'=>'q','m'=>'q','s'=>'q','tr'=>'q',
# issue 93 'and'=>'0',
'and'=>'o', # issue 93
'abs'=>'f', # SNOOPYJC
'alarm'=>'f', # issue 81
'assert'=>'c', # SNOOPYJC
'atan2'=>'f', # SNOOPYJC
'autoflush'=>'f', # SNOOPYJC
'basename'=>'f', # SNOOPYJC
'binmode'=>'f', # SNOOPYJC
'bless'=>'f', # SNOOPYJC
'break'=>'k', # issue s129
'caller'=>'f','chdir'=>'f','chomp'=>'f', 'chop'=>'f', 'chmod'=>'f','chr'=>'f','close'=>'f',
'chop_'=>'f', 'chomp_'=>'f', # issue s148
'continue'=>'C', # SNOOPYJC
'cos'=>'f', # issue s3
'carp'=>'f', 'confess'=>'f', 'croak'=>'f', 'cluck'=>'f', # SNOOPYJC
'longmess'=>'f', 'shortmess'=>'f', # SNOOPYJC
'cmp'=>'>', # SNOOPYJC: comparison
'delete'=>'f', # issue delete
'default'=>'C','defined'=>'f','die'=>'f',
'dirname'=>'f', # SNOOPYJC
'do'=>'C', # SNOOPYJC
'each'=>'f', # SNOOPYJC
'else'=>'C', 'elsif'=>'C', 'exists'=>'f', 'exit'=>'f',
# issue s280: No such function!!! 'export'=>'f',
'exec'=>'f', # issue s247
'__expand'=>'f', # issue s131
'exp'=>'f', # issue s3
'eval'=>'C', # issue 42
'fc'=>'f', # SNOOPYJC
'fileno'=>'f', # SNOOPYJC
'fileparse'=>'f', # SNOOPYJC
'flock'=>'f', # issue flock
'fork'=>'f', # SNOOPYJC
'glob'=>'f', # SNOOPYJC
'if'=>'c', 'index'=>'f',
'int'=>'f', # issue int
'isa'=>'f', # issue s54, issue s287: This could also be 'S' when it's an operator
'for'=>'c', 'foreach'=>'c',
'getopt'=>'f', 'getopts'=>'f', # issue s67
'GetOptions'=>'f', # issue 48
'goto'=>'k', # SNOOPYJC
'given'=>'c','grep'=>'f',
'hex'=>'f', # SNOOPYJC
'join'=>'f',
'keys'=>'f',
'kill'=>'f', # SNOOPYJC
'last'=>'k', 'lc'=>'f', 'length'=>'f', 'local'=>'t', 'localtime'=>'f',
'lcfirst'=>'f', # SNOOPYJC
'log'=>'f', # issue s3
'lstat'=>'f',
'my'=>'t', 'map'=>'f', 'mkdir'=>'f',
'next'=>'k','not'=>'!',
'no'=>'k', # SNOOPYJC
'our'=>'t', # SNOOPYJC
# issue 93 'or'=>'0',
'or'=>'o', # issue 93
# SNOOPYJC 'own'=>'t',
'oct'=>'f', 'ord'=>'f', 'open'=>'f',
'opendir'=>'f', 'closedir'=>'f', 'readdir'=>'f', 'seekdir'=>'f', 'telldir'=>'f', 'rewinddir'=>'f', # SNOOPYJC
'readline'=>'f', # issue s40
'push'=>'f', 'pop'=>'f', 'print'=>'f', 'package'=>'c',
'pack'=>'f',
'pos'=>'f', # SNOOPYJC
'printf'=>'f', # SNOOPYJC
'quotemeta'=>'f', # SNOOPYJC
'rand'=>'f', # SNOOPYJC
'redo'=>'k', # SNOOPYJC
'require'=>'k', # SNOOPYJC
'rindex'=>'f','read'=>'f',
'readlink'=>'f', # issue s128
'rename'=>'f', # SNOOPYJC
# issue 61 'return'=>'f',
'return'=>'k', # issue 61
'reverse'=>'f', # issue 65
'ref'=>'f',
'rmdir'=>'f', # SNOOPYJC
'say'=>'f','scalar'=>'f','shift'=>'f',
'select'=>'f', # SNOOPYJC
'sin'=>'f', # issue s3
'splice'=>'f', # issue splice
'split'=>'f', 'sprintf'=>'f', 'sort'=>'f','system'=>'f', 'state'=>'t',
'seek'=>'f', # SNOOPYJC
'sleep'=>'f', # SNOOPYJC
'sqrt'=>'f', # SNOOPYJC
'stat'=>'f','sub'=>'k','substr'=>'f','sysread'=>'f', 'sysseek'=>'f',
'stat_cando'=>'f',
'tell'=>'f', # SNOOPYJC
'tie'=>'f',
'tied'=>'f', # issue s154
'time'=>'f', 'gmtime'=>'f', 'timelocal'=>'f', 'timegm'=> 'f', # SNOOPYJC
'truncate'=>'f', # SNOOPYJC
'unlink'=>'f', # SNOOPYJC
'unpack'=>'f', # SNOOPYJC
'use'=>'k', # SNOOPYJC
'values'=>'f',
'warn'=>'f',
'when'=>'c', # issue s129
'while'=>'c',
'undef'=>'f', 'unless'=>'c', 'unshift'=>'f','until'=>'c','uc'=>'f', 'ucfirst'=>'f',
# SNOOPYJC 'use'=>'c',
'untie'=>'f',
'umask'=>'f', # SNOOPYJC
'utime'=>'f', # issue s32
'wait'=>'f', # SNOOPYJC
'waitpid'=>'f', # SNOOPYJC
'wantarray'=>'d', # SNOOPYJC
'xor'=>'o', # issue s237
'__FILE__'=>'"', '__LINE__'=>'d', '__PACKAGE__'=>'"', '__SUB__'=>'f', # SNOOPYJC
);
# NB: Use ValPerl[$i] as the key here!
%FuncType=( # a=Array, h=Hash, s=Scalar, I=Integer, F=Float, N=Numeric, S=String, u=undef, f=function, H=FileHandle, ?=Optional, m=mixed
'tie'=>'mSa?:s', 'untie'=>'m', 'tied'=>'m:s', # issue s154
'chop_'=>':S', 'chomp_'=>':S', # issue s148: New postfix versions
'_num'=>'m:N', '_int'=>'m:I', '_str'=>'m:S',
'_bn'=>'m:s', # issue s117
'_pb'=>'B:s', # issue s124
'_sl'=>'a:a', # issue s308
'_flt'=>'m:F', # issue s3
'_map_int'=>'a:a of I', '_map_num'=>'a:a of N', '_map_str'=>'a:a of S',
'_assign_global'=>'SSm:m', '_read'=>'HsII?:s',
'_set_breakpoint'=>':u', # issue s62
'__expand'=>'R:S', # issue s131
'xor' => 'mm:B', # issue s237
'_logical_xor' => 'mm:B', # issue s237
'exp'=>'F:F', 'log'=>'F:F', 'cos'=>'F:F', 'sin'=>'F:F', # issue s3
'$#'=>'a:I', # issue 119: _last_ndx
're'=>':S', 'tr'=>':S', # SNOOPYJC, issue s252: add ':'
'abs'=>'N:N', 'alarm'=>'N:N', 'atan2'=>'NN:F',
'autoflush'=>'I?:I', 'basename'=>'S:S', 'binmode'=>'HS?:m',
# issue s154 'bless'=>'mS?:m', # SNOOPYJC
'bless'=>'mm?:m', # SNOOPYJC, issue s154: bless function will take a class or instance, not just str
'caller'=>'I?:a',
'can'=>'mS:m', # issue s180
'carp'=>'a:u', 'confess'=>'a:u', 'croak'=>'a:u', 'cluck'=>'a:u', # SNOOPYJC
'longmess'=>'a:S', 'shortmess'=>'a:S', # SNOOPYJC
'chdir'=>'S:I',
# issue s48 'chomp'=>'S:m', 'chop'=>'S:m',
'chomp'=>'a?:m', 'chop'=>'a?:m', # issue s48
'chmod'=>'Ia:I','chr'=>'I?:S','close'=>'H:I',
# issue s238 'cmp'=>'SS:I',
'cmp'=>'mm:I', # issue s238: Don't convert to str here because it could be an object
'<=>'=>'NN:I',
# issue s262 '~~'=>'mm:I', # issue s251
'~~'=>'aa:I', # issue s251, issue s262: use list context for smartmatch
'delete'=>'u:a', 'defined'=>'u:I',
# issue s283 'die'=>'S:m',
'die'=>'a:m', # issue s283
'dirname'=>'S:S', 'each'=>'h:a', 'exists'=>'m:I',
# 'exec'=>'s?a:', # issue s247
'exec'=>'a:', # issue s247
'exit'=>'I?:u', 'fc'=>'S:S', 'flock'=>'HI:I', 'fork'=>':m', 'fileno'=>'H:I',
'fileparse'=>'Sm?:a of S', 'hex'=>'S?:I', 'GetOptions'=>'a:I',
'getopt'=>'a:I', 'getopts'=>'a:I', # issue s67
'glob'=>'S:a of S', 'index'=>'SSI?:I', 'int'=>'s:I',
# issue s153 'grep'=>'Sa:a of S',
'grep'=>'sa:a of S', # issue s153: Handle grep !/pat/, ...
'join'=>'Sa:S', 'keys'=>'h:a of S',
'isa'=>'mS:I', # issue s54
'kill'=>'mI:u', 'lc'=>'S:S', 'lstat'=>'m?:a of I',
'lcfirst'=>'S:S',
'length'=>'S:I', 'localtime'=>'I?:a of I', 'map'=>'fa:a', 'mkdir'=>'SI?:I', 'oct'=>'S?:I', 'ord'=>'S?:I',
# issue s166 'open'=>'HSS?:I',
'open'=>'HSs?:I', # issue s166: Don't convert the 3rd arg
'pack'=>'Sa:S',
'opendir'=>'HS:I', 'closedir'=>'H:I', 'readdir'=>'H:a of S', 'rename'=>'SS:I', 'rmdir'=>'S:I',
'readline'=>'H:a of S', # issue s40
'seekdir'=>'HI:I', 'telldir'=>'H:I', 'rewinddir'=>'H:m',
'push'=>'aa:I', 'pop'=>'a:s', 'pos'=>'s:I', 'print'=>'H?a:I', 'printf'=>'H?S?a:I', 'quotemeta'=>'S?:S', 'rand'=>'F?:F',
'rindex'=>'SSI?:I','read'=>'HsII?:I', '.read'=>'HsII?:I', 'reverse'=>'a?:a', 'ref'=>'u:S',
'readlink'=>'S:S', # issue s128
'_refs'=>'u:S', # issue s3
'say'=>'H?a:I',
# issue s254 'scalar'=>'a:I',
'scalar'=>'m:I', # issue s254
'seek'=>'HII:u', 'shift'=>'a?:s', 'sleep'=>'I:I', 'splice'=>'aI?I?a?:a',
'select'=>'H?:H', # SNOOPYJC
# issue s246 'split'=>'SSI?:a of m',
'split'=>'S?S?I?:a of m', # issue s246: add the '?' to everything
'sprintf'=>'Sa:S', 'sort'=>'f?a:a','system'=>'a:I',
'stat_cando'=>'aII:I', # issue s33
'sqrt'=>'N:F', 'stat'=>'m?:a of I', 'substr'=>'SII?S?:S','sysread'=>'HsII?:I', 'sysseek'=>'HII:I', 'tell'=>'H:I', 'time'=>':I', 'gmtime'=>'I?:a of I', 'timegm'=>'IIIIII:I',
'truncate'=>'HI:I',
'utime'=>'a:I', # issue s32
'timelocal'=>'IIIIII:I', 'unlink'=>'a?:I', 'values'=>'h:a', 'warn'=>'a:I', 'undef'=>'a?:u', 'unshift'=>'aa:I', 'uc'=>'S:S',
'unpack'=>'SS:a', 'ucfirst'=>'S:S', 'umask'=>'I?:I', 'wait'=>':I', 'waitpid'=>'II:I', '__SUB__'=>':f',
);
for my $func (values %ARRAY_INDEX_FUNCS) {
$FuncType{$func} = 'asN:N';
if($func =~ /concat/) {
$FuncType{$func} = 'asS:S';
} elsif($func =~ /set/) {
$FuncType{$func} = 'ass:s';
} elsif($func =~ /translate/) {
$FuncType{$func} = 'ass:S';
} elsif($func =~ /substitute/) {
$FuncType{$func} = 'asss:S';
}
}
%PyFuncType=(); # SNOOPYJC
for my $func (keys %FuncType) {
my $py = $func;
if(exists $keyword_tr{$func}) {
$py = $keyword_tr{$func};
}
$PyFuncType{$py} = $FuncType{$func};
}
%PyFuncType = (%PyFuncType, %SPECIAL_FUNCTION_TYPES); # SNOOPYJC: Add in the special scalar ones
# Handle a couple of special cases that are not words
$PyFuncType{_last_ndx} = $FuncType{'$#'};
$PyFuncType{_spaceship} = $FuncType{'<=>'};
$PyFuncType{_smartmatch} = $FuncType{'~~'}; # issue s251
$PyFuncType{_read} = $FuncType{read};
$PyFuncType{_sysread} = $FuncType{sysread};
$PyFuncType{_IOFile_open} = $FuncType{open};
$PyFuncType{_binmode} = $FuncType{binmode};
$PyFuncType{_assign_global} = 'SSm:m';
$PyFuncType{_substitute_global} = 'SSSS:s';
$PyFuncType{_translate_global} = 'SSm:s';
$PyFuncType{'signal.signal'} = 'If:f';
$PyFuncType{'signal.getsignal'} = 'I:f';
$PyFuncType{'pdb.set_trace'} = ':I';
$PyFuncType{'_get_element'} = 'mI:m'; # issue s43
$PyFuncType{'_set_element'} = 'msm:m'; # issue s148: _set_element works on Arrays and Hashes
$PyFuncType{_flatten} = 'a:a'; # issue s103
$PyFuncType{_chomp_with_result} = 'm:I'; # issue s167
$PyFuncType{_chop_with_result} = 'm:S'; # issue s167
$PyFuncType{_chop_without_result} = 'm:S'; # issue s167
$PYF_OUT_PARAMETERS{_chomp_with_result} = 1; # issue s167
$PYF_OUT_PARAMETERS{_chop_with_result} = 1; # issue s167
$PYF_OUT_PARAMETERS{_chop_without_result} = 1; # issue s167
$PyFuncType{_fetch_perl_global} = 'S:m'; # issue s176
$PyFuncType{_store_perl_global} = 'Smm?:m'; # issue s176
$PYF_OUT_PARAMETERS{_binmode} = 1; # issue s183
$PYF_OUT_PARAMETERS{_dup} = 1; # issue s183
$PYF_OUT_PARAMETERS{open} = 1; # issue s183
$PYF_OUT_PARAMETERS{_open} = 1; # issue s183
$PYF_OUT_PARAMETERS{'.read'} = 2; # issue s183
$PYF_OUT_PARAMETERS{'.sysread'} = 2; # issue s183
$PYF_OUT_PARAMETERS{'.rstrip("\n")'} = 1; # issue s183: chomp
$PYF_OUT_PARAMETERS{'[0:-1]'} = 1; # issue s183: chop
$PyFuncType{_store_out_parameter} = 'aImm?:m'; # issue s184
$PyFuncType{_fetch_out_parameter} = 'I:m'; # issue s184
$PyFuncType{_fetch_out_parameters} = 'mI?:m'; # issue s184
$PyFuncType{_init_out_parameters} = 'aa:'; # issue s184
$PyFuncType{setattr} = 'mSm:'; # issue s214
$PyFuncType{_get_subref} = 'm:m'; # issue s229
$PyFuncType{_method_call} = 'mSa?:m'; # issue s236
$PyFuncType{_raise} = 'm:';
$PyFuncType{lena} = 'a:I'; # issue s254: We put in this version of 'scalar' if they use a goatse to make sure the arg is in list context
$PyFuncType{_isa_op} = 'mS:B'; # issue s287
$PyFuncType{_reset_each} = 'h:'; # issue s309
$PyFuncType{_range_op} = 'II:a of I'; # issue s307
$PyFuncType{_list_to_hash} = 'a:h'; # issue s316
$PyFuncType{_set_signal} = 'mm:'; # issue s336
for my $d (keys %DASH_X) {
if($d =~ /[sMAC]/) { # issue s124
$FuncType{"-$d"} = 'm:I';
$PyFuncType{$DASH_X{$d}} = 'm:I';
} else { # issue s124
$FuncType{"-$d"} = 'm:B'; # issue s124: They now return boolean
$PyFuncType{$DASH_X{$d}} = 'm:B'; # issue s124
}
}
for my $pkg (keys %PREDEFINED_PACKAGES) { # See Pyconfig.pm
# test overload methods $BUILTIN_LIBRARY_SET{$pkg} = 1;
#$BUILTIN_LIBRARY_SET{$pkg} = 1 unless $pkg eq 'overload'; # test overload methods
$BUILTIN_LIBRARY_SET{$pkg} = 1;
for my $func_info (@{$PREDEFINED_PACKAGES{$pkg}}) {
if(exists $func_info->{import_it}) { # Needed for Time::HiRes (and overload)
delete $BUILTIN_LIBRARY_SET{$pkg};
next;
}
my $perl = $func_info->{perl};
my $type = $func_info->{type};
my $python = "_$perl";
$python = $func_info->{python} if(exists $func_info->{python});
if(exists $func_info->{calls}) {
$PYF_CALLS{$python} = $func_info->{calls};
}
if(exists $func_info->{out_parameter}) {
$PYF_OUT_PARAMETERS{$python} = $func_info->{out_parameter};
}
my $fullname = "${pkg}::$perl";
if(exists $func_info->{scalar}) {
my $scalar = $func_info->{scalar};
$SPECIAL_FUNCTION_MAPPINGS{$perl} = {scalar=>$scalar, list=>$python};
$SPECIAL_FUNCTION_MAPPINGS{$fullname} = {scalar=>$scalar, list=>$python};
if(exists $func_info->{scalar_calls}) {
$PYF_CALLS{$scalar} = $func_info->{scalar_calls};
}
$PyFuncType{$scalar} = $func_info->{scalar_type};
if(exists $func_info->{scalar_out_parameter}) {
$PYF_OUT_PARAMETERS{$scalar} = $func_info->{scalar_out_parameter};
}
}
if($perl ne 'new') {
$FuncType{$perl} = $type;
# issue s190 $TokenType{$perl} = 'f';
$TokenType{$perl} = 'F'; # issue s190: 'F' is a weak function, in other words, if there is a local sub of the same name it overrides it
if (exists $keyword_tr{$perl}) { # test_Time_HiRes: We will override this if the user imports the method
# NOTE: $::debug hasn't been set yet!!
#say STDERR "Found existing definition for $perl as $keyword_tr{$perl} as we're trying to set it to $python";
if($keyword_tr{$perl} ne $python) {
#say STDERR "Not overriding built-in $perl ($keyword_tr{$perl}) for new definition in $pkg ($python) unless it's imported";
;
}
} else {
$keyword_tr{$perl} = $python;
}
}
$PyFuncType{$python} = $type;
$TokenType{$fullname} = 'f';
$FuncType{$fullname} = $type;
$keyword_tr{$fullname} = $python;
}
}
#
# one to one translation of digramms. most are directly translatatble.
#
%digram_tokens=('++'=>'^', '--'=>'^', '+='=>'=', '-='=>'=', '.='=>'=', '%='=>'=',
'|='=>'=', '&='=>'=', # SNOOPYJC
'^='=>'=', # SNOOPYJC
# issue s151 '=~'=>'~','!~'=>'~',
'=~'=>'p','!~'=>'p', # issue s151
'=='=>'>', '!='=>'>', '>='=>'>', '<='=>'>', # comparison
'~~'=>'M', # issue s251
'=>'=>'A', '->'=>'D', # issue 93
'<<' => 'H', '>>'=>'I', '&&'=>'0', '||'=>'0', # issue 93
'*='=>'=', '/='=>'=', '**'=>'*', '::'=>'P' ); # issue 93
%digram_map=('++'=>'+=1','--'=>'-=1','+='=>'+=', '*='=>'*=', '/='=>'/=', '.='=>'+=', '=~'=>'','<>'=>'readline()','=>'=>': ','->'=>'.',
'&&'=>' and ', '||'=>' or ',
# SNOOPYJC '::'=>'.',
'::'=>'.__dict__', # SNOOPYJC
'~~'=>'_smartmatch', # issue s251
);
# %SpaceBefore=(in=>1, is=>1, an=>1, or=>1); # SNOOPYJC - always generate a space before these 2-letter output words
%SpaceBoth=('='=>1, '+='=>1, '-='=>1, '*='=>1, '/='=>1, '%='=>1,
'>'=>1, '>='=>1, '<'=>1, '<='=>1, '=='=>1, '!='=>1,
'||='=>1, '&&='=>1, # issue s3
'|='=>1, '&='=>1, '^='=>1, '>>='=>1, '<<='=>1, '**='=>1, '//='=>1); # SNOOPYJC - always generate a space before and after these
# issue 39 my ($source,$cut,$tno)=('',0,0);
my $source=''; # issue 39, issue 108
@lines_of_statement = (); # issue s278
$cut=0; # issue 39
$tno=0; # issue 108
@PythonCode=(); # array for generated code chunks
$PREV_HAD_COLON=1; # SNOOPYJC
@SavePythonCode=(); # issue 74
@BufferValClass=@BufferValCom=@BufferValPerl=@BufferValPy=();
@BufferValType=(); # issue 37
$TokenStr='';
$delayed_block_closure=0;
$nesting_level=0; # issue 94
@nesting_stack=(); # issue 94
$nesting_last=undef; # issue 94: Last thing we popped off the stack
$last_block_lno=0; # issue 94
$last_label=undef; # issue 94
%all_labels=(''=>1); # issue 94: all labels seen in this file
$uses_function_return_exception = 0; # SNOOPYJC
%sub_external_last_nexts=(); # issue 94: Map of subnames to set of all last/next labels that propagate out ('' if no label)
sub TRY_BLOCK_EXCEPTION { 1 }
sub TRY_BLOCK_FINALLY { 2 }
sub TRY_BLOCK_HAS_CONTINUE { 4 } # Has a 'continue' block
sub TRY_BLOCK_HAS_NEXT { 8 } # Has a 'last' stmt for this loop
sub TRY_BLOCK_HAS_LAST { 16 } # Has a 'next' stmt for this loop
sub TRY_BLOCK_REDO_LOOP { 32 } # Needs a nested loop for 'redo'
sub TRY_BLOCK_CONTINUE_NEEDED_ONE { 64 } # The 'continue' needed to use a try block: issue s49
sub TRY_BLOCK_FOREACH { 128 } # issue s100: used on foreach loop that needs a local var
$statement_starting_lno = 0; # issue 116
%line_contains_stmt_modifier=(); # issue 116
%line_contains_for_loop_with_modified_counter=(); # SNOOPYJC
%line_modifies_foreach_counter=(); # issue s252: lno=>foreach_loop_lno
%line_contains_local_for_loop_counter=(); # issue s100
%line_contains_pos_gen=(); # SNOOPYJC: {lno=>scalar, ...} on any stmt that can generate the pos of this scalar
%line_contains_for_given=(); # issue s129: Is this 'for' really a 'given'?
# issue s224 %line_contained_array_conversion=(); # issue s137
%scalar_pos_gen_line=(); # SNOOPYJC: {scalar=>last_lno, ...} - opposite of prev hash
%line_needs_try_block=(); # issue 94, issue 108: Map from line number to TRY_BLOCK_EXCEPTION|TRY_BLOCK_FINALLY if that line needs a try block
%line_locals=(); # issue 108: Map from line number to a list of locals
%line_locals_map=(); # issue 108: Map from line number to a map from perl name to python name
%line_sub=(); # issue 108: Map from line number to sub name
%line_substitutions=(); # SNOOPYJC: Map from line number to a hash ref of pattern substitutions needed
%line_varclasses=(); # SNOOPYJC: Map from line number to var classes (e.g. 'my', 'our', etc)
%sub_varclasses=(); # SNOOPYJC: Map from sub to var classses
$last_varclass_lno = 0; # SNOOPYJC: Last entry in the above
%last_varclass_sub=(); # SNOOPYJC: What sub were we in when we set the last %line_varclasses for this name
$ate_dollar = -1; # issue 50: if we ate a '$', where was it?
$add_comma_after_anon_sub_end = 0; # issue s39: Insert a ',' after the end of the anon sub we added
$last_expression_lno = 0; # issue implicit conditional return
$last_expression_level = -1; # issue implicit conditional return
%level_block_lnos = (); # {level=>0 -or- "lno,..."} issue implicit conditional return
%sub_lines_contain_potential_last_expression=(); # {'sub_name'=>'lno,...', ...} issue implicit conditional return
sub initialize # issue 94
{
$nesting_level = 0;
@nesting_stack = ();
$last_label = undef;
$last_block_lno=0;
$ate_dollar = -1;
$nesting_last=undef; # issue 94: Last thing we popped off the stack
$add_comma_after_anon_sub_end = 0; # issue s39
$last_expression_lno = 0; # issue implicit conditional return
$last_expression_level = -1; # issue implicit conditional return
%level_block_lnos = (); # issue implicit conditional return
if($Pythonizer::PassNo==&Pythonizer::PASS_1) {
push @UseLib, dirname($Pythonizer::fname); # SNOOPYJC: Always good to look here!
}
}
sub add_package_name
# Add the package name to this var if it's a global and it doesn't already have a package name
# Arg = the real perl name of this var, e.g. $xxx{} => %xxx
{
my $name = shift;
my $py = $ValPy[$tno];
#say STDERR "add_package_name($name), py=$py, lno=$.";
return if($::implicit_global_my);
return if(index($py, '.') >= 0);
return unless(exists $line_varclasses{$.});
if(substr($name,0,2) eq '$#') {
$name = '@' . substr($name,2);
}
return unless(exists $line_varclasses{$.}{$name});
my $class;
return unless(($class = $line_varclasses{$.}{$name}) =~ /global|local/);
my $sigil = substr($name,0,1);
$sigil = '' if($sigil =~ /\w/);
if($ValPy[$tno] =~ /^\(len\((.*)\)-1\)$/) { # for $#arr
my $id = $1;
# issue s102 $id = remap_conflicting_names(unescape_id($id, $name), $sigil, '', 1) if($::remap_global && !$::remap_all && $class eq 'global');
if($::remap_global && !$::remap_all && $class eq 'global') {
$id = unescape_id($id, $name); # issue s102
$id = remap_conflicting_names($id, $sigil, '', 1);
$id = escape_keywords($id); # issue s102
}
$ValPy[$tno] = '(len(' . cur_package() . '.' . $id . ')-1)';
}elsif($ValPy[$tno] =~ /^len\((.*)\)$/) { # issue bootstrap: for scalar(@arr)
my $id = $1;
# issue s102 $id = remap_conflicting_names(unescape_id($id, $name), $sigil, '', 1) if($::remap_global && !$::remap_all && $class eq 'global');
if($::remap_global && !$::remap_all && $class eq 'global') {
$id = unescape_id($id, $name); # issue s102
$id = remap_conflicting_names($id, $sigil, '', 1);
$id = escape_keywords($id); # issue s102
}
$ValPy[$tno] = 'len(' . cur_package() . '.' . $id . ')';
}elsif(substr($ValPy[$tno],0,1) eq '*') { # issue bootstrap: we splatted this reference
my $id = substr($ValPy[$tno],1);
# issue s102 $id = remap_conflicting_names(unescape_id($id, $name), $sigil, '', 1) if($::remap_global && !$::remap_all && $class eq 'global');
if($::remap_global && !$::remap_all && $class eq 'global') {
$id = unescape_id($id, $name); # issue s102
$id = remap_conflicting_names($id, $sigil, '', 1);
$id = escape_keywords($id); # issue s102
}
$ValPy[$tno] = '*' . cur_package() . '.' . $id; # Add the package name, moving the splat to the front
} else {
my $id = $ValPy[$tno];
# issue s102 $id = remap_conflicting_names(unescape_id($id, $name), $sigil, '', 1) if($::remap_global && !$::remap_all && $class eq 'global'); # issue s102
if($::remap_global && !$::remap_all && $class eq 'global') {
$id = unescape_id($id, $name); # issue s102
$id = remap_conflicting_names($id, $sigil, '', 1);
$id = escape_keywords($id); # issue s102
}
$ValPy[$tno] = cur_package() . '.' . $id; # Add the package name
}
if(in_starting_BEGIN()) { # issue s325
say STDERR "Mapped reference to $ValPy[$tno] prevents starting BEGIN on line $Pythonizer::StartingBeginLno from qualifying" if $::debug; # issue s325
$Pythonizer::StartingBeginLno = undef; # issue s325: Doesn't qualify if it needs our package name
} # issue s325
say STDERR "Changed $py to $ValPy[$tno] for global" if($::debug >= 5);
}
sub unescape_id # issue s102
# given an escaped name like bytes_, remove the '_'
# given a mapped name like bytes_v, remove the '_v' too
{
my $id = shift;
my $perl_name = shift;
return $id if substr($perl_name, -1, 1) eq '_';
return substr($id, 0, length($id)-1) if substr($id, -1, 1) eq '_';
return $id if substr($perl_name, -2, 2) =~ /^_[a-z]$/ && substr($perl_name, -1, 1) eq substr($id, -1, 1);
return substr($id, 0, length($id)-2) if substr($id, -2, 2) =~ /^_[a-z]$/;
return $id;
}
sub add_package_name_sub
# Add a package name to a sub call
# Arg: position of the 'i' token for the sub
# Returns: Updates $ValPy[$pos] if a change is needed
{
my $tno = shift;
my $perl_name = $ValPerl[$tno];
my $py = $ValPy[$tno];
# issue s282 return if($::implicit_global_my);
return if(index($py, '.') >= 0);
return if(substr($perl_name,0,1) eq '$'); # issue 117: Is a sub-ref, not a regular sub
return if($tno != 0 && $ValPy[$tno-1] eq '.');
# Here we check if it's actually defined locally (LocalSub == 1) or if
# it's imported by name (LocalSub == 2). It could also have the "8" value bit turned on,
# which only means it was referenced with a '&':
if($::fully_qualify_calls == 0) { # issue s284
return if(exists $Pythonizer::LocalSub{$py} && ($Pythonizer::LocalSub{$py} & 3));
}
return if $py =~ /^$ANONYMOUS_SUB\d+[a-z]?$/; # issue s284
if(substr($py,0,1) eq '*') { # issue s308: Sub has been splatted
$py = substr($py, 1); # issue s308: eat the splat
my $fullname = cur_package() . '.' . $py; # Add the package name
$ValPy[$tno] = '*' . $fullname; # add the splat to the front
$Pythonizer::LocalSub{$fullname} = $Pythonizer::LocalSub{$py} if exists $Pythonizer::LocalSub{$py};
&Pythonizer::clone_sub_attributes($py, $fullname);
} else { # issue s308
$ValPy[$tno] = cur_package() . '.' . $ValPy[$tno]; # Add the package name
$Pythonizer::LocalSub{$ValPy[$tno]} = $Pythonizer::LocalSub{$py} if exists $Pythonizer::LocalSub{$py}; # issue s3
&Pythonizer::clone_sub_attributes($py, $ValPy[$tno]); # issue s3, issue s241
}
say STDERR "Changed $py to $ValPy[$tno] for non-local sub" if($::debug >= 5);
}
sub add_package_name_fh
# Add a package name to a file handle
# Arg: position of the 'i' token for the sub
# Returns: Updates $ValPy[$pos] if a change is needed
{
my $tno = shift;
my $perl_name = $ValPerl[$tno];
my $py = $ValPy[$tno];
return if($::implicit_global_my);
return if(index($py, '.') >= 0);
my $name = '*' . $perl_name; # TypeGlob, e.g. local *FH;
if($Pythonizer::PassNo==&Pythonizer::PASS_1 && $last_varclass_lno != $. && $last_varclass_lno) {
# We don't capture filehandles, so we need to propagate the last line down on the first pass
$line_varclasses{$.} = dclone($line_varclasses{$last_varclass_lno});
$last_varclass_lno = $.;
}
my $class;
return if(exists $line_varclasses{$.} && exists $line_varclasses{$.}{$name} &&
$line_varclasses{$.}{$name} !~ /global|local/);