Brief Integration Update and Modules
UCLA brief update of where I am with UCL and integrating it into Dynamo-browse. I did managed to get it integrated, and it's now serving as the interpreter of commands entered in during a session.
It works⦠okay. I decided to avoid all the complexities I mentioned in
the last post β all that about continuations, etc. β and simply kept the
commands returning tea.Msg
values. The original idea was to have the
commands return usable values if they were invoked in a non-interactive
manner. For example, the table
command invoked in an interactive
session will bring up the table picker for the user to select the table.
But when invoked as part of a call to another command, maybe it would
return the current table name as a string, or something.
But I decided to ignore all that and simply kept the commands as they are. Maybe I'll add support for this in a few commands down the line? We'll see. I guess it depends on whether it's necessary.
Which brings me up to why this is only working "okay" at the moment.
Some commands return a tea.Msg
which ask for some input from the user.
The table
command is one; another is set-attr
, which prompts the
user to enter an attribute value. These are implemented as a message
which commands the UI to go into an "input mode", and will invoke a
callback on the message when the input is entered.
This is not an issue for single commands, but it becomes one when you
start entering multiple commands that prompt for input, such as two
set-attr
calls:
set-attr this -S ; set-attr that -S
What happens is that two messages to show the prompt are sent, but only one of them is shown to the user, while the other is simply swallowed.
Fixing this would require some re-engineering, either with how the controllers returning these messages work, or the command handlers themselves. I can probably live with this limitation for now β other than this, the UCL integration is working well β but I may need to revisit this down the line.
Modules
As for UCL itself, I've started working on the builtins. I'm planning to have a small set of core builtins for the most common stuff, and the rest implemented in the form of "modules". The idea is that the core will most likely be available all the time, but the modules can be turned on and off by the language embedder based on what they need or are comfortable having.
Each module is namespaces with a prefix, such as os
for operating
system operations, or fs
for file-system operations. I've chosen the
colon as the namespace separator, mainly so I can reserve the dot for
field dereferencing, but also because I think TCL uses the colon as a
namespace separator as well (I think I saw it in some sample code). The
first implementation of this was simply adding the colon to the list of
characters that make up the IDENT token. This broke the parser as the
colon is also use as the map key/value separator, and the parser
couldn't resolve maps anymore. I had to extend the "indent" parse rule
to support multiple IDENT tokens separated by colons. The module
builtins are simply added to the environment with there fully-qualified
name, complete prefix and colon, and invoking them with one of these
idents will just "flatten" all these colon-separated tokens into a
single string. Not sophisticated, but it'll work for now.
There aren't many builtins for these modules at the moment: just a few for reading environment variables and getting files as list of strings. Dynamo-browse is already using this in a feature branch, and it's allows me to finally add a long-standing feature I've been meaning to add for a while: automatically enabling read-only mode when accessing DynamoDB tables in production. With modules, this construct looks a little like the following:
if (eq (os:env "ENV") "prod") { set-opt ro }
It would've been possible to do this with the scripting language already used by Dynamo-browse. But this is the motivation of integrating UCL: it makes these sorts of constructs much easier to do, almost as one would do writing a shell-script over something in C.