Language Reference ================== BearVM's input format is a textual IR. Programs consist of optional struct definitions followed by one or more function definitions. The entry point is a function named ``main``. File Extension -------------- BearVM source files use the ``.bear`` extension. Types ----- The IR supports the following types: - ``int`` — 64-bit signed integer. - ``float`` — single-precision floating point. - ``double`` — double-precision floating point. - ``string`` — string value. Constants --------- The ``const`` keyword marks a value as a constant. Float and double literals require an explicit type annotation:: %n = const 42 %s = const "hello" %f = const 3.14: float %d = const 2.0: double Type Casts ---------- The ``cast`` instruction converts a value to another type:: %dbl = cast double %sum %back_to_float = cast float %dbl %int_from_float = cast int %f_result Any numeric type (``int``, ``float``, ``double``) can be cast to any other numeric type. Struct Definitions ------------------ Structs are defined at the top level, before any functions:: struct Person { name: string age: int } Fields may be of type ``int``, ``float``, ``double``, or ``string``. Struct definitions must appear before any function that uses them. Function Definitions -------------------- Functions are declared with ``@name``, an optional parameter list, and an optional return type:: @main(): int { ret 0 } @add(%a: int, %b: int): int { %result = add %a, %b ret %result } Functions with no return value omit the return type annotation:: @print_something { call puts("hello") ret 0 } Registers --------- All locals are registers, prefixed with ``%``:: %x = const 10 %y = add %x, 1 Registers have no declared type; their type is inferred from the instruction that produces them. A register may be reassigned within the high-level ``while`` sugar, but in explicit SSA form each name is assigned exactly once and ``phi`` is used at merge points. Explicit Basic Blocks (SSA form) --------------------------------- Functions can be written with explicit labeled basic blocks. Labels are declared with a name followed by a colon. Control flow between blocks uses ``jmp`` and ``br_if``. Values that flow across block boundaries are resolved with ``phi``:: @fib(%n: int): int { entry: %a0 = const 0 %b0 = const 1 %i0 = const 0 jmp loop_cond loop_cond: %cond0 = lt %i0, %n br_if %cond0, loop_body, loop_end loop_body: %tmp0 = add %a0, %b0 %a1 = %b0 %b1 = %tmp0 %i1 = add %i0, 1 %a0 = %a1 %b0 = %b1 %i0 = %i1 jmp loop_cond loop_end: ret %a0 } The ``phi`` instruction selects a value based on which block was the predecessor. Its syntax is:: %x = phi [label1: %reg1, label2: %reg2] The following example shows a float-returning function alongside the main entry point using ``cast`` and ``putf``:: @float_example(): float { entry: %f1 = const 3.14: float %f2 = const 2.0: float %sum = add %f1, %f2 %dbl = cast double %sum %back_to_float = cast float %dbl ret %back_to_float } @main(): int { entry: %n = const 10 %fib_result = call fib(%n) call puts(%fib_result) %f_result = call float_example() call putf(%f_result) %int_from_float = cast int %f_result call puts(%int_from_float) call flush() ret 0 } While Sugar ----------- For simpler control flow, the ``while`` construct is available:: @fib(%n: int): int { %a = const 0 %b = const 1 %i = const 0 while (lt %i, %n) { %tmp = add %a, %b %a = %b %b = %tmp %i = add %i, 1 } ret %a } ``while`` is the only high-level control flow construct. It is designed to make lowering complex control flow easier. It lowers to the same representation as the explicit basic-block form. Struct Literals --------------- A struct literal initialises all fields inline:: store %p_ptr, { name: "Alice", age: 25 } This form is used with ``store`` to initialise a heap-allocated struct. Field Access ------------ Fields of a struct stored in a register can be accessed and mutated with ``set``:: %p = Person { name: "Alice" age: 25 } call puts(%p.name) set %p.age = add %p.age, 1 For heap-allocated structs, use ``get_field_ref`` followed by ``load`` or ``store`` (see :doc:`instructions`). Named Constants --------------- Two named constants are defined for use with the ``open`` builtin: - ``READ`` — opens a file for reading. - ``WRITE`` — opens a file for writing. Entry Point ----------- Every program must define a ``@main`` function. The interpreter reports an error if it is absent. Comments -------- Comments begin with ``;`` and extend to the end of the line:: ; this is a comment %x = const 1 ; inline comment