Hi Alexey,
the fact that commands are not saved with a workspace is a bug and
I will fix it. Also )CLEAR or )LOAD should remove
existing user defined commands.
My point with the CONTINUE workspace was that this is exactly the
functionality
that you are proposing. It is executed before anything else if you
start APL. The only problem
is that the )CONTINUE command overrides the CONTINUE workspace.
But we could have
a workspace with a different name, like SETUP.apl that behaves
like CONTINUE but can not be
overridden by a command like )CONTINUE.
Running SETUP even if COUNTINUE is present would, in my opinion,
be wrong because the
expectation of )CONTINUE is that you continue at the same point,
which can not be guaranteed
because SETUP might do weird things that damage the CONTINUE
workspace.
So the logic would be:
- start apl,
if CONTINUE exists - load it,
otherwise if SETUP exists - load it.
I can take care of this because there are other aspects to consider,
see main.cc lines 417.
/// Jürgen
On 02/24/2017 08:24 PM, Alexey
Veretennikov wrote:
Hi,
The solution with )continue is not helping me: I want to have the my
commands available in all workspaces.
Right now if I )load workspace, all functions from previous workspace
got lost.
But user commands stays! meaning they will refer to unexisting
functions.
With the introduction of lambdas as user commands one could overcome
this limitation by encoding necessary functionality as lambdas.
In Dyalog APL I can create a file MyUCMDs/setup.dyalog with the
contents:
Setup←{_←⎕SE.UCMD'cd /Users/alexeyv/Sources/apl/dyalog-workspaces '}
and every time I start the interpreter my current directory is changed
to the specified.
I want to have something like this in GNU APL, so every time I run
interpreter I can:
- change the directory
- set my user commands
regardless of existence of CONTINUE workspace.
This could be solved by introducing the ~/.gnu-apl/setup.apl file with
APL source code, which if exists executes before any other workspaces.
How does it sound? If it is ok I'll implement it.
Juergen Sauermann <[email protected]> writes:
Hi Alexey,
I believe it would be more useful to have a facility that loads an arbitrary apl script at startup
instead of a specific one for user defined commands.
Actually you can do that already with the )CONTINUE workspace, which is loaded automatically
if it exists. You could replicate the )CONTINUE logic (or simply call your workspace CONTINUE.apl).
I would also suggest that we try to exploit existing functionalities before we invent new ones.
Most non-standard functions of GNU APL are fairly useless because nobody knows them.
/// Jürgen
On 02/23/2017 07:11 PM, Alexey Veretennikov wrote:
Hi,
Actually I'm thinking about a patch which will load these usercmds from
the config file at the startup. In this case every user will be
able to create own commands (like ]pwd and ]cd below) to interact with
interpreter and store them independent of the workspaces.
It will definitely helpful for me, what about others?
Christian Robert <[email protected]> writes:
It would be fun if those ]USERCMD could be saved in workspace and )loaded
back.
Not sure if it's possible ...
Xtian.
On 2017-02-23 12:04, Juergen Sauermann wrote:
Hi Alexey, Blake,
I have applied the patch, *SVN 892*.
I don't think that it hurts too much even though its not APL.
Nor are lambdas, so the ⍎ of )COMMANDs and {...} should fit nicely.
/// Jürgen
On 02/23/2017 08:47 AM, Alexey Veretennikov wrote:
Hi,
I'm updating the ]USERCMD functionality which is already non-standard
extension in GNU
APL. Similar extension exists in Dyalog APL for quite many years as
well. These commands targeted use in the interpreter and have nothing to do
with a new syntax.
What I did is just fixed its limitation where I always had to
create a named function to add a user command.
P.S. Example with ]pwd was bogus, the proper one is
]usercmd ]pwd {⎕FIO 30 ⍵}
User-defined command ]pwd installed.
]pwd
/Users/alexeyv
Blake McBride <[email protected]> writes:
Not sure I like this. Doesn't seem like APL. You are mangling
program-ability with system commands. APL
has no history of that. It may be an okay idea, but it's not APL.
Adding program-ability to system commands is essentially adding a whole new
syntax to APL.
Just one opinion.
Blake
On Wed, Feb 22, 2017 at 4:18 PM, Alexey Veretennikov
<[email protected]> wrote:
Hi,
The proposed patch allows usage of dfns as a ]USERCMD.
The mode (monadic or dyadic) is not needed since it is derived from the
lambda function itself.
Possibility to use lambdas as a user commands allows to have commands
without polluting the global namespace with the function names.
Usage example:
]usercmd ]pwd {⎕FIO 30 ⍵ ← ⍺}
User-defined command ]pwd installed.
]pwd
/Users/alexeyv/Sources/apl-svn/src
]usercmd ]cd {⎕FIO[54] (⎕IO+1) ⊃ ⍵ ← ⍺}
User-defined command ]cd installed.
]cd /Users/alexeyv
0
]pwd
/Users/alexeyv
--
Br,
/Alexey
Index: src/Command.cc
===================================================================
--- src/Command.cc (revision 891)
+++ src/Command.cc (working copy)
@@ -1277,6 +1277,7 @@
// ]USERCMD REMOVE ]existing-command
// ]USERCMD ]new-command APL-fun
// ]USERCMD ]new-command APL-fun mode
+ // ]USERCMD ]new-command LAMBDA-fun
//
if (args.size() == 0)
{
@@ -1321,14 +1322,54 @@
return;
}
- if (args.size() > 3)
+ // check if the user command is not followed by the string
+ if (args.size() == 1)
+ {
+ out << "BAD COMMAND+" << endl;
+ MORE_ERROR() << "user command syntax in ]USERCMD: ]new-command APL-fun [mode]";
+ return;
+ }
+ UCS_string command_name = args[0];
+ UCS_string apl_fun = args[1];
+ int mode = 0;
+
+ // check if lambda
+ bool is_lambda = false;
+ if (apl_fun[0] == '{')
{
+ // looks like the user command is a lambda function.
+ UCS_string result;
+ // lambdas could contain spaces, collect all arguments in one string
+ for (int i = 1; i < args.size(); ++ i)
+ {
+ result << args[i];
+ }
+ // check if lamda-function closed properly
+ if (result.last() == '}')
+ {
+ is_lambda = true;
+ apl_fun = result;
+ // determine the mode: if both alpha and omega present, assume dyadic,
+ // otherwise - monadic usage
+ mode = (apl_fun.contains(UNI_OMEGA) && apl_fun.contains(UNI_ALPHA)) ? 1 : 0;
+ }
+ else
+ {
+ out << "BAD COMMAND+" << endl;
+ MORE_ERROR() << "not found closing } in lambda function";
+ return;
+ }
+ }
+
+ if (args.size() > 3 && !is_lambda)
+ {
out << "BAD COMMAND+" << endl;
MORE_ERROR() << "too many parameters in command ]USERCMD";
return;
}
-const int mode = (args.size() == 3) ? args[2].atoi() : 0;
+ // check mode
+ if (!is_lambda && args.size() == 3) mode = args[2].atoi();
if (mode < 0 || mode > 1)
{
out << "BAD COMMAND+" << endl;
@@ -1339,11 +1380,11 @@
// check command name
//
- loop(c, args[0].size())
+ loop(c, command_name.size())
{
bool error = false;
- if (c == 0) error = error || args[0][c] != ']';
- else error = error || !Avec::is_symbol_char(args[0][c]);
+ if (c == 0) error = error || command_name[c] != ']';
+ else error = error || !Avec::is_symbol_char(command_name[c]);
if (error)
{
out << "BAD COMMAND+" << endl;
@@ -1355,28 +1396,31 @@
// check conflicts with existing commands
//
#define cmd_def(cmd_str, _cod, _arg, _hint) \
- if (check_name_conflict(out, cmd_str, args[0])) return;
+ if (check_name_conflict(out, cmd_str, command_name)) return;
#include "Command.def"
- if (check_redefinition(out, args[0], args[1], mode))
+ if (check_redefinition(out, command_name, apl_fun, mode))
{
out << " User-defined command "
- << args[0] << " installed." << endl;
+ << command_name << " installed." << endl;
return;
}
// check APL function name
- //
- loop(c, args[1].size())
+ // Only needed when not a lambda function
+ if (!is_lambda)
{
- if (!Avec::is_symbol_char(args[1][c]))
- {
- out << "BAD COMMAND+" << endl;
- MORE_ERROR() << "bad APL function name in command ]USERCMD";
- return;
- }
+ loop(c, apl_fun.size())
+ {
+ if (!Avec::is_symbol_char(apl_fun[c]))
+ {
+ out << "BAD COMMAND+" << endl;
+ MORE_ERROR() << "bad APL function name in command ]USERCMD";
+ return;
+ }
+ }
}
-user_command new_user_command = { args[0], args[1], mode };
+user_command new_user_command = { command_name, apl_fun, mode };
user_commands.append(new_user_command);
out << " User-defined command "
|