Nov.04.2015 -- CAlive to introduce casks

35 views
Skip to first unread message

Rick C. Hodgin

unread,
Nov 4, 2015, 12:04:21 PM11/4/15
to caliveprogra...@googlegroups.com
CAlive introduces the concept of the cask.

Note:  Casks were given their name because with use of their pipe signs, they look like a cask turned over on its side:
    https://pbs.twimg.com/profile_images/613435389513216000/yAzTSy1o.jpg

-----
Their purposes and usesin source code are varied based on their type.  There are currently five types defined:

    ~| utility |~       -- Injects arbitrary code
    <| logic |>         -- Responds to logic conditions
    (| reference |)     -- Reference things which exist
    [| definition |]    -- Defines things, or alters the definition of existing things
    \| code |/          -- Used or Side Coding

    /| auto |\          -- Automatically inserted by the compiler for meta data (implied casts, etc., visible only by viewing /|auto|\ casks)
    \| viz |\           -- Visualization start marker inserted by a GUI editor when a visual layer is applied atop raw source code
    /| viz |/           -- Visualization stop marker inserted by a GUI editor when a visual layer is applied atop raw source code

Note:  Each of these will be described in follow-up posts.

Casks are comprised of three basic parts, a left-slot, middle-slot, and right-slot:

    (|| left-slot | middle-slot | right-slot ||)

    (|| left-slot |
middle-slot | right-slot ||)
    (||
left-slot | middle-slot | right-slot ||)
    (||
left-slot | middle-slot | right-slot ||)

Based on their type and usage, those slots will be filled with various content.

-----
Casks can be followed-up with a .name() tag to give them a display name:

    (|reference|).name(abc)

This would then be reduced down in the GUI editor to its shortened form, hiding all of the details of whatever appears in the cask:

    (| abc |)

-----
Typically the middle-slot is used for the name for display purposes, but when there is data in a left-slot or right-slot, that information is collapsed.  To address this the concept of a pip is added:

    (|| return | name | params ||)

Reduced down to:

    (|o| name |o|)


When the content is lowered, it's a lower-case o pip.  When the content is raised, it's an upper-case O pip.

In this example, the two lower-case o pips indicates there is data in the left-slot and right-slot.  This allows those pips to be clicked on with an overlay window in the GUI editor popping up with their contents, changing the o to an O on the side which is clicked:

Going up:

     +--------+
     | return |
     |+-------+
     ||
    (|O|name|o|)

Or down:

    (|o|name|O|)
             ||
             |+-------+
             | params |
             +--------+


Or both:

      +--------+
      | return |
      |+-------+
      ||
     (|O|name|O|)
              ||
              |+-------+
              | params |
              +--------+


-----
Casks are fully encapsulated quantities (they contain a mated left- and right-side) so they can be injected anywhere in a statement or expression.  This does not alter the syntax of the expression, but provides the ability to insert code at any location which is then collapsed down to a graphical form in the GUI editor.

To illustrate their ability to be inserted into an otherwise syntatically correct statement, consider the snippet:

    if (x == 5) {
        // Do something
    } else {
        // Do something else
    }


Because <| logic |> casks exist, they can respond to the resulting logic condition of the (x == 5) test.  Two explicit <| logic |> cask types are defined for that purpose:

    <| meta |>      -- Responds when true
    <| mefa |>      -- Responds when false


These can then be inserted like this which would call the functions iftrue() and iffalse():

Note:  This is done in addition to going into the if { } else { } block.

    if (x == 5  <| meta | iftrue ||>  <| mefa | iffalse ||>) {
        // Do something
    } else {
        // Do something else
    }


And to use a custom condition test (in the form of ((cond) ? iftrue : iffalse), use the left-slot for the condition, and then the middle-slot and right-slot for true and false targets, respectively:

    <|| cond | iftrue | iffalse ||>

Best regards,
Rick C. Hodgin

Rick C. Hodgin

unread,
Nov 4, 2015, 12:07:15 PM11/4/15
to caliveprogra...@googlegroups.com
Here's a reply I posted to someone in this thread:
    https://groups.google.com/d/msg/comp.lang.c/LeL4CPfktfg/H0IUuADCBQAJ

I've left it un-edited as is, though some of the syntax is slightly off:

Casks are fully expanded forms in source code.  They can have return
values, function names, and parameters when in the form of a
(|reference|) cask, or a ~|utility|~ cask:

    (||return|function_name|
param1, param2, param3, ...||)
    ~||return|function_name|param1, param2, param3, ...||~

(|reference|) casks are used to call other things (functions, adhocs,
member functions), whereas ~|utility|~ casks can do that, but they
are designed more for injecting whatever code where you want it to
be:

    ~|x = 5; printf("%d\n", my_function(x));|~

And then to simplify them in the GUI editor, there are additional
parts which can be added:

    (||return|function_name|
param1, param2, param3, ...||).name(update_total)
    ~|x = 5; printf("%d\n", my_function(x));|~.name(debug_
print)

So that in the GUI editor they will appear in their short forms:

    (o|update_total|o)
    ~|debug_print|~

Since casks are enclosed expressions, they can be inserted anywhere in
code.  If they are inserted before a parameter is used, they will be
called before that parameter is put on the stack.  If they're inserted
after, then they'll be called after it's on the stack.  If they're
inserted before a logic test, then they'll be called before the test
is made.  If they're inserted after a logic test, then they'll be called
after the logic test is made (if the logic then reached that far, for
example).

And so on...

-----
There are two more types of casks:

    [|definition|]
    <|logic|>

[|definition|] casks alter the way things are defined.  You can put
in overrides, or augments to their definition.  An example people
might be aware of would be:

    char p [|const|];
    // same as "const char p;"

Why would someone do this?  Casks show up graphically in the editor,
and it may be more eye catching to see something which looks like this
in the GUI editor:

    [char p];

Where the coloring of the "char p" portion is highlighted so that it
conveys the const nature without the keyword const.  That's just an
example, by the way, but one I will probably include, along with other
similar ones.

-----
<|logic|> casks respond to true or false conditions set by flow control
operators, or they can inject their own as the left-most place in the
cask, then acting like a ((cond) ? iftrue : iffalse) expression:

    <||cond|iftrue|iffalse||>

There are specific types, however, which are called META and MEFA, for
true and false, respectively:

    <|meta|iftrue||>
    <|mefa|iffalse||>

In these cases, these casks can be added to expressions and then will
signal the code based on the logic condition result:

    if (x == 5 <|meta|iftrue||> <|meta|iffalse||>)
    {
        // Normal code here
    }

In this example, the equivalent code would be:

    llTest = (x == 5);
    if (!llTest)
    {
        iffalse();

    } else {
        iftrue();
        // Normal code here
    }

And they can be inserted anywhere there are logic tests.

There are two other types of logic cask which follows the meta/mefa form
that I haven't introduced yet.  They relate to new features of CAlive:

    <|meia|>   // Inquiry signal handler casks
    <|mema|>   // Message handler casks

If you think a line might throw an exception, which is called an inquiry
in CAlive, then you can attach a <|meia|> logic cask to it, and when
the inquiry happens, it will trigger that code:

    some_function()  <|meia|inquiry_handler||>;

Now, if something in some_function() or lower triggers an inquiry, it
will come back to this point and call the inquiry_handler() function.

And if there are specific types, then it can be moved to the left-most
slot for the testing:

    some_function()  <||_OUT_OF_MEMORY|meia|
inquiry_handler_memory||>
                     <||_FLOATING_POINT|meia|
inquiry_handler_fp||>
                     <|meia|inquiry_handler_
default||>;

In this case, those two types of inquirys are handled explicitly, with
all others falling through to the default handler.  If the default
handler wasn't specified, then other inquirys would not be handld here.

And <|meia|> casks can be inserted anywhere.  I also introduce a special
flow control block which is similar to try..catch which handles inquiries.

-----
<|mema|> are message hander casks.  It is a new CAlive feature to allow
not only a return value to be returned, but also a message.  Messages
are available specifically to trigger <|mema|> casks, and are ignored
otherwise.  Messages can return any combination of an integer, pointer
to text, or a pointer to any other thing, as int num, char* msg, and
void* p members.

    void handler_message(char* p, int i)
    {
        printf("%s on %d\n", p, i);
    }

    some_function()  <|mema|handler_message(mema.
msg, mema.num)||>;

    void some_function(void)
    {
        if (date_is_monday_thru_friday)
            return message "Hi, mom!", day_of_week_number;
    }

In this case, the message would be returned if the logic test passed,
and it would trigger the handler_message() function only in that case.
By embedding a ~|utility|~ cask within the <|mema|> cask, it then also
becomes possible to handle direct branching based on the returned
message, though this is typically handled through the flow { } blocks,
which I have not yet introduced, though I did introduce them many
months ago.

Rick C. Hodgin

unread,
Nov 6, 2015, 7:40:02 AM11/6/15
to caliveprogra...@googlegroups.com
Nov.05.2015 -- I've added a new type of non-user cask called the /| auto |\.  It is for things which are auto-inserted by the compiler.  The /| auto |\ will actually be a white cask and is used for things like implied castings, auto-translations, etc., and will be visible when the GUI editor has the "enable auto" feature turned on.

Rick C. Hodgin

unread,
Sep 8, 2017, 3:20:05 PM9/8/17
to CAlive Programming Language
Sep.08.2017 -- CAlive will introduce two standard logic casks that allow a natural flow progression based on a standard fail or okay result, based on the natural response of a function / assignment value.   CAlive will introduce tow additional logic casks that allows assignment to a logical variable based on the standard fail or okay result, or its logical inverse.

    flow
    {
        <|?failout|>  handle = openResource(...);
        <|?okayout|>  closeHandle(handle);
        writeError("Unable to close handle");
    }

The above code using logic casks would result in this flow:

    do
    {
        handle = openResource(...);
        if (!handle)
            break;

        if (closeHandle())
            break;

        writeError("Unable to close handle");

    } while (0);

To assign the value, this syntax is used with a variable name:

    bool llSuccess, llFail;

    <|?llSuccess|>  handle = openResource(...);
    <|!?llFail|>    handle = openResource(...);

In this case, the result of the standard test for the assigned value stores true if (handle), and false otherwise in the case of the <|?varName|> syntax.  In the case of the inverse form <|!?varName|> it stores the opposite result.

Thank you,
Rick C. Hodgin

Reply all
Reply to author
Forward
0 new messages