Skip to content

Flow System

Josh Weinstein edited this page Jun 22, 2018 · 2 revisions

Wind Flow System

The following page contains detailed information about the internal buffer system of the language.

Intro

Wind uses a multi-node buffer system internally to continuously process and and move data from one location to another. One of the defining principles of flow based programming is that data moves from one node or buffer to another. In Wind, that movement is usually combined with transformations.

Load Buffer

The very first buffer in Wind is the load buffer. When incoming source code is received by WindRun.h functions, the C-string of the source code is run through a series of nested switch statements to parse the commands and arguments in the string.

When a value is parsed, it is then loaded onto the load buffer, and prepended with a marked byte indicating it's type. Some values, such as WindType_Plus, do not have variable portions of their binary representation. They are simply a pure byte indicating a type.

Other types, like WindType_Bool, or WindType_Number, have bodies of data that represent their specifc value after the type byte. For example,

static unsigned char WIND_NUM[sizeof(double) + sizeof(unsigned char)] = {WindType_Number};

void WindLoad_number(const char** code)
{
        char** movedStr = &NUM_RESULT_INIT;
        *(double*)(WIND_NUM + sizeof(unsigned char)) = strtod(*code, movedStr);
        WindData_load_write(WIND_NUM, sizeof(WIND_NUM));
        // Sets the code to new location after number ends.
        *code = *movedStr;
}

is the relevant code that parses a number value, loads it into a typed sub-buffer, then copies that sub-buffer to the load buffer. The advantage of this is the type buffer never has to be written each time a new number is loaded.

Load Write

One main guarantee of the Wind language is that it does not use heap allocated or dynamic memory allocation. This makes it extremely versatile and suitable for embedded systems. To accomplish, the load buffer, along with the active, and inactive buffers exist as static arrays. The interface for communicating with them is defined in WindData.h

For the load buffer, the main function used to write to it is:

void WindData_load_write(void* data, size_t length)
{
        if(length > WindData_LOAD_END - WindData_LOAD_PTR)
        {
                fprintf(stderr, "%s\n", "Memory Error: Ran out of load buffer memory, exiting.");
                exit(1);
        }
        else
        {
                memcpy(WindData_LOAD_PTR, data, length);
                WindData_LOAD_PTR += length;
        }
}

Since Wind is using statically sized memory, the size of the load buffer or the other one's is determined via a Makefile flag. This allows the load buffer, upon compile time, to scale to any desired size. The adjustable memory component of Wind is another factor that makes it highly suitable for embedded systems.

Transition from Load

After values are loaded onto the load buffer, Wind enters the execution mode. This mode prompts the parsed command and arguments for execution. Depending on the command, data on the load buffer is moved to different destinations.

A common command is push, which appends all the data on the load buffer onto the active buffer. To do this, the write function of the active buffer, WindData_active_write() is called. However, commands are first dispatched to execution functions.

Here is the execution function for the push command.

int WindExec_push(void)
{
        size_t pushLen = WindData_load_len();
        WindData_active_write(WindData_load_start(), pushLen);
        return 1;
}

Once Data is on the active buffer, it can be flowed and transformed toward the inactive buffer, then rotated. This will be explained in a different page.

Clone this wiki locally