"elymasAsmLib.ey" include < { assembler -01 . } ":" deff { assemblerLibrary -01 . } "::" deff assembler .|label "@" deff "%" _ : -01 deff { [ } "[[" 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 [ /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 # 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: extension area is full" ::outputError :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 %10 /cl :cmpbImmReg /stringFunctionSJ :jeLbl8 %70 /cl :cmpbImmReg /unexecutable :jneLbl8 /arrayFunction :jmpLbl32 @unexecutable "not an executable thing" ::outputError :ud2 @stringFunctionSJ /stringFunction :jmpLbl32 @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 /untyped :jzLbl8 /typed :jmpLbl32 @untyped 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 # handle typed unscoped function 16 /rdx /rcx :movqMemDisp8Reg /rcx /rcx :testqRegReg /typedUnscoped :jnzLbl8 24 /rdx /rax :movqMemDisp8Reg 8 /rax :addqImm8Reg /rax :callqReg /r15 :pushqMem 8 /r15 :addqImm8Reg :retn @typedUnscoped # save current scope ::currentScope /rax :movqImmReg /rax /rsi :movqMemReg 8 /r15 :subqImm8Reg /rsi /r15 :movqRegMem /typed :jmpLbl32 @arrayFunction # rdx == array on heap /rbx :popqReg 7 /rbx /cl :movbMemDisp8Reg %F0 /cl :andbImmReg %00 /cl :cmpbImmReg /arrayIntArgument :jeLbl8 "FIXME: typed array application" ::outputError :ud2 @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 /rcx /rcx :testqRegReg /nonEmpty :jnzLbl8 "access into empty array" ::outputError :ud2 @nonEmpty /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 # quick check for the common case (and to avoid infinite recursion) 16 /rdx /rbx :movqMemDisp8Reg 8 /rbx /rcx :movqMemDisp8Reg # rcx == number of input stack elements 16 /rbx /rbx :leaqMemDisp8Reg # rbx == first input stack element /rsp /rdi :movqRegReg @typedCommonCheck /rbx /rsi :movqMemReg # rsi == address of abstract argument 7 /rsi /al :movbMemDisp8Reg # al == type of abstract argument %F0 /al :andbImmReg /rdi /rsi :movqMemReg # rsi == address of concrete argument 7 /rsi /sil :movbMemDisp8Reg # sil = type of concrete argument %F0 /sil :andbImmReg /al /sil :cmpbRegReg /typedNonCommon :jnzLbl8 # non-equal types %E0 /al :testbImmReg /typedNonCommon :jnzLbl8 # non-trivial types 8 /rdi :addqImm8Reg 8 /rbx :addqImm8Reg /typedCommonCheck :loopLbl8 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 @typedNonCommon # escape this to compiled high-level code /rdx :pushqReg /rax :movqImmOOBReg "sys" ::string /rax :pushqReg /rax :movqImmOOBReg "ey*" "ey|" ::linkAbs64 /rax :callqReg /rax :movqImmOOBReg "typed" ::string /rax :pushqReg /rax :movqImmOOBReg "ey*" "ey." ::linkAbs64 /rax :callqReg /rax :movqImmOOBReg "execute" ::string /rax :pushqReg /rax :movqImmOOBReg "ey*" "ey." ::linkAbs64 /rax :callqReg /r15 /rcx :movqMemReg ::currentScope /rax :movqImmReg /rcx /rax :movqRegMem 8 /r15 :addqImm8Reg /r15 :pushqMem 8 /r15 :addqImm8Reg :retn @stringFunction # rdx == string on heap /rbx :popqReg 7 /rbx /cl :movbMemDisp8Reg %F0 /cl :andbImmReg %00 /cl :cmpbImmReg /stringIntArgument :jeLbl8 "FIXME: typed string application" ::outputError :ud2 @stringIntArgument 8 /rbx /rax :movqMemDisp8Reg # rax == requested index 16 /rdx /rcx :movqMemDisp8Reg # load (exact) string length /rsi /rsi :xorqRegReg /rdx /rsi :xchgqRegReg /rcx /rcx :testqRegReg /nonEmptyString :jnzLbl8 "access into empty string" ::outputError :ud2 @nonEmptyString /rcx :divqReg # rsi == array object on heap # rdx == correct string index 24 1 /rdx /rsi /rbx :movzxMem8IndexScaleDisp8Reg64 # use some of the CISC goodness 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 ]] /ey* 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 /unknownType :jneLbl8 /stringCat :jmpLbl32 @unknownType "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 @mismatch "type mismatch in cat" ::outputError :ud2 @stringCat /rbx :popqReg 7 /rbx /cl :movbMemDisp8Reg %F0 /cl :andbImmReg %10 /cl :cmpbImmReg /mismatch :jneLbl8 16 /r15 :subqImm8Reg /rax /r15 :movqRegMem /rbx 8 /r15 :movqRegMemDisp8 # store 16 /rax /rdi :movqMemDisp8Reg 16 /rbx /rdi :addqMemDisp8Reg ::internalAllocateString /rax :movqImmReg /rax :callqReg /rax :pushqReg 24 /rax /rdi :leaqMemDisp8Reg 8 /r15 /rbx :movqMemDisp8Reg 16 /rbx /rcx :movqMemDisp8Reg 24 /rbx /rsi :leaqMemDisp8Reg :reprcx :movsb /r15 /rbx :movqMemReg 16 /rbx /rcx :movqMemDisp8Reg 24 /rbx /rsi :leaqMemDisp8Reg :reprcx :movsb 16 /r15 :addqImm8Reg @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 /positiveRange :jnsLbl8 /rdi /rdi :xorqRegReg ::internalAllocateArray /rax :movqImmReg /rax :callqReg /rax :pushqReg # store (empty) array on stack /done :jmpLbl8 @positiveRange 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 # die # 0 -> object explaining what went wrong [ /rbx :popqReg /rdi :popqReg ::internalDumpErrorString /rax :movqImmReg /rax :callqReg :ud2 /rbx :pushqReg :retn ] /eydie defv # determine current quoting mode # 0 <- an integer giving the current quoting level [[ /rbx :popqReg # allocate result int 16 /rdi :movqImmReg ::internalAllocate /rax :movqImmReg /rax :callqReg # and push to stack /rax :pushqReg ::currentQuoted /rcx :movqImmReg /rcx /rcx :movqMemReg /rcx 8 /rax :movqRegMemDisp8 /rbx :pushqReg :retn ]] /eyquoted 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 ==capturing [[ 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 capturing { ::currentScope /rax :movqImmReg /rax /rsi :movqMemReg } { /rsi /rsi :xorqRegReg } ? * /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 ]] } _ 1 ::scopingFunctionHeader ::scopingFunctionFooter -2103* /ey} defv _ 1 ::unscopingFunctionHeader ::unscopingFunctionFooter -2103* /ey}' defv # the following line - while very tempting - should not be enabled, as it would # destroy future possibility of detecting scope closedness. If you need to augment # caller scope names using nice syntax, employ macros and pass a { deff }' or similar -- # 0 ::unscopingFunctionHeader ::unscopingFunctionFooter -2103* /ey}" defv > _ ==globalMacros { defv }' ::allocateOffsetStruct < [ %10 %00 %00 %00 %00 %00 %00 %00 %01 %00 %00 %00 %00 %00 %00 %00 ] /t1 defv [ %28 %00 %00 %00 %00 %00 %00 %80 %01 %00 %00 %00 %00 %00 %00 %00 /t1t1 /t1 ::linkAbs64 %01 %00 %00 %00 %00 %00 %00 %00 /t1t1 /t1 ::linkAbs64 ] /t1t1 defv [ %30 %00 %00 %00 %00 %00 %00 %80 %02 %00 %00 %00 %00 %00 %00 %00 /t11t1 /t1 ::linkAbs64 /t11t1 /t1 ::linkAbs64 %01 %00 %00 %00 %00 %00 %00 %00 /t11t1 /t1 ::linkAbs64 ] /t11t1 defv [ %20 %00 %00 %00 %00 %00 %00 %10 %00 %00 %00 %00 %00 %00 %00 %00 %01 %00 %00 %00 %00 %00 %00 %00 %61 %00 %00 %00 %00 %00 %00 %00 ] /ta defv [ %30 %00 %00 %00 %00 %00 %00 %80 %02 %00 %00 %00 %00 %00 %00 %00 /taat1 /ta ::linkAbs64 /taat1 /ta ::linkAbs64 %01 %00 %00 %00 %00 %00 %00 %00 /taat1 /t1 ::linkAbs64 ] /taat1 defv > _ =globalTypes { defv }' ::allocateOffsetStruct < # 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 :cmovzqRegReg ] makeArith /eyneq 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 [[ /rcx /rcx :testqRegReg /yes :jnzLbl8 /rdx /rdx :testqRegReg /yes :jnzLbl8 /rdx /rdx :xorqRegReg /done :jmpLbl8 @yes 1 /rdx :movqImmReg @done ]] makeArith /eyor defv > _ =globalT11t1Functions { defv }' ::allocateOffsetStruct < [[ /rbx :popqReg # allocate result int 16 /rdi :movqImmReg ::internalAllocate /rax :movqImmReg /rax :callqReg /rdx :popqReg /rdi :popqReg /rax :pushqReg 16 /rdx /rsi :movqMemDisp8Reg 16 /rdi /rcx :movqMemDisp8Reg /rsi /rcx :cmpqRegReg /nonEqual :jneLbl8 24 /rdx /rsi :leaqMemDisp8Reg 24 /rdi /rdi :leaqMemDisp8Reg :repz :cmpsb /nonEqual :jneLbl8 /rdx /rdx :xorqRegReg /rdx :incqReg /done :jmpLbl8 @nonEqual /rdx /rdx :xorqRegReg @done /rdx 8 /rax :movqRegMemDisp8 /rbx :pushqReg :retn ]] /eystreq defv > _ =globalTaat1Functions { defv }' ::allocateOffsetStruct < # 0 -> integer # 0 <- the bitwise 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 # 0 -> integer # 0 <- the logically 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 /rdx /rdx :xorqRegReg /rcx /rcx :testqRegReg /zero :jnzLbl8 /rdx :incqReg @zero /rdx 8 /rax :movqRegMemDisp8 # push int address on program stack /rax :pushqReg /rbx :pushqReg :retn ]] /eynot defv > _ =globalT1t1Functions { defv }' ::allocateOffsetStruct { | }' ::linkResolve { =*resolve ==createScopeEntry { ==name # create function name resolve 8 sub /rdi :movqImmReg # adjust for expected (but non-existent) code block header size /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 { =*resolve ==typeToUse ==createScopeEntry { ==name # create function name resolve 8 sub /rdi :movqImmReg # adjust for expected (but non-existent) code block header size /rsi /rsi :xorqRegReg # library functions don't have a captured scope typeToUse /rdx :movqImmReg ::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 } /createTypedScopeEntries deff { [ /eydefv /eydeff /eydefq ] { ==name # create function name | 8 sub /rdi :movqImmReg # adjust for expected (but non-existent) code block header size ::currentScope /rsi :movqImmReg /rsi /rsi :movqMemReg /rdx /rdx :xorqRegReg # untyped ::internalAllocateFunction /rax :movqImmReg /rax :callqReg /rax :pushqReg # create string name "ey(.*)" regex assert ::constStringCode _ len dearray # enter into current scope |eydeff /rax :movqImmReg /rax :callqReg } each } /createScopeExtensionEntries deff [ globalFunctions keys len globalFunctions2 keys len add globalFunctions3 keys len add globalMacros keys len add globalT11t1Functions keys len add globalT1t1Functions keys len add globalTaat1Functions keys len add /rdi :movqImmReg /rsi /rsi :xorqRegReg ::internalAllocateScope /rax :movqImmReg /rax :callqReg ::currentScope /rdi :movqImmReg /rax /rdi :movqRegMem globalFunctions keys eydeff { | }' createScopeEntries globalFunctions2 keys eydeff { | }' createScopeEntries globalFunctions3 keys eydeff { | }' createScopeEntries globalMacros keys eydefq { | }' createScopeEntries globalT11t1Functions keys eydeff t11t1 { | }' createTypedScopeEntries globalT1t1Functions keys eydeff t1t1 { | }' createTypedScopeEntries globalTaat1Functions keys eydeff taat1 { | }' createTypedScopeEntries ] :execute { ==name [[ INITIALSCOPESIZE /rdi :movqImmReg ::currentScope /rsi :movqImmReg 8 /r15 :subqImm8Reg /rsi /rsi :movqMemReg /rsi /r15 :movqRegMem # save scope ::internalAllocateScope /rax :movqImmReg /rax :callqReg /rax :pushqReg /rax :pushqReg /rax :movqImmOOBReg name ::string /rax :pushqReg |eydefv /rax :movqImmReg /rax :callqReg ::currentScope /rsi :movqImmReg /rsi :popqMem ]] :execute } /enterSubScope deff { [[ ::currentScope /rsi :movqImmReg /r15 /rax :movqMemReg 8 /r15 :addqImm8Reg /rax /rsi :movqRegMem ]] :execute } /leaveSubScope deff "elymasGlobalSys.ey" include "elymasGlobalStr.ey" include > /global defv # vim: syn=elymas