diff options
Diffstat (limited to 'interpreter')
| -rw-r--r-- | interpreter/Elymas.pm | 3 | ||||
| -rw-r--r-- | interpreter/ElymasAsm.pm | 41 | ||||
| -rw-r--r-- | interpreter/ElymasGlobal.pm | 71 | ||||
| -rw-r--r-- | interpreter/ElymasSys.pm | 2 | ||||
| -rw-r--r-- | interpreter/Makefile | 8 |
5 files changed, 100 insertions, 25 deletions
diff --git a/interpreter/Elymas.pm b/interpreter/Elymas.pm index 6bfe4cf..0749443 100644 --- a/interpreter/Elymas.pm +++ b/interpreter/Elymas.pm @@ -52,7 +52,7 @@ sub arrayAccess { my $i = pop @$data or die "Stack underflow"; die "array index must be int" unless $i->[1] eq 'int'; - push @$data, $array->[0]->[$i->[0]]; + push @$data, $array->[0]->[$i->[0] % @{$array->[0]}]; } sub interpretCode { @@ -109,6 +109,7 @@ sub typeEqual { if($a->[0] eq 'range') { return $a->[1] == $b->[1] && $a->[2] == $b->[2]; } elsif($a->[0] eq 'array' or $a->[0] eq 'func') { + return 0 if(not defined $a->[2] or not defined $b->[2]); return 0 if(@{$a->[2]} != @{$b->[2]}); return 0 if(@{$a->[3]} != @{$b->[3]}); diff --git a/interpreter/ElymasAsm.pm b/interpreter/ElymasAsm.pm index 63b7803..2bf2295 100644 --- a/interpreter/ElymasAsm.pm +++ b/interpreter/ElymasAsm.pm @@ -6,25 +6,40 @@ use warnings; use Elymas; use ACME::Bare::Metal; +sub constructBlock { + my ($block, $size) = @_; + + my $scope; $scope = \{ + 'base' => [$block, 'int', 'passive'], + 'size' => [$size, 'int', 'passive'], + 'free' => [sub { + my ($data) = @_; + + ACME::Bare::Metal::deallocate($$scope->{'base'}->[0], $$scope->{'size'}->[0]); + }, ['func', 'sys .asm .free'], 'active'], + }; + + return $$scope; +} + our $asm = { 'alloc' => [sub { - my ($data) = @_; + my ($data) = @_; - my $size = popInt($data); - my $block = ACME::Bare::Metal::allocate($size); + my $size = popInt($data); + my $block = ACME::Bare::Metal::allocate($size); - my $scope; $scope = \{ - 'base' => [$block, 'int', 'passive'], - 'size' => [$size, 'int', 'passive'], - 'free' => [sub { - my ($data) = @_; + push @$data, [enstruct(constructBlock($block, $size))]; + }, ['func', 'sys .asm .alloc'], 'active'], + 'allocAt' => [sub { + my ($data) = @_; - ACME::Bare::Metal::deallocate($$scope->{'base'}->[0], $$scope->{'size'}->[0]); - }, ['func', 'sys .asm .free'], 'active'], - }; + my $addr = popInt($data); + my $size = popInt($data); + my $block = ACME::Bare::Metal::allocateAt($size, $addr); - push @$data, [enstruct($$scope)]; - }, ['func', 'sys .asm .alloc'], 'active'], + push @$data, [enstruct(constructBlock($block, $size))]; + }, ['func', 'sys .asm .alloc'], 'active'], 'poke' => [sub { my ($data, $scope) = @_; diff --git a/interpreter/ElymasGlobal.pm b/interpreter/ElymasGlobal.pm index 1a72a0e..66fedf1 100644 --- a/interpreter/ElymasGlobal.pm +++ b/interpreter/ElymasGlobal.pm @@ -66,6 +66,34 @@ our $global = { }, ['func', Dumper(\@code)]]; } }, ['func', '}'], 'quote'], + "}'" => [sub { + my ($data, $scope) = @_; + + --$quoted; + + my @code; + while(1) { + my $t = pop @$data or die "Stack underflow"; + last if($t->[1] eq 'tok' and $t->[0] eq '{'); + + unshift @code, $t; + }; + + if($quoted) { + push @$data, [sub { + my ($data, $scope) = @_; + push @$data, [sub { + my ($data) = @_; + interpretCode(\@code, $data, $scope); + }, ['func', Dumper(\@code)]]; + }, ['func', 'func-quoted'], \@code]; + } else { + push @$data, [sub { + my ($data) = @_; + interpretCode(\@code, $data, $scope); + }, ['func', Dumper(\@code)]]; + } + }, ['func', '}'], 'quote'], 'quoted' => [sub { my ($data, $scope) = @_; push @$data, [$quoted? 1: 0, 'int']; @@ -142,6 +170,8 @@ our $global = { # TODO permitted for now } elsif(ref($type) eq 'ARRAY' and $type->[0] eq 'array') { # TODO permitted for now + } elsif(ref($type) eq 'ARRAY' and $type->[0] eq 'struct') { + # TODO permitted for now } else { die "mismatched types in array: " . Dumper($type) unless typeEqual($type, $t->[1]); } @@ -175,7 +205,7 @@ our $global = { $member = $member->[0]; die "not a struct during member dereference in $struct" unless $struct->[1]->[0] eq 'struct'; - die "requested member $member is not in fact existent in " . Dumper($struct, $member) unless exists $struct->[1]->[1]->{$member}; + die Dumper($struct, $member) . "Cannot resolve requested member $member" unless exists $struct->[1]->[1]->{$member}; push @$data, $struct->[0]->{$member}; execute($data, $scope) if($data->[-1]->[2] eq 'active'); @@ -187,7 +217,7 @@ our $global = { my $struct = pop @$data; die "not a struct during member dereference in $struct" unless $struct->[1]->[0] eq 'struct'; - die "requested member $member is not in fact existent in " . Dumper($struct, $member) unless exists $struct->[1]->[1]->{$member}; + die Dumper($struct, $member) . "Cannot resolve requested member $member" unless exists $struct->[1]->[1]->{$member}; push @$data, $struct->[0]->{$member}; }, ['func', '.|'], 'active'], @@ -362,6 +392,27 @@ our $global = { my $d = pop @$data or die "Stack underflow"; die Dumper($d); # , $scope); }, ['func', 'die'], 'active'], + 'keys' => [sub { + my ($data, $scope) = @_; + + my $s = pop @$data or die "Stack underflow"; + + if(ref($s->[1]) eq 'ARRAY' and $s->[1]->[0] eq 'struct') { + my @keys = keys %{$s->[1]->[1]}; + + push @$data, [[map { [$_, 'string'] } @keys], ['array', '[]', [['range', 0, $#keys]], ['string']]]; + } else { + die "keys not supported on this value: " . Dumper($s); + } + }, ['func', 'keys'], 'active'], + 'strToUTF8Bytes' => [sub { + my ($data, $scope) = @_; + + my $str = popString($data); + + my @res = map { [ord, 'int'] } split //, $str; + push @$data, [\@res, ['array', 'from strToUTF8Bytes', [['range', 0, $#res]], ['int']]]; + }, ['func', 'strToUTF8Bytes'], 'active'], # stuff from J 'sig' => [sub { @@ -474,7 +525,7 @@ our $global = { push @$data, $a->[0]->{'dom'}; execute($data, $scope) if($data->[-1]->[2] eq 'active'); } else { - die "dom not supportde on this value: " . Dumper($a); + die "dom not supported on this value: " . Dumper($a); } }, ['func', 'dom'], 'active'], 'exe' => [sub { @@ -535,12 +586,12 @@ installGlobal2IntFunction('xor', sub { return ($_[0] xor $_[1])? 1: 0 }); installGlobal2IntFunction('nxor', sub { return (not ($_[0] xor $_[1]))? 1: 0 }); installGlobal2IntFunction('nor', sub { return (not ($_[0] or $_[1]))? 1: 0 }); -installGlobal2IntFunction('band', sub { return $_[0] & $_[1] }); -installGlobal2IntFunction('bnand', sub { return ~($_[0] & $_[1]) }); -installGlobal2IntFunction('bor', sub { return $_[0] | $_[1] }); -installGlobal2IntFunction('bxor', sub { return $_[0] ^ $_[1] }); -installGlobal2IntFunction('bnxor', sub { return ~($_[0] ^ $_[1]) }); -installGlobal2IntFunction('bnor', sub { return ~($_[0] | $_[1]) }); +installGlobal2IntFunction('band', sub { return (0 + $_[0]) & (0 + $_[1]) }); +installGlobal2IntFunction('bnand', sub { return ~((0 + $_[0]) & (0 + $_[1])) }); +installGlobal2IntFunction('bor', sub { return (0 + $_[0]) | (0 + $_[1]) }); +installGlobal2IntFunction('bxor', sub { return (0 + $_[0]) ^ (0 + $_[1]) }); +installGlobal2IntFunction('bnxor', sub { return ~((0 + $_[0]) ^ (0 + $_[1])) }); +installGlobal2IntFunction('bnor', sub { return ~((0 + $_[0]) | (0 + $_[1])) }); installGlobal2IntFunction('eq', sub { return ($_[0] == $_[1])? 1: 0 }); installGlobal2IntFunction('neq', sub { return ($_[0] != $_[1])? 1: 0 }); @@ -553,7 +604,7 @@ installGlobal2IntFunction('gcd', sub { my ($a, $b) = @_; ($a, $b) = ($b, $a % $b installGlobal1IntFunction('neg', sub { return -$_[0] }); installGlobal1IntFunction('not', sub { return not $_[0] }); -installGlobal1IntFunction('bnot', sub { return ~$_[0] }); +installGlobal1IntFunction('bnot', sub { return ~(0 + $_[0]) }); installGlobal1IntFunction('abs', sub { return abs $_[0] }); # FIXME: this API is ugly diff --git a/interpreter/ElymasSys.pm b/interpreter/ElymasSys.pm index d403bd6..2b7132f 100644 --- a/interpreter/ElymasSys.pm +++ b/interpreter/ElymasSys.pm @@ -107,7 +107,7 @@ sub createFile { die "read failed: $!" unless defined $ret; push @$data, [$buf, 'string']; - }, ['func', 'sys .file .writestr'], 'active'], + }, ['func', 'sys .file .readstr'], 'active'], 'write' => [sub { my ($data) = @_; diff --git a/interpreter/Makefile b/interpreter/Makefile index 278a9b0..d0b43c1 100644 --- a/interpreter/Makefile +++ b/interpreter/Makefile @@ -20,3 +20,11 @@ generate-test: 2> "test/$$f.err.correct" | tee "test/$$f.correct"; \ sleep 1; \ done + +generate-test-fast: + mkdir -p test + for f in $$(ls ../examples/working); do \ + echo $$f; \ + echo Input | ( cd ../examples/working; ../../interpreter/elymas "$$f"; echo ) \ + 2> "test/$$f.err.correct" | tee "test/$$f.correct"; \ + done |
