diff options
| author | Drahflow <drahflow@gmx.de> | 2013-01-24 15:13:26 +0100 |
|---|---|---|
| committer | Drahflow <drahflow@gmx.de> | 2013-01-24 15:13:26 +0100 |
| commit | a3e9bfdc218f6e0bda4a6f43c405475aa2542458 (patch) | |
| tree | 6001013dc8d21abea8e9ff6416d1ff8decb2afe5 /compiler | |
| parent | 6da4d865cd7d8051c8609e90b43a55fd26a74582 (diff) | |
Immediate (error) strings
Diffstat (limited to 'compiler')
| -rwxr-xr-x | compiler/elymas.ey | 1 | ||||
| -rw-r--r-- | compiler/elymasAsmLib.ey | 1672 | ||||
| -rw-r--r-- | compiler/elymasGlobal.ey | 1669 | ||||
| -rw-r--r-- | compiler/elymasLexer.ey | 92 |
4 files changed, 1721 insertions, 1713 deletions
diff --git a/compiler/elymas.ey b/compiler/elymas.ey index 217614f..5d1ca63 100755 --- a/compiler/elymas.ey +++ b/compiler/elymas.ey @@ -2,6 +2,7 @@ "standard.ey" include "elymasGlobal.ey" include +"elymasLexer.ey" include 0 sys .argv _ len not { "Usage: ./elymas <input file.ey>" die } rep * sys .file -010 .open executeFile diff --git a/compiler/elymasAsmLib.ey b/compiler/elymasAsmLib.ey index b5a338d..0c9c039 100644 --- a/compiler/elymasAsmLib.ey +++ b/compiler/elymasAsmLib.ey @@ -1,9 +1,6 @@ "elymasAsm.ey" include < - 256 ==INITIALEXTENSIONSIZE - 256 ==INITIALSCOPESIZE - { assembler -01 . } ":" deff assembler .|label "@" deff "%" _ : -01 deff @@ -36,6 +33,30 @@ [ 8 str len 8 mod sub %00 rep ] cat } /toConstString deff + [ ] ==stringHoles + [ ] ==stringValues + + { ==str + ] _ len ==offset + stringValues [ str ] cat =stringValues + stringHoles [ { ==allocatedStrings ==opcodes + [ allocatedStrings str . :imm64 ] =*bytesToPatch + 0 7 range { _ bytesToPatch -01 offset add opcodes =[] } each + } ] cat =stringHoles + [ -011 len dearray %00 %00 %00 %00 %00 %00 %00 %00 + } /string deff + + { ==opcodes + stringValues len 0 gt { + < < stringValues { _ toConstString -01 == }' each > { defv }' allocateOffsetStruct > ==allocatedStrings + stringHoles { opcodes allocatedStrings -102 * } each + [ ] =stringHoles + [ ] =stringValues + } rep + + opcodes + } /stringResolve deff + < # current end of heap memory (grows upwards) [ %00 %00 %00 %00 %00 %60 %00 %00 ] ==heapEnd @@ -48,18 +69,6 @@ # current parser quote state [ %00 %00 %00 %00 %00 %00 %00 %00 ] ==currentQuoted - - # error strings - "unresolved name: " toConstString ==errUnresolvedName - "neither string nor array in len" toConstString ==errNeitherStringNorArrayInLen - "not an executable thing" toConstString ==errNotExecutable - "neither string nor array in cat" toConstString ==errNeitherStringNorArrayInCat - "type mismatch within cat" toConstString ==errMismatchInCat - "non-array passed to dom" toConstString ==errNotArrayInDom - "non-array passed to =[]" toConstString ==errNotArrayInArrayAssign - - # more constant strings - "dom" toConstString ==strDom > { defv }' allocateOffsetStruct { _ =*array len _ 4 div ==largeMoves @@ -332,6 +341,12 @@ ] /internalAllocateArray defv > { defv }' allocateOffsetStruct + { ==str + /rdi :movqImmOOBReg str string + internalDumpErrorString /rax :movqImmReg + /rax :callqReg + } /outputError deff + [ 8 /r15 :subqImm8Reg /r15 :popqMem @@ -366,823 +381,6 @@ :retn ] /unscopingFunctionFooter defv - # elymas functions, stack based ABI - - 1 ==ARRAYMARKER - 2 ==QUOTEMARKER - - # 0 -> integer - # 1 -> integer - # 0 <- result of the arithmetic operation - { ==opcodes - [ - /rbx :popqReg - - # allocate result int - 16 /rdi :movqImmReg - internalAllocate /rax :movqImmReg - /rax :callqReg - - # type zero does not need to be changed - - # actual calculation - /rcx :popqReg - 8 /rcx /rcx :movqMemDisp8Reg - - /rdx :popqReg - 8 /rdx /rdx :movqMemDisp8Reg - - opcodes _ len dearray - /rdx 8 /rax :movqRegMemDisp8 - - # push int address on program stack - /rax :pushqReg - /rbx :pushqReg - :retn - ] - } /makeArith deff - - < - # do nothing - [ - :retn - ] /ey/ defv - - # resolve in scope but never execute - # 0 -> name to resolve - # 0 <- whatever the name resolved to - [ - /rcx :popqReg - /rbx :popqReg - /rcx :pushqReg - - # scope resolution - currentScope /rdi :movqImmReg - /rdi /rdi :movqMemReg - /rbx /rsi :movqRegReg - internalResolve /rax :movqImmReg - /rax :callqReg - - /rax /rax :testqRegReg - /found :jnzLbl8 - - errUnresolvedName /rdi :movqImmReg - internalDumpErrorString /rax :movqImmReg - /rax :callqReg - /rbx /rdi :movqRegReg - internalDumpErrorString /rax :movqImmReg - /rax :callqReg - :ud2 - - @found - /rcx :popqReg - /rax :pushqReg - /rcx :pushqReg - :retn - ] :labelResolve /ey| defv - - # arithmetic functions on ints - [ /rcx /rdx :addqRegReg ] makeArith /eyadd defv - [ /rcx /rdx :subqRegReg ] makeArith /eysub defv - [ /rcx /rdx :andqRegReg ] makeArith /eyband defv - [ /rcx /rdx :orqRegReg ] makeArith /eybor defv - [ /rcx /rdx :xorqRegReg ] makeArith /eybxor defv - - [ - /rdi /rdi :xorqRegReg - 1 /rsi :movqImmReg - /rdx /rcx :cmpqRegReg - /rsi /rdx :movqRegReg - /rdi /rdx :cmovnzqRegReg - ] makeArith /eyeq defv - [ - /rdi /rdi :xorqRegReg - 1 /rsi :movqImmReg - /rdx /rcx :cmpqRegReg - /rsi /rdx :movqRegReg - /rdi /rdx :cmovgeqRegReg - ] makeArith /eygt defv - [ - /rdi /rdi :xorqRegReg - 1 /rsi :movqImmReg - /rdx /rcx :cmpqRegReg - /rsi /rdx :movqRegReg - /rdi /rdx :cmovgqRegReg - ] makeArith /eyge defv - [ - /rdi /rdi :xorqRegReg - 1 /rsi :movqImmReg - /rdx /rcx :cmpqRegReg - /rsi /rdx :movqRegReg - /rdi /rdx :cmovngqRegReg - ] makeArith /eylt defv - [ - /rdi /rdi :xorqRegReg - 1 /rsi :movqImmReg - /rdx /rcx :cmpqRegReg - /rsi /rdx :movqRegReg - /rdi /rdx :cmovngeqRegReg - ] makeArith /eyle defv - - [ - /rax :pushqReg - /rcx /rax :movqRegReg - /rdx :mulqReg - /rax /rdx :movqRegReg - /rax :popqReg - ] makeArith /eymul defv - [ - /rax :pushqReg - /rdx /rax :movqRegReg - /rdx /rdx :xorqRegReg - /rcx :divqReg - /rax :popqReg - ] makeArith /eymod defv - [ - /rax :pushqReg - /rdx /rax :movqRegReg - /rdx /rdx :xorqRegReg - /rcx :divqReg - /rax /rdx :movqRegReg - /rax :popqReg - ] makeArith /eydiv defv - - [ - /rcx /rcx :testqRegReg - /no :jzLbl8 - /rdx /rdx :testqRegReg - /no :jzLbl8 - 1 /rdx :movqImmReg - /done :jmpLbl8 - - @no - /rdx /rdx :xorqRegReg - @done - ] :labelResolve makeArith /eyand defv - - # 0 -> integer - # 0 <- the negated integer - [ - /rbx :popqReg - - # allocate result int - 16 /rdi :movqImmReg - internalAllocate /rax :movqImmReg - /rax :callqReg - - # type zero does not need to be changed - - # actual negation - /rcx :popqReg - 8 /rcx /rcx :movqMemDisp8Reg - /rcx :negqReg - /rcx 8 /rax :movqRegMemDisp8 - - # push int address on program stack - /rax :pushqReg - /rbx :pushqReg - :retn - ] /eyneg defv - - # decide between two alternatives - # 0 -> alternative 0 - # 1 -> alternative not 0 - # 2 -> decision value - # 0 <- the selected alternative - [ - /rbx :popqReg - /rcx :popqReg - /rdx :popqReg - /rax :popqReg - 8 /rax /rax :movqMemDisp8Reg - /rax /rax :testqRegReg - /rcx /rdx :cmovzqRegReg - /rdx :pushqReg - /rbx :pushqReg - :retn - ] /ey? defv - - { ==activation - # create a new entry in the current scope for the given name - # mark that entry's default action according to activation - # 0 -> name, string - # 1 -> object - [ - 8 /r15 :subqImm8Reg - /r15 :popqMem - - /rdi :popqReg - - # search for name in nametable - currentScope /rax :movqImmReg - /rax /rbx :movqMemReg # rbx == start of scope in heap - 8 /rbx /rdx :movqMemDisp8Reg # rdx == start of nametable in heap - 8 /rbx /rsi :movqMemDisp8Reg # rsi == start of nametable in heap - 8 /rsi /rsi :addqMemDisp8Reg # rsi == end of nametable in heap (according to fill) - - @nameSearch - 16 /rdx :addqImm8Reg - - # rsi: end of nametable - # rdx: current element of nametable - - /rdx /rsi :cmpqRegReg - /nameUndefined :jbeLbl8 - - /rdx :pushqReg - /rsi :pushqReg - /rdi :pushqReg - /rcx :pushqReg - /rdx /rsi :movqMemReg - internalStringEqualsCode _ len dearray - /rcx :popqReg - /rdi :popqReg - /rsi :popqReg - /rdx :popqReg - /rax /rax :testqRegReg - /nameOffsetKnown :jnzLbl8 - - # if not exists, insert - @nameUndefined - 8 /rbx /rdx :movqMemDisp8Reg # rdx == start of nametable in heap - /rdx /eax :movlMemReg # add memory length to obtain memory end - /rax /rdx :addqRegReg - - /rsi /rdx :cmpqRegReg - /enlargeNameTable :jbeLbl8 - - # insert into name table - @insertIntoNameTable - /rdi /rsi :movqRegMem - activation 8 /rsi :movqImm32MemDisp8 # set default activation mode - 8 /rbx /rdx :movqMemDisp8Reg # rdx == start of nametable in heap - 16 8 /rdx :addqImm8MemDisp8 # increment fill - /rsi /rdx :movqRegReg - /nameOffsetKnown :jmpLbl8 - - @enlargeNameTable - # if name table is already full, double size - 8 /rbx /rdx :movqMemDisp8Reg # rdx == start of nametable in heap - /rdi :pushqReg - /rdx :pushqReg - /rdx /edi :movlMemReg # load current length - /rdi /rdi :addqRegReg - - internalAllocate /rax :movqImmReg - /rax :callqReg - %30 7 /rax :orbImmMemDisp8 # set type - /rdx :popqReg - 8 /rdx /rcx :movqMemDisp8Reg - /rcx 8 /rax :movqRegMemDisp8 # copy fill - - 16 /rdx /rsi :leaqMemDisp8Reg - 16 /rax /rdi :leaqMemDisp8Reg - 16 /rcx :subqImm8Reg - 3 /rcx :shrqImm8Reg - :reprcx :movsq # copy content - - # rax == enlarged name table on heap - - /rax 8 /rbx :movqRegMemDisp8 # switch scope to new name table - - # insert into name table - /rsi :popqReg - /rsi /rdi :xchgqRegReg - /insertIntoNameTable :jmpLbl8 - - @nameOffsetKnown - 8 /rbx /rdx :subqMemDisp8Reg # substract name table address - 16 /rdx :subqImm8Reg # substract name table header size - /rdx :shrq1Reg # divide by 2 to get offset within scope - - # rdx == offset in scope - # top of stack: the object to store - - # update - # if fits within main area, fine - 32 /rdx :addqImm8Reg # add scope header size - /edx /rbx :cmplRegMem - /inDataArea :jaLbl8 - - # update within extension area - /rbx /edx :sublMemReg # substract scope length - 24 /rbx /rdi :movqMemDisp8Reg # load extension area pointer - 8 /rdx :addqImm8Reg # add extension area header length - - # if extension area is non-existent, create - /rdi /rdi :testqRegReg - /extensionAreaExists :jnzLbl8 - - /rdx :pushqReg - INITIALEXTENSIONSIZE /rdi :movqImmReg - internalAllocate /rax :movqImmReg - /rax :callqReg - /rdx :popqReg - - /rax /rdi :movqRegReg - /rdi 24 /rbx :movqRegMemDisp8 # store new extension area - /inExtensionArea :jmpLbl8 - - @extensionAreaExists - - # if extension area is full, double size - /edx /rdi :cmplRegMem - /inExtensionArea :jnbLbl8 - - # FIXME - :ud2 - - @inExtensionArea - /rdi /rbx :movqRegReg - - @inDataArea - - /rax :popqReg - /rax /rbx /rdx :movqRegMemIndex # save entry pointer - - /r15 :pushqMem - 8 /r15 :addqImm8Reg - :retn - ] :labelResolve - } 0 -101* /eydefv defv - 1 -101* /eydeff defv - 2 -01* /eydefq defv - - # assign to a scope variable - # 0 -> name to assign to - # 1 -> value to assign - # does not change the default activation mode - [ - 8 /r15 :subqImm8Reg - /r15 :popqMem - - currentScope /rdi :movqImmReg - /rdi /rdi :movqMemReg - /rbx :popqReg - /rbx /rsi :movqRegReg - internalResolve /rax :movqImmReg - /rax :callqReg - - # rax == resolved value - # rcx == address of the value just resolved - - /rax /rax :testqRegReg - /found :jnzLbl8 - - errUnresolvedName /rdi :movqImmReg - internalDumpErrorString /rax :movqImmReg - /rax :callqReg - /rbx /rdi :movqRegReg - internalDumpErrorString /rax :movqImmReg - /rax :callqReg - :ud2 - - @found - /rcx :popqMem - - /r15 :pushqMem - 8 /r15 :addqImm8Reg - :retn - ] :labelResolve /ey= defv - - # execute top stack element - # 0 -> function to execute - [ - 8 /r15 :subqImm8Reg - /r15 :popqMem - - /rdx :popqReg - - 7 /rdx /cl :movbMemDisp8Reg - %F0 /cl :andbImmReg - %50 /cl :cmpbImmReg - /normalFunction :jeLbl8 - %70 /cl :cmpbImmReg - /arrayFunction :jeLbl8 - - errNotExecutable /rdi :movqImmReg - internalDumpErrorString /rax :movqImmReg - /rax :callqReg - :ud2 - - @normalFunction - # load scope - 8 /rdx /rcx :movqMemDisp8Reg - /rcx /rcx :testqRegReg - /unscoped :jzLbl8 - - # save current scope - currentScope /rax :movqImmReg - /rax /rsi :movqMemReg - 8 /r15 :subqImm8Reg - /rsi /r15 :movqRegMem - # enter scope - /rcx /rax :movqRegMem - - # handle typed function - 16 /rdx /rcx :movqMemDisp8Reg - /rcx /rcx :testqRegReg - /typed :jnzLbl8 - - 24 /rdx /rax :movqMemDisp8Reg - 8 /rax :addqImm8Reg - /rax :callqReg - - /r15 /rcx :movqMemReg - currentScope /rax :movqImmReg - /rcx /rax :movqRegMem - 8 /r15 :addqImm8Reg - /r15 :pushqMem - 8 /r15 :addqImm8Reg - :retn - - @unscoped - 24 /rdx /rax :movqMemDisp8Reg - 8 /rax :addqImm8Reg - /rax :callqReg - - /r15 :pushqMem - 8 /r15 :addqImm8Reg - :retn - - @unscopedTyped - # TODO think about whether this should be allowed to happen - :ud2 - - @arrayFunction - # rdx == array on heap - /rbx :popqReg - - 7 /rbx /cl :movbMemDisp8Reg - %F0 /cl :andbImmReg - %00 /cl :cmpbImmReg - /arrayIntArgument :jeLbl8 - :ud2 # TODO handle the fully typed case - - @arrayIntArgument - 8 /rbx /rax :movqMemDisp8Reg # rax == requested index - /rdx /ecx :movlMemReg # load array length - 3 /rcx :shrqImm8Reg # divide by object pointer size - /rcx :decqReg # rcx == number of elements in array - - /rsi /rsi :xorqRegReg - /rdx /rsi :xchgqRegReg - - # TODO: think about skipping this if index fits - /rcx :divqReg - - # rsi == array object on heap - # rdx == correct array index - 8 8 /rdx /rsi :pushqMemIndexScaleDisp8 # use some of the CISC goodness - - /r15 :pushqMem - 8 /r15 :addqImm8Reg - :retn - - @typed - :ud2 # TODO handle typed functions and autolooping - ] :labelResolve /ey* defv - - # dump top stack element (actually drop it for now) - # FIXME: this belongs in the standard library - [ - /rax :popqReg - /rcx :popqReg - /rax :pushqReg - :retn - ] /eydump defv - - # array construction, push begin marker on stack - [ - /rax :popqReg - ARRAYMARKER :pushqImm32 - /rax :pushqReg - :retn - ] /ey[ defv - - # array construction, create array from begin marker onwards - [ - 8 /r15 :subqImm8Reg - /r15 :popqMem - - ARRAYMARKER /rax :movqImmReg - /rsp /rdi :movqRegReg - 8 /rdi :subqImm8Reg - @search - 8 /rdi :addqImm8Reg - /rdi /rax :cmpqMemReg - /search :jneLbl8 - - /rdi /rcx :movqRegReg - /rsp /rdi :subqRegReg - /rcx :pushqReg - - # rdi == size of array - internalAllocateArray /rax :movqImmReg - /rax :callqReg - - /rdi :popqReg - /rax /rdi :movqRegMem # store array pointer instead of begin marker - - /rax /ecx :movlMemReg - 3 /rcx :shrqImm8Reg - /rcx :decqReg # rcx == number of array elements - /rcx /rcx :testqRegReg - /empty :jzLbl8 - - 8 /rcx /rax /rax :leaqMemIndexScaleReg # rax == address of last cell - @copy - /rax :popqMem - 8 /rax :subqImm8Reg - /copy :loopLbl8 - - @empty - /r15 :pushqMem - 8 /r15 :addqImm8Reg - :retn - ] :labelResolve /ey] defv - - # assign array cell - # 0 -> array - # 1 -> index in array - # 2 -> value to assign - [ - 8 /r15 :subqImm8Reg - /r15 :popqMem - - /rbx :popqReg - 7 /rbx /cl :movbMemDisp8Reg - %F0 /cl :andbImmReg - %70 /cl :cmpbImmReg - /arrayAssign :jeLbl8 - - errNotArrayInArrayAssign /rdi :movqImmReg - internalDumpErrorString /rax :movqImmReg - /rax :callqReg - :ud2 - - @arrayAssign - /rax :popqReg - 8 /rax /rax :movqMemDisp8Reg - - /rbx /ecx :movlMemReg # load array length - 3 /rcx :shrqImm8Reg # divide by object pointer size - /rcx :decqReg # rcx == number of elements in array - - /rdx /rdx :xorqRegReg - - # TODO: think about skipping this if index fits - /rcx :divqReg - - # rbx == array object on heap - # rdx == correct array index - - 8 8 /rdx /rbx :popqMemIndexScaleDisp8 # directly pop into array cell - - /r15 :pushqMem - 8 /r15 :addqImm8Reg - :retn - ] :labelResolve /ey=[] defv - - # length of array or string - # 0 -> array / string - # 0 <- number of elements / characters - [ - 8 /r15 :subqImm8Reg - /r15 :popqMem - - /rax :popqReg - 7 /rax /cl :movbMemDisp8Reg - %F0 /cl :andbImmReg - %10 /cl :cmpbImmReg - /stringLen :jeLbl8 - %70 /cl :cmpbImmReg - /arrayLen :jeLbl8 - - errNeitherStringNorArrayInLen /rdi :movqImmReg - internalDumpErrorString /rax :movqImmReg - /rax :callqReg - :ud2 - - @arrayLen - /rax /rbx :movqMemReg - 8 /rbx :shlqImm8Reg # clear type bits - 11 /rbx :shrqImm8Reg # divide by 8 - /rbx :decqReg # substract header size - /done :jmpLbl8 - - @stringLen - 16 /rax /rbx :movqMemDisp8Reg - - @done - 16 /rdi :movqImmReg - internalAllocate /rax :movqImmReg - /rax :callqReg - /rax :pushqReg # push integer on the stack - - /rbx 8 /rax :movqRegMemDisp8 # store integer value - - /r15 :pushqMem - 8 /r15 :addqImm8Reg - :retn - ] :labelResolve /eylen defv - - # concatenate two arrays or strings - # 0 -> second part of new array / string - # 1 -> first part of new array / string - # 0 <- concatenated array / string - [ - 8 /r15 :subqImm8Reg - /r15 :popqMem - - /rax :popqReg - 7 /rax /cl :movbMemDisp8Reg - %F0 /cl :andbImmReg - %70 /cl :cmpbImmReg - /arrayCat :jeLbl8 - %10 /cl :cmpbImmReg - /stringCat :jeLbl8 - - errNeitherStringNorArrayInCat /rdi :movqImmReg - internalDumpErrorString /rax :movqImmReg - /rax :callqReg - :ud2 - - @arrayCat - /rbx :popqReg - - 7 /rbx /cl :movbMemDisp8Reg - %F0 /cl :andbImmReg - %70 /cl :cmpbImmReg - /mismatch :jneLbl8 - - 16 /r15 :subqImm8Reg - /rax /r15 :movqRegMem - /rbx 8 /r15 :movqRegMemDisp8 # store - - /rax /edi :movlMemReg - /rbx /edi :addlMemReg - 16 /rdi :subqImm8Reg # sum of lengths - - internalAllocateArray /rax :movqImmReg - /rax :callqReg - /rax :pushqReg # result on stack - - 8 /rax /rdi :leaqMemDisp8Reg - - 8 /r15 /rbx :movqMemDisp8Reg - /rbx /ecx :movlMemReg - 8 /rbx /rsi :leaqMemDisp8Reg - 3 /rcx :shrqImm8Reg - /rcx :decqReg - :reprcx :movsq - - /r15 /rbx :movqMemReg - /rbx /ecx :movlMemReg - 8 /rbx /rsi :leaqMemDisp8Reg - 3 /rcx :shrqImm8Reg - /rcx :decqReg - :reprcx :movsq - - 16 /r15 :addqImm8Reg - /done :jmpLbl8 - - @stringCat - # TODO - :ud2 - - @mismatch - errMismatchInCat /rdi :movqImmReg - internalDumpErrorString /rax :movqImmReg - /rax :callqReg - :ud2 - - @done - /r15 :pushqMem - 8 /r15 :addqImm8Reg - :retn - ] :labelResolve /eycat defv - - # push array contents on stack - # 0 -> number of elements to push - # 1 -> array - # 0 ... <- array contents - [ - 8 /r15 :subqImm8Reg - /r15 :popqMem - - /rcx :popqReg - 8 /rcx /rcx :movqMemDisp8Reg - - /rax :popqReg - - /rcx /rcx :testqRegReg - /empty :jzLbl8 - 8 /rdi :movqImmReg - - @loop - 1 /rdi /rax :pushqMemIndexScale - 8 /rdi :addqImm8Reg - /edi /rax :cmplRegMem - /noreset :jaLbl8 - 8 /rdi :movqImmReg - @noreset - /loop :loopLbl8 - - @empty - /r15 :pushqMem - 8 /r15 :addqImm8Reg - :retn - ] :labelResolve /eydearray defv - - # create an array containing a continuous range of ints - # 0 -> last element included in range - # 1 -> first element included in range - [ - 8 /r15 :subqImm8Reg - /r15 :popqMem - - 8 /r15 :subqImm8Reg - /r15 :popqMem - - 8 /r15 :subqImm8Reg - /r15 :popqMem - - # 8 /r15 == last element - # /r15 == first element - - 8 /r15 /rdi :movqMemDisp8Reg - 8 /rdi /rdi :movqMemDisp8Reg - /r15 /rbx :movqMemReg - 8 /rbx /rbx :movqMemDisp8Reg - - /rbx /rdi :subqRegReg - 3 /rdi :shlqImm8Reg - 8 /rdi :addqImm8Reg # one extra element, TODO: consider whether this is actually a good idea - internalAllocateArray /rax :movqImmReg - /rax :callqReg - - /rax :pushqReg # store array on stack - - 8 /rax /rdi :leaqMemDisp8Reg # fill target - 8 /r15 /rax :movqMemDisp8Reg - 8 /rax /rax :movqMemDisp8Reg # largest element - - @fill - /rax /rbx :cmpqRegReg - /done :jaLbl8 - - /rax :pushqReg - /rdi :pushqReg - # create int - 16 /rdi :movqImmReg - internalAllocate /rax :movqImmReg - /rax :callqReg - /rbx 8 /rax :movqRegMemDisp8 # store value - /rdi :popqReg - /rax /rdi :movqRegMem # store into array - /rax :popqReg - - /rbx :incqReg - 8 /rdi :addqImm8Reg - /fill :jmpLbl8 - - @done - - 16 /r15 :addqImm8Reg - /r15 :pushqMem - 8 /r15 :addqImm8Reg - :retn - ] :labelResolve /eyrange defv - - # create a new scope capturing the current one - [ - currentScope /rbx :movqImmReg - - INITIALSCOPESIZE /rdi :movqImmReg - /rbx /rsi :movqMemReg - internalAllocateScope /rax :movqImmReg - /rax :callqReg - /rax /rbx :movqRegMem # switch to new scope - - :retn - ] /ey< defv - - # push current scope onto stack - # switch current scope to its parent - [ - /rbx :popqReg - currentScope /rax :movqImmReg - /rax :pushqMem - /rax /rcx :movqMemReg - 16 /rcx /rcx :movqMemDisp8Reg - /rcx /rax :movqRegMem - /rbx :pushqReg - - :retn - ] /ey> defv - > _ ==globalFunctions { defv }' allocateOffsetStruct - { :quoteEncodingBuffer /rax :movqImmReg /rax /rdi :subqRegReg @@ -1204,777 +402,6 @@ :reprcx :movsb } /allocateCodeFromEncodingBuffer deff - < - # resolve identifier without quoting considerations act accordingly - # 0 -> identifier to resolve - [ - 8 /r15 :subqImm8Reg - /r15 :popqMem - - 8 /r15 :subqImm8Reg - /r15 :popqMem # store identifier - - # scope resolution - currentScope /rdi :movqImmReg - /rdi /rdi :movqMemReg - /r15 /rsi :movqMemReg - internalResolve /rax :movqImmReg - /rax :callqReg - - /rax /rax :testqRegReg - /unresolved :jzLbl8 - /rax :pushqReg - - 0 /rdx :cmpqImm8Reg - /inactive :jzLbl8 - 1 /rdx :cmpqImm8Reg - /active :jzLbl8 - - # TODO: "invalid activation mode" - :ud2 - - @unresolved - errUnresolvedName /rdi :movqImmReg - internalDumpErrorString /rax :movqImmReg - /rax :callqReg - /r15 /rdi :movqMemReg - internalDumpErrorString /rax :movqImmReg - /rax :callqReg - :ud2 - - @active - |ey* /rax :movqImmReg - /rax :callqReg - - @inactive - @done - 8 /r15 :addqImm8Reg - /r15 :pushqMem - 8 /r15 :addqImm8Reg - :retn - ] :labelResolve /internalExecuteIdentifierUnquoted defv - > { defv }' allocateOffsetStruct - - < - # resolve identifier according to current scope and quote mode and act accordingly - # 0 -> identifier to resolve - [ - 8 /r15 :subqImm8Reg - /r15 :popqMem - - 8 /r15 :subqImm8Reg - /r15 :popqMem # store identifier - - # scope resolution - currentScope /rdi :movqImmReg - /rdi /rdi :movqMemReg - /r15 /rsi :movqMemReg - internalResolve /rax :movqImmReg - /rax :callqReg - - /rax /rax :testqRegReg - /unresolved :jzLbl8 - - 0 /rdx :cmpqImm8Reg - /inactive :jzLbl8 - 1 /rdx :cmpqImm8Reg - /active :jzLbl8 - 2 /rdx :cmpqImm8Reg - /quoteActive :jzLbl8 - - # TODO: "invalid activation mode" - :ud2 - - @unresolved - currentQuoted /rax :movqImmReg - /rax /rax :movqMemReg - /rax /rax :testqRegReg - /constructQuotedResolve :jnzLbl8 - - errUnresolvedName /rdi :movqImmReg - internalDumpErrorString /rax :movqImmReg - /rax :callqReg - /r15 /rdi :movqMemReg - internalDumpErrorString /rax :movqImmReg - /rax :callqReg - :ud2 - - @quoteActive - /rax :pushqReg - |ey* /rax :movqImmReg - /rax :callqReg - /done :jmpLbl8 - - @active - currentQuoted /rbx :movqImmReg - /rbx /rbx :movqMemReg - /rbx /rbx :testqRegReg - /constructQuotedResolve :jnzLbl8 - - /rax :pushqReg - |ey* /rax :movqImmReg - /rax :callqReg - /done :jmpLbl8 - - @inactive - currentQuoted /rbx :movqImmReg - /rbx /rbx :movqMemReg - /rbx /rbx :testqRegReg - /constructQuotedResolve :jnzLbl8 - /rax :pushqReg - - @done - 8 /r15 :addqImm8Reg - /r15 :pushqMem - 8 /r15 :addqImm8Reg - :retn - - @constructQuotedResolve - # construct non-capturing function - :quoteEncodingBuffer /rdi :movqImmReg - unscopingFunctionHeader loadToRdi - - # push identifier - [ /rax :movqImmOOBReg ] _ len 2 eq assert - 2 dearray 256 mul add - /rdi :movwImmMem - /r15 /rsi :movqMemReg - /rsi 2 /rdi :movqRegMemDisp8 - 10 /rdi :addqImm8Reg - - [ - /rax :pushqReg - internalExecuteIdentifierUnquoted /rax :movqImmReg - /rax :callqReg - ] unscopingFunctionFooter cat loadToRdi - - allocateCodeFromEncodingBuffer - # rax == code block on heap - - # create non-capturing function object - /rax /rdi :movqRegReg - /rsi /rsi :xorqRegReg - /rdx /rdx :xorqRegReg - internalAllocateFunction /rax :movqImmReg - /rax :callqReg - - # rax == function object on heap - /rax :pushqReg - /done :jmpLbl32 - ] :labelResolve /internalExecuteIdentifier defv - > { defv }' allocateOffsetStruct - - < - # concatenate two functions - # 0 -> function g - # 1 -> function f - # 0 <- (f g) - [ - 8 /r15 :subqImm8Reg - /r15 :popqMem - - # construct non-capturing function - :quoteEncodingBuffer /rdi :movqImmReg - unscopingFunctionHeader loadToRdi - - /rcx :popqReg - /rdx :popqReg - - # push function f - [ /rax :movqImmOOBReg ] _ len 2 eq assert - 2 dearray 256 mul add - /rdi :movwImmMem - /rdx 2 /rdi :movqRegMemDisp8 - 10 /rdi :addqImm8Reg - [ - /rax :pushqReg - |ey* /rax :movqImmReg - /rax :callqReg - /rax :movqImmOOBReg - ] loadToRdi - # push function g - /rcx /rdi :movqRegMem - 8 /rdi :addqImm8Reg - [ - /rax :pushqReg - |ey* /rax :movqImmReg - /rax :callqReg - ] unscopingFunctionFooter cat loadToRdi - - allocateCodeFromEncodingBuffer - # rax == code block on heap - - # create non-capturing function object - /rax /rdi :movqRegReg - /rsi /rsi :xorqRegReg - /rdx /rdx :xorqRegReg - internalAllocateFunction /rax :movqImmReg - /rax :callqReg - - # rax == function object on heap - /rax :pushqReg - - /r15 :pushqMem - 8 /r15 :addqImm8Reg - :retn - ] :labelResolve /ey; defv - - # drop top stack element - [ - /rax :popqReg - /rcx :popqReg - /rax :pushqReg - :retn - ] /ey-- defv - - # duplicate top stack element - [ - /rax :popqReg - /rcx :popqReg - /rcx :pushqReg - /rcx :pushqReg - /rax :pushqReg - :retn - ] /ey_ defv - - # top stack element is a string defining a stack shuffle - # 0-9: push the thusly numbered element - # *: execute top element - # pops as many elements as the highest number specifies - [ - 8 /r15 :subqImm8Reg - /r15 :popqMem - 80 /r15 :subqImm8Reg - - /rdi :popqReg - 16 /rdi /rcx :movqMemDisp8Reg # load string length - 24 /rdi /rax :leaqMemDisp8Reg # rax to begin of string - - 42 /rsi :movqImmReg # initialize with '*' - - # find maximal element, note that '*' < '0' - @maximalElementSearch - /rax /rdx :movzxMem8Reg64 - /rsi /rdx :cmpqRegReg - /rdx /rsi :cmovaqRegReg - /rax :incqReg - /maximalElementSearch :loopLbl8 - - # move elements to temporary storage - 42 /rsi :cmpqImm8Reg - /elementsSaved :jeLbl8 - - 47 /rsi :subqImm8Reg # substract '0'-1 - /rsi /rcx :movqRegReg - /rsi /rsi :xorqRegReg - - @saveElements - 8 /rsi /r15 :popqMemIndexScale - /rsi :incqReg - /saveElements :loopLbl8 - - # execute shuffle specification - @elementsSaved - 16 /rdi /rcx :movqMemDisp8Reg # load string length - 24 /rdi /rax :leaqMemDisp8Reg # rax to begin of string - - @executeSpec - /rax /rdx :movzxMem8Reg64 - /rax :incqReg - - 42 /rdx :cmpqImm8Reg - /executeTop :jeLbl8 - - 48 /rdx :subqImm8Reg # substract '0' - 8 /rdx /r15 :pushqMemIndexScale - /executeSpec :loopLbl8 - /done :jmpLbl8 - - @executeTop - 24 /r15 :subqImm8Reg - /rax 16 /r15 :movqRegMemDisp8 - /rcx 8 /r15 :movqRegMemDisp8 - /rdx /r15 :movqRegMem - |ey* /rax :movqImmReg - /rax :callqReg - /r15 /rdx :movqMemReg - 8 /r15 /rcx :movqMemDisp8Reg - 16 /r15 /rax :movqMemDisp8Reg - 24 /r15 :addqImm8Reg - /executeSpec :loopLbl8 - - @done - 80 /r15 :addqImm8Reg - /r15 :pushqMem - 8 /r15 :addqImm8Reg - :retn - ] :labelResolve /ey- defv - - # execute top stack element multiple times - # 0 -> function to execute - # 1 -> how often to execute it - [ - 8 /r15 :subqImm8Reg - /r15 :popqMem - - 8 /r15 :subqImm8Reg - /r15 :popqMem # store function to call - - 8 /r15 :subqImm8Reg - /rcx :popqReg - 8 /rcx /rcx :movqMemDisp8Reg - - /rcx /rcx :testqRegReg - /end :jzLbl8 - - @loop - /rcx /r15 :movqRegMem - - 8 /r15 :pushqMemDisp8 - |ey* /rax :movqImmReg - /rax :callqReg - - /r15 /rcx :movqMemReg - /loop :loopLbl8 - - @end - 16 /r15 :addqImm8Reg - - /r15 :pushqMem - 8 /r15 :addqImm8Reg - :retn - ] :labelResolve /eyrep defv - - # a normal loop - # 0 -> second part of loop - # 1 -> first part of loop - # execute first part, if top of stack is nonzero, execute second part, repeat - [ - 8 /r15 :subqImm8Reg - /r15 :popqMem - - 8 /r15 :subqImm8Reg - /r15 :popqMem - - 8 /r15 :subqImm8Reg - /r15 :popqMem - - # /r15 -> first part - # 8 /r15 -> second part - - @loop - /r15 :pushqMem - |ey* /rax :movqImmReg - /rax :callqReg - - /rax :popqReg - 0 8 /rax :cmpqImm8MemDisp8 - /end :jzLbl8 - - 8 /r15 :pushqMemDisp8 - |ey* /rax :movqImmReg - /rax :callqReg - /loop :jmpLbl8 - - @end - - 16 /r15 :addqImm8Reg - - /r15 :pushqMem - 8 /r15 :addqImm8Reg - :retn - ] :labelResolve /eyloop defv - - # a foreach loop - # 0 -> code to execute - # 1 -> array to loop over - # for each element in array, push it onto stack then execute the code - [ - 8 /r15 :subqImm8Reg - /r15 :popqMem - - 8 /r15 :subqImm8Reg - /r15 :popqMem - - 16 /r15 :subqImm8Reg - - /rax :popqReg - 8 /rax /rcx :leaqMemDisp8Reg - /rcx /r15 :movqRegMem - - /rax /edx :movlMemReg - 1 /rdx /rax /rcx :leaqMemIndexScaleReg - /rcx 8 /r15 :movqRegMemDisp8 - - # /r15 -> current array element - # 8 /r15 -> address after last array element - # 16 /r15 -> code to execute - - @loop - /r15 /rax :movqMemReg - 8 /r15 /rax :cmpqMemDisp8Reg - /end :jnbLbl8 - - /rax :pushqMem # push array element - 16 /r15 :pushqMemDisp8 # push code - |ey* /rax :movqImmReg - /rax :callqReg - - 8 /r15 :addqImm8Mem - /loop :jmpLbl8 - - @end - - 24 /r15 :addqImm8Reg - /r15 :pushqMem - 8 /r15 :addqImm8Reg - :retn - ] :labelResolve /eyeach defv - - # explicitely resolve a scope member - # 0 -> member name - # 1 -> scope - [ - 8 /r15 :subqImm8Reg - /r15 :popqMem - - 8 /r15 :subqImm8Reg - /r15 :popqMem # store identifier - - /rdi :popqReg # fetch scope - /r15 /rsi :movqMemReg - internalResolve /rax :movqImmReg - /rax :callqReg - - /rax /rax :testqRegReg - /unresolved :jzLbl8 - /rax :pushqReg - - 0 /rdx :cmpqImm8Reg - /inactive :jzLbl8 - 1 /rdx :cmpqImm8Reg - /active :jzLbl8 - - # TODO: "invalid activation mode" - :ud2 - - @unresolved - errUnresolvedName /rdi :movqImmReg - internalDumpErrorString /rax :movqImmReg - /rax :callqReg - /r15 /rdi :movqMemReg - internalDumpErrorString /rax :movqImmReg - /rax :callqReg - :ud2 - - @active - |ey* /rax :movqImmReg - /rax :callqReg - - @inactive - @done - 8 /r15 :addqImm8Reg - /r15 :pushqMem - 8 /r15 :addqImm8Reg - :retn - ] :labelResolve /ey. defv - - # explicitely resolve a scope member, but never execute - # 0 -> member name - # 1 -> scope - [ - 8 /r15 :subqImm8Reg - /r15 :popqMem - - 8 /r15 :subqImm8Reg - /r15 :popqMem # store identifier - - /rdi :popqReg # fetch scope - /r15 /rsi :movqMemReg - internalResolve /rax :movqImmReg - /rax :callqReg - - /rax /rax :testqRegReg - /unresolved :jzLbl8 - /rax :pushqReg - - 8 /r15 :addqImm8Reg - /r15 :pushqMem - 8 /r15 :addqImm8Reg - :retn - - @unresolved - errUnresolvedName /rdi :movqImmReg - internalDumpErrorString /rax :movqImmReg - /rax :callqReg - /r15 /rdi :movqMemReg - internalDumpErrorString /rax :movqImmReg - /rax :callqReg - :ud2 - ] :labelResolve /ey.| defv - - # enumerate scope keys - # 0 -> scope - # 0 <- array of keys - [ - 8 /r15 :subqImm8Reg - /r15 :popqMem - - /rax :popqReg - 8 /rax /rax :movqMemDisp8Reg - - 16 /rax /rsi :leaqMemDisp8Reg - /rsi :pushqReg - 8 /rax /rdi :movqMemDisp8Reg - 16 /rdi :subqImm8Reg - /rdi :pushqReg - /rdi :shrq1Reg - internalAllocateArray /rax :movqImmReg - /rax :callqReg - - 8 /rax /rdi :leaqMemDisp8Reg - /rcx :popqReg - /rsi :popqReg - 4 /rcx :shrqImm8Reg - /empty :jzLbl8 - @loop - :movsq - 8 /rsi :addqImm8Reg - /loop :loopLbl8 - @empty - - /rax :pushqReg - - /r15 :pushqMem - 8 /r15 :addqImm8Reg - :retn - ] :labelResolve /eykeys defv - > _ ==globalFunctions2 { defv }' allocateOffsetStruct - - < - # domain of an array - # 0 -> array - # 0 <- an array containing the integers from 0 to len 1 sub - [ - 8 /r15 :subqImm8Reg - /r15 :popqMem - - /rax :popqReg - 7 /rax /cl :movbMemDisp8Reg - %F0 /cl :andbImmReg - %70 /cl :cmpbImmReg - /arrayDom :jeLbl8 - %20 /cl :cmpbImmReg - /scopeDom :jeLbl8 - - errNotArrayInDom /rdi :movqImmReg - internalDumpErrorString /rax :movqImmReg - /rax :callqReg - :ud2 - - @arrayDom - /rax /edi :movlMemReg - 8 /rdi :subqImm8Reg # substract header length - - internalAllocateArray /rax :movqImmReg - /rax :callqReg - /rax :pushqReg # result on stack - - 8 /rax /rdi :leaqMemDisp8Reg - /rbx /rbx :xorqRegReg - /rax /ecx :movlMemReg - 3 /rcx :shrqImm8Reg - /rcx :decqReg - - @loop - /rcx /rbx :cmpqRegReg - /end :jnbLbl8 - - /rdi :pushqReg - /rcx :pushqReg - 16 /rdi :movqImmReg - internalAllocate /rax :movqImmReg - /rax :callqReg - /rcx :popqReg - /rdi :popqReg - /rax 8 /rbx /rdi :movqRegMemIndexScale # store in array - /rbx 8 /rax :movqRegMemDisp8 # store value in int - /rbx :incqReg - /loop :jmpLbl8 - - @end - /r15 :pushqMem - 8 /r15 :addqImm8Reg - :retn - - @scopeDom - /rax :pushqReg - strDom /rax :movqImmReg - /rax :pushqReg - |ey. /rax :movqImmReg - /rax :callqReg - /end :jmpLbl8 - ] :labelResolve /eydom defv - > _ ==globalFunctions3 { defv }' allocateOffsetStruct - - < - # quote construction, push begin marker on stack - [ - /rax :popqReg - QUOTEMARKER :pushqImm32 - currentQuoted /rcx :movqImmReg - /rcx :incqMem - /rax :pushqReg - :retn - ] /ey{ defv - - # quote construction, create function from begin marker onwards - { ==footer ==header - [ - 8 /r15 :subqImm8Reg - /r15 :popqMem - - currentQuoted /rcx :movqImmReg - /rcx :decqMem - - QUOTEMARKER /rcx :movqImmReg - /rcx :pushqReg - /rsp /rdx :movqRegReg - @backwardsSearch - 8 /rdx :addqImm8Reg - /rdx /rcx :cmpqMemReg - /backwardsSearch :jneLbl8 - - /rdx :pushqReg # store address of begin marker - - :quoteEncodingBuffer /rdi :movqImmReg - header loadToRdi - - @search - 8 /rdx :subqImm8Reg - /rdx /rcx :cmpqMemReg - /markerFound :jeLbl8 - - /rdx /rsi :movqMemReg - 7 /rsi /al :movbMemDisp8Reg - %F0 /al :andbImmReg - /immediateFound :jzLbl8 - %10 /al :cmpbImmReg - /immediateFound :jzLbl8 - %50 /al :cmpbImmReg - /functionFound :jzLbl8 - %70 /al :cmpbImmReg - /arrayFound :jzLbl8 - - # TODO: "invalid object during quote construction" - :ud2 - - @immediateFound - [ /rax :movqImmOOBReg ] _ len 2 eq assert - 2 dearray 256 mul add - /rdi :movwImmMem - /rsi 2 /rdi :movqRegMemDisp8 - [ /rax :pushqReg ] _ len 1 eq assert - 1 dearray - 10 /rdi :movbImmMemDisp8 - 11 /rdi :addqImm8Reg - /search :jmpLbl8 - - @functionFound - [ /rax :movqImmOOBReg ] _ len 2 eq assert - 2 dearray 256 mul add - /rdi :movwImmMem - /rsi 2 /rdi :movqRegMemDisp8 - [ /rax :pushqReg ] _ len 1 eq assert - 1 dearray - 10 /rdi :movbImmMemDisp8 - 11 /rdi :addqImm8Reg - [ - |ey* /rax :movqImmReg - /rax :callqReg - ] loadToRdi - /search :jmpLbl8 - - @arrayFound - # FIXME allow macros to put byte arrays into quoted contexts and thereby generate assembly - :ud2 - /search :jmpLbl8 - - @markerFound - - footer loadToRdi - allocateCodeFromEncodingBuffer - - # rax == code block on heap - - currentQuoted /rcx :movqImmReg - /rcx /rcx :movqMemReg - /rcx /rcx :testqRegReg - /quoted :jnzLbl8 - - # create function object - /rax /rdi :movqRegReg - currentScope /rax :movqImmReg - /rax /rsi :movqMemReg - /rdx /rdx :xorqRegReg - internalAllocateFunction /rax :movqImmReg - /rax :callqReg - - @done - # rax == function object on heap - - # store function instead of begin marker - /rdx :popqReg - /rax /rdx :movqRegMem - /rdx /rsp :movqRegReg # and drop quoted stuff from stack - - /r15 :pushqMem - 8 /r15 :addqImm8Reg - :retn - - @quoted - # rax == (inner) code object on heap - - # create function which - # returns a function with the current scope captured - :quoteEncodingBuffer /rdi :movqImmReg - unscopingFunctionHeader loadToRdi - - # 1. load inner code block - [ /rdi :movqImmOOBReg ] _ len 2 eq assert - 2 dearray 256 mul add - /rdi :movwImmMem - /rax 2 /rdi :movqRegMemDisp8 - 10 /rdi :addqImm8Reg - - [ - currentScope /rax :movqImmReg - /rax /rsi :movqMemReg - /rdx /rdx :xorqRegReg - internalAllocateFunction /rax :movqImmReg - /rax :callqReg - /rax :pushqReg - ] unscopingFunctionFooter cat loadToRdi - - allocateCodeFromEncodingBuffer - - # rax == code object on heap - - # create function object - /rax /rdi :movqRegReg - /rsi /rsi :xorqRegReg # non-capturing - /rdx /rdx :xorqRegReg - internalAllocateFunction /rax :movqImmReg - /rax :callqReg - - # rax == function object on heap - - /done :jmpLbl32 - ] :labelResolve - } _ scopingFunctionHeader scopingFunctionFooter -102* /ey} defv - unscopingFunctionHeader unscopingFunctionFooter -102* /ey}' defv - > _ ==globalMacros { defv }' allocateOffsetStruct - { strToUTF8Bytes _ =*v len _ ==exactLength 1 sub 8 div 4 add 8 mul ==memoryLength @@ -2012,45 +439,6 @@ ] } /constStringCode deff - [ - globalFunctions keys len - globalFunctions2 keys len add - globalFunctions3 keys len add - globalMacros keys len add - /rdi :movqImmReg - /rsi /rsi :xorqRegReg - internalAllocateScope /rax :movqImmReg - /rax :callqReg - - currentScope /rdi :movqImmReg - /rax /rdi :movqRegMem - - { ==createScopeEntry - { ==name - # create function - name | 8 sub /rdi :movqImmReg - /rsi /rsi :xorqRegReg # library functions don't have a captured scope - # TODO: put a type here where applicable - /rdx /rdx :xorqRegReg - - internalAllocateFunction /rax :movqImmReg - /rax :callqReg - /rax :pushqReg - - # create string - name "ey(.*)" regex assert constStringCode _ len dearray - - # enter into current (i.e. global) scope - createScopeEntry /rax :movqImmReg - /rax :callqReg - } each - } /createScopeEntries deff - globalFunctions keys eydeff createScopeEntries - globalFunctions2 keys eydeff createScopeEntries - globalFunctions3 keys eydeff createScopeEntries - globalMacros keys eydefq createScopeEntries - ] :execute - < [ 32 { "." } rep diff --git a/compiler/elymasGlobal.ey b/compiler/elymasGlobal.ey index a015c07..a5e58c7 100644 --- a/compiler/elymasGlobal.ey +++ b/compiler/elymasGlobal.ey @@ -1,92 +1,1619 @@ "elymasAsmLib.ey" include < - [ /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 assembler .|label "@" deff "%" _ : -01 deff - { .value base10decode ==v + { [ } "[[" deff + { ] :labelResolve ::stringResolve } "]]" deff + + 256 ==INITIALEXTENSIONSIZE + 256 ==INITIALSCOPESIZE + + # elymas functions, stack based ABI + + 1 ==ARRAYMARKER + 2 ==QUOTEMARKER + + # 0 -> integer + # 1 -> integer + # 0 <- result of the arithmetic operation + { ==opcodes [ - # allocate int + /rbx :popqReg + + # allocate result int 16 /rdi :movqImmReg ::internalAllocate /rax :movqImmReg /rax :callqReg + # type zero does not need to be changed + + # actual calculation + /rcx :popqReg + 8 /rcx /rcx :movqMemDisp8Reg + + /rdx :popqReg + 8 /rdx /rdx :movqMemDisp8Reg + + opcodes _ len dearray + /rdx 8 /rax :movqRegMemDisp8 + # push int address on program stack /rax :pushqReg + /rbx :pushqReg + :retn + ] + } /makeArith deff + + < + # do nothing + [ + :retn + ] /ey/ defv + + # resolve in scope but never execute + # 0 -> name to resolve + # 0 <- whatever the name resolved to + [[ + /rcx :popqReg + /rbx :popqReg + /rcx :pushqReg + + # scope resolution + ::currentScope /rdi :movqImmReg + /rdi /rdi :movqMemReg + /rbx /rsi :movqRegReg + ::internalResolve /rax :movqImmReg + /rax :callqReg + + /rax /rax :testqRegReg + /found :jnzLbl8 + + "unresolved name: " ::outputError + /rbx /rdi :movqRegReg + ::internalDumpErrorString /rax :movqImmReg + /rax :callqReg + :ud2 + + @found + /rcx :popqReg + /rax :pushqReg + /rcx :pushqReg + :retn + ]] /ey| defv + + # arithmetic functions on ints + [ /rcx /rdx :addqRegReg ] makeArith /eyadd defv + [ /rcx /rdx :subqRegReg ] makeArith /eysub defv + [ /rcx /rdx :andqRegReg ] makeArith /eyband defv + [ /rcx /rdx :orqRegReg ] makeArith /eybor defv + [ /rcx /rdx :xorqRegReg ] makeArith /eybxor defv + + [ + /rdi /rdi :xorqRegReg + 1 /rsi :movqImmReg + /rdx /rcx :cmpqRegReg + /rsi /rdx :movqRegReg + /rdi /rdx :cmovnzqRegReg + ] makeArith /eyeq defv + [ + /rdi /rdi :xorqRegReg + 1 /rsi :movqImmReg + /rdx /rcx :cmpqRegReg + /rsi /rdx :movqRegReg + /rdi /rdx :cmovgeqRegReg + ] makeArith /eygt defv + [ + /rdi /rdi :xorqRegReg + 1 /rsi :movqImmReg + /rdx /rcx :cmpqRegReg + /rsi /rdx :movqRegReg + /rdi /rdx :cmovgqRegReg + ] makeArith /eyge defv + [ + /rdi /rdi :xorqRegReg + 1 /rsi :movqImmReg + /rdx /rcx :cmpqRegReg + /rsi /rdx :movqRegReg + /rdi /rdx :cmovngqRegReg + ] makeArith /eylt defv + [ + /rdi /rdi :xorqRegReg + 1 /rsi :movqImmReg + /rdx /rcx :cmpqRegReg + /rsi /rdx :movqRegReg + /rdi /rdx :cmovngeqRegReg + ] makeArith /eyle defv + + [ + /rax :pushqReg + /rcx /rax :movqRegReg + /rdx :mulqReg + /rax /rdx :movqRegReg + /rax :popqReg + ] makeArith /eymul defv + [ + /rax :pushqReg + /rdx /rax :movqRegReg + /rdx /rdx :xorqRegReg + /rcx :divqReg + /rax :popqReg + ] makeArith /eymod defv + [ + /rax :pushqReg + /rdx /rax :movqRegReg + /rdx /rdx :xorqRegReg + /rcx :divqReg + /rax /rdx :movqRegReg + /rax :popqReg + ] makeArith /eydiv defv + + [[ + /rcx /rcx :testqRegReg + /no :jzLbl8 + /rdx /rdx :testqRegReg + /no :jzLbl8 + 1 /rdx :movqImmReg + /done :jmpLbl8 + + @no + /rdx /rdx :xorqRegReg + @done + ]] makeArith /eyand defv + + # 0 -> integer + # 0 <- the negated integer + [ + /rbx :popqReg + + # allocate result int + 16 /rdi :movqImmReg + ::internalAllocate /rax :movqImmReg + /rax :callqReg # type zero does not need to be changed - # load value + # actual negation + /rcx :popqReg + 8 /rcx /rcx :movqMemDisp8Reg + /rcx :negqReg + /rcx 8 /rax :movqRegMemDisp8 + + # push int address on program stack + /rax :pushqReg + /rbx :pushqReg + :retn + ] /eyneg defv + + # decide between two alternatives + # 0 -> alternative 0 + # 1 -> alternative not 0 + # 2 -> decision value + # 0 <- the selected alternative + [ + /rbx :popqReg + /rcx :popqReg + /rdx :popqReg + /rax :popqReg + 8 /rax /rax :movqMemDisp8Reg + /rax /rax :testqRegReg + /rcx /rdx :cmovzqRegReg + /rdx :pushqReg + /rbx :pushqReg + :retn + ] /ey? defv + + { ==activation + # create a new entry in the current scope for the given name + # mark that entry's default action according to activation + # 0 -> name, string + # 1 -> object + [[ + 8 /r15 :subqImm8Reg + /r15 :popqMem + + /rdi :popqReg + + # search for name in nametable + ::currentScope /rax :movqImmReg + /rax /rbx :movqMemReg # rbx == start of scope in heap + 8 /rbx /rdx :movqMemDisp8Reg # rdx == start of nametable in heap + 8 /rbx /rsi :movqMemDisp8Reg # rsi == start of nametable in heap + 8 /rsi /rsi :addqMemDisp8Reg # rsi == end of nametable in heap (according to fill) + + @nameSearch + 16 /rdx :addqImm8Reg + + # rsi: end of nametable + # rdx: current element of nametable + + /rdx /rsi :cmpqRegReg + /nameUndefined :jbeLbl8 + + /rdx :pushqReg + /rsi :pushqReg + /rdi :pushqReg + /rcx :pushqReg + /rdx /rsi :movqMemReg + ::internalStringEqualsCode _ len dearray + /rcx :popqReg + /rdi :popqReg + /rsi :popqReg + /rdx :popqReg + /rax /rax :testqRegReg + /nameOffsetKnown :jnzLbl8 + + # if not exists, insert + @nameUndefined + 8 /rbx /rdx :movqMemDisp8Reg # rdx == start of nametable in heap + /rdx /eax :movlMemReg # add memory length to obtain memory end + /rax /rdx :addqRegReg + + /rsi /rdx :cmpqRegReg + /enlargeNameTable :jbeLbl8 + + # insert into name table + @insertIntoNameTable + /rdi /rsi :movqRegMem + activation 8 /rsi :movqImm32MemDisp8 # set default activation mode + 8 /rbx /rdx :movqMemDisp8Reg # rdx == start of nametable in heap + 16 8 /rdx :addqImm8MemDisp8 # increment fill + /rsi /rdx :movqRegReg + /nameOffsetKnown :jmpLbl8 + + @enlargeNameTable + # if name table is already full, double size + 8 /rbx /rdx :movqMemDisp8Reg # rdx == start of nametable in heap + /rdi :pushqReg + /rdx :pushqReg + /rdx /edi :movlMemReg # load current length + /rdi /rdi :addqRegReg + + ::internalAllocate /rax :movqImmReg + /rax :callqReg + %30 7 /rax :orbImmMemDisp8 # set type + /rdx :popqReg + 8 /rdx /rcx :movqMemDisp8Reg + /rcx 8 /rax :movqRegMemDisp8 # copy fill + + 16 /rdx /rsi :leaqMemDisp8Reg + 16 /rax /rdi :leaqMemDisp8Reg + 16 /rcx :subqImm8Reg + 3 /rcx :shrqImm8Reg + :reprcx :movsq # copy content + + # rax == enlarged name table on heap + + /rax 8 /rbx :movqRegMemDisp8 # switch scope to new name table + + # insert into name table + /rsi :popqReg + /rsi /rdi :xchgqRegReg + /insertIntoNameTable :jmpLbl8 + + @nameOffsetKnown + 8 /rbx /rdx :subqMemDisp8Reg # substract name table address + 16 /rdx :subqImm8Reg # substract name table header size + /rdx :shrq1Reg # divide by 2 to get offset within scope + + # rdx == offset in scope + # top of stack: the object to store + + # update + # if fits within main area, fine + 32 /rdx :addqImm8Reg # add scope header size + /edx /rbx :cmplRegMem + /inDataArea :jaLbl8 + + # update within extension area + /rbx /edx :sublMemReg # substract scope length + 24 /rbx /rdi :movqMemDisp8Reg # load extension area pointer + 8 /rdx :addqImm8Reg # add extension area header length + + # if extension area is non-existent, create + /rdi /rdi :testqRegReg + /extensionAreaExists :jnzLbl8 + + /rdx :pushqReg + INITIALEXTENSIONSIZE /rdi :movqImmReg + ::internalAllocate /rax :movqImmReg + /rax :callqReg + /rdx :popqReg + + /rax /rdi :movqRegReg + /rdi 24 /rbx :movqRegMemDisp8 # store new extension area + /inExtensionArea :jmpLbl8 + + @extensionAreaExists + + # if extension area is full, double size + /edx /rdi :cmplRegMem + /inExtensionArea :jnbLbl8 + + # FIXME + :ud2 + + @inExtensionArea + /rdi /rbx :movqRegReg + + @inDataArea + + /rax :popqReg + /rax /rbx /rdx :movqRegMemIndex # save entry pointer + + /r15 :pushqMem + 8 /r15 :addqImm8Reg + :retn + ]] + } 0 -101* /eydefv defv + 1 -101* /eydeff defv + 2 -01* /eydefq defv + + # assign to a scope variable + # 0 -> name to assign to + # 1 -> value to assign + # does not change the default activation mode + [[ + 8 /r15 :subqImm8Reg + /r15 :popqMem + + ::currentScope /rdi :movqImmReg + /rdi /rdi :movqMemReg + /rbx :popqReg + /rbx /rsi :movqRegReg + ::internalResolve /rax :movqImmReg + /rax :callqReg + + # rax == resolved value + # rcx == address of the value just resolved + + /rax /rax :testqRegReg + /found :jnzLbl8 + + "unresolved name: " ::outputError + /rbx /rdi :movqRegReg + ::internalDumpErrorString /rax :movqImmReg + /rax :callqReg + :ud2 + + @found + /rcx :popqMem + + /r15 :pushqMem + 8 /r15 :addqImm8Reg + :retn + ]] /ey= defv + + # execute top stack element + # 0 -> function to execute + [[ + 8 /r15 :subqImm8Reg + /r15 :popqMem + + /rdx :popqReg + + 7 /rdx /cl :movbMemDisp8Reg + %F0 /cl :andbImmReg + %50 /cl :cmpbImmReg + /normalFunction :jeLbl8 + %70 /cl :cmpbImmReg + /arrayFunction :jeLbl8 + + "not an executable thing" ::outputError + :ud2 + + @normalFunction + # load scope + 8 /rdx /rcx :movqMemDisp8Reg + /rcx /rcx :testqRegReg + /unscoped :jzLbl8 + + # save current scope + ::currentScope /rax :movqImmReg + /rax /rsi :movqMemReg + 8 /r15 :subqImm8Reg + /rsi /r15 :movqRegMem + # enter scope + /rcx /rax :movqRegMem + + # handle typed function + 16 /rdx /rcx :movqMemDisp8Reg + /rcx /rcx :testqRegReg + /typed :jnzLbl8 + + 24 /rdx /rax :movqMemDisp8Reg + 8 /rax :addqImm8Reg + /rax :callqReg + + /r15 /rcx :movqMemReg + ::currentScope /rax :movqImmReg + /rcx /rax :movqRegMem + 8 /r15 :addqImm8Reg + /r15 :pushqMem + 8 /r15 :addqImm8Reg + :retn + + @unscoped + 24 /rdx /rax :movqMemDisp8Reg 8 /rax :addqImm8Reg - v /rdx :movqImmReg - /rdx /rax :movqRegMem - ] :execute - } /TOKINT - - { .value ::constStringCode :execute } /TOKSTR - - { .value ::constStringCode - [ - ::internalExecuteIdentifier /rax :movqImmReg - /rax :callqReg - ] cat :execute - } /TOKID -> -- 3 |defv rep - -{ /f deff -101 /s defv regex { f } { s } ? * } /rxparse deff - -{ " " cat - { < /handle deff /value defv > } /token deff - [ -01 { _ "" streq not } { - 0 /matched defv { /f deff matched { -- } { { 1 =matched f } rxparse } ? * } /parse deff - - "^ (.*)" { } parse - "^#" { "" } parse - "^(\\d+) +(.*)" { TOKINT token -01 } parse - "^\"(.*)" { - "" /str defv - { _ "^\"(.*)" regex { -01 -- 0 } { 1 } ? * } { - 0 /strmatched defv { /f deff strmatched { -- } { { 1 =strmatched f } rxparse } ? * } /strparse deff - - "^\\\\\\\\(.*)" { str "\\" cat =str } strparse - "^\\\\n(.*)" { str "\n" cat =str } strparse - "^\\\\\"(.*)" { str "\"" cat =str } strparse - "^([^\"\\\\])(.*)" { str -01 cat =str } strparse - strmatched not { "Tokenization of string-like failed" die } rep - } loop - str TOKSTR token -01 - } parse - "^([^a-zA-Z0-9 ]+)([a-zA-Z0-9][^ ]*) +(.*)" { -201 TOKSTR token " " -1203 cat cat } parse - "^([a-zA-Z0-9]+|[^a-zA-Z0-9 ]+) +(.*)" { TOKID token -01 } parse - - matched not { "Tokenization failed: " -01 cat die } rep - } loop -- ] -} /tokenize deff - -{ /input defv - "" { - 4096 input .readstr cat - _ "" streq not - } { - { _ "([^\\n]*)\\n(.*)" regex } { -102 -- tokenize { - _ .handle - assemblerLibrary .stackDump - # assemblerLibrary .globalScopeDump - } each } loop - } loop -} /executeFile deff + /rax :callqReg + + /r15 :pushqMem + 8 /r15 :addqImm8Reg + :retn + + @unscopedTyped + # TODO think about whether this should be allowed to happen + :ud2 + + @arrayFunction + # rdx == array on heap + /rbx :popqReg + + 7 /rbx /cl :movbMemDisp8Reg + %F0 /cl :andbImmReg + %00 /cl :cmpbImmReg + /arrayIntArgument :jeLbl8 + :ud2 # TODO handle the fully typed case + + @arrayIntArgument + 8 /rbx /rax :movqMemDisp8Reg # rax == requested index + /rdx /ecx :movlMemReg # load array length + 3 /rcx :shrqImm8Reg # divide by object pointer size + /rcx :decqReg # rcx == number of elements in array + + /rsi /rsi :xorqRegReg + /rdx /rsi :xchgqRegReg + + # TODO: think about skipping this if index fits + /rcx :divqReg + + # rsi == array object on heap + # rdx == correct array index + 8 8 /rdx /rsi :pushqMemIndexScaleDisp8 # use some of the CISC goodness + + /r15 :pushqMem + 8 /r15 :addqImm8Reg + :retn + + @typed + :ud2 # TODO handle typed functions and autolooping + ]] /ey* defv + + # dump top stack element (actually drop it for now) + # FIXME: this belongs in the standard library + [ + /rax :popqReg + /rcx :popqReg + /rax :pushqReg + :retn + ] /eydump defv + + # array construction, push begin marker on stack + [ + /rax :popqReg + ARRAYMARKER :pushqImm32 + /rax :pushqReg + :retn + ] /ey[ defv + + # array construction, create array from begin marker onwards + [[ + 8 /r15 :subqImm8Reg + /r15 :popqMem + + ARRAYMARKER /rax :movqImmReg + /rsp /rdi :movqRegReg + 8 /rdi :subqImm8Reg + @search + 8 /rdi :addqImm8Reg + /rdi /rax :cmpqMemReg + /search :jneLbl8 + + /rdi /rcx :movqRegReg + /rsp /rdi :subqRegReg + /rcx :pushqReg + + # rdi == size of array + ::internalAllocateArray /rax :movqImmReg + /rax :callqReg + + /rdi :popqReg + /rax /rdi :movqRegMem # store array pointer instead of begin marker + + /rax /ecx :movlMemReg + 3 /rcx :shrqImm8Reg + /rcx :decqReg # rcx == number of array elements + /rcx /rcx :testqRegReg + /empty :jzLbl8 + + 8 /rcx /rax /rax :leaqMemIndexScaleReg # rax == address of last cell + @copy + /rax :popqMem + 8 /rax :subqImm8Reg + /copy :loopLbl8 + + @empty + /r15 :pushqMem + 8 /r15 :addqImm8Reg + :retn + ]] /ey] defv + + # assign array cell + # 0 -> array + # 1 -> index in array + # 2 -> value to assign + [[ + 8 /r15 :subqImm8Reg + /r15 :popqMem + + /rbx :popqReg + 7 /rbx /cl :movbMemDisp8Reg + %F0 /cl :andbImmReg + %70 /cl :cmpbImmReg + /arrayAssign :jeLbl8 + + "non-array passed to =[]" ::outputError + :ud2 + + @arrayAssign + /rax :popqReg + 8 /rax /rax :movqMemDisp8Reg + + /rbx /ecx :movlMemReg # load array length + 3 /rcx :shrqImm8Reg # divide by object pointer size + /rcx :decqReg # rcx == number of elements in array + + /rdx /rdx :xorqRegReg + + # TODO: think about skipping this if index fits + /rcx :divqReg + + # rbx == array object on heap + # rdx == correct array index + + 8 8 /rdx /rbx :popqMemIndexScaleDisp8 # directly pop into array cell + + /r15 :pushqMem + 8 /r15 :addqImm8Reg + :retn + ]] /ey=[] defv + + # length of array or string + # 0 -> array / string + # 0 <- number of elements / characters + [[ + 8 /r15 :subqImm8Reg + /r15 :popqMem + + /rax :popqReg + 7 /rax /cl :movbMemDisp8Reg + %F0 /cl :andbImmReg + %10 /cl :cmpbImmReg + /stringLen :jeLbl8 + %70 /cl :cmpbImmReg + /arrayLen :jeLbl8 + + "neither string nor array in len" ::outputError + :ud2 + + @arrayLen + /rax /rbx :movqMemReg + 8 /rbx :shlqImm8Reg # clear type bits + 11 /rbx :shrqImm8Reg # divide by 8 + /rbx :decqReg # substract header size + /done :jmpLbl8 + + @stringLen + 16 /rax /rbx :movqMemDisp8Reg + + @done + 16 /rdi :movqImmReg + ::internalAllocate /rax :movqImmReg + /rax :callqReg + /rax :pushqReg # push integer on the stack + + /rbx 8 /rax :movqRegMemDisp8 # store integer value + + /r15 :pushqMem + 8 /r15 :addqImm8Reg + :retn + ]] /eylen defv + + # concatenate two arrays or strings + # 0 -> second part of new array / string + # 1 -> first part of new array / string + # 0 <- concatenated array / string + [[ + 8 /r15 :subqImm8Reg + /r15 :popqMem + + /rax :popqReg + 7 /rax /cl :movbMemDisp8Reg + %F0 /cl :andbImmReg + %70 /cl :cmpbImmReg + /arrayCat :jeLbl8 + %10 /cl :cmpbImmReg + /stringCat :jeLbl8 + + "neither string nor array in cat" ::outputError + :ud2 + + @arrayCat + /rbx :popqReg + + 7 /rbx /cl :movbMemDisp8Reg + %F0 /cl :andbImmReg + %70 /cl :cmpbImmReg + /mismatch :jneLbl8 + + 16 /r15 :subqImm8Reg + /rax /r15 :movqRegMem + /rbx 8 /r15 :movqRegMemDisp8 # store + + /rax /edi :movlMemReg + /rbx /edi :addlMemReg + 16 /rdi :subqImm8Reg # sum of lengths + + ::internalAllocateArray /rax :movqImmReg + /rax :callqReg + /rax :pushqReg # result on stack + + 8 /rax /rdi :leaqMemDisp8Reg + + 8 /r15 /rbx :movqMemDisp8Reg + /rbx /ecx :movlMemReg + 8 /rbx /rsi :leaqMemDisp8Reg + 3 /rcx :shrqImm8Reg + /rcx :decqReg + :reprcx :movsq + + /r15 /rbx :movqMemReg + /rbx /ecx :movlMemReg + 8 /rbx /rsi :leaqMemDisp8Reg + 3 /rcx :shrqImm8Reg + /rcx :decqReg + :reprcx :movsq + + 16 /r15 :addqImm8Reg + /done :jmpLbl8 + + @stringCat + # TODO + :ud2 + + @mismatch + "type mismatch in cat" ::outputError + :ud2 + + @done + /r15 :pushqMem + 8 /r15 :addqImm8Reg + :retn + ]] /eycat defv + + # push array contents on stack + # 0 -> number of elements to push + # 1 -> array + # 0 ... <- array contents + [[ + 8 /r15 :subqImm8Reg + /r15 :popqMem + + /rcx :popqReg + 8 /rcx /rcx :movqMemDisp8Reg + + /rax :popqReg + + /rcx /rcx :testqRegReg + /empty :jzLbl8 + 8 /rdi :movqImmReg + + @loop + 1 /rdi /rax :pushqMemIndexScale + 8 /rdi :addqImm8Reg + /edi /rax :cmplRegMem + /noreset :jaLbl8 + 8 /rdi :movqImmReg + @noreset + /loop :loopLbl8 + + @empty + /r15 :pushqMem + 8 /r15 :addqImm8Reg + :retn + ]] /eydearray defv + + # create an array containing a continuous range of ints + # 0 -> last element included in range + # 1 -> first element included in range + [[ + 8 /r15 :subqImm8Reg + /r15 :popqMem + + 8 /r15 :subqImm8Reg + /r15 :popqMem + + 8 /r15 :subqImm8Reg + /r15 :popqMem + + # 8 /r15 == last element + # /r15 == first element + + 8 /r15 /rdi :movqMemDisp8Reg + 8 /rdi /rdi :movqMemDisp8Reg + /r15 /rbx :movqMemReg + 8 /rbx /rbx :movqMemDisp8Reg + + /rbx /rdi :subqRegReg + 3 /rdi :shlqImm8Reg + 8 /rdi :addqImm8Reg # one extra element, TODO: consider whether this is actually a good idea + ::internalAllocateArray /rax :movqImmReg + /rax :callqReg + + /rax :pushqReg # store array on stack + + 8 /rax /rdi :leaqMemDisp8Reg # fill target + 8 /r15 /rax :movqMemDisp8Reg + 8 /rax /rax :movqMemDisp8Reg # largest element + + @fill + /rax /rbx :cmpqRegReg + /done :jaLbl8 + + /rax :pushqReg + /rdi :pushqReg + # create int + 16 /rdi :movqImmReg + ::internalAllocate /rax :movqImmReg + /rax :callqReg + /rbx 8 /rax :movqRegMemDisp8 # store value + /rdi :popqReg + /rax /rdi :movqRegMem # store into array + /rax :popqReg + + /rbx :incqReg + 8 /rdi :addqImm8Reg + /fill :jmpLbl8 + + @done + + 16 /r15 :addqImm8Reg + /r15 :pushqMem + 8 /r15 :addqImm8Reg + :retn + ]] /eyrange defv + + # create a new scope capturing the current one + [ + ::currentScope /rbx :movqImmReg + + INITIALSCOPESIZE /rdi :movqImmReg + /rbx /rsi :movqMemReg + ::internalAllocateScope /rax :movqImmReg + /rax :callqReg + /rax /rbx :movqRegMem # switch to new scope + + :retn + ] /ey< defv + + # push current scope onto stack + # switch current scope to its parent + [ + /rbx :popqReg + ::currentScope /rax :movqImmReg + /rax :pushqMem + /rax /rcx :movqMemReg + 16 /rcx /rcx :movqMemDisp8Reg + /rcx /rax :movqRegMem + /rbx :pushqReg + + :retn + ] /ey> defv + > _ ==globalFunctions { defv }' ::allocateOffsetStruct + + < + # resolve identifier without quoting considerations act accordingly + # 0 -> identifier to resolve + [[ + 8 /r15 :subqImm8Reg + /r15 :popqMem + + 8 /r15 :subqImm8Reg + /r15 :popqMem # store identifier + + # scope resolution + ::currentScope /rdi :movqImmReg + /rdi /rdi :movqMemReg + /r15 /rsi :movqMemReg + ::internalResolve /rax :movqImmReg + /rax :callqReg + + /rax /rax :testqRegReg + /unresolved :jzLbl8 + /rax :pushqReg + + 0 /rdx :cmpqImm8Reg + /inactive :jzLbl8 + 1 /rdx :cmpqImm8Reg + /active :jzLbl8 + + # TODO: "invalid activation mode" + :ud2 + + @unresolved + "unresolved name: " ::outputError + /r15 /rdi :movqMemReg + ::internalDumpErrorString /rax :movqImmReg + /rax :callqReg + :ud2 + + @active + |ey* /rax :movqImmReg + /rax :callqReg + + @inactive + @done + 8 /r15 :addqImm8Reg + /r15 :pushqMem + 8 /r15 :addqImm8Reg + :retn + ]] /internalExecuteIdentifierUnquoted defv + > { defv }' ::allocateOffsetStruct + + < + # resolve identifier according to current scope and quote mode and act accordingly + # 0 -> identifier to resolve + [[ + 8 /r15 :subqImm8Reg + /r15 :popqMem + + 8 /r15 :subqImm8Reg + /r15 :popqMem # store identifier + + # scope resolution + ::currentScope /rdi :movqImmReg + /rdi /rdi :movqMemReg + /r15 /rsi :movqMemReg + ::internalResolve /rax :movqImmReg + /rax :callqReg + + /rax /rax :testqRegReg + /unresolved :jzLbl8 + + 0 /rdx :cmpqImm8Reg + /inactive :jzLbl8 + 1 /rdx :cmpqImm8Reg + /active :jzLbl8 + 2 /rdx :cmpqImm8Reg + /quoteActive :jzLbl8 + + # TODO: "invalid activation mode" + :ud2 + + @unresolved + ::currentQuoted /rax :movqImmReg + /rax /rax :movqMemReg + /rax /rax :testqRegReg + /constructQuotedResolve :jnzLbl8 + + "unresolved name: " ::outputError + /r15 /rdi :movqMemReg + ::internalDumpErrorString /rax :movqImmReg + /rax :callqReg + :ud2 + + @quoteActive + /rax :pushqReg + |ey* /rax :movqImmReg + /rax :callqReg + /done :jmpLbl8 + + @active + ::currentQuoted /rbx :movqImmReg + /rbx /rbx :movqMemReg + /rbx /rbx :testqRegReg + /constructQuotedResolve :jnzLbl8 + + /rax :pushqReg + |ey* /rax :movqImmReg + /rax :callqReg + /done :jmpLbl8 + + @inactive + ::currentQuoted /rbx :movqImmReg + /rbx /rbx :movqMemReg + /rbx /rbx :testqRegReg + /constructQuotedResolve :jnzLbl8 + /rax :pushqReg + + @done + 8 /r15 :addqImm8Reg + /r15 :pushqMem + 8 /r15 :addqImm8Reg + :retn + + @constructQuotedResolve + # construct non-capturing function + :quoteEncodingBuffer /rdi :movqImmReg + ::unscopingFunctionHeader ::loadToRdi + + # push identifier + [ /rax :movqImmOOBReg ] _ len 2 eq assert + 2 dearray 256 mul add + /rdi :movwImmMem + /r15 /rsi :movqMemReg + /rsi 2 /rdi :movqRegMemDisp8 + 10 /rdi :addqImm8Reg + + [ + /rax :pushqReg + internalExecuteIdentifierUnquoted /rax :movqImmReg + /rax :callqReg + ] ::unscopingFunctionFooter cat ::loadToRdi + + ::allocateCodeFromEncodingBuffer + # rax == code block on heap + + # create non-capturing function object + /rax /rdi :movqRegReg + /rsi /rsi :xorqRegReg + /rdx /rdx :xorqRegReg + ::internalAllocateFunction /rax :movqImmReg + /rax :callqReg + + # rax == function object on heap + /rax :pushqReg + /done :jmpLbl32 + ]] /internalExecuteIdentifier defv + > { defv }' ::allocateOffsetStruct + + < + # concatenate two functions + # 0 -> function g + # 1 -> function f + # 0 <- (f g) + [[ + 8 /r15 :subqImm8Reg + /r15 :popqMem + + # construct non-capturing function + :quoteEncodingBuffer /rdi :movqImmReg + ::unscopingFunctionHeader ::loadToRdi + + /rcx :popqReg + /rdx :popqReg + + # push function f + [ /rax :movqImmOOBReg ] _ len 2 eq assert + 2 dearray 256 mul add + /rdi :movwImmMem + /rdx 2 /rdi :movqRegMemDisp8 + 10 /rdi :addqImm8Reg + [ + /rax :pushqReg + |ey* /rax :movqImmReg + /rax :callqReg + /rax :movqImmOOBReg + ] ::loadToRdi + # push function g + /rcx /rdi :movqRegMem + 8 /rdi :addqImm8Reg + [ + /rax :pushqReg + |ey* /rax :movqImmReg + /rax :callqReg + ] ::unscopingFunctionFooter cat ::loadToRdi + + ::allocateCodeFromEncodingBuffer + # rax == code block on heap + + # create non-capturing function object + /rax /rdi :movqRegReg + /rsi /rsi :xorqRegReg + /rdx /rdx :xorqRegReg + ::internalAllocateFunction /rax :movqImmReg + /rax :callqReg + + # rax == function object on heap + /rax :pushqReg + + /r15 :pushqMem + 8 /r15 :addqImm8Reg + :retn + ]] /ey; defv + + # drop top stack element + [ + /rax :popqReg + /rcx :popqReg + /rax :pushqReg + :retn + ] /ey-- defv + + # duplicate top stack element + [ + /rax :popqReg + /rcx :popqReg + /rcx :pushqReg + /rcx :pushqReg + /rax :pushqReg + :retn + ] /ey_ defv + + # top stack element is a string defining a stack shuffle + # 0-9: push the thusly numbered element + # *: execute top element + # pops as many elements as the highest number specifies + [[ + 8 /r15 :subqImm8Reg + /r15 :popqMem + 80 /r15 :subqImm8Reg + + /rdi :popqReg + 16 /rdi /rcx :movqMemDisp8Reg # load string length + 24 /rdi /rax :leaqMemDisp8Reg # rax to begin of string + + 42 /rsi :movqImmReg # initialize with '*' + + # find maximal element, note that '*' < '0' + @maximalElementSearch + /rax /rdx :movzxMem8Reg64 + /rsi /rdx :cmpqRegReg + /rdx /rsi :cmovaqRegReg + /rax :incqReg + /maximalElementSearch :loopLbl8 + + # move elements to temporary storage + 42 /rsi :cmpqImm8Reg + /elementsSaved :jeLbl8 + + 47 /rsi :subqImm8Reg # substract '0'-1 + /rsi /rcx :movqRegReg + /rsi /rsi :xorqRegReg + + @saveElements + 8 /rsi /r15 :popqMemIndexScale + /rsi :incqReg + /saveElements :loopLbl8 + + # execute shuffle specification + @elementsSaved + 16 /rdi /rcx :movqMemDisp8Reg # load string length + 24 /rdi /rax :leaqMemDisp8Reg # rax to begin of string + + @executeSpec + /rax /rdx :movzxMem8Reg64 + /rax :incqReg + + 42 /rdx :cmpqImm8Reg + /executeTop :jeLbl8 + + 48 /rdx :subqImm8Reg # substract '0' + 8 /rdx /r15 :pushqMemIndexScale + /executeSpec :loopLbl8 + /done :jmpLbl8 + + @executeTop + 24 /r15 :subqImm8Reg + /rax 16 /r15 :movqRegMemDisp8 + /rcx 8 /r15 :movqRegMemDisp8 + /rdx /r15 :movqRegMem + |ey* /rax :movqImmReg + /rax :callqReg + /r15 /rdx :movqMemReg + 8 /r15 /rcx :movqMemDisp8Reg + 16 /r15 /rax :movqMemDisp8Reg + 24 /r15 :addqImm8Reg + /executeSpec :loopLbl8 + + @done + 80 /r15 :addqImm8Reg + /r15 :pushqMem + 8 /r15 :addqImm8Reg + :retn + ]] /ey- defv + + # execute top stack element multiple times + # 0 -> function to execute + # 1 -> how often to execute it + [[ + 8 /r15 :subqImm8Reg + /r15 :popqMem + + 8 /r15 :subqImm8Reg + /r15 :popqMem # store function to call + + 8 /r15 :subqImm8Reg + /rcx :popqReg + 8 /rcx /rcx :movqMemDisp8Reg + + /rcx /rcx :testqRegReg + /end :jzLbl8 + + @loop + /rcx /r15 :movqRegMem + + 8 /r15 :pushqMemDisp8 + |ey* /rax :movqImmReg + /rax :callqReg + + /r15 /rcx :movqMemReg + /loop :loopLbl8 + + @end + 16 /r15 :addqImm8Reg + + /r15 :pushqMem + 8 /r15 :addqImm8Reg + :retn + ]] /eyrep defv + + # a normal loop + # 0 -> second part of loop + # 1 -> first part of loop + # execute first part, if top of stack is nonzero, execute second part, repeat + [[ + 8 /r15 :subqImm8Reg + /r15 :popqMem + + 8 /r15 :subqImm8Reg + /r15 :popqMem + + 8 /r15 :subqImm8Reg + /r15 :popqMem + + # /r15 -> first part + # 8 /r15 -> second part + + @loop + /r15 :pushqMem + |ey* /rax :movqImmReg + /rax :callqReg + + /rax :popqReg + 0 8 /rax :cmpqImm8MemDisp8 + /end :jzLbl8 + + 8 /r15 :pushqMemDisp8 + |ey* /rax :movqImmReg + /rax :callqReg + /loop :jmpLbl8 + + @end + + 16 /r15 :addqImm8Reg + + /r15 :pushqMem + 8 /r15 :addqImm8Reg + :retn + ]] /eyloop defv + + # a foreach loop + # 0 -> code to execute + # 1 -> array to loop over + # for each element in array, push it onto stack then execute the code + [[ + 8 /r15 :subqImm8Reg + /r15 :popqMem + + 8 /r15 :subqImm8Reg + /r15 :popqMem + + 16 /r15 :subqImm8Reg + + /rax :popqReg + 8 /rax /rcx :leaqMemDisp8Reg + /rcx /r15 :movqRegMem + + /rax /edx :movlMemReg + 1 /rdx /rax /rcx :leaqMemIndexScaleReg + /rcx 8 /r15 :movqRegMemDisp8 + + # /r15 -> current array element + # 8 /r15 -> address after last array element + # 16 /r15 -> code to execute + + @loop + /r15 /rax :movqMemReg + 8 /r15 /rax :cmpqMemDisp8Reg + /end :jnbLbl8 + + /rax :pushqMem # push array element + 16 /r15 :pushqMemDisp8 # push code + |ey* /rax :movqImmReg + /rax :callqReg + + 8 /r15 :addqImm8Mem + /loop :jmpLbl8 + + @end + + 24 /r15 :addqImm8Reg + /r15 :pushqMem + 8 /r15 :addqImm8Reg + :retn + ]] /eyeach defv + + # explicitely resolve a scope member + # 0 -> member name + # 1 -> scope + [[ + 8 /r15 :subqImm8Reg + /r15 :popqMem + + 8 /r15 :subqImm8Reg + /r15 :popqMem # store identifier + + /rdi :popqReg # fetch scope + /r15 /rsi :movqMemReg + ::internalResolve /rax :movqImmReg + /rax :callqReg + + /rax /rax :testqRegReg + /unresolved :jzLbl8 + /rax :pushqReg + + 0 /rdx :cmpqImm8Reg + /inactive :jzLbl8 + 1 /rdx :cmpqImm8Reg + /active :jzLbl8 + + # TODO: "invalid activation mode" + :ud2 + + @unresolved + "unresolved name: " ::outputError + /r15 /rdi :movqMemReg + ::internalDumpErrorString /rax :movqImmReg + /rax :callqReg + :ud2 + + @active + |ey* /rax :movqImmReg + /rax :callqReg + + @inactive + @done + 8 /r15 :addqImm8Reg + /r15 :pushqMem + 8 /r15 :addqImm8Reg + :retn + ]] /ey. defv + + # explicitely resolve a scope member, but never execute + # 0 -> member name + # 1 -> scope + [[ + 8 /r15 :subqImm8Reg + /r15 :popqMem + + 8 /r15 :subqImm8Reg + /r15 :popqMem # store identifier + + /rdi :popqReg # fetch scope + /r15 /rsi :movqMemReg + ::internalResolve /rax :movqImmReg + /rax :callqReg + + /rax /rax :testqRegReg + /unresolved :jzLbl8 + /rax :pushqReg + + 8 /r15 :addqImm8Reg + /r15 :pushqMem + 8 /r15 :addqImm8Reg + :retn + + @unresolved + "unresolved name: " ::outputError + /r15 /rdi :movqMemReg + ::internalDumpErrorString /rax :movqImmReg + /rax :callqReg + :ud2 + ]] /ey.| defv + + # enumerate scope keys + # 0 -> scope + # 0 <- array of keys + [[ + 8 /r15 :subqImm8Reg + /r15 :popqMem + + /rax :popqReg + 8 /rax /rax :movqMemDisp8Reg + + 16 /rax /rsi :leaqMemDisp8Reg + /rsi :pushqReg + 8 /rax /rdi :movqMemDisp8Reg + 16 /rdi :subqImm8Reg + /rdi :pushqReg + /rdi :shrq1Reg + ::internalAllocateArray /rax :movqImmReg + /rax :callqReg + + 8 /rax /rdi :leaqMemDisp8Reg + /rcx :popqReg + /rsi :popqReg + 4 /rcx :shrqImm8Reg + /empty :jzLbl8 + @loop + :movsq + 8 /rsi :addqImm8Reg + /loop :loopLbl8 + @empty + + /rax :pushqReg + + /r15 :pushqMem + 8 /r15 :addqImm8Reg + :retn + ]] /eykeys defv + > _ ==globalFunctions2 { defv }' ::allocateOffsetStruct + + < + # domain of an array + # 0 -> array + # 0 <- an array containing the integers from 0 to len 1 sub + [[ + 8 /r15 :subqImm8Reg + /r15 :popqMem + + /rax :popqReg + 7 /rax /cl :movbMemDisp8Reg + %F0 /cl :andbImmReg + %70 /cl :cmpbImmReg + /arrayDom :jeLbl8 + %20 /cl :cmpbImmReg + /scopeDom :jeLbl8 + + "non-array passed to dom" ::outputError + :ud2 + + @arrayDom + /rax /edi :movlMemReg + 8 /rdi :subqImm8Reg # substract header length + + ::internalAllocateArray /rax :movqImmReg + /rax :callqReg + /rax :pushqReg # result on stack + + 8 /rax /rdi :leaqMemDisp8Reg + /rbx /rbx :xorqRegReg + /rax /ecx :movlMemReg + 3 /rcx :shrqImm8Reg + /rcx :decqReg + + @loop + /rcx /rbx :cmpqRegReg + /end :jnbLbl8 + + /rdi :pushqReg + /rcx :pushqReg + 16 /rdi :movqImmReg + ::internalAllocate /rax :movqImmReg + /rax :callqReg + /rcx :popqReg + /rdi :popqReg + /rax 8 /rbx /rdi :movqRegMemIndexScale # store in array + /rbx 8 /rax :movqRegMemDisp8 # store value in int + /rbx :incqReg + /loop :jmpLbl8 + + @end + /r15 :pushqMem + 8 /r15 :addqImm8Reg + :retn + + @scopeDom + /rax :pushqReg + /rax :movqImmOOBReg "dom" ::string + /rax :pushqReg + |ey. /rax :movqImmReg + /rax :callqReg + /end :jmpLbl8 + ]] /eydom defv + > _ ==globalFunctions3 { defv }' ::allocateOffsetStruct + + < + # quote construction, push begin marker on stack + [ + /rax :popqReg + QUOTEMARKER :pushqImm32 + ::currentQuoted /rcx :movqImmReg + /rcx :incqMem + /rax :pushqReg + :retn + ] /ey{ defv + + # quote construction, create function from begin marker onwards + { ==footer ==header + [[ + 8 /r15 :subqImm8Reg + /r15 :popqMem + + ::currentQuoted /rcx :movqImmReg + /rcx :decqMem + + QUOTEMARKER /rcx :movqImmReg + /rcx :pushqReg + /rsp /rdx :movqRegReg + @backwardsSearch + 8 /rdx :addqImm8Reg + /rdx /rcx :cmpqMemReg + /backwardsSearch :jneLbl8 + + /rdx :pushqReg # store address of begin marker + + :quoteEncodingBuffer /rdi :movqImmReg + header ::loadToRdi + + @search + 8 /rdx :subqImm8Reg + /rdx /rcx :cmpqMemReg + /markerFound :jeLbl8 + + /rdx /rsi :movqMemReg + 7 /rsi /al :movbMemDisp8Reg + %F0 /al :andbImmReg + /immediateFound :jzLbl8 + %10 /al :cmpbImmReg + /immediateFound :jzLbl8 + %50 /al :cmpbImmReg + /functionFound :jzLbl8 + %70 /al :cmpbImmReg + /arrayFound :jzLbl8 + + # TODO: "invalid object during quote construction" + :ud2 + + @immediateFound + [ /rax :movqImmOOBReg ] _ len 2 eq assert + 2 dearray 256 mul add + /rdi :movwImmMem + /rsi 2 /rdi :movqRegMemDisp8 + [ /rax :pushqReg ] _ len 1 eq assert + 1 dearray + 10 /rdi :movbImmMemDisp8 + 11 /rdi :addqImm8Reg + /search :jmpLbl8 + + @functionFound + [ /rax :movqImmOOBReg ] _ len 2 eq assert + 2 dearray 256 mul add + /rdi :movwImmMem + /rsi 2 /rdi :movqRegMemDisp8 + [ /rax :pushqReg ] _ len 1 eq assert + 1 dearray + 10 /rdi :movbImmMemDisp8 + 11 /rdi :addqImm8Reg + [ + |ey* /rax :movqImmReg + /rax :callqReg + ] ::loadToRdi + /search :jmpLbl8 + + @arrayFound + # FIXME allow macros to put byte arrays into quoted contexts and thereby generate assembly + :ud2 + /search :jmpLbl8 + + @markerFound + + footer ::loadToRdi + ::allocateCodeFromEncodingBuffer + + # rax == code block on heap + + ::currentQuoted /rcx :movqImmReg + /rcx /rcx :movqMemReg + /rcx /rcx :testqRegReg + /quoted :jnzLbl8 + + # create function object + /rax /rdi :movqRegReg + ::currentScope /rax :movqImmReg + /rax /rsi :movqMemReg + /rdx /rdx :xorqRegReg + ::internalAllocateFunction /rax :movqImmReg + /rax :callqReg + + @done + # rax == function object on heap + + # store function instead of begin marker + /rdx :popqReg + /rax /rdx :movqRegMem + /rdx /rsp :movqRegReg # and drop quoted stuff from stack + + /r15 :pushqMem + 8 /r15 :addqImm8Reg + :retn + + @quoted + # rax == (inner) code object on heap + + # create function which + # returns a function with the current scope captured + :quoteEncodingBuffer /rdi :movqImmReg + ::unscopingFunctionHeader ::loadToRdi + + # 1. load inner code block + [ /rdi :movqImmOOBReg ] _ len 2 eq assert + 2 dearray 256 mul add + /rdi :movwImmMem + /rax 2 /rdi :movqRegMemDisp8 + 10 /rdi :addqImm8Reg + + [ + ::currentScope /rax :movqImmReg + /rax /rsi :movqMemReg + /rdx /rdx :xorqRegReg + ::internalAllocateFunction /rax :movqImmReg + /rax :callqReg + /rax :pushqReg + ] ::unscopingFunctionFooter cat ::loadToRdi + + ::allocateCodeFromEncodingBuffer + + # rax == code object on heap + + # create function object + /rax /rdi :movqRegReg + /rsi /rsi :xorqRegReg # non-capturing + /rdx /rdx :xorqRegReg + ::internalAllocateFunction /rax :movqImmReg + /rax :callqReg + + # rax == function object on heap + + /done :jmpLbl32 + ]] + } _ ::scopingFunctionHeader ::scopingFunctionFooter -102* /ey} defv + ::unscopingFunctionHeader ::unscopingFunctionFooter -102* /ey}' defv + > _ ==globalMacros { defv }' ::allocateOffsetStruct + + [ + globalFunctions keys len + globalFunctions2 keys len add + globalFunctions3 keys len add + globalMacros keys len add + /rdi :movqImmReg + /rsi /rsi :xorqRegReg + ::internalAllocateScope /rax :movqImmReg + /rax :callqReg + + ::currentScope /rdi :movqImmReg + /rax /rdi :movqRegMem + + { ==createScopeEntry + { ==name + # create function + name | 8 sub /rdi :movqImmReg + /rsi /rsi :xorqRegReg # library functions don't have a captured scope + # TODO: put a type here where applicable + /rdx /rdx :xorqRegReg + + ::internalAllocateFunction /rax :movqImmReg + /rax :callqReg + /rax :pushqReg + + # create string + name "ey(.*)" regex assert ::constStringCode _ len dearray + + # enter into current (i.e. global) scope + createScopeEntry /rax :movqImmReg + /rax :callqReg + } each + } /createScopeEntries deff + globalFunctions keys eydeff createScopeEntries + globalFunctions2 keys eydeff createScopeEntries + globalFunctions3 keys eydeff createScopeEntries + globalMacros keys eydefq createScopeEntries + ] :execute +> /global defv # vim: syn=elymas diff --git a/compiler/elymasLexer.ey b/compiler/elymasLexer.ey new file mode 100644 index 0000000..b86f0be --- /dev/null +++ b/compiler/elymasLexer.ey @@ -0,0 +1,92 @@ +"elymasGlobal.ey" include + +< + [ /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 + assembler .|label "@" 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 ::constStringCode :execute } /TOKSTR + + { .value ::constStringCode + [ + global .internalExecuteIdentifier /rax :movqImmReg + /rax :callqReg + ] cat :execute + } /TOKID +> -- 3 |defv rep + +{ /f deff -101 /s defv regex { f } { s } ? * } /rxparse deff + +{ " " cat + { < /handle deff /value defv > } /token deff + [ -01 { _ "" streq not } { + 0 /matched defv { /f deff matched { -- } { { 1 =matched f } rxparse } ? * } /parse deff + + "^ (.*)" { } parse + "^#" { "" } parse + "^(\\d+) +(.*)" { TOKINT token -01 } parse + "^\"(.*)" { + "" /str defv + { _ "^\"(.*)" regex { -01 -- 0 } { 1 } ? * } { + 0 /strmatched defv { /f deff strmatched { -- } { { 1 =strmatched f } rxparse } ? * } /strparse deff + + "^\\\\\\\\(.*)" { str "\\" cat =str } strparse + "^\\\\n(.*)" { str "\n" cat =str } strparse + "^\\\\\"(.*)" { str "\"" cat =str } strparse + "^([^\"\\\\])(.*)" { str -01 cat =str } strparse + strmatched not { "Tokenization of string-like failed" die } rep + } loop + str TOKSTR token -01 + } parse + "^([^a-zA-Z0-9 ]+)([a-zA-Z0-9][^ ]*) +(.*)" { -201 TOKSTR token " " -1203 cat cat } parse + "^([a-zA-Z0-9]+|[^a-zA-Z0-9 ]+) +(.*)" { TOKID token -01 } parse + + matched not { "Tokenization failed: " -01 cat die } rep + } loop -- ] +} /tokenize deff + +{ /input defv + "" { + 4096 input .readstr cat + _ "" streq not + } { + { _ "([^\\n]*)\\n(.*)" regex } { -102 -- tokenize { + _ .handle + assemblerLibrary .stackDump + # assemblerLibrary .globalScopeDump + } each } loop + } loop +} /executeFile deff + +# vim: syn=elymas |
