aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDrahflow <drahflow@gmx.de>2013-01-03 22:11:37 +0100
committerDrahflow <drahflow@gmx.de>2013-01-03 22:11:37 +0100
commit19d573cf7c6dd729289ef5151f15db51bcc79d91 (patch)
tree288980504ab3721cfa7fd0aea59514957c17b45d
parentd7d307dc6563fe27bf43cab1e83ac21204fea6c6 (diff)
Compiler can now push ints and strings
-rw-r--r--ACME-Bare-Metal/Metal.xs10
-rw-r--r--ACME-Bare-Metal/t/ACME-Bare-Metal.t11
-rw-r--r--compiler/elymasAsm.ey277
-rw-r--r--compiler/elymasAsmLib.ey81
-rw-r--r--compiler/elymasGlobal.ey93
-rw-r--r--compiler/standard.ey14
-rw-r--r--examples/working/bor.ey1
-rw-r--r--examples/working/int.ey6
-rw-r--r--examples/working/reverse.ey5
-rw-r--r--examples/working/string.ey1
-rw-r--r--interpreter/Elymas.pm3
-rw-r--r--interpreter/ElymasAsm.pm41
-rw-r--r--interpreter/ElymasGlobal.pm71
-rw-r--r--interpreter/ElymasSys.pm2
-rw-r--r--interpreter/Makefile8
-rw-r--r--notes50
16 files changed, 598 insertions, 76 deletions
diff --git a/ACME-Bare-Metal/Metal.xs b/ACME-Bare-Metal/Metal.xs
index cb7e5a0..a4e16d3 100644
--- a/ACME-Bare-Metal/Metal.xs
+++ b/ACME-Bare-Metal/Metal.xs
@@ -17,6 +17,16 @@ allocate(length)
OUTPUT:
RETVAL
+void *
+allocateAt(length, addr)
+ int length
+ void *addr
+ CODE:
+ RETVAL = mmap(addr, length, PROT_EXEC | PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
+ OUTPUT:
+ RETVAL
+
void
deallocate(block, length)
void *block
diff --git a/ACME-Bare-Metal/t/ACME-Bare-Metal.t b/ACME-Bare-Metal/t/ACME-Bare-Metal.t
index 0975996..e7e5c26 100644
--- a/ACME-Bare-Metal/t/ACME-Bare-Metal.t
+++ b/ACME-Bare-Metal/t/ACME-Bare-Metal.t
@@ -8,7 +8,7 @@
use strict;
use warnings;
-use Test::More tests => 3;
+use Test::More tests => 5;
BEGIN { use_ok('ACME::Bare::Metal') };
#########################
@@ -24,3 +24,12 @@ ok(ACME::Bare::Metal::peek($block) == 0xC3);
ACME::Bare::Metal::execute($block);
ACME::Bare::Metal::deallocate($block, 4096);
+
+$block = ACME::Bare::Metal::allocateAt(4096, 0x0000700000000000);
+ok($block > 0, "Block allocation");
+
+ACME::Bare::Metal::poke($block, 0xC3);
+ok(ACME::Bare::Metal::peek($block) == 0xC3);
+
+ACME::Bare::Metal::execute($block);
+ACME::Bare::Metal::deallocate($block, 4096);
diff --git a/compiler/elymasAsm.ey b/compiler/elymasAsm.ey
index f62f979..f11f950 100644
--- a/compiler/elymasAsm.ey
+++ b/compiler/elymasAsm.ey
@@ -3,13 +3,6 @@
16777216 ==STACKSIZE
128 ==STACKSTART
- STACKSIZE sys .asm .alloc ==mainStack
-
- # global stack layout
- # 0 - STACKSTART : global variables
- # 0 : current stack pointer
- # STACKSTART - ...: real stack
-
# hex decoding
{
"(.)(.)" regex { } { "not a valid hex-string" die } ? *
@@ -25,14 +18,14 @@
{ { streq any }_ ==reg
[
- [ /al /ax /eax /rax /none ]
- [ /cl /cx /ecx /rcx ]
- [ /dl /dx /edx /rdx ]
- [ /bl /bx /ebx /rbx ]
- [ /spl /ah /sp /esp /rsp ]
- [ /bpl /ch /bp /ebp /rbp ]
- [ /sil /si /esi /rsi ]
- [ /dil /di /edi /rdi ]
+ [ /zero /al /ax /eax /rax /none ]
+ [ /one /cl /cx /ecx /rcx ]
+ [ /two /dl /dx /edx /rdx ]
+ [ /three /bl /bx /ebx /rbx ]
+ [ /four /spl /ah /sp /esp /rsp ]
+ [ /five /bpl /ch /bp /ebp /rbp ]
+ [ /six /sil /si /esi /rsi ]
+ [ /seven /dil /di /edi /rdi ]
[ /r8b /r8w /r8d /r8 ]
[ /r9b /r9w /r9d /r9 ]
[ /r10b /r10w /r10d /r10 ]
@@ -62,26 +55,89 @@
reg regno 8 mul %38 band add
} /modrm00 deff
- { 8 { _ 256 mod -01 256 div } rep -- } /imm64 deff
- { 4 { _ 256 mod -01 256 div } rep -- } /imm32 deff
- { 2 { _ 256 mod -01 256 div } rep -- } /imm16 deff
- { } /imm8 deff
+ { =mem =reg
+ %C0
+ mem regno %07 band add
+ reg regno 8 mul %38 band add
+ } /modrm11 deff
+
+ { _ 0 ge assert 8 { _ 256 mod -01 256 div } rep -- } /imm64 deff
+ { _ 0 ge assert 4 { _ 256 mod -01 256 div } rep -- } /imm32 deff
+ { _ 0 ge assert 2 { _ 256 mod -01 256 div } rep -- } /imm16 deff
+ { _ 0 ge assert 255 band } /imm8 deff
# instructions
{ ==reg ==i
reg bit64 assert
+ i 256 lt assert
+
+ 1 /none /none reg rex
+ %83
+ /zero reg modrm11
+ i imm8
+ } /addqImm8Reg deff
+
+ { ==dst ==src
+ dst bit64 assert
+ src bit64 assert
+
+ 1 src /none dst rex
+ %01
+ src dst modrm11
+ } /addqRegReg deff
+
+ { ==reg
+ reg bit64 assert
+
+ reg regno %07 gt { 1 /none /none reg rex } rep
+ %FF
+ /two reg modrm11
+ } /callqReg deff
+
+ { ==dst ==src
+ dst bit64 assert
+ src bit64 assert
+
+ 1 src /none dst rex
+ %39
+ src dst modrm11
+ } /cmpqRegReg deff
+
+ { ==offset
+ offset 128 lt assert
+
+ %76
+ offset imm8
+ } /jbeRel8 deff
+
+ { ==offset
+ offset 128 lt assert
+
+ %7E
+ offset imm8
+ } /jleRel8 deff
+
+ { ==reg ==i
+ reg bit64 assert
1 /none /none reg rex
%B8 reg regno %07 band add
i imm64
} /movqImmReg deff
+ { ==reg
+ reg bit64 assert
+
+ 1 /none /none reg rex
+ %B8 reg regno %07 band add
+ } /movqImmOOBReg deff
+
{ ==reg ==mem
reg bit64 assert
mem bit64 assert
1 reg /none mem rex
- %89
+ %8B
reg mem modrm00
} /movqMemReg deff
@@ -90,42 +146,195 @@
mem bit64 assert
1 reg /none mem rex
- %8B
+ %89
reg mem modrm00
} /movqRegMem deff
- { =reg
+ { ==dst ==src
+ src bit64 assert
+ dst bit64 assert
+
+ 1 src /none dst rex
+ %89
+ src dst modrm11
+ } /movqRegReg deff
+
+ { ==mem ==i
+ mem bit64 assert
+ i 256 lt assert
+
+ %80
+ /one mem modrm00
+ i imm8
+ } /orbImmMem64 deff
+
+ { ==reg
reg regno %07 gt { 1 /none /none reg rex } rep
%58 reg regno %07 band add
- } /popq deff
+ } /popqReg deff
- { =reg
+ { ==reg
reg regno %07 gt { 1 /none /none reg rex } rep
%50 reg regno %07 band add
- } /pushq deff
+ } /pushqReg deff
+
+ { ==imm
+ %68
+ imm imm32
+ } /pushqImm32 deff
{
%C3
} /retn deff
+ { ==dst ==src
+ dst bit64 assert
+ src bit64 assert
+
+ 1 src /none dst rex
+ %29
+ src dst modrm11
+ } /subqRegReg deff
+
+ {
+ %0F %05
+ } /syscall deff
+
+ { ==reg ==mem
+ reg bit64 assert
+ mem bit64 assert
+
+ 1 reg /none mem rex
+ %33
+ reg mem modrm00
+ } /xorqMemReg deff
+
+ { ==mem ==reg
+ reg bit64 assert
+ mem bit64 assert
+
+ 1 reg /none mem rex
+ %31
+ reg mem modrm00
+ } /xorqRegMem deff
+
+ { ==dst ==src
+ dst bit64 assert
+ src bit64 assert
+
+ 1 src /none dst rex
+ %31
+ src dst modrm11
+ } /xorqRegReg deff
+
+ # data manipulation functions
+ { # ==addr
+ [ -01 8 { _ sys .asm .peek -01 1 add } rep -- ] reverse { -01 256 mul add } fold
+ } /peekImm64 deff
+
+ { # ==addr
+ [ -01 4 { _ sys .asm .peek -01 1 add } rep -- ] reverse { -01 256 mul add } fold
+ } /peekImm32 deff
+
+ # global stack layout
+ # 0 - STACKSTART : global variables
+ # %0 : current stack pointer
+ # %8 : current scope
+ # %10 : currently quoted
+ # STACKSTART - ...: real stack
+ STACKSIZE sys .asm .alloc ==mainStack
+ <
+ mainStack .base ==i
+ [
+ mainStack .base STACKSIZE add imm64
+ ] { i sys .asm .poke i 1 add =i } each
+ > --
+
+ {
+ [ -01 16 { _ 16 mod -01 16 div } rep -- ]
+ [ /0 /1 /2 /3 /4 /5 /6 /7 /8 /9 /A /B /C /D /E /F ] *
+ reverse |cat fold
+ } /base16encode64 deff
+
+ {
+ [ -01 8 { _ 16 mod -01 16 div } rep -- ]
+ [ /0 /1 /2 /3 /4 /5 /6 /7 /8 /9 /A /B /C /D /E /F ] *
+ reverse |cat fold
+ } /base16encode32 deff
+
+ <
+ [
+ 32 { "." } rep
+ " " "!" "\"" "#" "$" "%" "&" "ยด" "(" ")" "*" "+" "," "-" "." "/"
+ /0 /1 /2 /3 /4 /5 /6 /7 /8 /9 ":" ";" "<" "=" ">" "?"
+ "@" /A /B /C /D /E /F /G /H /I /J /K /L /M /N /O /P
+ /Q /R /S /T /U /V /W /X /Y /Z "[" "\\" "]" "^" "_"
+ "`" /a /b /c /d /e /f /g /h /i /j /k /l /m /n /o /p
+ /q /r /s /t /u /v /w /x /y /z "{" "|" "}" "~" "."
+ 128 { "." } rep
+ ] /ASCII defv
+
+ {
+ mainStack .base STACKSIZE add ==stackEnd
+ "Stack ------------\n" sys .out .writestr
+ mainStack .base peekImm64 ==addr
+ addr stackEnd gt { [ -01 stackEnd ] die } rep # Stack corrupted
+
+ { addr stackEnd lt } {
+ [
+ addr base16encode64 ": "
+ addr peekImm64 ==value
+ value base16encode64
+ value 105553116266496 ge value 123145302310912 lt and {
+ value peekImm32
+ value 4 add peekImm32 16777215 band 4294967296 mul
+ add 8 div ==length
+ 0 length 1 sub range {
+ 8 mul value add ==heapAddr
+ "\n "
+ heapAddr base16encode64
+ ": "
+ # the perl interpreter does not like full 64bit numbers and converts them into floats
+ heapAddr 4 add peekImm32 _ ==heapValueB base16encode32
+ heapAddr peekImm32 _ ==heapValueA base16encode32
+ " "
+ [ [ heapValueA heapValueB ] { 4 { _ 256 mod -01 256 div } rep -- } each ] ASCII * 8 dearray
+ } each
+ } rep
+ "\n"
+ ] |cat fold sys .out .writestr
+ addr 8 add =addr
+ } loop
+ "^^^^^^^^^^^^^^^^^^\n" sys .out .writestr
+ }
+ > -- /stackDump deff
+
+ { ==opcodes
+ opcodes len 1 sub PAGESIZE div 1 add PAGESIZE mul sys .asm .alloc /codearea defv
+ codearea .base ==i
+ opcodes { i sys .asm .poke i 1 add =i } each
+ codearea
+ } /arrayToCode deff
+
# take an array of instruction bytes and execute it on the given stack
{ ==stack ==opcodes
[
- /rbx pushq
+ /rbx pushqReg
stack /rbx movqImmReg
- /rbx /rsp movqMemReg
+ /rbx /rsp xorqMemReg
+ /rsp /rbx xorqRegMem
+ /rbx /rsp xorqMemReg
] opcodes [
stack /rbx movqImmReg
- /rsp /rbx movqRegMem
- /rbx popq
+ /rbx /rsp xorqMemReg
+ /rsp /rbx xorqRegMem
+ /rbx /rsp xorqMemReg
+ /rbx popqReg
retn
] cat cat =opcodes
- opcodes len 1 sub PAGESIZE div 1 add PAGESIZE mul sys .asm .alloc /codearea defv
- codearea .base ==i
- opcodes { i sys .asm .poke i 1 add =i } each
- codearea .base sys .asm .execute
- codearea .free
+ opcodes arrayToCode _ .base sys .asm .execute
+ .free
} /executeOn deff
{ mainStack .base executeOn } /execute deff
diff --git a/compiler/elymasAsmLib.ey b/compiler/elymasAsmLib.ey
new file mode 100644
index 0000000..341c07a
--- /dev/null
+++ b/compiler/elymasAsmLib.ey
@@ -0,0 +1,81 @@
+"elymasAsm.ey" include
+
+<
+ { assembler -01 . } ":" deff
+ "%" _ : -01 deff
+
+ <
+ 1 ==PROT_READ
+ 2 ==PROT_WRITE
+ 4 ==PROT_EXEC
+
+ 2 ==MAP_PRIVATE
+ 16 ==MAP_FIXED
+ 32 ==MAP_ANONYMOUS
+ > ==MMAP
+
+ <
+ 9 ==mmap
+ > ==SYSCALL
+
+ { =*def ==struct
+ struct values |cat fold :arrayToCode .base ==address
+ struct keys { address -101 def struct -01 . len address add =address } each
+ } /allocateOffsetStruct deff
+
+ # global data
+ <
+ # current end of heap memory (grows upwards)
+ [ %00 %00 %00 %00 %00 %60 %00 %00 ] ==heapEnd
+
+ # next free byte at end of heap
+ [ %00 %00 %00 %00 %00 %60 %00 %00 ] ==unusedHeapStart
+ > { defv }' allocateOffsetStruct
+
+ # internal functions, ABI follows SysV standards
+
+ <
+ # allocate a chunk of memory
+ # rdi -> size of chunk in bytes
+ # rax <- address of allocated chunk
+ # chunk will have GC length header initialized correctly
+ # FIXME put a real allocator here
+ [
+ /rbx :pushqReg
+ /rdi :pushqReg
+ unusedHeapStart /rax :movqImmReg
+ /rax /rcx :movqMemReg
+ /rcx /rbx :movqRegReg
+ /rcx /rdx :movqRegReg
+ /rdi /rcx :addqRegReg
+ /rcx /rax :movqRegMem
+ heapEnd /rax :movqImmReg
+ /rax /rdi :movqMemReg
+ /rdi /rcx :cmpqRegReg
+ [
+ 4096 4096 mul /rsi :movqImmReg
+ /rsi /rdi :addqRegReg
+ /rdi /rax :movqRegMem
+ /rsi /rdi :subqRegReg
+
+ SYSCALL .mmap /rax :movqImmReg
+ # /rdi already fine
+ # /rsi already fine
+ < { MMAP -01 . } "!" deff
+ !PROT_READ !PROT_WRITE !PROT_EXEC bor bor /rdx :movqImmReg
+ !MAP_PRIVATE !MAP_FIXED !MAP_ANONYMOUS bor bor /r10 :movqImmReg
+ > --
+ /r8 :movqImmOOBReg %FF %FF %FF %FF %FF %FF %FF %FF
+ 0 /r9 :movqImmReg
+ :syscall
+ ] |len { :jbeRel8 } -21*0*221* dearray
+ /rbx /rax :movqRegReg
+ /rdi :popqReg
+ /rdi /rax :movqRegMem
+ /rbx :popqReg
+ :retn
+ ] /internalAllocate defv
+ > { defv }' allocateOffsetStruct
+> /assemblerLibrary defv
+
+# vim: syn=elymas
diff --git a/compiler/elymasGlobal.ey b/compiler/elymasGlobal.ey
index c339ede..6a92f50 100644
--- a/compiler/elymasGlobal.ey
+++ b/compiler/elymasGlobal.ey
@@ -1,13 +1,89 @@
-"elymasAsm.ey" include
+"elymasAsmLib.ey" include
-0 /TOKINT defv
-1 /TOKSTR defv
-2 /TOKID defv
+<
+ [ /0 /1 /2 /3 /4 /5 /6 /7 /8 /9 ] ==digits
+
+ { 0 ==result
+ { "(.)(.*)" regex } {
+ { streq }_ digits -01 index result 10 mul add =result
+ } loop
+ result
+ }
+> -- /base10decode deff
+
+<
+ { assembler -01 . } ":" deff
+ { assemblerLibrary -01 . } "::" deff
+ "%" _ : -01 deff
+
+ { .value base10decode ==v
+ [
+ # allocate int
+ 16 /rdi :movqImmReg
+ ::internalAllocate /rax :movqImmReg
+ /rax :callqReg
+
+ # push int address on program stack
+ /rax :pushqReg
+
+ # type zero does not need to be changed
+
+ # load value
+ 8 /rax :addqImm8Reg
+ v /rdx :movqImmReg
+ /rdx /rax :movqRegMem
+ ] :execute
+ } /TOKINT
+
+ { .value strToUTF8Bytes _ =*v len _ ==exactLength
+ 1 sub 8 div 4 add 8 mul ==memoryLength
+
+ memoryLength 2147483648 lt assert
+
+ [
+ # allocate string
+ memoryLength /rdi :movqImmReg
+ ::internalAllocate /rax :movqImmReg
+ /rax :callqReg
+
+ # push string address on program stack
+ /rax :pushqReg
+
+ # set type
+ 7 /rax :addqImm8Reg
+ %10 /rax :orbImmMem64
+
+ # clear hash value
+ 1 /rax :addqImm8Reg
+ /rdx /rdx :xorqRegReg
+ /rdx /rax :movqRegMem
+
+ # load exact length
+ 8 /rax :addqImm8Reg
+ exactLength /rdx :movqImmReg
+ /rdx /rax :movqRegMem
+
+ # load string contents
+ 0 exactLength 8 div range { 8 mul ==i
+ 8 /rax :addqImm8Reg
+ /rdx :movqImmOOBReg i _ 7 add range v 8 dearray
+ /rdx /rax :movqRegMem
+ } each
+ ] :execute
+ } /TOKSTR -1010 deff
+
+ { ==token
+ # string value
+ token TOKSTR
+ # scope resolution
+ # FIXME
+ } /TOKID
+> -- 3 |defv rep
{ /f deff -101 /s defv regex { f } { s } ? * } /rxparse deff
{ " " cat
- { < /type defv /value defv > } /token deff
+ { < /handle deff /value defv > } /token deff
[ -01 { _ "" streq not } {
0 /matched defv { /f deff matched { -- } { { 1 =matched f } rxparse } ? * } /parse deff
@@ -34,17 +110,12 @@
} loop -- ]
} /tokenize deff
-{
- dump
- [ ] assembler .execute
-} /interpretToken deff
-
{ /input defv
"" {
4096 input .readstr cat
_ "" streq not
} {
- { _ "([^\\n]*)\\n(.*)" regex } { -102 -- tokenize |interpretToken each } loop
+ { _ "([^\\n]*)\\n(.*)" regex } { -102 -- tokenize { _ .handle assembler .stackDump } each } loop
} loop
} /executeFile deff
diff --git a/compiler/standard.ey b/compiler/standard.ey
index 0d96431..7df61f3 100644
--- a/compiler/standard.ey
+++ b/compiler/standard.ey
@@ -7,14 +7,18 @@
} quoted { } { * } ? *
} "}_" defq
-{ ==f _ ==a len ==l
+{ =*f _ =*a len ==l
l {
- 0 a *
- 1 l 1 sub range { a * f * } each
+ 0 a
+ 1 l 1 sub range { a f } each
} { "fold on empty array" die }
? *
} /fold deff
+{ _ =*a len ==l
+ [ 1 l range { l -01 sub a } each ]
+} /reverse deff
+
{ |or fold } /any deff
{ |and fold } /all deff
@@ -41,4 +45,8 @@
not { "Assertion failure" die } rep
} /assert deff
+{ ==s
+ [ s keys { s -01 . } each ]
+} /values deff
+
# vim: syn=elymas
diff --git a/examples/working/bor.ey b/examples/working/bor.ey
new file mode 100644
index 0000000..71386df
--- /dev/null
+++ b/examples/working/bor.ey
@@ -0,0 +1 @@
+16 2 bor dump
diff --git a/examples/working/int.ey b/examples/working/int.ey
new file mode 100644
index 0000000..1f595ec
--- /dev/null
+++ b/examples/working/int.ey
@@ -0,0 +1,6 @@
+0 dump
+1 dump
+2 dump
+1 1 add dump
+1 2 add dump
+2 1 add dump
diff --git a/examples/working/reverse.ey b/examples/working/reverse.ey
new file mode 100644
index 0000000..32d0b24
--- /dev/null
+++ b/examples/working/reverse.ey
@@ -0,0 +1,5 @@
+{ _ /a deff len /l defv
+ [ 1 l range { l -01 sub a } each ]
+} /reverse deff
+
+[ 3 2 1 ] reverse dump
diff --git a/examples/working/string.ey b/examples/working/string.ey
index 1174e14..54d1838 100644
--- a/examples/working/string.ey
+++ b/examples/working/string.ey
@@ -2,3 +2,4 @@
"a\nb" dump
"a\\b" dump
"a\"b" dump
+"thisisalongstring" dump
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
diff --git a/notes b/notes
index 368d2a0..a8be229 100644
--- a/notes
+++ b/notes
@@ -1,4 +1,7 @@
-Expressions:
+RegEx stuff: http://sebfisch.github.com/haskell-regexp/
+
+= Expressions =
+
0 1 2... -> just push themselves on the stack
"string" -> pushes "string" on the stack
<non-bareword><bareword> -> "bareword" <non-bareword>
@@ -9,6 +12,7 @@ Expressions:
bareword -> lookup "bareword" in current scopes
-> passive -> push value on the stack
-> active -> call value on current stack
+ -> quote -> call value on current stack, even in quoted mode
/ -> nop
"string" | -> resolve "string" in current scope, push value
@@ -71,7 +75,8 @@ _<digits> -> copy stack contents according to digits
A->int B->int add -> B->A->int
A->int A->int add -> A->int
-Characters:
+= Characters =
+
!: <open>
": string quote
#: line comment
@@ -107,3 +112,44 @@ a-z: bareword characters
|: passify
}: quote end
~: <open>
+
+
+= Memory Management =
+
+Inspiration: http://wiki.luajit.org/new-garbage-collector
+
+0x6???????????: Heap memory ("16 TB should be enough for everyone.")
+0x5???????????: GC black bitmap
+0x4???????????: GC allocation maps
+
+Large set of reachable, old objects
+Large set of unreachable, new objects
+Small set in between
+
+
+== Object Memory Layout ==
+
+=== Int ===
+* Length in bytes (including header, always 16)
+ bit 63-60: 0 0 0 0
+ bit 59: reserved for GC
+* value
+
+=== String ===
+* Length in bytes (including header)
+ bit 63-60: 0 0 0 1
+ bit 59: reserved for GC
+* hash (0 if not yet calculated)
+* Exact length
+* data (UTF-8)
+
+=== Struct ===
+* Length in bytes (including header)
+ bit 63-60: 0 0 1 0
+ bit 59: reserved for GC
+ bit 58: parent pointer exists (for scopes)
+ bit 57: extension area pointer exists
+* hashtable name -> offset including headers
+* parent scope (0 if no parent)
+* extension area pointer (0 if no extra members (yet))
+* data