Backus-Naur form

<program> ::= <comment_block>* <import_block>? <variable_declaration>* <function_block>*

<comment_block> ::= "%%" <comment_content> "%%"
<comment_content> ::= (%any_character% | "\n")*

<import_block> ::= "import" <string_literal>

<function_block> ::= <function_signature> "=" (<identifier> (" " <identifier>)*)? <block>
<function_signature> ::= <identifier> ":" <type>* "->" <type>

<type_definition> ::= <identifier> "::" <type>
<type> ::= "int" | "double" | "float" | "char" | "byte" | "never" | "bool" | "*"<type> | "struct" "{" <struct_field>* "}" | <type>* "->" <type> | <user_defined_type>

<struct_field> ::= <identifier> "->" <type>
<user_defined_type> ::= <identifier>

<statement> ::= <variable_declaration> | <loop> | <for_loop> | <if_statement> | <function_call> | <expression> | <return_statement>

<variable_declaration> ::= <identifier> ":" <type> "=" <expression>
<expression> ::= <literal>
               | <binary_expression>
               | <unary_expression>
               | <function_call>
               | <type_conversion>
               | <array_access>
               | <struct_access>
               | <assignment>

<literal> ::= <int_literal> | <float_literal> | <array_literal> | <byte_literal> | <bool_literal> | <struct_literal>
<int_literal> ::= [0-9]+
<float_literal> ::= [0-9]+ "," [0-9]+
<byte_literal> ::= "'%any_printable_character%'"
<bool_literal> ::= "true" | "false"
<array_literal> ::= <string_literal> | <literal_array_literal>
<string_literal> ::= '"' <string_characters> '"'
<struct_literal> :: = <identifier> "{" <field_list> "}"
<field_list> ::= <field> (" " <field>)*
<field> ::= <identifier> "=" <literal>
<string_characters> ::= (%any_printable_character% - '"')*
<literal_array_literal> ::= "[" <expression> (" " <expression>)* "]"


<binary_expression> ::= <expression> <binary_operator> <expression>
<binary_operator> ::= "*" | "/" | "mod"
                    | "+" | "-"
                    | "&" | "|" | "^" | "<<" | ">>"
                    | "==" | "is" | "!=" | "<=" | ">=" | "<" | ">"
                    | "and" | "or"

<unary_expression> ::= <prefix_operator> <expression> | <expression> <postfix_operator>
<prefix_operator> ::= "!" | "not" | "~" | "++" | "--"
<postfix_operator> ::= "++" | "--" | ".*" | ".&"

<type_conversion> ::= "@<type>" "(" <expression> ")"

<array_access> ::= <identifier> ".#" "(" <expression> ")"
<struct_access> ::= <identifier> "." <identifier>

<assignment> ::= <identifier> "=" <expression>

<loop> ::= "loop" "(" <expression> ")" <block>
<for_loop> ::= "from" <expression> "to" <expression> "by" <expression> "|" <identifier> ":" <type> "|" <block>
<if_statement> ::= "if" <expression> <block> <else_clause>?
<else_clause> ::= "else" <block>
<block> ::= "{" <statement>* "}"

<function_call> ::= <identifier> "(" (<expression> (" " <expression>)*)? ")"
<return_statement> ::= "ret" <expression> | <expression>

<identifier> ::= [a-zA-Z_$][a-zA-Z0-9_$]*

Details on the BNF

Program Structure

A Frost program consists of the following components:

  • <comment_block>: Comments enclosed in %% markers. These are ignored by the parser and provide documentation or notes.

  • <import_block>: Statements to import external modules or dependencies.

  • <function_block>: Function definitions that include the function signature, optional arguments, and a block of statements.

Example:

%%
This is a comment block.
It provides information about the code.
%%
import "std/io.ff"

main: never -> int = {
    % Main function implementation
}

Include Statements

You can include external modules using import statements:

  • <import_block>: Specifies the inclusion of an external module.

  • <string_literal>: The name of the module, enclosed in quotes.

Example:

import "std/io.ff"

Functions

Functions in Frost are defined as follows:

  • <function_block>: A function definition that includes:

    • <function_signature>: Declares the function name, parameter types, and return type.

    • Optional arguments: A space-separated list of parameter names.

    • <block>: A code block containing the function's statements.

  • <function_signature>: Specifies the name, parameter types, and return type of the function.

  • <identifier>: The name of the function or its parameters.

Example:

sum: int int -> int = a b {
    ret a + b
}

Data Types

Frost supports a variety of data types, including primitives, pointers, and composite types:

  • <type>:

    • Primitive types: int, float, double, char, byte, bool, never.

    • Pointer types: Denoted as *<type>.

    • Struct types: Defined using struct with fields.

    • User-defined types: Custom types defined by the user.

  • <struct_field>: Fields in a struct, defined as <identifier> -> <type>.

Example:

personType :: struct {
    name -> char
    age -> int
}

Statements

A Frost program consists of individual statements that define the program's behavior. These include:

  • <variable_declaration>: Declares and initializes variables.

  • <loop>: Iterative constructs.

  • <if_statement>: Conditional constructs.

  • <function_call>: Calls to functions.

  • <expression>: Mathematical, logical, or function-related expressions.

  • <return_statement>: Specifies the value returned by a function.

Example:

SET_WIDTH: int = 100

if x < 10 {
    ret x * 2
} else {
    ret x + 2
}

Expressions

Expressions in Frost represent calculations, operations, or data manipulation. They include:

  • <literal>: Constants like numbers, strings, booleans, or null.

  • <binary_expression>: Expressions involving binary operators (e.g., a + b).

  • <unary_expression>: Expressions with prefix or postfix operators.

  • <function_call>: Invocations of functions.

  • <type_conversion>: Explicit type conversions.

  • <array_access>: Accessing elements of arrays.

  • <struct_access>: Accessing fields of structs.

  • <assignment>: Assigning values to variables.

Example:

char_index = iter * CHARSET_LENGTH / MAX_ITER
value: int = arr.#(index)

Literals

Literals represent fixed values in Frost, such as numbers, strings, and booleans:

  • <int_literal>: Integer values, e.g., 42.

  • <float_literal>: Floating-point values, e.g., 3.14.

  • <byte_literal>: A single byte enclosed in single quotes, e.g., 'A'.

  • <bool_literal>: Boolean values, true or false.

  • <array_literal>: Arrays of literals or strings.

    • <string_literal>: Strings enclosed in double quotes.

    • <literal_array_literal>: Arrays enclosed in square brackets.

Example:

42          % Integer
3,14        % Float
'A'         % Byte
true        % Boolean
"hello"     % String
[1 2 3]   % Array

Control Flow

Control flow constructs allow conditional and iterative execution:

  • <if_statement>: Conditional statements with optional else clauses.

  • <loop>: Repeatedly executes a block of code while a condition holds true.

  • <for_loop>: Structured iteration over a range with a specific step size. Following the format:

    • from <start> to <end> by <step>: Specifies the range and step size.

    • |<var>: <type>|: Declares the loop variable and its type.

    • <block>: Contains the statements executed in each iteration.

Example:

if x > 0 {
    ret x
} else {
    ret -x
}

loop (i < 10) {
    i = i + 1
}

from 0 to SET_HEIGHT by 1 |y: int| {
    from 0 to SET_WIDTH by 1 |x: int| {
        sine_value: double = amplitude * sin(frequency * @double(x) / @double(SET_WIDTH) * 2,0 * M_PI + phase)

        scaled_y: int = SET_HEIGHT / 2 - @int(sine_value * @double(SET_HEIGHT) / (2,0 * amplitude))

        if y is scaled_y {
            printf("\x1b[%d;%dH*" y x)
        }
    }
    printf("\n" 0)
}

Comments

Comments in Frost are enclosed in %% markers. They are ignored by the parser and provide documentation for the code.

Example:

%%
% This function calculates the sum of two numbers.
%%
add: int int -> int = num1 num2 {
    ret num1 + num2
}

Last updated