Metadata-Version: 2.1
Name: macal
Version: 5.5.0a5
Summary: Macal DSL is used for collecting and transforming data from various sources.
Author-email: Marco Caspers <SamaDevTeam@westcon.com>
Project-URL: Homepage, https://github.com/Sama-Developer/macal
Classifier: Development Status :: 3 - Alpha
Classifier: Programming Language :: Python :: 3.9
Classifier: Intended Audience :: Developers
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE.txt
Requires-Dist: unidecode
Requires-Dist: keyring
Requires-Dist: keyrings.alt
Requires-Dist: meraki
Requires-Dist: pydantic
Requires-Dist: python-jose[cryptography]

# Macal DSL 5.5 Alpha 5

## Introduction

This is version 5.5 of the Macal DSL language
This is an interim version.

I have removed the bytecode compiler and runtime.
Version 5.5 is to fix several problems in regards to scope and the way functions were implemented.
Version 6.0 will use llvmlite and jit compilation.

Known issues:
1).  If you include a file for which there are multiple files in the file search path that have the same file name, 
     there is no way of telling which one gets included.
     A safeguard is in place to prevent importing a file from itself, but i can't exclude multiple files with
     the same name on the search path other than the user controlling the search path.

2). The utilities mi and mr have been replaced with mrepl and mrun respectively.
    Utilities mc and md have been removed.

## Installation

```bash
python3 -m pip install macal==5.5.0.alpha.5
```

## Usage

Macal can be used in 3 main ways:

1). Use it on the commandline with 'mrepl' to run interactively.

2). Use it on the commandline with 'mrun' to run a file. (type mrun -h to get help).

3). Include the class in your product and work from there.
    An example will be provided in a later chapter.

4). After installing the mide package you can use the mide utility which is a very simple cli/text based editor/ide.


## Instruction set "EBNF"


letter = "a".."z" | "A".."Z"

digit = "0".."9"

ident = letter | "_" | digit

stmt = return_stmt | continue_stmt | break_stmt | halt_stmt | if_stmt | while_stmt | foreach_stmt | switch_stmt |
       include_stmt | select_stmt | functiondefinition_stmt | external_stmt | vardeclaration_stmt | functioncall_stmt | builtin_functions

builtin_functions = print_stmt | is_type_stmt | type_stmt
is_type_stmt = isrecord_stmt | isarray_stmt | isstring_stmt | isint_stmt | isfloat_stmt | isbool_stmt | isnil_stmt |
               isfunction_stmt | isobject_stmt

return_stmt = "return" [ expr ] ";"

continue_stmt = "continue" ";"

break_stmt = "break" ";"

halt_stmt = "halt" [ expr ] ";"

if_stmt = "if" expr "{" stmt... "}" [ "elif" expr "{" stmt... "}" ... ] [ "else" "{" stmt... "}" ]

while_stmt = "while" expr "{" stmt... "}"

foreach_stmt = "foreach" expr "{" stmt... "}"

switch_stmt = "switch" expr "{" case_stmt... [ default_stmt ] "}"

case_stmt = "case" expr ":" "{" stmt... "}"

default_stmt = "default" ":" "{" stmt... "}"

include_stmt = "include" lib_name [ "," lib_name... ] ";"

select_stmt = "select" [ "distinct" ] field_list "from" expr [ "where" expr ] [ "merge" ] "into" expr ";"

lib_name = ident

field_list = field ([ "," field ])*

field = field_name [ "as" alias ]

field_name = ident

functioncall_stmt = ident "(" expr ["," expr]... ")" ";"

functiondefinition_stmt = ident "=>" "(" [ ident [ "," ident ]... ] ")" "{" stmt... "}"

external_stmt = ident "=>" "(" [ ident [ "," ident ]... ] ")" "external" python_module "," external_function_name

python_module = string_literal

external_function_name = string_literal

vardeclaration_stmt = ident "=" ([ident "="])* expr ";"

isrecord_stmt = isRecord( expr ) ";"

isarray_stmt = isArray( expr ) ";"

isstring_stmt = isString( expr ) ";"

isint_stmt = isInt( expr ) ";"

isfloat_stmt = isFloat( expr ) ";"

isbool_stmt = isBool( expr ) ";"

isnil_stmt = isNil( expr ) ";"

isfunction_stmt = isFunction( expr ) ";"

isobject_stmt = isObject( expr ) ";" ;

type_stmt = "type" "(" expr ")" ";"

print_stmt = "print" "(" expr ([, expr])* ")" ";"

array_variable = ident "[" expression "]"

record_variable = ident ({ "." ident | "[" string_literal "]" })*

string_literal = '"' literal '"'

expr = assignment_expr

assignment_expr = string_concatenation ( "=" | "+=" | "-=" | "*=" | "/=" | "%=" | "^=" | ".=" ) assignment_expr

string_concatenation = object_expr ( "+." ) object_expr

object_expr = object "{" ident ":" expr ([ "," ident ":" expr ])* "}" | array_expr

array_expr = "[" expr (["," expr])* "]"

record_expr = "{" expr (["," expr])* "}"

logical_expr = comparison_expr ("and", "or", "xor", "&&", "||") comparison_expr

comparison_expr = addition_expr ({"<", "<=", ">", ">=", "==", "!="}) addition_expr

addition_expr = multiplication_expr ("+", "-") multiplication_expr

multiplication_expr = power_expr ("*", "/", "%") power_expr

power_expr = unary_expr ("^") unary_expr

unary_expr = ("-", "++", "--") unary_expr | call_member_expr

call_member_expr = member_expr | "(" call_expr

call_expr = args "(" call_expr(callee)

args = "(" arg_list ")"

arg_list = expr (",") expr

member_expr = primary_expr ("." primary_expr | "[" "]" new array_element | "[" expr "]") 

new_array_element = "=" expr

primary_expr = ident | int_number | float_number | string_literal | "(" expr ")" | array_literal | record_literal |
               type_stmt | is_type_stmt


## Statements

a = 1;          // integer type is inferred from the assignment
f = 1.0;        // a float
b = true;       // boolean
s = "this is a string"; // string
s2 = 'this is also a string';
s3 = $"this is a string with {a} {b} {s} interpolation.";

arr = ["item1", "item2", "item3"];  // create a variable arr that has an array with 3 elements.
rec = {"key1": "value1", "key2": 2, "key3": nil}; // create a variable rec with 3 key/value pairs.
// alternative method to define the same array and record in a different way.
arr = array;
arr[] = "item1";
arr[] = "item2";
arr[] = "item3";
rec = record;
rec["key1"] = "value1";
rec["key2"] = 2;
rec["key3"] = nil;

// getting the value from an array:
print(arr[0]);
print(arr[2]);

// getting the values from a record, method 1:
print(rec["key1"]);
print(rec["key2"]);
// Alternative way for getting the values from a record:
print(rec.key1);
print(rec.key2);


print(a);
print(s3);
print(a, f, b);

if <condition> {

} elif <condition> {

} else {

}

while <condition> {
    // can use continue to continue the loop.
    // can use break to break out of the loop.
}

foreach <iterable> {
    print(it); // The it variable contains the current value of the iterator that is iterating over the iterable.
    // can use continue to continue the loop.
    // can use break to break out of the loop.
}

func_name => (a, b) { // function definition
    print(a);
    print(b);
    return a + b;
}

// Defines a function that links to an external function that lives in a python module
// called <module_name>.py with the name <ext_unc_name>
func_name_2 => (a, b) external "<module_name>", "<ext_func_name>";


switch <expr> {
    case <expr> : {
        break;
    }
    case <expr>: {

    }
    case <expr>: {

    }
    default : {

    }
}

q = [{}];
select distinct a as b from x() where c == 42 and d == "hot" merge into q;

halt 1; // terminates execution.
