Skip to content

Commit 283ea50

Browse files
committed
Perlito5 - parser - precedence fix; Tests=863
1 parent 3b33471 commit 283ea50

File tree

6 files changed

+96
-17
lines changed

6 files changed

+96
-17
lines changed

html/perlito5.js

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -527,6 +527,17 @@ p5decr = function(o) {
527527
return p5num(o) - 1;
528528
};
529529

530+
p5modulo = function(o, k) {
531+
var m = o % k;
532+
if ( k < 0 && m > 0 ) {
533+
m = m + k;
534+
}
535+
else if ( k > 0 && m < 0 ) {
536+
m = m + k;
537+
}
538+
return m;
539+
};
540+
530541
p5shift_left = function(o, k) {
531542
return k < 31 ? o << k : o * Math.pow(2, k);
532543
};
@@ -2299,7 +2310,7 @@ var p5100 = p5pkg['main'];
22992310
// our p5pkg["Perlito5::Javascript2"]["Hash_op_infix_js_str"]
23002311
(p5pkg["Perlito5::Javascript2"]["Hash_op_infix_js_str"] = {'infix:<eq>' : ' == ', 'infix:<ne>' : ' != ', 'infix:<le>' : ' <= ', 'infix:<ge>' : ' >= ', 'infix:<lt>' : ' < ', 'infix:<gt>' : ' > '});
23012312
// our p5pkg["Perlito5::Javascript2"]["Hash_op_infix_js_num"]
2302-
(p5pkg["Perlito5::Javascript2"]["Hash_op_infix_js_num"] = {'infix:<==>' : ' == ', 'infix:<!=>' : ' != ', 'infix:<+>' : ' + ', 'infix:<->' : ' - ', 'infix:<*>' : ' * ', 'infix:</>' : ' / ', 'infix:<%>' : ' % ', 'infix:<>>' : ' > ', 'infix:<<>' : ' < ', 'infix:<>=>' : ' >= ', 'infix:<<=>' : ' <= ', 'infix:<&>' : ' & ', 'infix:<|>' : ' | ', 'infix:<^>' : ' ^ ', 'infix:<>>>' : ' >>> '});
2313+
(p5pkg["Perlito5::Javascript2"]["Hash_op_infix_js_num"] = {'infix:<==>' : ' == ', 'infix:<!=>' : ' != ', 'infix:<+>' : ' + ', 'infix:<->' : ' - ', 'infix:<*>' : ' * ', 'infix:</>' : ' / ', 'infix:<>>' : ' > ', 'infix:<<>' : ' < ', 'infix:<>=>' : ' >= ', 'infix:<<=>' : ' <= ', 'infix:<&>' : ' & ', 'infix:<|>' : ' | ', 'infix:<^>' : ' ^ ', 'infix:<>>>' : ' >>> '});
23032314
// our p5pkg["Perlito5::Javascript2"]["Hash_op_to_bool"]
23042315
(p5pkg["Perlito5::Javascript2"]["Hash_op_to_bool"] = p5a_to_h(p5list_to_a(p5map(p5pkg["Perlito5::Javascript2"], function (p5want) {
23052316
return ((p5context([p5pkg["Perlito5::Javascript2"]["v__"], 1], p5want)));
@@ -3632,6 +3643,12 @@ var p5100 = p5pkg['main'];
36323643
(v_self = (List__.p5aget(0)));
36333644
return (p5context([('p5shift_left(' + p5pkg["Perlito5::AST::Apply"].join([', ', p5list_to_a(p5map(p5pkg["Perlito5::AST::Apply"], function (p5want) {
36343645
return (p5pkg["Perlito5::Javascript2"].to_num([p5pkg["Perlito5::AST::Apply"]["v__"]], p5want));
3646+
}, p5list_to_a((v_self || (v_self = new p5HashRef({})))._hash_.p5hget_array('arguments')._array_)))], 0) + ')')], p5want));
3647+
}, 'infix:<%>', function (List__, p5want) {
3648+
var v_self;
3649+
(v_self = (List__.p5aget(0)));
3650+
return (p5context([('p5modulo(' + p5pkg["Perlito5::AST::Apply"].join([', ', p5list_to_a(p5map(p5pkg["Perlito5::AST::Apply"], function (p5want) {
3651+
return (p5pkg["Perlito5::Javascript2"].to_num([p5pkg["Perlito5::AST::Apply"]["v__"]], p5want));
36353652
}, p5list_to_a((v_self || (v_self = new p5HashRef({})))._hash_.p5hget_array('arguments')._array_)))], 0) + ')')], p5want));
36363653
}, 'prefix:<!>', function (List__, p5want) {
36373654
var v_self;
@@ -4681,6 +4698,8 @@ var p5100 = p5pkg['main'];
46814698
(v_Operator = ((new p5HashRef({}))));
46824699
var v_Precedence;
46834700
(v_Precedence = ((new p5HashRef({}))));
4701+
var v_PrefixPrecedence;
4702+
(v_PrefixPrecedence = ((new p5HashRef({}))));
46844703
var v_Assoc;
46854704
(v_Assoc = ((new p5HashRef({}))));
46864705
p5make_sub("Perlito5::Precedence", "is_assoc_type", function (List__, p5want) {
@@ -4894,6 +4913,9 @@ var p5100 = p5pkg['main'];
48944913
(v_assoc = (p5or((v_param || (v_param = new p5HashRef({})))._hash_.p5hget('assoc'), function () { return 'left' })));
48954914
(v_Operator || (v_Operator = new p5HashRef({})))._hash_.p5hget_hash(p5str(v_fixity))._hash_.p5hset(p5str(v_name), (1));
48964915
(v_Precedence || (v_Precedence = new p5HashRef({})))._hash_.p5hset(p5str(v_name), (v_precedence));
4916+
if ( (p5str(v_fixity) == 'prefix') ) {
4917+
(v_PrefixPrecedence || (v_PrefixPrecedence = new p5HashRef({})))._hash_.p5hset(p5str(v_name), (v_precedence));
4918+
};
48974919
(v_Assoc || (v_Assoc = new p5HashRef({})))._hash_.p5hget_hash(p5str(v_assoc))._hash_.p5hset(p5str(v_name), (1));
48984920
return (Hash_Op.p5hset(p5str(v_name), (1)));
48994921
});
@@ -5005,6 +5027,24 @@ var p5100 = p5pkg['main'];
50055027
p5pkg["Perlito5::Precedence"].add_op(['infix', 'xor', v_prec], null);
50065028
(v_prec = ((p5num(v_prec) - 1)));
50075029
p5pkg["Perlito5::Precedence"].add_op(['infix', '*start*', v_prec], null);
5030+
p5make_sub("Perlito5::Precedence", "get_token_precedence", function (List__, p5want) {
5031+
try {
5032+
var v_token;
5033+
(v_token = (List__.p5aget(0)));
5034+
if ( (p5str((v_token || (v_token = new p5ArrayRef([])))._array_.p5aget(0)) == 'prefix') ) {
5035+
throw((v_PrefixPrecedence || (v_PrefixPrecedence = new p5HashRef({})))._hash_.p5hget(p5str((v_token || (v_token = new p5ArrayRef([])))._array_.p5aget(1))));
5036+
};
5037+
return ((v_Precedence || (v_Precedence = new p5HashRef({})))._hash_.p5hget(p5str((v_token || (v_token = new p5ArrayRef([])))._array_.p5aget(1))));
5038+
}
5039+
catch(err) {
5040+
if ( err instanceof Error ) {
5041+
throw(err);
5042+
}
5043+
else {
5044+
return(err);
5045+
}
5046+
}
5047+
});
50085048
p5make_sub("Perlito5::Precedence", "precedence_parse", function (List__, p5want) {
50095049
var v_self;
50105050
(v_self = (List__.shift()));
@@ -5048,7 +5088,7 @@ var p5100 = p5pkg['main'];
50485088
(v_pr = ((v_Precedence || (v_Precedence = new p5HashRef({})))._hash_.p5hget(p5str((v_token || (v_token = new p5ArrayRef([])))._array_.p5aget(1)))));
50495089
p5while(function () {
50505090
(v_reduce)([v_op_stack, v_num_stack], null);
5051-
}, function () { return p5and(((v_op_stack || (v_op_stack = new p5ArrayRef([])))._array_), function () { return p5context([(p5num(v_pr) <= p5num((v_Precedence || (v_Precedence = new p5HashRef({})))._hash_.p5hget(p5str((p5context([(v_op_stack || (v_op_stack = new p5ArrayRef([])))._array_.p5aget(0)], 0) || (p5context([(v_op_stack || (v_op_stack = new p5ArrayRef([])))._array_.p5aget(0)], 0) = new p5ArrayRef([])))._array_.p5aget(1)))))], 0) }) }, false, "");
5091+
}, function () { return p5and(((v_op_stack || (v_op_stack = new p5ArrayRef([])))._array_), function () { return p5context([(p5num(v_pr) <= p5num(p5pkg["Perlito5::Precedence"].get_token_precedence(p5list_to_a((v_op_stack || (v_op_stack = new p5ArrayRef([])))._array_.p5aget(0)), 0)))], 0) }) }, false, "");
50525092
if ( (p5str((v_token || (v_token = new p5ArrayRef([])))._array_.p5aget(0)) != 'postfix_or_term') ) {
50535093
(v_token || (v_token = new p5ArrayRef([])))._array_.p5aset(0, ('postfix'));
50545094
};
@@ -5074,12 +5114,12 @@ var p5100 = p5pkg['main'];
50745114
if ( p5bool((v_Assoc || (v_Assoc = new p5HashRef({})))._hash_.p5hget_hash('right')._hash_.p5hget(p5str((v_token || (v_token = new p5ArrayRef([])))._array_.p5aget(1)))) ) {
50755115
p5while(function () {
50765116
(v_reduce)([v_op_stack, v_num_stack], null);
5077-
}, function () { return p5and(((v_op_stack || (v_op_stack = new p5ArrayRef([])))._array_), function () { return p5context([(p5num(v_pr) < p5num((v_Precedence || (v_Precedence = new p5HashRef({})))._hash_.p5hget(p5str((p5context([(v_op_stack || (v_op_stack = new p5ArrayRef([])))._array_.p5aget(0)], 0) || (p5context([(v_op_stack || (v_op_stack = new p5ArrayRef([])))._array_.p5aget(0)], 0) = new p5ArrayRef([])))._array_.p5aget(1)))))], 0) }) }, false, "");
5117+
}, function () { return p5and(((v_op_stack || (v_op_stack = new p5ArrayRef([])))._array_), function () { return p5context([(p5num(v_pr) < p5num(p5pkg["Perlito5::Precedence"].get_token_precedence(p5list_to_a((v_op_stack || (v_op_stack = new p5ArrayRef([])))._array_.p5aget(0)), 0)))], 0) }) }, false, "");
50785118
}
50795119
else {
50805120
p5while(function () {
50815121
(v_reduce)([v_op_stack, v_num_stack], null);
5082-
}, function () { return p5and(((v_op_stack || (v_op_stack = new p5ArrayRef([])))._array_), function () { return p5context([(p5num(v_pr) <= p5num((v_Precedence || (v_Precedence = new p5HashRef({})))._hash_.p5hget(p5str((p5context([(v_op_stack || (v_op_stack = new p5ArrayRef([])))._array_.p5aget(0)], 0) || (p5context([(v_op_stack || (v_op_stack = new p5ArrayRef([])))._array_.p5aget(0)], 0) = new p5ArrayRef([])))._array_.p5aget(1)))))], 0) }) }, false, "");
5122+
}, function () { return p5and(((v_op_stack || (v_op_stack = new p5ArrayRef([])))._array_), function () { return p5context([(p5num(v_pr) <= p5num(p5pkg["Perlito5::Precedence"].get_token_precedence(p5list_to_a((v_op_stack || (v_op_stack = new p5ArrayRef([])))._array_.p5aget(0)), 0)))], 0) }) }, false, "");
50835123
};
50845124
if ( p5bool((v_Operator || (v_Operator = new p5HashRef({})))._hash_.p5hget_hash('ternary')._hash_.p5hget(p5str((v_token || (v_token = new p5ArrayRef([])))._array_.p5aget(1)))) ) {
50855125
(v_token || (v_token = new p5ArrayRef([])))._array_.p5aset(0, ('ternary'));

perlito5.pl

Lines changed: 19 additions & 5 deletions
Large diffs are not rendered by default.

src5/lib/Perlito5/Javascript2/Emitter.pm

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ package Perlito5::Javascript2;
5454
'infix:<->' => ' - ',
5555
'infix:<*>' => ' * ',
5656
'infix:</>' => ' / ',
57-
'infix:<%>' => ' % ',
57+
# 'infix:<%>' => ' % ',
5858
'infix:<>>' => ' > ',
5959
'infix:<<>' => ' < ',
6060
'infix:<>=>' => ' >= ',
@@ -1392,6 +1392,10 @@ package Perlito5::AST::Apply;
13921392
my $self = $_[0];
13931393
'p5shift_left(' . join( ', ', map( Perlito5::Javascript2::to_num($_), @{ $self->{arguments} } ) ) . ')';
13941394
},
1395+
'infix:<%>' => sub {
1396+
my $self = $_[0];
1397+
'p5modulo(' . join( ', ', map( Perlito5::Javascript2::to_num($_), @{ $self->{arguments} } ) ) . ')';
1398+
},
13951399
'prefix:<!>' => sub {
13961400
my $self = shift;
13971401
my $level = shift;

src5/lib/Perlito5/Javascript2/Runtime.pm

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -533,6 +533,17 @@ p5decr = function(o) {
533533
return p5num(o) - 1;
534534
};
535535
536+
p5modulo = function(o, k) {
537+
var m = o % k;
538+
if ( k < 0 && m > 0 ) {
539+
m = m + k;
540+
}
541+
else if ( k > 0 && m < 0 ) {
542+
m = m + k;
543+
}
544+
return m;
545+
};
546+
536547
p5shift_left = function(o, k) {
537548
return k < 31 ? o << k : o * Math.pow(2, k);
538549
};

src5/lib/Perlito5/Precedence.pm

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,10 @@ sub new {
1414
bless {@_}, $class
1515
}
1616

17-
my $Operator = {};
18-
my $Precedence = {}; # integer 0..100
19-
my $Assoc = {}; # right, left, list
17+
my $Operator = {};
18+
my $Precedence = {}; # integer 0..100
19+
my $PrefixPrecedence = {}; # integer 0..100; 'prefix' operations
20+
my $Assoc = {}; # right, left, list
2021

2122
sub is_assoc_type {
2223
my $assoc_type = shift;
@@ -201,6 +202,7 @@ sub add_op {
201202
my $assoc = $param->{assoc} || 'left';
202203
$Operator->{$fixity}{$name} = 1;
203204
$Precedence->{$name} = $precedence;
205+
$PrefixPrecedence->{$name} = $precedence if $fixity eq 'prefix';
204206
$Assoc->{$assoc}{$name} = 1;
205207
$Op{$name} = 1;
206208
}
@@ -381,6 +383,14 @@ $prec = $prec - 1;
381383
add_op( 'infix', '*start*', $prec );
382384

383385

386+
sub get_token_precedence {
387+
my $token = $_[0];
388+
if ( $token->[0] eq 'prefix' ) {
389+
return $PrefixPrecedence->{ $token->[1] }
390+
}
391+
return $Precedence->{ $token->[1] }
392+
}
393+
384394
sub precedence_parse {
385395

386396
# this routine implements operator precedence
@@ -427,7 +437,7 @@ sub precedence_parse {
427437
elsif ( $Operator->{postfix}{$token->[1]} && $last_is_term )
428438
{
429439
my $pr = $Precedence->{$token->[1]};
430-
while (scalar(@$op_stack) && ($pr <= $Precedence->{ ($op_stack->[0])[1] })) {
440+
while (scalar(@$op_stack) && ($pr <= get_token_precedence($op_stack->[0]))) {
431441
$reduce->($op_stack, $num_stack);
432442
}
433443
if ($token->[0] ne 'postfix_or_term') {
@@ -450,12 +460,12 @@ sub precedence_parse {
450460
elsif ($Precedence->{$token->[1]}) {
451461
my $pr = $Precedence->{$token->[1]};
452462
if ($Assoc->{right}{$token->[1]}) {
453-
while (scalar(@$op_stack) && ( $pr < $Precedence->{ ($op_stack->[0])[1] } )) {
463+
while (scalar(@$op_stack) && ( $pr < get_token_precedence($op_stack->[0]))) {
454464
$reduce->($op_stack, $num_stack);
455465
}
456466
}
457467
else {
458-
while (scalar(@$op_stack) && ( $pr <= $Precedence->{ ($op_stack->[0])[1] } )) {
468+
while (scalar(@$op_stack) && ( $pr <= get_token_precedence($op_stack->[0]))) {
459469
$reduce->($op_stack, $num_stack);
460470
}
461471
}

t5/op/arith.t

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ BEGIN {
55
@INC = '../lib';
66
}
77

8-
print "1..145\n";
8+
print "1..144\n";
99

1010
sub try ($$) {
1111
print +($_[1] ? "ok" : "not ok"), " $_[0]\n";

0 commit comments

Comments
 (0)