• Expressions

    Expressions are the basis of Kipper, as every operation in a program is made up of single expressions that perform certain actions, like reading a value, calculating something, calling a function, comparing values…

    A simple example for expressions can be a simple calculation, like this:

    val1 + val2 * val3; // Mathematical/Arithmetic expression

    Notice how in this case we are not assigning the result to anything? This is an important fact of expressions that they are usually independent and do a single task, meaning if we wanted to assign this result to a variable, we would have to use an assignment expression like this:

    // Assign and arithmetic expression
    var result: num = val1 + val2 * val3;

    In this case, we also now created an expression statement (ends in ;), which wraps an expression and allows it to be used inside a program. Expression statements will be explained further in the docs page Statements.

    Kipper Operators and Expressions Precedence

    The following table shows all valid operators and expressions in the Kipper language, with their respective precedence. The higher the precedence the higher the importance of the item, and the order of evaluation.

    Precedence Operator / Expression Description Associativity
    14 ( ... ) Tangled expression - Forced increased precedence n/a
    13 ++ ... / -- ...
    call ... ( ... )
    ... [ ... ]
    ... . ...
    Prefix increment and decrement (Suffix)
    Function Call
    List subscripting
    Object member accessing
    Left-To-Right
    12 ... ++/ ... --
    Postfix increment and decrement
    n/a
    11 + ... / - ...
    ! ...
    Unary plus and minus
    Logical NOT
    Right-To-Left
    10 ... as ... Type conversion Left-To-Right
    9 ... * ...
    ... / ...
    ... % ...
    ... ** ...
    Multiplication
    Division
    Modulus
    Power-To
    8 ... + ... / ... - ... Addition and subtraction
    7 ... < ... / ... <= ...
    ... > ... / ... => ...
    More than / More or Equal to
    Less than / Less or Equal to
    6 ... == ... / ... != ... Relational comparison (Equal / Not equal to)
    5 ... && ...
    Logical AND
    4 ... || ... Logical OR
    3 ... ? ... : ...
    Ternary expression
    Right-To-Left
    2 ... = ...
    ... += ... / ... -= ...
    ... *= ...
    ... /= ...
    ... %= ...
    Simple assignment
    Increment or Decrement assignment
    Multiplicative assignment
    Divisional assignment
    Rest of Division / Remainder assignment
    1 ... , ... Comma Left-To-Right

    How does precedence of operators and expressions affect a program?

    The order of precedence is a very vital concept in programming languages, as they define how expressions are going to be evaluated. This directly can affect how your code runs, as certain parts might be evaluated first before others and change the entire course of your program.

    A simple example of this are arithmetic expressions + - * / %, which have per mathematical conventions their own order of precedence. For example, multiplication and division signs always come first before plus and minus, unless you explicitly use brackets, like these ( ). The same can be done here in Kipper as well, where you can forcefully increase the order of precedence using brackets:

    15 + 4 * 6; // -> (15 + (4 * 6)) -> (15 + 24) -> 39

    Forced higher precedence using brackets:

    (15 + 4) * 6; // -> ((15 + 4) * 6) -> (19 * 6) -> 114

    What does associativity mean?

    As you should have already seen in the table above, there is an extra column defining the so-called associativity. What does that mean? It's relatively simple and means whether the following (( ) meaning the expression is read first):

    a OPR b OPR c

    is evaluated as (left-associative - Reads from left to right):

    (a OPR b) OPR c

    or as (right-associative - reads from right to left):

    a OPR (b OPR c)

    This is especially important as it can change how certain things are evaluated, and also cause unwanted errors! For example the following would be interpreted as (left-associative):

    32 / 4 / 4; // -> ((32 / 4) / 4) -> (8 / 4) -> 2

    List of expressions in the Kipper language

    This is a concise list of all expressions in the Kipper language that may be used:

    Arithmetic Expression

    Arithmetic expressions are simple mathematical calculations, where a numeric result is returned after the expression was evaluated. They may also be chained based on their order of precedence, where each item is one by one evaluated.

    Syntax

    EXP ( + | - | * | / | ** | % ) EXP

    Examples

    // Plus
    400.3 + 26.3; // -> 426.6
    
    // Minus
    87 - 2.5; // -> 84.5
    
    // Multiply
    2.4 * 5; // -> 12
    
    // Divide
    25 / 4; // -> 6.25
    
    // Power to
    2 ** 8; // -> 256
    
    // Rest of Divide
    51 % 10; // -> 1

    Relational Expressions (Comparisons)

    Relational expressions are comparative expressions that compare two other expressions/values with a specific operator. They evaluate to true if the condition of the operator is true, for example < (less than) with 1 < 5, and evaluate to false if the condition is false, for example > (greater than) with 1 > 5.

    Such expressions are essential for conditional expressions that are used in statements such as:

    Syntax

    EXP ( == | != | > | >= | < | <= ) EXP

    Examples

    // Equal to
    20 == 20; // -> true
    92 == 20; // -> false
    
    // Not equal to
    21 != 9; // -> true
    21 != 21; // -> false
    
    // Is greater than
    20 > 5; // -> true
    20 > 20; // -> false
    
    // Is greater or equal to
    11 >= 5; // -> true
    20 >= 20; // -> true
    32 >= 99; // -> false
    
    // Is less than
    10 < 78; // -> true
    43 < 14; // -> false
    
    // Is less or equal to
    12 <= 29; // -> true
    56 <= 56; // -> true
    21 <= 13; // -> false

    Logical Expressions

    Logical expressions combine two or more expressions/conditions and evaluate to a bool value (Either true or false) based on the specific operator used.

    The NOT operator (!) is also a logical operator, even though unlike the other operators it can be only used on a single expression, and can be used to invert the result of a logical expression.

    Syntax

    For the logical AND and OR:

    EXP ( && | || ) EXP

    For the logical NOT:

    !VALUE;

    Examples

    // Logical AND - All must be true
    true && true; // -> true
    false && true; // -> false
    true && false; // -> false
    false && false; // -> false
    
    // Logical OR - One must be true
    true || true; // -> true
    false || true; // -> true
    true || false; // -> true
    false || false; // -> false
    
    // Logical NOT - Negate
    !false; // -> true
    !true; // -> false

    Logical Expressions may be also chained together as long as you want. For example:

    // Chained Logical AND - All must be true
    true && true && true; // -> true
    true && false && true; // -> false
    
    // Chained Logical OR - One must be true
    true || true || true; // -> true
    true || false || true; // -> true
    false || false || false; // -> false

    You can also combine relational expressions with logical expressions, like this for example:

    // ✓ Combined relational and logical expressions
    (3 == 4 && 3 != 4) || (2 != 22 && 3 == 3);
    
    // Following the order of precedence:
    // -> (false && true) || (true && true)
    // -> (false) || (true)
    // -> true

    Conditional Expressions (Ternary conditional)

    Conditional expressions are like if-statements with the major difference and advantage of being in-line and allowing evaluation of specific expressions based on a condition.

    If the CONDITION evaluates to true, the left side of the : operator is evaluated and returned, otherwise the right side is evaluated and returned.

    Syntax

    CONDITION ? EVALUATE_IF_TRUE : EVALUATE_IF_FALSE;

    Examples

    // ✓ Simple evaluation of a number
    true ? 3 : 2; // -> 3
    false ? 3 : 2; // -> 2
    
    // ✓ Simple evaluation of a number that will be assigned
    var var1: num = 2;
    var var2: num = 9;
    var smallestOrEqual: num = var1 < var2 ? var1 : var2; // -> 2

    As the ternary operator evaluates to more expressions, you can also chain it like this:

    // ✓ Valid - Chained if ... else-if ... else-if ... else ternary operator
    val result: num = condition1 ? value1
         : condition2 ? value2
         : condition3 ? value3
         : value4;
    
    // -> Equivalent to:
    if (condition1) { var result = value1; }
    else if (condition2) { var result = value2; }
    else if (condition3) { var result = value3; }
    else { var result = value4; }

    Convert Expression

    Conversion expressions convert the value of an expression to a target type using pre-defined built-in conversion functions. Such conversions are essential for using values of different types in the same expression and avoiding type errors.

    An important example of this are print function call expressions, as the print function is a built-in function that only allows a string as a parameter. Therefore, to print out a number you first have to convert it to a string.

    Syntax

    EXP as TYPE;

    Allowed conversions

    From str to num

    Converts a string to a number, if it meets the following requirements:

    • Only contains numeric characters (0 - 9)
    • Is not empty (length > 0)

    Otherwise if the string does not meet the above requirements, it will return NaN (Not a number). In future releases, though this will throw a ConversionError.

    "203" as num; // -> 203

    From num to str

    Converts a number to an identical string representation of the number.

    203 as str; // -> "203"

    From char to str

    Converts a single character to a string.

    "c" as str; // -> "c"

    From num to bool

    Converts a number to a bool. This evaluates to true if it's a non-zero value.

    20 as bool; // -> true
    0 as bool; // -> false

    From bool to num

    Converts a bool to a number. This evaluates to 1 if it's true, otherwise it's 0.

    true as num; // -> 1
    false as num; // -> 0

    From bool to str

    Converts a string to a number. This evaluates to "true" if it's true, otherwise it's "false".

    true as str; // -> "true"
    false as str; // -> "false"

    Function Call Expression

    Function call expression are expressions that call and run a specified function and evaluates to the return of the function. In case that the return is not assigned to any variable or used in another expression, then it will be simply discarded.

    If the return type of the function is void, then the function call expression will not return any value.

    Syntax

    call FUNC(ARGS...)

    Examples

    // ✓ Calling a defined function
    def func1() -> num { return 5; }
    call func1(); // -> 5
    
    // ✓ Calling a defined function and assigning it to a variable
    def func2() -> num { return 10; }
    var example1: num = call func2(); // -> 10
    
    // ✓ Multiple function calls with the end-result being assigned to a variable
    def func3() -> num { return 25; }
    var example2: num = call func2() + call func2(); // -> 50
    
    // ✓ Using the return of a function with a return type of void and assigning it to a variable
    def func4() -> void {}
    var example3: void = call func4(); // -> void
    
    // X Can not use the return of a void function with any other expression
    def func4() -> void {}
    4 + call func5(); // -> Error: Invalid arithmetic operation between types 'num' and 'void'.