Jump to content

Nested function: Difference between revisions

→‎{{header|Phix}}: replaced with two work-arounds
(→‎{{header|Phix}}: replaced with two work-arounds)
Line 1,017:
 
=={{header|Phix}}==
There is only partial support for nested functions in Phix. Some prior work (over a single afternoon) has been left
{{improve|Phix|The Phix compiler needs enhancing to fully support nested functions.}}
unfinished, anyone interested can see it at [[Nested_function/Phix]], but it was just enough to open the door for
 
the two following reasonably acceptable work-arounds.<br>
Prior to this task, Phix had no support whatsoever for nested functions.<br>
Note that in both the following you cannot reference any local variables or parameters of the containing function,
Instead I have taken the first baby steps and documented them.<br>
but must pass in everything you need explicitly, and anything you need to update must be a reference type, which
If your distribution does not include the following demo, you need a later version (not yet uploaded at the
is only dictionaries and class instances, not integers, atoms, sequences, strings, or any user-defined types, as
time of writing). The source of that demo contains far more detailed information, and any updates.<br>
they are all effectively read-only. Also note that the compiler will not (as yet) issue any proper errors or
 
warnings should you break that restriction, instead it simply won't work as hoped for.
Yes, this is pig-ugly, and incomplete. But it is a good start for anyone that needs nested functions, and
=== using a dictionary ===
shows what can be done in just a few (less than six) hours.
<lang Phix>function MakeList(string sep=". ")
 
function MakeItem(integer env, string sep)
NB as it stands, the compiler front-end "thinks" that l_counter and sep live in the same place. They are
integer counter = getd("counter",env)+1
properly separate in the runtime/VM, but the front-end will happily emit nonsense code if you let it.
setd("counter",counter,env)
<lang Phix>--
return sprintf("%d%s%s",{counter,sep,{"first","second","third"}[counter]})
-- 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
integer counter = new_dict({{"counter",0}})
sequence res = {}
for i=1 to 3 do
res = append(res,MakeItem(counter,sep))
end for
return res
end function
 
?MakeList()</lang>
{{out}}
Line 1,147 ⟶ 1,045:
{"1. first","2. second","3. third"}
</pre>
=== using a class ===
Same output. I trust it is obvious that if you passed in c.count, you would not be able to update it.
<lang Phix>class counter
public integer count
end class
function MakeList(string sep=". ")
function MakeItem(counter c, string sep)
c.count += 1
return sprintf("%d%s%s",{c.count,sep,{"first","second","third"}[c.count]})
end function
counter c = new()
sequence res = {}
for i=1 to 3 do
res = append(res,MakeItem(c,sep))
end for
return res
end function
?MakeList()</lang>
 
=={{header|PHP}}==
7,820

edits

Cookies help us deliver our services. By using our services, you agree to our use of cookies.