aboutsummaryrefslogtreecommitdiff
path: root/compiler
diff options
context:
space:
mode:
authorDrahflow <drahflow@gmx.de>2013-01-24 15:13:26 +0100
committerDrahflow <drahflow@gmx.de>2013-01-24 15:13:26 +0100
commita3e9bfdc218f6e0bda4a6f43c405475aa2542458 (patch)
tree6001013dc8d21abea8e9ff6416d1ff8decb2afe5 /compiler
parent6da4d865cd7d8051c8609e90b43a55fd26a74582 (diff)
Immediate (error) strings
Diffstat (limited to 'compiler')
-rwxr-xr-xcompiler/elymas.ey1
-rw-r--r--compiler/elymasAsmLib.ey1672
-rw-r--r--compiler/elymasGlobal.ey1669
-rw-r--r--compiler/elymasLexer.ey92
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