# New Ticket Created by Jürgen Bömmels # Please include the string: [perl #18379] # in the subject line of all future correspondence about this issue. # <URL: http://rt.perl.org/rt2/Ticket/Display.html?id=18379 >
Hello, I used Jonathan Sillito's patch [#18170] to implement functions in scheme. It has lambda expressions, function defines, and basic let functionality. Testcases are included. (New file defines.t) One thing I'm not very happy about that I need 2 pop_pads at function return, one cleaning up the newly generated pad from new_pad, and one for cleaning up the stored scope of function definition. I have no idea how to solve this. This patch obsoletes #17109 (which isn't applied yet). bye b. DEPENDS ON #18170 -- attachment 1 ------------------------------------------------------ url: http://rt.perl.org/rt2/attach/41631/33455/33b0f8/scheme.diff -- attachment 2 ------------------------------------------------------ url: http://rt.perl.org/rt2/attach/41631/33456/41cd7b/new_pad.diff
Index: MANIFEST =================================================================== RCS file: /cvs/public/parrot/MANIFEST,v retrieving revision 1.249 diff -u -r1.249 MANIFEST --- MANIFEST 9 Nov 2002 12:42:54 -0000 1.249 +++ MANIFEST 13 Nov 2002 21:36:24 -0000 @@ -36,6 +36,7 @@ classes/pmc2c.pl classes/pointer.pmc classes/scalar.pmc +classes/scratchpad.pmc classes/sub.pmc config/auto/alignptrs.pl config/auto/alignptrs/test_c.in @@ -1534,6 +1535,7 @@ languages/scheme/t/io/basic.t languages/scheme/t/logic/basic.t languages/scheme/t/logic/lists.t +languages/scheme/t/logic/defines.t lib/Class/Struct.pm lib/Digest/Perl/MD5.pm lib/Make.pm Index: languages/scheme/Scheme/Builtins.pm =================================================================== RCS file: /cvs/public/parrot/languages/scheme/Scheme/Builtins.pm,v retrieving revision 1.1 diff -u -r1.1 Builtins.pm --- languages/scheme/Scheme/Builtins.pm 5 Sep 2002 19:54:42 -0000 1.1 +++ languages/scheme/Scheme/Builtins.pm 13 Nov 2002 21:36:24 -0000 @@ -6,20 +6,22 @@ ( write => [['# Write function', ''], - ['write_ENTRY', 'save', 'I0'], - ['', 'typeof', 'I0', 'P5'], + ['write_ENTRY', 'typeof', 'I0', 'P5'], ['', 'ne', 'I0', '.PerlUndef', 'write_N_UNDEF'], ['', 'print', '"()"'], - ['', 'branch', 'write_RET0'], - ['write_N_UNDEF','eq', 'I0', '.Array', 'write_ARRAY'], + ['', 'branch', 'write_RET'], + ['write_N_UNDEF','ne', 'I0', '.Scratchpad', 'write_N_LAMBDA'], + ['', 'print', '"lambda"'], + ['', 'branch', 'write_RET'], + ['write_N_LAMBDA','eq', 'I0', '.Array', 'write_ARRAY'], ['', 'print', 'P5'], - ['', 'branch', 'write_RET0'], - ['write_ARRAY', 'save', 'P5'], - ['', 'save', 'P6'], - ['', 'print', '"("'], + ['', 'branch', 'write_RET'], + ['write_ARRAY', 'print', '"("'], ['write_NEXT', 'set', 'P6', 'P5'], ['', 'set', 'P5', 'P6[0]'], + ['', 'save', 'P6'], ['', 'bsr', 'write_ENTRY'], + ['', 'restore', 'P6'], ['', 'set', 'P5', 'P6[1]'], ['', 'typeof', 'I0', 'P5'], ['', 'eq', 'I0', '.PerlUndef', 'write_KET'], @@ -29,10 +31,24 @@ ['write_DOT', 'print', '" . "'], ['', 'bsr', 'write_ENTRY'], ['write_KET', 'print', '")"'], - ['', 'restore', 'P6'], - ['', 'restore', 'P5'], - ['write_RET0', 'restore', 'I0'], - ['', 'ret'], + ['write_RET', 'ret'], + ], + apply => + [['# apply Function',''], + ['apply_ENTRY', 'set', 'P7', 'P5[0]'], + ['', 'push_pad', 'P7'], + ['', 'new_pad', '-1'], + ['', 'set', 'P7', 'P5[2]'], + ['apply_NEXT', 'typeof', 'I0', 'P6'], + ['', 'eq', 'I0', '.PerlUndef', 'apply_LAST'], + ['', 'set', 'S0', 'P7[0]'], + ['', 'set', 'P8', 'P6[0]'], + ['', 'store_lex', '-1', 'S0', 'P8'], + ['', 'set', 'P6', 'P6[1]'], + ['', 'set', 'P7', 'P7[1]'], + ['', 'branch', 'apply_NEXT'], + ['apply_LAST', 'set', 'I0', 'P5[1]'], + ['', 'jump', 'I0'], ] ); Index: languages/scheme/Scheme/Generator.pm =================================================================== RCS file: /cvs/public/parrot/languages/scheme/Scheme/Generator.pm,v retrieving revision 1.3 diff -u -r1.3 Generator.pm --- languages/scheme/Scheme/Generator.pm 5 Sep 2002 15:03:55 -0000 1.3 +++ languages/scheme/Scheme/Generator.pm 13 Nov 2002 21:36:25 -0000 @@ -15,14 +15,17 @@ #------------------------------------ -my $regs = { - I => { map { $_ => 0 } (0..31) }, - N => { map { $_ => 0 } (0..31) }, - S => { map { $_ => 0 } (0..31) }, - P => { map { $_ => 0 } (0..31) }, +sub _new_regs { + { + I => { map { $_ => 0 } (0..31) }, + N => { map { $_ => 0 } (0..31) }, + S => { map { $_ => 0 } (0..31) }, + P => { map { $_ => 0 } (0..31) }, + }; }; sub _save { + my $self = shift; my $count = shift; my $type = shift || 'I'; die "No registers to save" @@ -31,39 +34,101 @@ unless $type and $type=~/^[INPS]$/; my @temp; for(0..31) { - next if $regs->{$type}{$_} == 1; + next if $self->{regs}->{$type}{$_} == 1; last if $count<=0; push @temp,"$type$_"; - $regs->{$type}{$_}=1; + $self->{regs}->{$type}{$_}=1; $count--; } @temp; } +sub _save_set { + my $self = shift; + my %regs = %{$self->{regs}}; + for my $type (keys %regs) { + for my $count (0..31) { + $self->_add_inst ('', 'save', ["$type$count"]) + if $regs{$type}->{$count}; + } + } +} + sub _save_1 { + my $self = shift; my $type = shift || 'I'; - my @temp = _save 1, $type; + my @temp = $self->_save(1, $type); $temp[0]; } sub _restore { + my $self = shift; + die "Nothing to restore" unless defined @_; - for(@_) { - s/^(\w)//; + foreach my $reg (@_) { + next if grep { $_ eq $reg } qw (none); + $reg =~ /^(\w)(\d+)/; die "Missing register type" unless defined $1; - $regs->{$1}{$_}=0; + if ($self->{regs}->{$1}{$2}) { + $self->{regs}->{$1}{$2} = 0; + } + } +} + +sub _restore_set { + my $self = shift; + my %regs = %{$self->{regs}}; + + for my $type (reverse keys %regs) { + for (my $count=31; $count>=0; $count--) { + $self->_add_inst ('','restore',["$type$count"]) + if $regs{$type}->{$count}; + } } } sub _num_arg { my ($node, $expected, $name) = @_; - my $children = scalar @{$node->{children}}; + my $args = scalar @{$node->{children}} - 1; + + die "$name: Wrong number of arguments (expected $expected, got $args).\n" + if ($args != $expected); +} + +sub _get_arg { + my ($node, $num) = @_; + $node->{children}->[$num]; +} + +sub _get_args { + my ($node, $num) = @_; + $num = 1 unless defined $num; - die "$name: Wrong number of arguments (expected $expected, got $children).\n" - if ($children != $expected); + my @args = @{$node->{children}}; + splice @args, 0, $num; + + return @args; +} + +# until there is a working find_lex/store_lex +sub _find_lex { + my ($self, $symbol) = @_; + my $return = $self->_save_1 ('P'); + $self->_add_inst ('','find_lex',[$return,"\"$symbol\""]); + return $return; +} + +sub _store_lex { + my ($self, $symbol,$value) = @_; + $self->_add_inst ('','store_lex',["\"$symbol\"",$value]); +} + +sub _new_lex { + my ($self, $symbol, $value) = @_; + $self->_add_inst ('','store_lex',[-1,"\"$symbol\"",$value]); } #------------------------------------ @@ -78,29 +143,141 @@ #------------------------------------ -sub _op_constant { - my ($self,$node) = @_; - my ($num_registers,$type) = @{$type_map->{$node->{type}}}; - my @register = _save($num_registers,$type); - for(@register) { - $self->_add_inst('','set',[$_,$node->{value}]); +sub _constant { + my ($self, $value) = @_; + my $return; + + if ($value =~ /^[-+]?\d+$/) { + $return = $self->_save_1 ('I'); + $self->_add_inst ('', 'set', [$return,$value]); + } + elsif ($value =~ /^[-+]?((\d+\.\d*)|(\.d+))([eE][-+]?\d+)?$/) { + $return = $self->_save_1 ('N'); + $self->_add_inst ('', 'set', [$return,$value]); + } + else { + $return = $self->_save_1 ('I'); + $self->_add_inst ('', 'set', [$return,0]); } - return $register[0]; -} -sub _constant { - my ($self,$value) = @_; - return $self->_generate({value=>$value,type=>'INTEGER'}); + return $return; } -#------------------------------------ +sub _morph { + my ($self, $to, $from) = @_; + + if ($to =~ /P/) { + if ($from =~ /P/) { + $self->_add_inst ('', 'clone',[$to,$from]); + } elsif ($from =~ /I/) { + $self->_add_inst ('', 'new',[$to,'.PerlInt']); + $self->_add_inst ('', 'set',[$to,$from]); + } elsif ($from =~ /N/) { + $self->_add_inst ('', 'new',[$to,'.PerlNum']); + $self->_add_inst ('', 'set',[$to,$from]); + } + } +} #---- Section 4 ---- +sub __quoted { + my ($self, $node) = @_; + my $return = $self->_save_1 ('P'); + + if (exists $node->{value}) { + my $value = $node->{value}; + if ($value =~ /^[-+]?\d+$/) { + $self->_add_inst ('', 'new',[$return,'.PerlInt']); + $self->_add_inst ('', 'set',[$return,$value]); + } + elsif ($value =~ /^[-+]?((\d+\.\d*)|(\.d+))([eE][-+]?\d+)?$/) { + $self->_add_inst ('', 'new',[$return,'.PerlNum']); + $self->_add_inst ('', 'set',[$return,$value]); + } + else { # assume its a symbol + $self->_add_inst ('', 'new',[$return,'.PerlString']); + $self->_add_inst ('', 'set',[$return,"\"$value\""]); + } + } + elsif (exists $node->{children}) { + $self->_add_inst ('', 'new', [$return,'.PerlUndef']); + for (reverse @{$node->{children}}) { + + my $item = __quoted ($self, $_); + my $pair = $self->_save_1 ('P'); + $self->_add_inst ('', 'new', [$pair,'.Array']); + $self->_add_inst ('', 'set', [$pair,2]); + $self->_add_inst ('', 'set', [$pair.'[0]',$item]); + $self->_add_inst ('', 'set', [$pair.'[1]',$return]); + $self->_add_inst ('', 'set', [$return,$pair]); + $self->_restore ($item, $pair); + } + } + + return $return; +} + sub _op_quote { + my ($self, $node) = @_; + my $return; + + _num_arg ($node, 1, 'quote'); + + my $item = _get_arg($node,1); + + return __quoted ($self, $item); } sub _op_lambda { + my ($self,$node) = @_; + my $return; + my $label = $self->_gensym(); + my $temp; + + $return = $self->_save_1 ('P'); + + $self->_add_inst ('', 'new',[$return,'.Array']); + $self->_add_inst ('', 'set',[$return,3]); + + $temp = $self->_save_1 ('P'); + $self->_add_inst ('', 'peek_pad', [$temp]); + $self->_add_inst ('', 'set',[$return.'[0]',$temp]); + $self->_restore($temp); + + my $addr = $self->_save_1 ('I'); + $self->_add_inst ('', 'set_addr',[$addr,"LAMBDA_$label"]); + $self->_add_inst ('', 'set',[$return.'[1]',$addr]); + $self->_restore ($addr); + + $temp = __quoted ($self,_get_arg($node,1)); + $self->_add_inst ('', 'set',[$return.'[2]',$temp]); + $self->_restore ($temp); + + $self->_add_inst ('', 'branch',["DONE_$label"]); + $self->_add_inst ("LAMBDA_$label"); + + # caller saved => start a new frame + push @{$self->{frames}}, $self->{regs}; + $self->{regs} = _new_regs; + + $temp = 'none'; + for (_get_args($node,2)) { + $self->_restore ($temp); + $temp = $self->_generate($_); + } + + $self->_add_inst('', 'set', ['P5', $temp]); + + $self->_add_inst('', 'pop_pad'); + # XXX: new_pad is the only way to create a new scope + $self->_add_inst('', 'pop_pad'); + $self->_add_inst('', 'ret'); + $self->_add_inst("DONE_$label"); + + $self->{regs} = pop @{$self->{frames}}; + + return $return; } sub _op_if { @@ -108,23 +285,79 @@ my $return; my $label = $self->_gensym(); - $return = "I"._save(1,'I'); - my $cond = $self->_generate($node->{children}[0]); + my $cond = $self->_generate(_get_arg($node,1)); $self->_add_inst('','eq',[$cond,0,"FALSE_$label"]); - my $true = $self->_generate($node->{children}[1]); - $self->_add_inst('','set',[$return,$true]); + $self->_restore($cond); + $return = $self->_save_1 ('P'); + + my $true = $self->_generate(_get_arg($node,2)); + $self->_morph($return,$true); $self->_add_inst('','branch',["DONE_$label"]); + $self->_restore($true); + $self->_add_inst("FALSE_$label"); - _restore($true); - _restore($cond); - my $false = $self->_generate($node->{children}[2]); - $self->_add_inst('','set',[$return,$false]); - _restore($false); + my $false = $self->_generate(_get_arg($node,3)); + $self->_morph($return,$false); + $self->_restore($false); + $self->_add_inst("DONE_$label"); return $return; } +sub _op_define { + my ($self, $node) = @_; + + _num_arg ($node, 2, 'define'); + + my ($symbol, $value); + + if (exists _get_arg($node,1)->{children}) { + my @formals; + ($symbol, @formals) = @{_get_arg($node,1)->{children}}; + $symbol = $symbol->{value}; + my $lambda = { children => [ { value => 'lambda' }, + { children => [ @formals ] }, + _get_args ($node, 2) ] }; + $value = $self->_generate($lambda); + } + else { + $symbol = _get_arg($node,1)->{value}; + $value = $self->_generate (_get_arg($node,2)); + } + + if (exists $self->{scope}->{$symbol}) { + die "define: $symbol is already defined\n"; + } + + if ($value !~ /^P/) { + my $pmc = $self->_save_1 ('P'); + $self->_morph ($pmc, $value); + $self->_restore ($value); + $value = $pmc; + } + + $self->{scope}->{$symbol} = 1; + $self->_new_lex ($symbol,$value); + + return $value; +} + sub _op_set_bang { + my ($self, $node) = @_; + + _num_arg ($node, 2, 'set!'); + + my $symbol = _get_arg ($node, 1)->{value}; + my $temp = $self->_generate(_get_arg($node,2)); + if ($temp !~ /^P/) { + my $pmc = $self->_save_1 ('P'); + $self->_morph ($pmc, $temp); + $self->_restore ($temp); + $temp = $pmc; + } + $self->_store_lex ($symbol,$temp); + + return $temp; } sub _op_cond { @@ -139,10 +372,10 @@ my $label = $self->_gensym(); $return = $self->_constant(0); - for(@{$node->{children}}) { + for(_get_args($node)) { my $temp = $self->_generate($_); $self->_add_inst('' ,'eq' ,[$temp,0,"DONE_$label"]); - _restore($temp); + $self->_restore($temp); } $self->_add_inst('' ,'set',[$return,1]); $self->_add_inst("DONE_$label"); @@ -155,10 +388,10 @@ my $label = $self->_gensym(); $return = $self->_constant(1); - for(@{$node->{children}}) { + for(_get_args($node)) { my $temp = $self->_generate($_); $self->_add_inst('' ,'eq' ,[$temp,1,"DONE_$label"]); - _restore($temp); + $self->_restore($temp); } $self->_add_inst('' ,'set',[$return,0]); $self->_add_inst("DONE_$label"); @@ -166,6 +399,28 @@ } sub _op_let { + my ($self, $node) = @_; + my $return; + + my ($locals, @body) = _get_args ($node,1); + my (@variables, @values); + for (@{$locals->{children}}) { + _num_arg ($_, 1, 'let locals'); + my ($var, $val) = _get_args ($_, 0); + push @variables, $var; + push @values, $val; + } + + my $let = { children => [ + { children => [ { value => 'lambda' }, + { children => [ @variables ] }, + @body ]}, + @values + ]}; + + $return = $self->_generate($let); + + return $return; } sub _op_let_star { @@ -175,6 +430,16 @@ } sub _op_begin { + my ($self, $node) = @_; + my $temp = 'none'; + + my @args = _get_args ($node); + + for (@args) { + $self->_restore ($temp); + $temp = $self->_generate ($_); + } + return $temp; } sub _op_do { @@ -189,13 +454,13 @@ #---- Section 6 ---- sub _op_not { - my ($self,$node,$return) = @_; + my ($self,$node) = @_; - my @temp = _save(1); - $self->_generate($node->{children}[0],$temp[0]); - $self->_add_inst('','not',[$temp[0],$temp[0]]); - $self->_add_inst('','and',[$return,$temp[0],1]); - _restore(@temp); + my $return = $self->_save_1 ('I'); + $self->_generate(_get_arg($node,1)); + $self->_add_inst('','not',[$return,$return]); + + $return; } sub _op_boolean_p { @@ -217,9 +482,9 @@ _num_arg ($node, 1, 'pair?'); - my $item = $self->_generate($node->{children}->[0]); + my $item = $self->_generate(_get_arg($node,1)); - $return = _save_1 ('I'); + $return = $self->_save_1 ('I'); if ($item =~ /^[INS]/) { $self->_add_inst ('', 'set', [$return,0]); @@ -244,17 +509,17 @@ _num_arg ($node, 2, 'cons'); - my $car = $self->_generate($node->{children}->[0]); - $return = _save_1('P'); + my $car = $self->_generate(_get_arg($node,1)); + $return = $self->_save_1('P'); $self->_add_inst ('', 'new', [$return,'.Array']); $self->_add_inst ('', 'set', [$return,2]); $self->_add_inst ('', 'set', [$return.'[0]',$car]); - _restore ($car); + $self->_restore ($car); - my $cdr = $self->_generate($node->{children}->[1]); + my $cdr = $self->_generate(_get_arg($node,2)); $self->_add_inst ('', 'set', [$return.'[1]', $cdr]); - _restore ($cdr); + $self->_restore ($cdr); return $return; } @@ -264,7 +529,7 @@ _num_arg ($node, 1, 'car'); - my $return = $self->_generate ($node->{children}->[0]); + my $return = $self->_generate (_get_arg($node,1)); die "car: Element not pair\n" unless $return =~ /^P/; $self->_add_inst ('', 'set', [$return,$return.'[0]']); @@ -276,7 +541,7 @@ _num_arg ($node, 1, 'cdr'); - my $return = $self->_generate ($node->{children}->[0]); + my $return = $self->_generate (_get_arg($node,1)); die "cdr: Element not pair\n" unless $return =~ /^P/; $self->_add_inst ('', 'set', [$return,$return.'[1]']); @@ -288,11 +553,11 @@ _num_arg ($node, 2, 'set-car!'); - my $return = $self->_generate ($node->{children}->[0]); + my $return = $self->_generate (_get_arg($node,1)); die "set-car!: Element not pair\n" unless $return =~ /^P/; - my $value = $self->_generate ($node->{children}->[1]); + my $value = $self->_generate (_get_arg($node,2)); $self->_add_inst ('', 'set', [$return.'[0]',$value]); - _restore ($value); + $self->_restore ($value); return $return; } @@ -302,16 +567,32 @@ _num_arg ($node, 2, 'set-cdr!'); - my $return = $self->_generate ($node->{children}->[0]); + my $return = $self->_generate (_get_arg($node,1)); die "set-cdr!: Element not pair\n" unless $return =~ /^P/; - my $value = $self->_generate ($node->{children}->[1]); + my $value = $self->_generate (_get_arg($node,2)); $self->_add_inst ('', 'set', [$return.'[1]',$value]); - _restore ($value); + $self->_restore ($value); return $return; } -sub _op_null { +sub _op_null_p { + my ($self, $node) = @_; + my $return = $self->_save_1 ('I'); + my $label = $self->_gensym(); + + _num_arg ($node, 1, 'null?'); + + my $temp = $self->_generate(_get_arg($node,1)); + $self->_add_inst ('', 'typeof',[$return,$temp]); + $self->_add_inst ('', 'ne', [$return,'.PerlUndef',"FAIL_$label"]); + $self->_add_inst ('', 'set', [$return,1]); + $self->_add_inst ('', 'branch', ["DONE_$label"]); + $self->_add_inst ("FAIL_$label", 'set', [$return,0]); + $self->_add_inst ("DONE_$label"); + $self->_restore ($temp); + + return $return; } sub _op_list_p { @@ -320,15 +601,15 @@ sub _op_list { my ($self, $node) = @_; my $label = $self->_gensym (); - my $return = _save_1 ('P'); + my $return = $self->_save_1 ('P'); $self->_add_inst ('', 'new',[$return,'.PerlUndef']); - return $return unless exists $node->{children}; + my @reverse = reverse _get_args($node); - for (reverse @{$node->{children}}) { + for (@reverse) { my $item = $self->_generate($_); - my $pair = _save_1 ('P'); + my $pair = $self->_save_1 ('P'); $self->_add_inst ('', 'new',[$pair,'.Array']); $self->_add_inst ('', 'set',[$pair,2]); @@ -336,7 +617,7 @@ $self->_add_inst ('', 'set',[$pair.'[1]',$return]); $self->_add_inst ('', 'set',[$return,$pair]); - _restore($item, $pair); + $self->_restore($item, $pair); } return $return; @@ -345,14 +626,14 @@ sub _op_length { my ($self, $node) = @_; my $label = $self->_gensym (); - my $return = _save_1 ('I'); + my $return = $self->_save_1 ('I'); _num_arg ($node, 1, 'length'); - my $list = $self->_generate($node->{children}->[0]); + my $list = $self->_generate(_get_arg($node,1)); $self->_add_inst ('', 'set',[$return,'0']); - my $type = _save_1 ('I'); + my $type = $self->_save_1 ('I'); $self->_add_inst ("NEXT_$label", 'typeof',[$type,$list]); $self->_add_inst ('', 'eq',[$type,'.PerlUndef', "DONE_$label"]); $self->_add_inst ('', 'ne',[$type,'.Array', "ERR_$label"]); @@ -430,15 +711,21 @@ my $label = $self->_gensym(); $return = $self->_constant(0); - my $temp_0 = $self->_generate($node->{children}[0]); - for(1..$#{$node->{children}}) { - my $temp_1 = $self->_generate($node->{children}[1]); - $self->_add_inst('','ne',[$temp_0,$temp_1,"DONE_$label"]); - _restore($temp_1); + my $temp_0 = $self->_generate($node->{children}[1]); + for(2..$#{$node->{children}}) { + my $temp_1 = $self->_generate($node->{children}[$_]); + if (substr ($temp_0, 0, 1) ne substr ($temp_1, 0, 1)) { + my $temp_2 = $self->_save_1(substr ($temp_0, 0, 1)); + $self->_morph($temp_2, $temp_1); + $self->_restore ($temp_1); + $temp_1 = $temp_2; + } + $self->_add_inst ('', 'ne', [$temp_0,$temp_1,"DONE_$label"]); + $self->_restore($temp_1); } $self->_add_inst('','set',[$return,1]); $self->_add_inst("DONE_$label"); - _restore($temp_0); + $self->_restore($temp_0); return $return; } @@ -448,15 +735,15 @@ my $label = $self->_gensym(); $return = $self->_constant(0); - my $temp_0 = $self->_generate($node->{children}[0]); - for(1..$#{$node->{children}}) { - my $temp_1 = $self->_generate($node->{children}[1]); + my $temp_0 = $self->_generate($node->{children}[1]); + for(2..$#{$node->{children}}) { + my $temp_1 = $self->_generate($node->{children}[$_]); $self->_add_inst('','ge',[$temp_0,$temp_1,"DONE_$label"]); - _restore($temp_1); + $self->_restore($temp_1); } $self->_add_inst('','set',[$return,1]); $self->_add_inst("DONE_$label"); - _restore($temp_0); + $self->_restore($temp_0); return $return; } @@ -466,15 +753,15 @@ my $label = $self->_gensym(); $return = $self->_constant(0); - my $temp_0 = $self->_generate($node->{children}[0]); - for(1..$#{$node->{children}}) { - my $temp_1 = $self->_generate($node->{children}[1]); + my $temp_0 = $self->_generate($node->{children}[1]); + for(2..$#{$node->{children}}) { + my $temp_1 = $self->_generate($node->{children}[$_]); $self->_add_inst('','le',[$temp_0,$temp_1,"DONE_$label"]); - _restore($temp_1); + $self->_restore($temp_1); } $self->_add_inst('','set',[$return,1]); $self->_add_inst("DONE_$label"); - _restore($temp_0); + $self->_restore($temp_0); return $return; } @@ -484,15 +771,15 @@ my $label = $self->_gensym(); $return = $self->_constant(0); - my $temp_0 = $self->_generate($node->{children}[0]); - for(1..$#{$node->{children}}) { - my $temp_1 = $self->_generate($node->{children}[1]); + my $temp_0 = $self->_generate($node->{children}[1]); + for(2..$#{$node->{children}}) { + my $temp_1 = $self->_generate($node->{children}[$_]); $self->_add_inst('','gt',[$temp_0,$temp_1,"DONE_$label"]); - _restore($temp_1); + $self->_restore($temp_1); } $self->_add_inst('','set',[$return,1]); $self->_add_inst("DONE_$label"); - _restore($temp_0); + $self->_restore($temp_0); return $return; } @@ -502,15 +789,15 @@ my $label = $self->_gensym(); $return = $self->_constant(0); - my $temp_0 = $self->_generate($node->{children}[0]); - for(1..$#{$node->{children}}) { - my $temp_1 = $self->_generate($node->{children}[1]); + my $temp_0 = $self->_generate($node->{children}[1]); + for(2..$#{$node->{children}}) { + my $temp_1 = $self->_generate($node->{children}[$1]); $self->_add_inst('','lt',[$temp_0,$temp_1,"DONE_$label"]); - _restore($temp_1); + $self->_restore($temp_1); } $self->_add_inst('','set',[$return,1]); $self->_add_inst("DONE_$label"); - _restore($temp_0); + $self->_restore($temp_0); return $return; } @@ -520,12 +807,11 @@ my $label = $self->_gensym(); $return = $self->_constant(0); - my @temp = _save(1); $self->_add_inst('' ,'set' ,[$return,1]); - my $temp = $self->_generate($node->{children}[0]); + my $temp = $self->_generate($node->{children}[1]); $self->_add_inst('' ,'eq' ,[$temp,0,"DONE_$label"]); - _restore($temp); + $self->_restore($temp); $self->_add_inst('' ,'set' ,[$return,0]); $self->_add_inst("DONE_$label"); return $return; @@ -537,9 +823,9 @@ my $label = $self->_gensym(); $return = $self->_constant(1); - my $temp = $self->_generate($node->{children}[0]); + my $temp = $self->_generate($node->{children}[1]); $self->_add_inst('' ,'gt' ,[$temp,0,"DONE_$label"]); - _restore($temp); + $self->_restore($temp); $self->_add_inst('' ,'set' ,[$return,0]); $self->_add_inst("DONE_$label"); return $return; @@ -551,9 +837,9 @@ my $label = $self->_gensym(); $return = $self->_constant(1); - my $temp = $self->_generate($node->{children}[0]); + my $temp = $self->_generate($node->{children}[1]); $self->_add_inst('' ,'lt' ,[$temp,0,"DONE_$label"]); - _restore($temp); + $self->_restore($temp); $self->_add_inst('' ,'set' ,[$return,0]); $self->_add_inst("DONE_$label"); return $return; @@ -564,14 +850,14 @@ my $return; my $label = $self->_gensym(); - my $temp_0 = $self->_generate($node->{children}[0]); + my $temp_0 = $self->_generate($node->{children}[1]); $return = $self->_constant(1); my $temp_1 = $self->_constant(2); $self->_add_inst('' ,'mod' ,[$temp_0,$temp_0,$temp_1]); $self->_add_inst('' ,'eq' ,[$temp_0,1,"DONE_$label"]); $self->_add_inst('' ,'set' ,[$return,0]); $self->_add_inst("DONE_$label"); - _restore($temp_0,$temp_1); + $self->_restore($temp_0,$temp_1); return $return; } @@ -580,14 +866,14 @@ my $return; my $label = $self->_gensym(); - my $temp_0 = $self->_generate($node->{children}[0]); + my $temp_0 = $self->_generate($node->{children}[1]); $return = $self->_constant(1); my $temp_1 = $self->_constant(2); $self->_add_inst('' ,'mod' ,[$temp_0,$temp_0,$temp_1]); $self->_add_inst('' ,'eq' ,[$temp_0,0,"DONE_$label"]); $self->_add_inst('' ,'set' ,[$return,0]); $self->_add_inst("DONE_$label"); - _restore($temp_0,$temp_1); + $self->_restore($temp_0,$temp_1); return $return; } @@ -596,14 +882,14 @@ my $return; my $label = $self->_gensym(); - $return = $self->_generate($node->{children}[0]); - for(1..$#{$node->{children}}) { + $return = $self->_generate($node->{children}[1]); + for(2..$#{$node->{children}}) { my $temp = $self->_generate($node->{children}[$_]); my $label = $self->_gensym(); $self->_add_inst('','gt', [$return,$temp,"NEXT_$label"]); $self->_add_inst('','set',[$return,$temp]); $self->_add_inst("NEXT_$label"); - _restore($temp); + $self->_restore($temp); } return $return; } @@ -613,14 +899,14 @@ my $return; my $label = $self->_gensym(); - $return = $self->_generate($node->{children}[0]); - for(1..$#{$node->{children}}) { + $return = $self->_generate($node->{children}[1]); + for(2..$#{$node->{children}}) { my $temp = $self->_generate($node->{children}[$_]); my $label = $self->_gensym(); $self->_add_inst('','lt', [$return,$temp,"NEXT_$label"]); $self->_add_inst('','set',[$return,$temp]); $self->_add_inst("NEXT_$label"); - _restore($temp); + $self->_restore($temp); } return $return; } @@ -628,17 +914,29 @@ sub _op_plus { my ($self,$node) = @_; my $return; - my $num_children = defined $node->{children} ? @{$node->{children}} : 0; + my $num_children = defined $node->{children} ? @{$node->{children}} - 1 : 0; if($num_children==0) { $return = $self->_constant(0); } elsif($num_children==1) { - $return = $self->_generate($node->{children}[0]); + $return = $self->_generate($node->{children}[1]); + if ($return =~ /^P/) { + my $temp = $self->_save_1 ('P'); + $self->_morph ($temp, $return); + $self->_restore ($return); + $return = $temp; + } } else { - $return = $self->_generate($node->{children}[0]); - for(1..$#{$node->{children}}) { + $return = $self->_generate($node->{children}[1]); + if ($return =~ /^P/) { + my $temp = $self->_save_1 ('P'); + $self->_morph ($temp, $return); + $self->_restore ($return); + $return = $temp; + } + for(2..$#{$node->{children}}) { my $temp = $self->_generate($node->{children}[$_]); $self->_add_inst('','add',[$return,$return,$temp]); - _restore($temp); + $self->_restore($temp); } } return $return; @@ -647,22 +945,34 @@ sub _op_minus { my ($self,$node) = @_; my $return; - my $num_children = defined $node->{children} ? @{$node->{children}} : 0; + my $num_children = defined $node->{children} ? @{$node->{children}} - 1 : 0; if($num_children==0) { $return = $self->_constant(0); } elsif($num_children==1) { - $return = $self->_generate($node->{children}[0]); + $return = $self->_generate($node->{children}[1]); + if ($return =~ /^P/) { + my $temp = $self->_save_1 ('P'); + $self->_morph ($temp, $return); + $self->_restore ($return); + $return = $temp; + } my $temp = $self->_constant(0); $self->_add_inst('','sub',[$return,$temp,$return]); - _restore($temp); + $self->_restore($temp); } else { - $return = $self->_generate($node->{children}[0]); - for(1..$#{$node->{children}}) { - my $temp = $self->_generate($node->{children}[$_]); - $self->_add_inst('','sub',[$return,$return,$temp]); - _restore($temp); - } + $return = $self->_generate($node->{children}[1]); + if ($return =~ /^P/) { + my $temp = $self->_save_1 ('P'); + $self->_morph ($temp, $return); + $self->_restore ($return); + $return = $temp; + } + for(2..$#{$node->{children}}) { + my $temp = $self->_generate($node->{children}[$_]); + $self->_add_inst('','sub',[$return,$return,$temp]); + $self->_restore($temp); + } } return $return; } @@ -670,18 +980,30 @@ sub _op_times { my ($self,$node) = @_; my $return; - my $num_children = defined $node->{children} ? @{$node->{children}} : 0; + my $num_children = defined $node->{children} ? @{$node->{children}} - 1: 0; if($num_children==0) { $return = $self->_constant(0); } elsif($num_children==1) { - $return = $self->_generate($node->{children}[0]); + $return = $self->_generate($node->{children}[1]); + if ($return =~ /^P/) { + my $temp = $self->_save_1 ('P'); + $self->_morph ($temp, $return); + $self->_restore ($return); + $return = $temp; + } } else { - $return = $self->_generate($node->{children}[0]); - for(1..$#{$node->{children}}) { + $return = $self->_generate($node->{children}[1]); + if ($return =~ /^P/) { + my $temp = $self->_save_1 ('P'); + $self->_morph ($temp, $return); + $self->_restore ($return); + $return = $temp; + } + for(2..$#{$node->{children}}) { my $temp = $self->_generate($node->{children}[$_]); $self->_add_inst('','mul',[$return,$return,$temp]); - _restore($temp); + $self->_restore($temp); } } return $return; @@ -690,21 +1012,33 @@ sub _op_divide { my ($self,$node) = @_; my $return; - my $num_children = defined $node->{children} ? @{$node->{children}} : 0; + my $num_children = defined $node->{children} ? @{$node->{children}} - 1 : 0; if($num_children==0) { $return = $self->_constant(0); } elsif($num_children==1) { - $return = $self->_generate($node->{children}[0]); + $return = $self->_generate($node->{children}[1]); + if ($return =~ /^P/) { + my $temp = $self->_save_1 ('P'); + $self->_morph ($temp, $return); + $self->_restore ($return); + $return = $temp; + } my $temp = $self->_constant(1); $self->_add_inst('','div',[$return,$temp,$return]); - _restore($temp); + $self->_restore($temp); } else { - $return = $self->_generate($node->{children}[0]); - for(1..$#{$node->{children}}) { + $return = $self->_generate($node->{children}[1]); + if ($return =~ /^P/) { + my $temp = $self->_save_1 ('P'); + $self->_morph ($temp, $return); + $self->_restore ($return); + $return = $temp; + } + for(2..$#{$node->{children}}) { my $temp = $self->_generate($node->{children}[$_]); $self->_add_inst('','div',[$return,$return,$temp]); - _restore($temp); + $self->_restore($temp); } } return $return; @@ -715,11 +1049,11 @@ my $return; my $label = $self->_gensym(); - $return = $self->_generate($node->{children}[0]); + $return = $self->_generate($node->{children}[1]); $self->_add_inst('', 'gt', [$return,0,"DONE_$label"]); my $temp = $self->_constant(-1); $self->_add_inst('', 'mul',[$return,$return,$temp]); - _restore($temp); + $self->_restore($temp); $self->_add_inst("DONE_$label"); return $return; } @@ -974,9 +1308,41 @@ } sub _op_procedure_p { + my ($self, $node) = @_; + my $return; + + _check_num_arg ($node, 1, 'procedure?'); + + $return = self->_constant(0); + + my $temp = $self->_generate(_get_arg($node,1)); + if ($temp =~ /^P/) { + } + + return $return; } sub _op_apply { + my ($self, $node) = @_; + my $return; + + my $func = $self->_generate(_get_arg ($node, 1)); + my @args = _get_args ($node, 2); + die "apply: wrong number of args\n" unless @args; + + my $argl = $self->_generate(pop @args); + while (@args) { + my $elem = $self->_generate(pop @args); + my $pair = _save_1('P'); + $self->_add_inst ('','new',[$pair,'.Array']); + $self->_add_inst ('','set',[$pair,2]); + $self->_add_inst ('','set',[$pair.'[0]',$elem]); + $self->_add_inst ('','set',[$pair.'[1]',$argl]); + } + + $return = $self->_call_function ('apply'); + + return $return; } sub _op_map { @@ -1044,24 +1410,19 @@ sub _op_write { my ($self,$node) = @_; - for(@{$node->{children}}) { - my $temp = $self->_generate($_); + my $temp = 'none'; + + for(_get_args($node)) { + $self->_restore ($temp); + $temp = $self->_generate($_); if ($temp =~ /[INS]/) { $self->_add_inst('','print',[$temp]); } else { - $self->_use_function ('write'); - if ($temp ne 'P5') { - $self->_add_inst('', 'save', ['P5']) if $regs->{P}{5}; - $self->_add_inst('', 'set', ['P5',$temp]); - } - $self->_add_inst('', 'bsr', ['write_ENTRY']); - if ($temp ne 'P5' && $regs->{P}{5}) { - $self->_add_inst('', 'restore', ['P5']); - } + $self->_call_function ('write',$temp); } - _restore($temp); } + return $temp; # We need to return something } sub _op_display { @@ -1122,8 +1483,6 @@ my %global_ops = ( - 'CONSTANT' => \&_op_constant, - #---------------------- # # Section 4 Expressions @@ -1133,6 +1492,7 @@ 'quote' => \&_op_quote, 'lambda' => \&_op_lambda, 'if' => \&_op_if, + 'define' => \&_op_define, 'set!' => \&_op_set_bang, 'cond' => \&_op_cond, 'case' => \&_op_case, @@ -1420,11 +1780,47 @@ @max_len; } -sub _use_function { - my ($self, $name) = @_; +sub _call_function { + my $self = shift; + my $func = shift; + + push @{$self->{functions}}, $func + unless grep { $_ eq $func } @{$self->{functions}}; + + my $return = $self->_save_1 ('P'); + $self->_restore ($return); # dont need to save this + + $self->_save_set; + + my $count = 5; + my $empty = $return; + while (my $arg = shift) { + if ($arg ne "P$count") { + # Check if any later argument needs the old value of P$count + my $moved; + for (@_) { + if ($_ eq "P$count") { + $moved = $_; + $_ = $empty; + } + } + if ($moved) { + $self->_add_inst ('', 'set',[$empty,"P$count"]); + $empty = $moved; + } + $self->_add_inst ('','set',["P$count",$arg]); + } + $count++; + } + + $self->_add_inst ('', 'bsr', [$func.'_ENTRY']); + $self->_add_inst ('', 'set', [$return,'P5']) unless $return eq 'P5'; + $self->_restore_set; + + $return =~ /(\w)(\d+)/; + $self->{regs}->{$1}->{$2} = 1; - push @{$self->{functions}}, $name - unless grep { $_ eq $name } @{$self->{functitons}}; + return $return; } sub _format_columns { @@ -1451,7 +1847,8 @@ my $tree = shift; my $self = { tree => $tree, - register => [(0) x 32], + regs => _new_regs, + frames => [], gensym => 0, functions=> [], }; @@ -1475,15 +1872,37 @@ my ($self,$node) = @_; my $return; - if($node->{value} =~ /\d/) { - $return = $global_ops{CONSTANT}->($self,$node); + if (exists $node->{children}) { + my $func = _get_arg ($node, 0); + if (exists $func->{value}) { + my $symbol = $func->{value}; + if (exists $global_ops{$symbol}) { + $return = $global_ops{$symbol}->($self, $node); + } else { + my $func_obj = $self->_find_lex ($symbol); + my $argl = $self->_op_list ($node); + $return = $self->_call_function('apply', $func_obj, $argl); + $self->_restore ($func_obj, $argl); + } + } else { + my $func_obj = $self->_generate ($func); + my $argl = $self->_op_list ($node); + $return = $self->_call_function('apply', $func_obj, $argl); + $self->_restore ($func_obj, $argl); + } } else { - $return = $global_ops{$node->{value}}->($self,$node); + my $value = $node->{value}; + if ($value =~ /^[a-zA-Z]/) { + $return = $self->_find_lex($value); + } + else { + $return = $self->_constant($node->{value}); + } } - $return; + return $return; } -sub _link_buildins { +sub _link_builtins { my ($self) = @_; for (@{$self->{functions}}) { @@ -1493,12 +1912,18 @@ sub generate { my $self = shift; - my @temp = _save(1); - $self->_generate($self->{tree},$temp[0]); + my $temp; + + $self->{scope} = {}; + $self->_add_inst ('', 'new_pad',[0]); + + $temp = $self->_generate($self->{tree}); + + $self->_add_inst ('', 'pop_pad'); #die Dumper($self->{tree}); - _restore(@temp); + $self->_restore($temp); $self->_add_inst('',"end"); - $self->_link_buildins(); + $self->_link_builtins(); $self->_format_columns(); } Index: languages/scheme/Scheme/Parser.pm =================================================================== RCS file: /cvs/public/parrot/languages/scheme/Scheme/Parser.pm,v retrieving revision 1.2 diff -u -r1.2 Parser.pm --- languages/scheme/Scheme/Parser.pm 24 Mar 2002 23:42:38 -0000 1.2 +++ languages/scheme/Scheme/Parser.pm 13 Nov 2002 21:36:25 -0000 @@ -9,27 +9,34 @@ use Data::Dumper; +my $ind = 0; sub _build_tree { my ($tokens,$count) = @_; my $temp = {}; - $count++; + die "EOF reached" if $count >= $#$tokens; - while($tokens->[$count] ne ')') { - if($tokens->[$count] eq '(') { - my ($lcount,$ltemp) = _build_tree($tokens,$count); - $count = $lcount; - push @{$temp->{children}},$ltemp; - } else { - if(exists $temp->{value} or exists $temp->{children}) { - push @{$temp->{children}},{value=>$tokens->[$count]}; - } else { - $temp->{value} = $tokens->[$count]; - } + if ($tokens->[$count] eq '(') { + $temp->{children} = []; + $count++; + while($tokens->[$count] ne ')') { + my $expr; + ($count, $expr) = _build_tree ($tokens, $count); + push @{$temp->{children}}, $expr; } $count++; } - + elsif ($tokens->[$count] eq "'") { + $temp = { children => [{ value => 'quote' }] }; + my $expr; + $count++; + ($count, $expr) = _build_tree ($tokens, $count); + push @{$temp->{children}}, $expr; + } + else { + $temp->{value} = $tokens->[$count++]; + } + return ($count,$temp); } @@ -57,9 +64,23 @@ sub parse { my $tokens = shift; - my (undef,$tree) = _build_tree($tokens,0); - _dataflow($tree); + my @tree; + my $tree; + my $count = 0; + + while ($count < scalar @$tokens) { + #print Dumper $tokens; + ($count,$tree) = _build_tree($tokens,$count); + #_dataflow($tree); + #print Data::Dumper->Dump ([$count, $tree]); + push @tree, $tree; + } + + # Implicit begin at toplevel + if (@tree > 1) { + $tree = { children => [ { value => 'begin' }, @tree ] }; + } return $tree; } Index: languages/scheme/Scheme/Tokenizer.pm =================================================================== RCS file: /cvs/public/parrot/languages/scheme/Scheme/Tokenizer.pm,v retrieving revision 1.3 diff -u -r1.3 Tokenizer.pm --- languages/scheme/Scheme/Tokenizer.pm 5 Sep 2002 15:03:55 -0000 1.3 +++ languages/scheme/Scheme/Tokenizer.pm 13 Nov 2002 21:36:25 -0000 @@ -18,6 +18,7 @@ open SOURCE,"<$file"; while(<SOURCE>) { next if /^\s*;/; + s/;.*$//; $text .= $_; } close SOURCE; Index: languages/scheme/t/logic/defines.t =================================================================== RCS file: languages/scheme/t/logic/defines.t diff -N languages/scheme/t/logic/defines.t --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ languages/scheme/t/logic/defines.t 13 Nov 2002 21:36:26 -0000 @@ -0,0 +1,100 @@ +#! perl -w + +use Scheme::Test tests => 12; + +output_is (<<'CODE', 'a', 'a symbol'); +(write 'a) ; for emacs ') +CODE + +output_is (<<'CODE', '5', 'define'); +(define a 5) +(write a) +CODE + +output_is (<<'CODE', '5', 'define II'); +(define a 4) +(define b (+ a 1)) +(write b) +CODE + +output_is (<<'CODE', '8', 'set!'); +(define a 5) +(set! a 8) +(write a) +CODE + +output_is (<<'CODE', '13', 'set! II'); +(define a 5) +(set! a (+ a 8)) +(write a) +CODE + +output_is (<<'CODE', '(2 1)', 'define function'); +(define (f a b) (list b a)) +(write (f 1 2)) +CODE + +output_is (<<'CODE', '3', 'define via lambda'); +(define sum (lambda (a b) (+ a b))) +(write (sum 1 2)) +CODE + +output_is (<<'CODE', '101', 'let'); +(let ((a 1)) + (write a) + (let ((a 0) + (b 0)) + (write a)) + (write a)) +CODE + +output_is (<<'CODE', '321', 'counter'); +(define (make-counter val) + (lambda () + (set! val (- val 1)) + val) +) +(define counter (make-counter 4)) +(write (counter)) +(write (counter)) +(write (counter)) +CODE + +output_is (<<'CODE', '9837', '2 counter'); +(define (make-counter val) + (lambda () + (set! val (- val 1)) + val) +) +(define ci (make-counter 10)) +(write (ci)) +(define cii (make-counter 4)) +(write (ci)) +(write (cii)) +(write (ci)) +CODE + +output_is (<<'CODE', '012023', 'yet another counter'); +(define (make-counter incr) + (let ((val 0)) + (lambda () + (let ((ret val)) + (set! val (+ incr val)) + ret)))) +(define ci (make-counter 1)) +(write (ci)) +(write (ci)) +(define cii (make-counter 2)) +(write (ci)) +(write (cii)) +(write (cii)) +(write (ci)) +CODE + +output_is (<<'CODE','120','fakultaet'); +(define (fak n) + (if (= n 0) + 1 + (* n (fak (- n 1))))) +(write (fak 5)) +CODE Index: languages/scheme/t/logic/lists.t =================================================================== RCS file: /cvs/public/parrot/languages/scheme/t/logic/lists.t,v retrieving revision 1.1 diff -u -r1.1 lists.t --- languages/scheme/t/logic/lists.t 5 Sep 2002 19:55:13 -0000 1.1 +++ languages/scheme/t/logic/lists.t 13 Nov 2002 21:36:26 -0000 @@ -1,10 +1,6 @@ #! perl -w -use Scheme::Test tests => 15; - -### -### Add -### +use Scheme::Test tests => 21; output_is(<<'CODE', '(2 . 5)', 'cons'); (write (cons 2 5)) @@ -81,4 +77,32 @@ output_is(<<'CODE', '(1 4 2)', 'set-cdr!'); (write (set-cdr! (list 1 2 3) (list 4 2))) +CODE + +output_is(<<'CODE', '(1 2 3 4)', 'quoted list'); +(write '(1 2 3 4)) ; for emacs ') +CODE + +output_is(<<'CODE', '1', 'null?'); +(write + (null? (list))) +CODE + +output_is (<<'CODE', '()', "'()"); +(write '()) ; for emacs ') +CODE + +output_is (<<'CODE', '0', 'failed null?'); +(write + (null? (list 1))) +CODE + +output_is (<<'CODE', '(1 2 (3 4))', 'complex list'); +(write + '(1 2 (3 4))) ; for emacs ') +CODE + +output_is (<<'CODE', '(1 2 (3 4))', 'complex list II'); +(write + (list 1 2 (list 3 4))) CODE
--- sub.c.orig +++ sub.c Thu Nov 7 23:15:06 2002 @@ -139,7 +139,13 @@ PMC * pad_pmc = pmc_new(interp, enum_class_Scratchpad); pad_pmc->cache.int_val = 0; - if ((base && depth > base->cache.int_val) || (!base && depth != 0)) { + if (base && depth < 0) { + depth = base->cache.int_val + depth + 1; + } + + if ((depth < 0) + || (base && depth > base->cache.int_val) + || (!base && depth != 0)) { internal_exception(-1, "-scratch_pad: too deep\n"); return NULL; }