GitHub - SenseLogic/GENERIS: Versatile Go code generator. (original) (raw)

Generis

Versatile Go code generator.

Description

Generis is a lightweight code preprocessor adding the following features to the Go language :

Sample

package main;

// -- IMPORTS

import ( "html" "io" "log" "net/http" "net/url" "strconv" );

// -- DEFINITIONS

#define DebugMode #as true

// ~~

#define HttpPort #as 8080

// ~~

#define WriteLine( {{text}} ) #as log.Println( {{text}} )

// ~~

#define local {{variable}} : {{type}}; #as var {{variable}} {{type}};

// ~~

#define DeclareStack( {{type}}, {{name}} ) #as // -- TYPES

type {{name}}Stack struct
{
    ElementArray []{{type}};
}

// -- INQUIRIES

func ( stack * {{name}}Stack ) IsEmpty(
    ) bool
{
    return len( stack.ElementArray ) == 0;
}

// -- OPERATIONS

func ( stack * {{name}}Stack ) Push(
    element {{type}}
    )
{
    stack.ElementArray = append( stack.ElementArray, element );
}

// ~~

func ( stack * {{name}}Stack ) Pop(
    ) {{type}}
{
    local
        element : {{type}};

    element = stack.ElementArray[ len( stack.ElementArray ) - 1 ];

    stack.ElementArray = stack.ElementArray[ : len( stack.ElementArray ) - 1 ];

    return element;
}

#end

// ~~

#define DeclareStack( {{type}} ) #as DeclareStack( {{type}}, {{type:PascalCase}} )

// -- TYPES

DeclareStack( string ) DeclareStack( int32 )

// -- FUNCTIONS

func HandleRootPage( response_writer http.ResponseWriter, request * http.Request ) { local boolean : bool; local natural : uint; local integer : int; local real : float64; local escaped_html_text, escaped_url_text, text : string; local integer_stack : Int32Stack;

boolean = true;
natural = 10;
integer = 20;
real = 30.0;
text = "text";
escaped_url_text = "&escaped text?";
escaped_html_text = "<escaped text/>";

integer_stack.Push( 10 );
integer_stack.Push( 20 );
integer_stack.Push( 30 );

#write response_writer
    <!DOCTYPE html>
    <html lang="en">
        <head>
            <meta charset="utf-8">
            <title><%= request.URL.Path %></title>
        </head>
        <body>
            <% if ( boolean ) { %>
                <%= "URL : " + request.URL.Path %>
                <br/>
                <%@ natural %>
                <%# integer %>
                <%& real %>
                <br/>
                <%~ text %>
                <%^ escaped_url_text %>
                <%= escaped_html_text %>
                <%= "<%% ignored %%>" %>
                <%% ignored %%>
            <% } %>
            <br/>
            Stack :
            <br/>
            <% for !integer_stack.IsEmpty() { %>
                <%# integer_stack.Pop() %>
            <% } %>
        </body>
    </html>
#end

}

// ~~

func main() { http.HandleFunc( "/", HandleRootPage );

#if DebugMode
    WriteLine( "Listening on http://localhost:HttpPort" );
#end

log.Fatal(
    http.ListenAndServe( ":HttpPort", nil )
    );

}

Syntax

#define directive

Constants and generic code can be defined with the following syntax :

#define old code #as new code

#define old code #as new code #end

#define old code #as new code

#define old code #as new code #end

#define parameter

The #define directive can contain one or several parameters :

{{variable name}} : hierarchical code (with properly matching brackets and parentheses) {{variable name#}} : statement code (hierarchical code without semicolon) {{variable name$}} : plain code {{variable name:boolean expression}} : conditional hierarchical code {{variable name#:boolean expression}} : conditional statement code {{variable name$:boolean expression}} : conditional plain code

They can have a boolean expression to require they match specific conditions :

HasText text HasPrefix prefix HasSuffix suffix HasIdentifier text false true !expression expression && expression expression || expression ( expression )

The #define directive must not start or end with a parameter.

#as parameter

The #as directive can use the value of the #define parameters :

{{variable name}} {{variable name:filter function}} {{variable name:filter function:filter function:...}}

Their value can be changed through one or several filter functions :

LowerCase UpperCase MinorCase MajorCase SnakeCase PascalCase CamelCase RemoveComments RemoveBlanks PackStrings PackIdentifiers ReplacePrefix old_prefix new_prefix ReplaceSuffix old_suffix new_suffix ReplaceText old_text new_text ReplaceIdentifier old_identifier new_identifier AddPrefix prefix AddSuffix suffix RemovePrefix prefix RemoveSuffix suffix RemoveText text RemoveIdentifier identifier

#if directive

Conditional code can be defined with the following syntax :

#if boolean expression #if boolean expression ... #else ... #end #else #if boolean expression ... #else ... #end #end

The boolean expression can use the following operators :

false true !expression expression && expression expression || expression ( expression )

#write directive

Templated HTML code can be sent to a stream writer using the following syntax :

#write writer expression <% code %> <%@ natural expression %> <%# integer expression %> <%& real expression %> <%~ text expression %> <%= escaped text expression %> <%! removed content %> <%% ignored tags %%> #end

Limitations

Installation

Install the DMD 2 compiler (using the MinGW setup option on Windows).

Build the executable with the following command line :

Command line

Options

--prefix # : set the command prefix
--parse INPUT_FOLDER/ : parse the definitions of the Generis files in the input folder
--process INPUT_FOLDER/ OUTPUT_FOLDER/ : reads the Generis files in the input folder and writes the processed files in the output folder
--trim : trim the HTML templates
--join : join the split statements
--create : create the output folders if needed
--watch : watch the Generis files for modifications
--pause 500 : time to wait before checking the Generis files again
--tabulation 4 : set the tabulation space count
--extension .go : generate files with this extension

Examples

generis --process GS/ GO/

Reads the Generis files in the GS/ folder and writes Go files in the GO/ folder.

generis --process GS/ GO/ --create

Reads the Generis files in the GS/ folder and writes Go files in the GO/ folder, creating the output folders if needed.

generis --process GS/ GO/ --create --watch

Reads the Generis files in the GS/ folder and writes Go files in the GO/ folder, creating the output folders if needed and watching the Generis files for modifications.

generis --process GS/ GO/ --trim --join --create --watch

Reads the Generis files in the GS/ folder and writes Go files in the GO/ folder, trimming the HTML templates, joining the split statements, creating the output folders if needed and watching the Generis files for modifications.

Version

2.0

Author

Eric Pelzer (ecstatic.coder@gmail.com).

License

This project is licensed under the GNU General Public License version 3.

See the LICENSE.md file for details.