* Bug 16529 fixed: deff() upgraded: output arg added, one-string def, etc 71/21571/4
Samuel GOUGEON [Fri, 7 Aug 2020 20:33:40 +0000 (22:33 +0200)]
  http://bugzilla.scilab.org/16529

  New deff() page (PDF): http://bugzilla.scilab.org/attachment.cgi?id=5175

Change-Id: I37cff6f15eeb1730137e2ce21aaf63ee3a8dba5b

scilab/CHANGES.md
scilab/modules/functions/help/en_US/deff.xml
scilab/modules/functions/help/ja_JP/deff.xml [deleted file]
scilab/modules/functions/help/pt_BR/deff.xml [deleted file]
scilab/modules/functions/help/ru_RU/deff.xml
scilab/modules/functions/macros/deff.sci
scilab/modules/functions/tests/unit_tests/deff.dia.ref [deleted file]
scilab/modules/functions/tests/unit_tests/deff.tst

index c36c1fd..8b8545b 100644 (file)
@@ -227,6 +227,11 @@ Feature changes and additions on 6.1.1
 * `polyint` is introduced to compute polynomial antiderivatives.
 * Listbox uicontrol callback is now triggered by item click in single selection mode. For example, it allows successive execution of a demo in the demonstrations gui.
 * `det` is now actually extended to sparse matrices.
+* `deff` is upgraded:
+   - The created function may be returned  as output argument.
+   - Providing the function headline and body concatenated in a single input text vector is possible.
+   - For a simple function, a single string input definition can be provided.
+   - For assignable calls to `deff`, the `@` symbol can be used as function pseudo-name.
 
 
 Help pages:
@@ -398,6 +403,7 @@ Bug Fixes
 * [#16458](https://bugzilla.scilab.org/16458): `mean()` did not handle sparse numerical matrices.
 * [#16465](https://bugzilla.scilab.org/16465): Scinotes OpenRecent menu was not updated when it should.
 * [#16473](https://bugzilla.scilab.org/16473): Deleting rows in a sparse squared the matrix with padding zeros (Scilab 6 regression).
+<<<<<<< HEAD
 * [#16474](https://bugzilla.scilab.org/16474): `imult(%z)` crashed Scilab.
 * [#16476](https://bugzilla.scilab.org/16476): `issquare` was not overloaded.
 * [#16488](https://bugzilla.scilab.org/16488): Concatenations mixing boolean and double with at least one operand being sparse were not supported.
@@ -447,6 +453,10 @@ Bug Fixes
 
 =======
 >>>>>>> afb92ac5368 (* Bug 16614 fixed: replot() could fail out of gcf())
+=======
+* [#16529](https://bugzilla.scilab.org/16529): `deff` could not return the created function as output argument, preventing to cretae and use anonymous functions. The function's headline and body had to be provided separately. For Simple functions, a one-string input (possibly console-oriented) definition was not supported.
+
+>>>>>>> 75a0ccd0638 (* Bug 16529 fixed: deff() upgraded: output arg added, one-string def, etc)
 
 ### Bugs fixed in 6.1.0:
 * [#2694](https://bugzilla.scilab.org/2694): `bitget` did not accept positive integers of types int8, int16 or int32.
index 497a965..54fc0b0 100644 (file)
@@ -2,9 +2,8 @@
 <!--
  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
  * Copyright (C) XXXX-2008 - INRIA
- * Copyright (C) 2018 - Samuel GOUGEON
- *
  * Copyright (C) 2012 - 2016 - Scilab Enterprises
+ * Copyright (C) 2018 - 2020 - Samuel GOUGEON
  *
  * This file is hereby licensed under the terms of the GNU GPL v2.0,
  * pursuant to article 5.3.4 of the CeCILL v.2.1.
           xml:lang="en" xml:id="deff">
     <refnamediv>
         <refname>deff</refname>
-        <refpurpose>in-line definition of a function in Scilab language</refpurpose>
+        <refpurpose>in-line definition of a (anonymous) function in Scilab language</refpurpose>
     </refnamediv>
     <refsynopsisdiv>
         <title>Syntax</title>
-        <synopsis>deff('[s1, s2, ...] = newfunction(e1, e2, ...)',text)</synopsis>
+        <synopsis>
+            deff(funcHeadline, funcBody)
+            deff(definition)
+            deff("[r1, r2, ...] = myFunc(in1, in2, ...)", funcBody)
+            deff "r = myFunc(x,y) r = x^2 - y"
+            deff "r = myFunc(x,y) x^2 - y"
+            deff("r = @(x,y) x^2 - y")      // as anonymous container's element
+
+            myFunc = deff(funcHeadline, funcBody)
+            myFunc = deff(definition)
+            myFunc = deff("[r1, r2, ...] = fakeName(in1, in2, ...)", funcBody)
+            myFunc = deff("r = fakeName(x,y) r = x^2 - y")
+            myFunc = deff("r = fakeName(x,y) x^2 - y")
+            myFunc = deff("r = @(x,y) x^2 - y")
+        </synopsis>
     </refsynopsisdiv>
     <refsection>
         <title>Arguments</title>
         <variablelist>
             <varlistentry>
-                <term>e1, e2, ...</term>
+                <term>x, y, in1, in2, ...</term>
+                <listitem>
+                    input arguments of the defined function. This one can have any number
+                    of input arguments, from 0 to any N.
+                    <para/>
+                </listitem>
+            </varlistentry>
+            <varlistentry>
+                <term>r, r1, r2, ...</term>
                 <listitem>
-                    <para>input variables.</para>
+                    Output results of the defined function. This one can have any number
+                    of output results, from 0 to any M. If any, all output arguments
+                    must be explicit = written on the left-hand-side of the function name.
+                    <para/>
                 </listitem>
             </varlistentry>
             <varlistentry>
-                <term>s1, s2, ...</term>
+                <term>funcHeadline</term>
                 <listitem>
-                    <para>output variables.</para>
+                    Single string: Function's headline = its first line giving the local
+                    function's name and the lists of its right-hand-side input arguments
+                    and left-hand-side output arguments. Examples:
+                    <itemizedlist>
+                        <listitem>
+                            <literal>"myFunction(x,y)"</literal> : no output
+                        </listitem>
+                        <listitem>
+                            <literal>"r = myFunction(x,y)"</literal> : single output
+                        </listitem>
+                        <listitem>
+                            <literal>"[a,b] = myFunction(x,y)"</literal> : two outputs. Etc..
+                        </listitem>
+                    </itemizedlist>
+                    Please note that a) the <literal>function</literal> keyword
+                    must not be provided. b) If any, writting output arguments in the
+                    left-hand-side part of the headline is mandatory.
+                    <para/>
                 </listitem>
             </varlistentry>
             <varlistentry>
-                <term>text</term>
+                <term>funcBody</term>
                 <listitem>
-                    <para>a matrix of character strings.</para>
+                    a vector of texts = Scilab instructions of the function's body, in the order
+                    they must be executed. These instructions must define and assign the value
+                    of all output arguments. No trailing "endfunction" keyword is expected.
+                    <para/>
+                    This vector is expected when deff(…) is called with two input arguments.
+                    <para/>
+                    <warning>
+                        Single or double quotes included in instructions must be doubled to be
+                        protected.
+                    </warning>
+                    <para/>
+                </listitem>
+            </varlistentry>
+            <varlistentry>
+                <term>definition</term>
+                <listitem>
+                    Single text or vector of texts, including both the function's headline and body.
+                    <itemizedlist>
+                        <listitem>
+                            If it's a vector, it is equivalent to
+                            <literal>definition = [funcHeadline ; funcBody]</literal>.
+                        </listitem>
+                        <listitem>
+                            Otherwise, the one-string definition is equivalent to
+                            <literal>funcHeadline + " " + strcat(funcBody,"; ")</literal>.
+                        </listitem>
+                    </itemizedlist>
+                    Please see the Description and Examples sections.
+                    <para/>
+                </listitem>
+            </varlistentry>
+            <varlistentry>
+                <term>myFunc</term>
+                <listitem>
+                    Public name and identifier of the defined function, as implicitly
+                    returned in the current environment, or explicitly assigned to the
+                    deff(…)'s output variable.
+                    <para/>
+                    <note>
+                        When deff(…) is called without explicit output argument but
+                        as an element of a container or as input argument of another function,
+                        it is implicitly assigned to this element or argument,
+                        which is anonymous. It is then an
+                        <emphasis role="bold">anonymous function</emphasis>. Example:
+                        <para/>
+                        <literal>L = list(3, deff("r=noName(x) x.^2+1"), "Hello");</literal>.
+                        The result of deff(…) is assigned to L(2). Then,
+                        <literal>L(2)(3.5) // ➜ 13.25</literal>.
+                    </note>
+                    <para/>
                 </listitem>
             </varlistentry>
         </variablelist>
     <refsection>
         <title>Description</title>
         <para>
-            <function>deff</function> can be used to define functions from sequences of instructions
-            written in text strings. The resulting function object has the same properties
-            of any other function defined in a text file and loaded with <function>exec</function>.
+            deff(…) can be used to define a <emphasis>single</emphasis> function from Scilab
+            instructions provided through a matrix of text, instead of through any external
+            text file of instructions written in a <literal>function … endfunction</literal>
+            block to be executed.
         </para>
-        <warning>
-            Quotes included in instructions given in strings must be doubled to be protected.
-        </warning>
+        <para>
+            A source file of Scilab code can include the definition of several public functions.
+            This is not possible with deff(…): Only one public function can be defined.
+            However, as with a file, the body of the defined function can include one
+            or several <literal>function … endfunction</literal> blocks defining
+            some nested private functions.
+        </para>
+        <para>
+            Whatever is the deff(…) syntax used to provide the source code (see below), if this one
+            includes a syntax error, deff(…) will yield a compilation error and stop.
+        </para>
+        <refsect3>
+            <title>Providing the source code</title>
+            <para>
+                <emphasis role="bold">deff(funcHeadline, funcBody)</emphasis> (2 inputs) and
+                <emphasis role="bold">deff([funcHeadline ; funcBody])</emphasis>
+                (single concatenated input) are equivalent.
+            </para>
+            <para>
+                When <varname>funcBody</varname> is made of only one (short) string, it may be glued
+                to and passed with the <varname>funcHeadline</varname>, as a one-line function
+                definition. Examples:
+                <table cellpadding="0" cellspacing="0">
+                    <tr><td><literal>deff("[a,b] = myFunction(x,y) a = x.^2; b = x-y;")</literal></td>
+                    </tr>
+                    <tr><td>
+                            <literal>deff("r = myFunction(x,y) r = (x-y).^2")</literal>.
+                            This can even be simplified into
+                        </td>
+                    </tr>
+                    <tr><td>
+                            <literal>deff("r = myFunction(x,y) (x-y).^2")</literal>
+                        </td>
+                    </tr>
+                    <tr><td><literal>deff("myFunction(x,y) disp(x.^2 - b)")</literal></td>
+                    </tr>
+                </table>
+            </para>
+            <para>
+                When the result of deff(…) is assigned to or inserted into any anonymous element
+                of a container, then it comes that the pseudo-name <varname>fakeName</varname>
+                defined in the <varname>funcHeadline</varname>
+                has no role at all, and could in no way be used to call the function.
+                This name can then be replaced with the "@" character in the <varname>funcHeadline</varname>,
+                to highlight that the defined function becomes <emphasis>anonymous</emphasis>.
+            </para>
+        </refsect3>
+        <refsect3>
+            <title>Identifier of the defined function</title>
+            <para>
+                The identifier is the actual word (name) to use to call the defined function.
+                The 3 following cases are illustrated in examples.
+            </para>
+            <para>
+                When the defined function is not expected as a assignable result, its identifier
+                is returned directly in the calling environment. Its public name is then the name
+                used in the headline of the provided source code.
+            </para>
+            <para>
+                Otherwise, when deff(…) is called with an explicit output argument, the name
+                of this one becomes the only actual public function's identifier. As a consequence,
+                the function name used in the source code can't be used to call it. It becomes
+                a pseudo-name. For this reason, the "@" symbol (standing for "anonymous") can then
+                be used in the function code's headline, instead of any valid function's name.
+                Of course, nothing prevents to use an output name identical to any valid
+                function name defined in the headline. But it's not mandatory.
+            </para>
+            <para>
+                The last case is using deff(…) as an element of a container, for instance
+                when defining or inserting into a list, or as input argument of another function.
+                Then deff(…) works in an assignable way. It returns the identifier of the defined
+                function and assigns it to the considered list element or input argument.
+                These ones are nameless, since the <literal>deff(…)</literal> call is an expression.
+                The defined function then becomes really <emphasis>anonymous</emphasis>.
+            </para>
+        </refsect3>
     </refsection>
     <refsection>
         <title>Examples</title>
-        <programlisting role="example"><![CDATA[
-deff('x = myplus(y,z)', 'x = y+z')
-myplus(1,%i)
+        <refsect3>
+            <title>Unassigned functions</title>
+            <para/>
+            <programlisting role="example"><![CDATA[
+                deff('x = myplus(y,z)', 'x = y+z')
+                myplus(1,%i)
 
-deff('[y, z] = mymacro(x)', ['y = 3*x+1'; 'z = a*x + x.^2'])
-a = 3;
-[u, v] = mymacro(2)
- ]]></programlisting>
-    <screen><![CDATA[
+                deff('[y, z] = mymacro(x)', ['y = 3*x+1'; 'z = a*x + x.^2'])
+                a = 3;
+                [u, v] = mymacro(2)
+         ]]></programlisting>
+            <screen><![CDATA[
 --> deff('x = myplus(y,z)', 'x = y+z')
 --> myplus(1,%i)
  ans  =
@@ -85,6 +252,154 @@ a = 3;
  u  =
    7.
 ]]></screen>
+            <para>
+                With some single input and output:
+            </para>
+            <programlisting role="example"><![CDATA[
+                clear myFunc
+                source = ["r = myFunc(x,y)" ; "r = x.*(x-y)"]
+                deff(source)
+                myFunc(3, -2)
+         ]]></programlisting>
+            <screen><![CDATA[
+--> source = ["r = myFunc(x,y)" ; "r = x.*(x-y)"]
+ source  =
+  "r = myFunc(x,y)"
+  "r = x.*(x-y)"
+
+--> deff(source)
+--> myFunc(3, -2)
+ ans  =
+   15.
+]]></screen>
+            <para>
+                Same example with a one-line definition, that then allows a console-oriented
+                syntax (without optional deff parentheses, but with still mandatory delimiting quotes):
+            </para>
+            <programlisting role="example"><![CDATA[
+                clear myFunc
+                deff "r = myFunc(x,y) r = x.*(x-y)"
+                myFunc(1:3, -2)
+         ]]></programlisting>
+            <screen><![CDATA[
+--> deff "r = myFunc(x,y) r = x.*(x-y)"
+--> myFunc(1:3, -2)
+ ans  =
+   3.   8.   15.
+]]></screen>
+            <para>
+                For a one-line direct definition with a single output, we can even omit the "r = " duplicate in the body:
+            </para>
+            <programlisting role="example"><![CDATA[
+                clear myFunc
+                deff "r = myFunc(x,y) x.*(x-y)"
+                myFunc(1:3, -2)
+         ]]></programlisting>
+            <screen><![CDATA[
+--> deff "r = myFunc(x,y) x.*(x-y)"
+--> myFunc(1:3, -2)
+ ans  =
+   3.   8.   15.
+]]></screen>
+            <para>
+                Function with no assignable output: Note also the usage of doubled quotes to protect
+                them in the definition string:
+            </para>
+            <programlisting role="example"><![CDATA[
+                clear myFunc
+                deff("myFunc(x, y) messagebox(prettyprint(x.*(x-y), ""html"",""""))")
+                myFunc([1 2 ; 3 4], -2)
+         ]]></programlisting>
+        </refsect3>
+        <refsect3>
+            <title>Defined function assigned to a recipient</title>
+            <para>
+                Let's keep similar examples as above:
+            </para>
+            <programlisting role="example"><![CDATA[
+                clear myFunc actualName
+                actualName = deff("r = myFunc(x,y) x.*(x-y)")
+                isdef(["myFunc" "actualName"])
+                actualName(1:3, -2)
+                myFunc(1:3, -2)
+         ]]></programlisting>
+            <screen><![CDATA[
+--> actualName = deff("r = myFunc(x,y) x.*(x-y)")
+ actualName  =
+[r]=actualName(x,y)
+
+--> isdef(["myFunc" "actualName"])
+ ans  =
+  F T
+
+--> actualName(1:3, -2)
+ ans  =
+   3.   8.   15.
+
+--> myFunc(1:3, -2)
+Undefined variable: myFunc
+]]></screen>
+            <para>
+                Since the "internal" function name is fake, we can use "@" instead
+                (the "@" character is not allowed in actual function names):
+            </para>
+            <programlisting role="example"><![CDATA[
+                clear actualName
+                actualName = deff("r = @(x,y) x.*(x-y)");
+                actualName(1:3, -2)
+         ]]></programlisting>
+            <screen><![CDATA[
+--> actualName = deff("r = @(x,y) x.*(x-y)");
+--> actualName(1:3, -2)
+ ans  =
+   3.   8.   15.
+]]></screen>
+            <para>
+                Now, let's directly assign the created function to a nameless recipient.
+                Although the function becomes anonymous, we can still call it:
+            </para>
+            <programlisting role="example"><![CDATA[
+                L = list("abc", deff("r = @(x,y) x.*(x-y)"), %z);
+                L(2)(1.1:4, -2.1)
+                // We can extract and set a name to the anonymous function:
+                Abc = L(2)
+                Abc(1.1:4, -2.1)
+         ]]></programlisting>
+            <screen><![CDATA[
+--> L = list("abc", deff("r = @(x,y) x.*(x-y)"), %z);
+--> L(2)(1.1:4, -2.1)
+ ans  =
+   3.52   8.82   16.12
+
+--> Abc = L(2)
+ Abc  =
+[r]=Abc(x,y)
+
+--> Abc(1.1:4, -2.1)
+ ans  =
+   3.52   8.82   16.12
+]]></screen>
+            <para>
+                Finally, let's use deff() to directly define and pass a function
+                as an input argument of another function:
+            </para>
+            <programlisting role="example"><![CDATA[
+                function r = test(txt, x, theFunc)
+                    r = x + theFunc(txt)
+                endfunction
+
+                test(rand(2,3), 0.7, deff("r = @(M) sum(size(M).^2)"))
+         ]]></programlisting>
+            <screen><![CDATA[
+--> test(rand(2,3), 0.7, deff("r = @(M) sum(size(M).^2)"))
+ ans  =
+   13.7
+]]></screen>
+        <para>
+            In this example, the passed function is anonymous in the calling environment,
+            but is assigned and gets its "theFunct" name from inside the called function.
+        </para>
+        </refsect3>
     </refsection>
     <refsection role="see also">
         <title>See also</title>
@@ -128,6 +443,25 @@ a = 3;
                   </itemizedlist>
                 </revdescription>
             </revision>
+            <revision>
+                <revnumber>6.1.1</revnumber>
+                <revdescription>
+                   <itemizedlist>
+                     <listitem>
+                        Output optional argument added. Anonymous functions can be defined.
+                     </listitem>
+                     <listitem>
+                        Single input argument supported, concatenating the function headline and body.
+                     </listitem>
+                     <listitem>
+                        Single string syntax supported, like <literal>deff "r = myFun(x,y) x.^2-y"</literal>
+                     </listitem>
+                     <listitem>
+                        "@" function's pseudo-name supported.
+                     </listitem>
+                  </itemizedlist>
+                </revdescription>
+            </revision>
         </revhistory>
     </refsection>
 </refentry>
diff --git a/scilab/modules/functions/help/ja_JP/deff.xml b/scilab/modules/functions/help/ja_JP/deff.xml
deleted file mode 100644 (file)
index 4d871a8..0000000
+++ /dev/null
@@ -1,137 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
- * Copyright (C) XXXX-2008 - INRIA
- * Copyright (C) 2018 - Samuel GOUGEON
- *
- * Copyright (C) 2012 - 2016 - Scilab Enterprises
- *
- * This file is hereby licensed under the terms of the GNU GPL v2.0,
- * pursuant to article 5.3.4 of the CeCILL v.2.1.
- * This file was originally licensed under the terms of the CeCILL v2.1,
- * and continues to be available under such terms.
- * For more information, see the COPYING file which you should have received
- * along with this program.
- *
- -->
-<refentry xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink"
-        xmlns:svg="http://www.w3.org/2000/svg" xmlns:mml="http://www.w3.org/1998/Math/MathML"
-        xmlns:db="http://docbook.org/ns/docbook" xmlns:scilab="http://www.scilab.org"
-        xml:lang="ja" xml:id="deff">
-    <refnamediv>
-        <refname>deff</refname>
-        <refpurpose>関数のオンライン定義</refpurpose>
-    </refnamediv>
-    <refsynopsisdiv>
-        <title>呼び出し手順</title>
-        <synopsis>deff('[s1, s2,...] = newfunction(e1, e2,...)',text)</synopsis>
-    </refsynopsisdiv>
-    <refsection>
-        <title>引数</title>
-        <variablelist>
-            <varlistentry>
-                <term>e1, e2, ...</term>
-                <listitem>
-                    <para>入力変数.</para>
-                </listitem>
-            </varlistentry>
-            <varlistentry>
-                <term>s1, s2, ...</term>
-                <listitem>
-                    <para>出力変数.</para>
-                </listitem>
-            </varlistentry>
-            <varlistentry>
-                <term>text</term>
-                <listitem>
-                    <para>文字列行列</para>
-                </listitem>
-            </varlistentry>
-        </variablelist>
-    </refsection>
-    <refsection>
-        <title>説明</title>
-        <para>
-            <function>deff</function> はテキスト文字列で記述された一連の命令から
-            関数を定義する際に使用されます.
-            得られる関数オブジェクトはテキストファイルで定義され,
-            <function>exec</function> または <function>exec</function> で
-            定義された他の関数と同じ特性を有しています.
-        </para>
-        <warning>>
-            命令の中の引用符(文字列の区切りまたは行列の転置を意味する)は,
-            ただしく解釈されるように二重化する必要があります(<link linkend="quote">quote</link>のヘルプを参照).
-            この仕様のため,作成作業はやや不便となります.
-        </warning>
-    </refsection>
-    <refsection>
-        <title>例</title>
-        <programlisting role="example"><![CDATA[
-deff('x = myplus(y,z)', 'x = y+z')
-myplus(1,%i)
-
-deff('[y, z] = mymacro(x)', ['y = 3*x+1'; 'z = a*x + x.^2'])
-a = 3;
-[u, v] = mymacro(2)
- ]]></programlisting>
-    <screen><![CDATA[
---> deff('x = myplus(y,z)', 'x = y+z')
---> myplus(1,%i)
- ans  =
-   1. + i
-
---> deff('[y, z] = mymacro(x)', ['y = 3*x+1'; 'z = a*x + x.^2'])
---> a = 3;
---> [u, v] = mymacro(2)
- v  =
-   10.
-
- u  =
-   7.
-]]></screen>
-    </refsection>
-    <refsection role="see also">
-        <title>参照</title>
-        <simplelist type="inline">
-            <member>
-                <link linkend="function">function</link>
-            </member>
-            <member>
-                <link linkend="exec">exec</link>
-            </member>
-            <member>
-                <link linkend="getd">getd</link>
-            </member>
-            <member>
-                <link linkend="genlib">genlib</link>
-            </member>
-            <member>
-                <link linkend="jdeff">jdeff</link>
-            </member>
-            <member>
-                <link linkend="jcompile">jcompile</link>
-            </member>
-        </simplelist>
-    </refsection>
-    <refsection role="history">
-        <title>履歴</title>
-        <revhistory>
-            <revision>
-                <revnumber>6.0.0</revnumber>
-                <revdescription>
-                   <itemizedlist>
-                     <listitem>
-                       The input option
-                       <ulink url="https://help.scilab.org/docs/5.5.2/ja_JP/deff.html">
-                         <varname>opt="c"|"p"|"n"</varname>
-                       </ulink> is no longer available.
-                     </listitem>
-                     <listitem>
-                        The defined <varname>newfunction</varname> is now of type 13 (instead of 11).
-                     </listitem>
-                  </itemizedlist>
-                </revdescription>
-            </revision>
-        </revhistory>
-    </refsection>
-</refentry>
\ No newline at end of file
diff --git a/scilab/modules/functions/help/pt_BR/deff.xml b/scilab/modules/functions/help/pt_BR/deff.xml
deleted file mode 100644 (file)
index 55c7050..0000000
+++ /dev/null
@@ -1,132 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
- * Copyright (C) XXXX-2008 - INRIA
- * Copyright (C) 2018 - Samuel GOUGEON
- *
- * Copyright (C) 2012 - 2016 - Scilab Enterprises
- *
- * This file is hereby licensed under the terms of the GNU GPL v2.0,
- * pursuant to article 5.3.4 of the CeCILL v.2.1.
- * This file was originally licensed under the terms of the CeCILL v2.1,
- * and continues to be available under such terms.
- * For more information, see the COPYING file which you should have received
- * along with this program.
- *
- -->
-<refentry xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink"
-        xmlns:svg="http://www.w3.org/2000/svg" xmlns:ns3="http://www.w3.org/1999/xhtml"
-        xmlns:mml="http://www.w3.org/1998/Math/MathML" xmlns:db="http://docbook.org/ns/docbook"
-        xmlns:scilab="http://www.scilab.org" xml:id="deff" xml:lang="pt">
-    <refnamediv>
-        <refname>deff</refname>
-        <refpurpose>definição on-line de função</refpurpose>
-    </refnamediv>
-    <refsynopsisdiv>
-        <title>Seqüência de Chamamento</title>
-        <synopsis>deff('[s1, s2, ...] = newfunction(e1, e2,...)',text)</synopsis>
-    </refsynopsisdiv>
-    <refsection>
-        <title>Parâmetros</title>
-        <variablelist>
-            <varlistentry>
-                <term>e1, e2, ...</term>
-                <listitem>
-                    <para>variáveis de entrada.</para>
-                </listitem>
-            </varlistentry>
-            <varlistentry>
-                <term>s1, s2, ...</term>
-                <listitem>
-                    <para>variáveis de saída.</para>
-                </listitem>
-            </varlistentry>
-            <varlistentry>
-                <term>text</term>
-                <listitem>
-                    <para>matriz de strings.</para>
-                </listitem>
-            </varlistentry>
-        </variablelist>
-    </refsection>
-    <refsection>
-        <title>Descrição</title>
-        <para>
-            <function>deff</function> pode ser usada para definir funções de
-            seqüências de instruções escritas em strings de textos. Objeto função
-            resultante tem as mesmas propriedades que qualquer outra função definida
-            em um arquivo de texto e carregada através de <function>exec</function> ou
-            <function>exec</function>.
-        </para>
-    </refsection>
-    <refsection>
-        <title>Exemplos</title>
-        <programlisting role="example"><![CDATA[
-deff('x = myplus(y,z)', 'x = y+z')
-myplus(1,%i)
-
-deff('[y, z] = mymacro(x)', ['y = 3*x+1'; 'z = a*x + x.^2'])
-a = 3;
-[u, v] = mymacro(2)
- ]]></programlisting>
-    <screen><![CDATA[
---> deff('x = myplus(y,z)', 'x = y+z')
---> myplus(1,%i)
- ans  =
-   1. + i
-
---> deff('[y, z] = mymacro(x)', ['y = 3*x+1'; 'z = a*x + x.^2'])
---> a = 3;
---> [u, v] = mymacro(2)
- v  =
-   10.
-
- u  =
-   7.
-]]></screen>
-    </refsection>
-    <refsection role="see also">
-        <title>Ver Também</title>
-        <simplelist type="inline">
-            <member>
-                <link linkend="function">function</link>
-            </member>
-            <member>
-                <link linkend="exec">exec</link>
-            </member>
-            <member>
-                <link linkend="getd">getd</link>
-            </member>
-            <member>
-                <link linkend="genlib">genlib</link>
-            </member>
-            <member>
-                <link linkend="jdeff">jdeff</link>
-            </member>
-            <member>
-                <link linkend="jcompile">jcompile</link>
-            </member>
-        </simplelist>
-    </refsection>
-    <refsection role="history">
-        <title>Histórico</title>
-        <revhistory>
-            <revision>
-                <revnumber>6.0.0</revnumber>
-                <revdescription>
-                   <itemizedlist>
-                     <listitem>
-                       The input option
-                       <ulink url="https://help.scilab.org/docs/5.5.2/pt_BR/deff.html">
-                         <varname>opt="c"|"p"|"n"</varname>
-                       </ulink> is no longer available.
-                     </listitem>
-                     <listitem>
-                        The defined <varname>newfunction</varname> is now of type 13 (instead of 11).
-                     </listitem>
-                  </itemizedlist>
-                </revdescription>
-            </revision>
-        </revhistory>
-    </refsection>
-</refentry>
index bd38b86..2fc5d50 100644 (file)
@@ -2,9 +2,8 @@
 <!--
  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
  * Copyright (C) XXXX-2008 - INRIA
- * Copyright (C) 2018 - Samuel GOUGEON
- *
  * Copyright (C) 2012 - 2016 - Scilab Enterprises
+ * Copyright (C) 2018 - 2020 - Samuel GOUGEON
  *
  * This file is hereby licensed under the terms of the GNU GPL v2.0,
  * pursuant to article 5.3.4 of the CeCILL v.2.1.
  *
  -->
 <refentry xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink"
-        xmlns:svg="http://www.w3.org/2000/svg" xmlns:mml="http://www.w3.org/1998/Math/MathML"
-        xmlns:db="http://docbook.org/ns/docbook" xmlns:scilab="http://www.scilab.org"
-        xml:lang="ru" xml:id="deff">
+          xmlns:svg="http://www.w3.org/2000/svg" xmlns:mml="http://www.w3.org/1998/Math/MathML"
+          xmlns:db="http://docbook.org/ns/docbook" xmlns:scilab="http://www.scilab.org"
+          xml:lang="ru" xml:id="deff">
     <refnamediv>
         <refname>deff</refname>
         <refpurpose>
-            определение функции во время выполнения программы
+            вставленное определение (анонимной) функции на языке Scilab
         </refpurpose>
     </refnamediv>
     <refsynopsisdiv>
         <title>Синтаксис</title>
-        <synopsis>deff('[s1, s2, ...] = newfunction(e1, e2, ...)',text)</synopsis>
+        <synopsis>
+            deff(funcHeadline, funcBody)
+            deff(definition)
+            deff("[r1, r2, ...] = myFunc(in1, in2, ...)", funcBody)
+            deff "r = myFunc(x,y) r = x^2 - y"
+            deff "r = myFunc(x,y) x^2 - y"
+            deff("r = @(x,y) x^2 - y")      // в качестве элемента анонимного контейнера
+
+            myFunc = deff(funcHeadline, funcBody)
+            myFunc = deff(definition)
+            myFunc = deff("[r1, r2, ...] = fakeName(in1, in2, ...)", funcBody)
+            myFunc = deff("r = fakeName(x,y) r = x^2 - y")
+            myFunc = deff("r = fakeName(x,y) x^2 - y")
+            myFunc = deff("r = @(x,y) x^2 - y")
+        </synopsis>
     </refsynopsisdiv>
     <refsection>
         <title>Аргументы</title>
         <variablelist>
             <varlistentry>
-                <term>e1, e2, ...</term>
+                <term>x, y, in1, in2, ...</term>
+                <listitem>
+                    входные аргументы определяемой функции. Последняя может иметь
+                    любое количество входных аргументов, от 0 до любого N.
+                    <para/>
+                </listitem>
+            </varlistentry>
+            <varlistentry>
+                <term>r, r1, r2, ...</term>
                 <listitem>
-                    <para>входные переменные.</para>
+                    результаты на выходе определяемой функции. Последняя может
+                    иметь любое количество результатов на выходе, от 0 до любого
+                    M. Все выходные аргументы должны быть явными, то есть,
+                    записанными слева от имени функции.
+                    <para/>
                 </listitem>
             </varlistentry>
             <varlistentry>
-                <term>s1, s2, ...</term>
+                <term>funcHeadline</term>
                 <listitem>
-                    <para>выходные переменные.</para>
+                    одиночная строка: заголовок функции, то есть, её первая строчка,
+                    указывающая локальное имя функции и списки её входных аргументов
+                    с правой стороны и выходных аргументов с левой стороны. Примеры:
+                    <itemizedlist>
+                        <listitem>
+                            <literal>"myFunction(x,y)"</literal> : нет аргументов на выходе
+                        </listitem>
+                        <listitem>
+                            <literal>"r = myFunction(x,y)"</literal> : один аргумент на выходе
+                        </listitem>
+                        <listitem>
+                            <literal>"[a,b] = myFunction(x,y)"</literal> : два аргумента
+                            на выходе. И т.д.
+                        </listitem>
+                    </itemizedlist>
+                    Пожалуйста, обратите внимание, что a) ключевое слово <literal>function</literal>
+                    не обязательно указывать. b) запись выходных аргументов, если они есть, на левой
+                    части заголовочной строчки является обязательной.
+                    <para/>
                 </listitem>
             </varlistentry>
             <varlistentry>
-                <term>text</term>
+                <term>funcBody</term>
                 <listitem>
-                    <para>матрица символьных строк.</para>
+                    вектор текстов, то есть Scilab-инструкций тела функции, в том
+                    порядке, в котором они должны быть выполнены. Эти инструкции
+                    должны определять и назначать значения всех выходных аргументов.
+                    Завершающее ключевое слово "endfunction" не ожидается.
+                    <para/>
+                    Этот вектор ожидается, когда <literal>deff(…)</literal> вызывается
+                    с двумя входными аргументами.
+                    <para/>
+                    <warning>
+                        Одинарные или двойные кавычки внутри инструкций должны
+                        дублироваться для защиты.
+                    </warning>
+                    <para/>
+                </listitem>
+            </varlistentry>
+            <varlistentry>
+                <term>definition</term>
+                <listitem>
+                    Отдельный текст или вектор текстов, включая как заголовочную
+                    строчку функции, так и тело.
+                    <itemizedlist>
+                        <listitem>
+                            Если это вектор, то это эквивалентно
+                            <literal>definition = [funcHeadline ; funcBody]</literal>.
+                        </listitem>
+                        <listitem>
+                            В противном случае одностроковое определение эквивалентно
+                            <literal>funcHeadline + " " + strcat(funcBody,"; ")</literal>.
+                        </listitem>
+                    </itemizedlist>
+                    Пожалуйста, смотрите разделы "Описание" и "Примеры".
+                    <para/>
+                </listitem>
+            </varlistentry>
+            <varlistentry>
+                <term>myFunc</term>
+                <listitem>
+                    Публичное имя и идентификатор определяемой функции, неявно
+                    возвращаемый в текущее окружение, либо явно присваиваемый
+                    переменной на выходе <literal>deff(…)</literal>.
+                    <para/>
+                    <note>
+                        Когда <literal>deff(…)</literal> вызывается без явных выходных
+                        аргументов, но в качестве элемента контейнера или в качестве
+                        входного аргумента другой функции, то она неявно присваивается
+                        этому элементу или аргументу, который является анонимным. То
+                        тогда она является
+                        <emphasis role="bold">анонимной функцией</emphasis>. Например:
+                        <para/>
+                        <literal>L = list(3, deff("r=noName(x) x.^2+1"), "Hello");</literal>.
+                        Результат <literal>deff(…)</literal> присваивается <literal>L(2)</literal>.
+                        Тогда <literal>L(2)(3.5) // ➜ 13.25</literal>.
+                    </note>
+                    <para/>
                 </listitem>
             </varlistentry>
         </variablelist>
     <refsection>
         <title>Описание</title>
         <para>
-            Функция <function>deff</function> может быть использована для определения функций из
-            ряда инструкций, написанных в текстовых строках. Полученный объект функции имеет те же
-            свойства, что и любая другая функция, определённая в текстовом файле и загруженная
-            с помощью функции <function>exec</function>.
+            <literal>deff(…)</literal> может использоваться для определения
+            <emphasis>отдельной</emphasis> функции из инструкций Scilab, указанных
+            через матрицу текстов, вместо любого внешнего текстового файла с
+            инструкциями для исполнения, записанными в блок <literal>function … endfunction</literal>.
         </para>
+        <para>
+            Файл исходного Scilab-кода может включать в себя определение нескольких
+            публичных функций. Это не возможно сделать с помощью <literal>deff(…)</literal>:
+            только одну публичную функцию можно определить. Однако, как и в случае
+            с файлом, тело определяемой функции может включать в себя один или
+            несколько блоков <literal>function … endfunction</literal>, определяющих
+            вложенные приватные функции.
+        </para>
+        <para>
+            Независимо от синтаксиса <literal>deff(…)</literal>, используемого для
+            обеспечения исходного кода (см. ниже), если он содержит синтаксическую
+            ошибку, то <literal>deff(…)</literal> выдаст ошибку компиляции
+            и остановит работу.
+        </para>
+        <refsect3>
+            <title>Указание исходного кода</title>
+            <para>
+                <emphasis role="bold">deff(funcHeadline, funcBody)</emphasis> (2 входа) и
+                <emphasis role="bold">deff([funcHeadline ; funcBody])</emphasis>
+                (единый конкатенированный вход) эквивалентны.
+            </para>
+            <para>
+                Когда <varname>funcBody</varname> сделана только из одной (короткой)
+                строки, она может быть приклеена и передана вместе с
+                <varname>funcHeadline</varname>, как одностроковое определение функции.
+                Примеры:
+                <table cellpadding="0" cellspacing="0">
+                    <tr><td><literal>deff("[a,b] = myFunction(x,y) a = x.^2; b = x-y;")</literal></td>
+                    </tr>
+                    <tr><td>
+                            <literal>deff("r = myFunction(x,y) r = (x-y).^2")</literal>.
+                            Это можно даже упростить до
+                        </td>
+                    </tr>
+                    <tr><td>
+                            <literal>deff("r = myFunction(x,y) (x-y).^2")</literal>
+                        </td>
+                    </tr>
+                    <tr><td><literal>deff("myFunction(x,y) disp(x.^2 - b)")</literal></td>
+                    </tr>
+                </table>
+            </para>
+            <para>
+                Когда результат <literal>deff(…)</literal> присваивается или вводится
+                в любой анонимный контейнер, то оказывается, что псевдоимя
+                <varname>fakeName</varname>, определённое в <varname>funcHeadline</varname>
+                не играет роли вообще, и может совсем не использоваться для вызова
+                функции. Это имя может быть тогда заменено символом "@" в
+                <varname>funcHeadline</varname> для указания, что определяемая
+                функция становится <emphasis>анонимной</emphasis>.
+            </para>
+        </refsect3>
+        <refsect3>
+            <title>Идентификатор определяемой функции</title>
+            <para>
+                Идентификатор - это фактическое слово (имя), которое используется
+                для вызова определяемой функции. Следующие три случая представлены
+                для примера.
+            </para>
+            <para>
+                Когда определяемая функция не предполагает присваиваемый результат,
+                то её идентификатор возвращается напрямую в вызывающее окружение.
+                Её публичное имя тогда является именем, используемым в заголовочной
+                строчке представленного исходного кода.
+            </para>
+            <para>
+                В противном случае, когда <literal>deff(…)</literal> вызывается с
+                явным выходным аргументом, то его имя становится единственным
+                фактическим  идентификатором публичной функции. В результате, имя
+                функции, используемой в исходном коде, нельзя использовать для её
+                вызова. Оно становится псевдоименем. По этой причине в заголовочной
+                строчке может быть использован символ "@" (ставящийся для "анонимок")
+                вместо какого-либо корректного имени функции, определённой в заголовочной
+                строчке. Но это не обязательно.
+            </para>
+            <para>
+                Последний случай использования <literal>deff(…)</literal> в качестве
+                элемента контейнера, например когда определяется или вводится в список,
+                либо в качестве входного аргумента другой функции. Тогда
+                <literal>deff(…)</literal> работает как присвоение. Она возвращает
+                идентификатор определяемой функции и присваивает его соответствующему
+                элементу списка или входного аргумента. Они безымянны, следовательно
+                вызов <literal>deff(…)</literal> является выражением. Определяемая
+                функция тогда становиться реально <emphasis>анонимной</emphasis>.
+            </para>
+        </refsect3>
     </refsection>
     <refsection>
         <title>Примеры</title>
-        <programlisting role="example"><![CDATA[
-deff('x = myplus(y,z)', 'x = y+z')
-myplus(1,%i)
+        <refsect3>
+            <title>Неприсваивающие функции</title>
+            <para/>
+            <programlisting role="example"><![CDATA[
+                deff('x = myplus(y,z)', 'x = y+z')
+                myplus(1,%i)
 
-deff('[y, z] = mymacro(x)', ['y = 3*x+1'; 'z = a*x + x.^2'])
-a = 3;
-[u, v] = mymacro(2)
- ]]></programlisting>
-    <screen><![CDATA[
+                deff('[y, z] = mymacro(x)', ['y = 3*x+1'; 'z = a*x + x.^2'])
+                a = 3;
+                [u, v] = mymacro(2)
+         ]]></programlisting>
+            <screen><![CDATA[
 --> deff('x = myplus(y,z)', 'x = y+z')
 --> myplus(1,%i)
  ans  =
@@ -85,6 +270,159 @@ a = 3;
  u  =
    7.
 ]]></screen>
+            <para>
+                С единственным входным и выходным аргументом:
+            </para>
+            <programlisting role="example"><![CDATA[
+                clear myFunc
+                source = ["r = myFunc(x,y)" ; "r = x.*(x-y)"]
+                deff(source)
+                myFunc(3, -2)
+         ]]></programlisting>
+            <screen><![CDATA[
+--> source = ["r = myFunc(x,y)" ; "r = x.*(x-y)"]
+ source  =
+  "r = myFunc(x,y)"
+  "r = x.*(x-y)"
+
+--> deff(source)
+--> myFunc(3, -2)
+ ans  =
+   15.
+]]></screen>
+            <para>
+                Тот же пример с одностроковым определением, которое затем позволяет
+                синтаксис, ориентированный на командную строку (без необязательных
+                скобок deff, но с, по-прежнему, обязательными разделительными кавычками):
+            </para>
+            <programlisting role="example"><![CDATA[
+                clear myFunc
+                deff "r = myFunc(x,y) r = x.*(x-y)"
+                myFunc(1:3, -2)
+         ]]></programlisting>
+            <screen><![CDATA[
+--> deff "r = myFunc(x,y) r = x.*(x-y)"
+--> myFunc(1:3, -2)
+ ans  =
+   3.   8.   15.
+]]></screen>
+            <para>
+                Для однострокового прямого определения с единственным выходным аргументом,
+                мы можем даже опустить дубликат "r = " в теле функции:
+            </para>
+            <programlisting role="example"><![CDATA[
+                clear myFunc
+                deff "r = myFunc(x,y) x.*(x-y)"
+                myFunc(1:3, -2)
+         ]]></programlisting>
+            <screen><![CDATA[
+--> deff "r = myFunc(x,y) x.*(x-y)"
+--> myFunc(1:3, -2)
+ ans  =
+   3.   8.   15.
+]]></screen>
+            <para>
+                Функция без присваиваемого выходного аргумента: обратите также внимание
+                на использование удвоенных кавычек для защиты их в строке определения:
+            </para>
+            <programlisting role="example"><![CDATA[
+                clear myFunc
+                deff("myFunc(x, y) messagebox(prettyprint(x.*(x-y), ""html"",""""))")
+                myFunc([1 2 ; 3 4], -2)
+         ]]></programlisting>
+        </refsect3>
+        <refsect3>
+            <title>Определяемая функция, присваиваемая реципиенту</title>
+            <para>
+                Придержимся примеров, похожих на приведённые выше:
+            </para>
+            <programlisting role="example"><![CDATA[
+                clear myFunc actualName
+                actualName = deff("r = myFunc(x,y) x.*(x-y)")
+                isdef(["myFunc" "actualName"])
+                actualName(1:3, -2)
+                myFunc(1:3, -2)
+         ]]></programlisting>
+            <screen><![CDATA[
+--> actualName = deff("r = myFunc(x,y) x.*(x-y)")
+ actualName  =
+[r]=actualName(x,y)
+
+--> isdef(["myFunc" "actualName"])
+ ans  =
+  F T
+
+--> actualName(1:3, -2)
+ ans  =
+   3.   8.   15.
+
+--> myFunc(1:3, -2)
+Undefined variable: myFunc
+]]></screen>
+            <para>
+                Поскольку имя "внутренней" функции является псевдоименем, то мы
+                можем вместо него использовать "@" (символ "@" нельзя использовать
+                в фактических именах функций):
+            </para>
+            <programlisting role="example"><![CDATA[
+                clear actualName
+                actualName = deff("r = @(x,y) x.*(x-y)");
+                actualName(1:3, -2)
+         ]]></programlisting>
+            <screen><![CDATA[
+--> actualName = deff("r = @(x,y) x.*(x-y)");
+--> actualName(1:3, -2)
+ ans  =
+   3.   8.   15.
+]]></screen>
+            <para>
+                Теперь напрямую присвоим созданную функцию безымянному реципиенту.
+                Хотя функция становится анонимной, мы, по-прежнему, можем вызывать её:
+            </para>
+            <programlisting role="example"><![CDATA[
+                L = list("abc", deff("r = @(x,y) x.*(x-y)"), %z);
+                L(2)(1.1:4, -2.1)
+                // Мы можем извлекать и устанавливать имя анонимной функции:
+                Abc = L(2)
+                Abc(1.1:4, -2.1)
+         ]]></programlisting>
+            <screen><![CDATA[
+--> L = list("abc", deff("r = @(x,y) x.*(x-y)"), %z);
+--> L(2)(1.1:4, -2.1)
+ ans  =
+   3.52   8.82   16.12
+
+--> Abc = L(2)
+ Abc  =
+[r]=Abc(x,y)
+
+--> Abc(1.1:4, -2.1)
+ ans  =
+   3.52   8.82   16.12
+]]></screen>
+            <para>
+                Наконец, давайте используем <literal>deff()</literal> для прямого
+                определения и передачи функции в качестве входного элемента другой
+                функции:
+            </para>
+            <programlisting role="example"><![CDATA[
+                function r = test(txt, x, theFunc)
+                    r = x + theFunc(txt)
+                endfunction
+
+                test(rand(2,3), 0.7, deff("r = @(M) sum(size(M).^2)"))
+         ]]></programlisting>
+            <screen><![CDATA[
+--> test(rand(2,3), 0.7, deff("r = @(M) sum(size(M).^2)"))
+ ans  =
+   13.7
+]]></screen>
+        <para>
+            В этом примере передаваемая функция является анонимной в вызывающем
+            окружении, но присваивается и получает своё имя "theFunct" внутри
+            вызываемой функции.
+        </para>
+        </refsect3>
     </refsection>
     <refsection role="see also">
         <title>Смотрите также</title>
@@ -118,12 +456,35 @@ a = 3;
                    <itemizedlist>
                      <listitem>
                        Входная опция
-                       <ulink url="https://help.scilab.org/docs/5.5.2/ru_RU/deff.html">
+                       <ulink url="https://help.scilab.org/docs/5.5.2/en_US/deff.html">
                          <varname>opt="c"|"p"|"n"</varname>
-                       </ulink> более не доступна.
+                       </ulink> больше не доступна.
+                     </listitem>
+                     <listitem>
+                        Определяемая <varname>newfunction</varname> теперь имеет
+                        тип 13 (вместо 11).
+                     </listitem>
+                  </itemizedlist>
+                </revdescription>
+            </revision>
+            <revision>
+                <revnumber>6.1.1</revnumber>
+                <revdescription>
+                   <itemizedlist>
+                     <listitem>
+                        Добавлен необязательный выходной аргумент. Могут определяться
+                        анонимные функции.
+                     </listitem>
+                     <listitem>
+                        Поддерживаются одиночные входные аргументы, конкатенирующие
+                        заголовочную строку функции и её тело.
+                     </listitem>
+                     <listitem>
+                        Поддерживается синтаксис одиночной строки, вроде
+                        <literal>deff "r = myFun(x,y) x.^2-y"</literal>
                      </listitem>
                      <listitem>
-                        Определённая новая функция <varname>newfunction</varname> теперь имеет тип 13 (вместо 11).
+                        Поддерживается псевдоимя функции "@".
                      </listitem>
                   </itemizedlist>
                 </revdescription>
index b4e0c6f..9d75208 100644 (file)
@@ -1,21 +1,60 @@
-function deff(varargin)
-    if size(varargin) <> 2  then
-        error(msprintf(_("%s: Wrong number of input arguments: %d expected.\n"), "deff", 2));
-    end
+// Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+// Copyright (C) INRIA
+// Copyright (C) 2012 - 2016 - Scilab Enterprises
+// Copyright (C) 2020 - Samuel GOUGEON
+//
+// This file is hereby licensed under the terms of the GNU GPL v2.0,
+// pursuant to article 5.3.4 of the CeCILL v.2.1.
+// This file was originally licensed under the terms of the CeCILL v2.1,
+// and continues to be available under such terms.
+// For more information, see the COPYING file which you should have received
+// along with this program.
 
-    //try to build execstr string
-    str = "function " + varargin(1);
-    str = [str ; varargin(2)(:); "endfunction"];
+function varargout = deff(varargin)
+    [lhs, rhs] = argn();
+    if rhs < 1 | rhs > 2  then
+        msg = _("%s: Wrong number of input arguments: %d or %d expected.\n")
+        error(msprintf(msg, "deff", 1, 2))
+    end
+    if rhs == 2 then    // Usual deff syntax
+        prototype = varargin(1)
+        text = matrix(varargin(2), -1, 1)
+    else
+        text = matrix(varargin(1), -1, 1)
+        if size(text,"*")==1
+            // We must split the input into the prototype and the definition
+            // The prototype is ended with the first ")":
+            [b, e, prototype] = regexp(text,"/.*?\)/", "o")
+            text = part(text,e+1:$)
+            // Case r = fun(x,y) x^2+y (single output, no r= in the definition:
+            if grep(prototype, "=") <> [] & grep(text,"=")==[]
+                outvar = strtok(prototype, "=")
+                if grep(outvar,",")==[]
+                    text = outvar + " = " + text
+                end
+            end
+        else
+            prototype = varargin(1)(1)
+            text = varargin(1)(2:$)
+        end
+    end
+    // Detect @ in the prototype and replace it, if any (can't be a function's name):
+    if grep(prototype, "@") <> [] // "/(?:[^(]*?)=\s*(.+?)(?:\s*\()/")
+        prototype = strsubst(prototype, "@", "%funcname");
+    end
 
+    // try to build execstr string
+    str = ["function " + prototype ; text ; "endfunction"];
     execstr(str);
-    funcs = funclist();
 
-    if size(funcs, "*") <= 0 then
-        return;
-    elseif size(funcs, "*") <> 1 then
-        return;
+    %deff_func = funclist();
+    if size(%deff_func, "*") <= 0 | size(%deff_func, "*") <> 1 then
+        return
     else
-        execstr(funcs + "= return(" + funcs + ")");
+        if argn(1) == 0
+            execstr(%deff_func + "= return(" + %deff_func + ")");
+        else
+            execstr("varargout = list(" + %deff_func + ");")
+        end
     end
-
 endfunction
diff --git a/scilab/modules/functions/tests/unit_tests/deff.dia.ref b/scilab/modules/functions/tests/unit_tests/deff.dia.ref
deleted file mode 100644 (file)
index b760f5d..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-// =============================================================================
-// Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
-// Copyright (C) 2009 - DIGITEO - Allan CORNET
-//
-//  This file is distributed under the same license as the Scilab package.
-// =============================================================================
-// <-- CLI SHELL MODE -->
-deff("[x] = myplus(y,z)","x=y+z");
-assert_checktrue(isdef("myplus"));
-assert_checkequal(myplus(3,2), 5);
-clear myplus;
-assert_checkfalse(isdef("myplus"));
-deff("[x] = mymacro(y,z)",["a=3*y+1"; "x=a*z+y"]);
-assert_checktrue(isdef("mymacro"));
-assert_checkequal(mymacro(5,2), 37);
-clear mymacro;
-assert_checkfalse(isdef("mymacro"));
-deff("[a,b,c] = mymacro(varargin)",["a = varargin(1); b = varargin(2) * a; c = varargin(3) * b"]);
-assert_checktrue(isdef("mymacro"));
-[a,b,c] = mymacro(3,4,5);
-assert_checkequal(a, 3);
-assert_checkequal(b, 12);
-assert_checkequal(c, 60);
-clear mymacro;
-assert_checkfalse(isdef("mymacro"));
-deff("[varargout] = mymacro(varargin)",["for i = 1 : size(varargin)"; "    varargout(i) = varargin(i) * 2;";"end"]);
-assert_checktrue(isdef("mymacro"));
-[a,b,c] = mymacro(3,4,5);
-assert_checkequal(a, 6);
-assert_checkequal(b, 8);
-assert_checkequal(c, 10);
-clear mymacro;
-assert_checkfalse(isdef("mymacro"));
-deff("[varargout] = mymacro(varargin)", ["deff(""varargout = mymacro2(varargin)"", [""for i = 1 : size(varargin)""; ""    varargout(i) = varargin(i) * 2;"";""end""]);";"[a,b,c] = mymacro2(varargin(:));";"varargout(1) = a*2;";"varargout(2) = b*2;";"varargout(3) = c*2;"]);
-assert_checktrue(isdef("mymacro"));
-assert_checkfalse(isdef("mymacro2"));
-[a,b,c] = mymacro(3,4,5);
-assert_checkequal(a, 12);
-assert_checkequal(b, 16);
-assert_checkequal(c, 20);
-assert_checkfalse(isdef("mymacro2"));
-clear mymacro;
-assert_checkfalse(isdef("mymacro"));
index b724c91..ef0002b 100644 (file)
@@ -1,11 +1,14 @@
 // =============================================================================
 // Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
 // Copyright (C) 2009 - DIGITEO - Allan CORNET
+// Copyright (C) 2020 - Samuel GOUGEON
 //
 //  This file is distributed under the same license as the Scilab package.
 // =============================================================================
 
 // <-- CLI SHELL MODE -->
+// <-- NO CHECK REF -->
+
 
 deff("[x] = myplus(y,z)","x=y+z");
 assert_checktrue(isdef("myplus"));
@@ -48,3 +51,53 @@ assert_checkfalse(isdef("mymacro2"));
 clear mymacro;
 assert_checkfalse(isdef("mymacro"));
 
+// Other syntaxes
+clear Fun
+deff(["r = Fun(x)" "r = x.^2 - 3"]);    // Only one deff argin, being a vector
+assert_checktrue(isdef("Fun","l"));
+assert_checkequal(Fun(4), 13);
+clear Fun
+deff "r = Fun(x) r = x.^2 - 3";         // Only one deff argin, being a scalar
+assert_checktrue(isdef("Fun","l"));
+assert_checkequal(Fun(4), 13);
+clear Fun
+deff("r = Fun(x) x.^2 - 3");    // Fun argout implicit assignment (missing in definition)
+assert_checktrue(isdef("Fun","l"));
+assert_checkequal(Fun(4), 13);
+
+// output = deff(..)
+// =================
+clear Fun myFun
+myFun = deff("res = Fun(a,b)",["res = a+b" "res = res.^2"]);
+assert_checkequal(myFun(1,1), 4);
+assert_checkfalse(isdef("Fun","l"));
+
+clear myFun
+e = execstr("myFun = deff(""res = Fun(a,b)"",[""res = a+"" ""res = res.^2""]);", "errcatch");
+assert_checktrue(e <> 0);             // syntax error ^^^
+assert_checkfalse(isdef("myFun","l"));
+assert_checkfalse(isdef("Fun","l"));
+
+in = list(["r = Fun(x)" "r = x.^2"], .. // Only one deff argin, being a vector
+           "r = Fun(x) r = x.^2", ..    // Only one deff scalar argin
+           "r = Fun(x) x.^2",..  // Fun argout implicit assignment (missing in definition):
+           "[a,b] = Fun(x) a=x.^2; b=x-3"); // Only one deff scalar argin. 2 outputs
+for argin = in
+    clear myFun
+    myFun = deff(argin);
+    assert_checktrue(isdef("myFun","l"));
+    assert_checkfalse(isdef("Fun","l"));
+    if grep(argin(1), "[a,b]") <> []
+        [u,v] = myFun(4);
+        assert_checkequal([u v], [16 1]);
+    else
+        assert_checkequal(myFun(4), 16);
+    end
+
+    // Anonymous "@"
+    clear myFun
+    argin = strsubst(argin, "Fun", "@")
+    myFun = deff(argin);
+    assert_checktrue(isdef("myFun","l"));
+    assert_checkequal(myFun(4), 16);
+end