I'm working on modernizing Rosetta Code's infrastructure. Starting with communications. Please accept this time-limited open invite to RC's Slack.. --Michael Mol (talk) 20:59, 30 May 2020 (UTC)

Nested function/Phix

From Rosetta Code

Archived from Nested_function#Phix
The following was written in a single afternoon, and nearly four years later I have to accept that I will likely never finish it.
I have however penned two reasonably acceptable work-arounds, that have now taken it's place.

Prior to this task, Phix had no support whatsoever for nested functions.
Instead I have taken the first baby steps and documented them.
The indicated source of the demo contains some far more detailed information.

Yes, this is pig-ugly, and incomplete. But it is a good start for anyone that needs nested functions, and shows what can be done in just a few (less than six) hours.

NB as it stands, the compiler front-end "thinks" that l_counter and sep live in the same place. They are properly separate in the runtime/VM, but the front-end will happily emit nonsense code if you let it.

--  demo\rosetta\Nested_function.exw
#ilASM{ jmp :fin
--
-- This is, of course, something the compiler should end up doing automatically,
-- and this assembly, or something similar, should be hidden away in builtins/VM.
--
 :%opGetnlv -- [edi] := [esi] from frame edx
-- nb no reference counting (would be rqd)
[32]
sub esi,ebp -- --> frame offset
@@:
mov ecx,[ebp+20] -- ebp_prev
cmp [ecx+8],edx -- rtn
jne @b
mov eax,[esi+ecx]
mov [edi],eax
[64]
sub rsi,rbp -- --> frame offset
@@:
mov rcx,[rbp+40] -- rbp_prev
cmp [rcx+16],rdx -- rtn
jne @b
mov rax,[rsi+rcx]
mov [rdi],rax
[]
ret
 
 :%opSetnlv -- [edi] in frame edx := [esi] (zeroed)
[32]
sub edi,ebp -- --> frame offset
@@:
mov ecx,[ebp+20] -- ebp_prev
cmp [ecx+8],edx -- rtn
jne @b
mov eax,[esi]
mov [edi+ecx],eax
-- mov [esi],ebx -- zero src
[64]
sub rdi,rbp -- --> frame offset
@@:
mov rcx,[rbp+40] -- rbp_prev
cmp [rcx+16],rdx -- rtn
jne @b
mov eax,[rsi]
mov [rdi+rcx],rax
-- mov [rsi],rbx -- zero src
[]
ret
 ::fin
}
 
function MakeList(string sep=". ")
integer counter = 0
function MakeItem()
-- -- what we'd really like to see:
-- counter += 1
-- return sprintf("%d%s%s",{counter,sep,{"first","second","third"}[counter]})
-- bar these locals, some idea of what the compiler should be doing:
integer l_counter
string l_sep
#ilASM{
[32]
mov edx,routine_id(MakeList)
lea esi,[counter]
lea edi,[l_counter]
call :%opGetnlv
lea esi,[sep]
lea edi,[l_sep]
call :%opGetnlv
[64]
mov rdx,routine_id(MakeList)
lea rsi,[counter]
lea rdi,[l_counter]
call :%opGetnlv
lea rsi,[sep]
lea rdi,[l_sep]
call :%opGetnlv
[]
}
l_counter += 1
#ilASM{
[32]
mov edx,routine_id(MakeList)
lea esi,[l_counter]
lea edi,[counter]
call :%opSetnlv
[64]
mov rdx,routine_id(MakeList)
lea rsi,[l_counter]
lea rdi,[counter]
call :%opSetnlv
[]
}
string res = sprintf("%d%s%s",{l_counter,l_sep,{"first","second","third"}[l_counter]})
#ilASM{
[32]
mov [l_sep],ebx -- (in lieu of proper refcounting)
[64]
mov [l_sep],rbx -- (in lieu of proper refcounting)
[]
}
return res
end function
sequence res = {}
for i=1 to 3 do
res = append(res,MakeItem())
end for
return res
end function
 
?MakeList()
Output:
{"1.  first","2.  second","3.  third"}