Basic Syntax

    This article is an introduction to the Cyrus Programming Language. It assumes you already have a basic understanding of programming concepts such as variables, statements, and types. Here, you’ll see how familiar ideas are expressed in Cyrus, while also being introduced to new concepts that make the language unique.

    If you haven't installed Cyrus yet, start with the Getting Started guide before continuing.

    Comments

    Comments are pieces of text ignored by the compiler. They're useful for explaining code, leaving notes, or temporarily disabling parts of a program. Cyrus supports both single-line and multi-line comments.

    • Single-line Comments
    // This is a single-line comment
    var msg: char* = "Hello, Cyrus!"; // You can also place it after code
    
    • Multi-line Comments
    /*
      Outer comment start
      /* Nested comment inside */
      Outer comment end
    
      Multi-line comments can also be nested!
    */
    

    Const string and Character Literals

    String literals in Cyrus are enclosed in double quotes "xxx", while character literals are enclosed in single quotes 'x'. Both forms represent sequences of Unicode characters, but they differ in intent and usage:

    • String literals produce values of type char*, which can hold arbitrarily many characters.
    • Character literals produce values of type char, which always represent exactly one Unicode scalar value.
    var greeting: char* = "Hello, Cyrus!";
    var letter: char = 'A';
    

    Escapes

    Special characters that are difficult to type directly or would otherwise break the syntax can be written using escape sequences. All escape sequences begin with a backslash ().

    Common escapes include:

    • \n - newline (line feed, U+000A)
    • \t - horizontal tab (U+0009)
    • \r - carriage return (U+000D)
    • \b - backspace (U+0008)
    • \a - bell/alert (U+0007)
    • \v - vertical tab (U+000B)
    • \f - form feed (U+000C)
    • \ - literal backslash
    • " - double quote (inside strings)
    • ' - single quote (inside chars or strings)

    Example:

    var poem: char* = "Line one\nLine two\nLine three";
    var quote: char* = "She said: \"Cyrus is great!\"";
    var backslash: char = '\\';
    
    var paragraph: char* = "Lorem Ipsum is simply dummy text of the printing and typesetting industry.
    Lorem Ipsum has been the industry's standard dummy text ever since the 1500s,
    when an unknown printer took a galley of type and scrambled it to make a type specimen book.";
    

    Unicode and Emojis

    Cyrus supports Unicode characters directly in string and character literals. You can type emojis, accented letters, or any other Unicode characters inside quotes:

    var letter: char = 'A';                     // valid
    var smile: char* = "😇";                    // valid
    var rocket: string = "Let's go! \u{1F680}"; // valid "Let's go! 🚀"
    var greek_alpha: char* = "\u03B1";          // valid "α"
    var emoji_char: char = '😇';                // NOT VALID
    var multibyte_char: char = '\u263A';        // NOT VALID
    

    Integer Constants

    Numeric constants in Cyrus can be written in decimal, hexadecimal, octal, or binary formats:

    • Decimal (Base 10):
    var a = 1234;
    
    • Hexadecimal (Base 16, prefix with 0x or 0X):
    var b = 0x42EDAA02;
    
    • Binary (Base 2, prefix with 0b or 0B):
    var c = 0b101010;
    

    Numeric literals may include underscores _ between digits for readability; these are ignored by the compiler:

    var million = 1_000_000;
    var hex_val = 0xDE_AD_BE_EF;
    

    Literal Suffixes

    Cyrus allows explicit type suffixes on numeric literals to specify their type. This is useful when the compiler cannot infer the type or when you want to guarantee a specific type.

    Integer Suffixes

    Valid integer suffixes include:

    • uintptr
    • intptr
    • usize
    • isize
    • int
    • int8
    • int16
    • int32
    • int64
    • int128
    • uint
    • uint8
    • uint16
    • uint32
    • uint64
    • uint128

    Valid float suffixes include:

    • float16
    • float32
    • float64
    • float128

    Example:

    var a = 1234int64;
    var b = 3.14float64;
    

    Default Type of Literals

    If you don't specify a type suffix, Cyrus assigns int as the default type for integer literals, and float64 as the default type for floating-point literals.

    Type suffixes can be used to explicitly control the size and signedness of an integer literal, or to select a different floating-point precision.

    Arrays

    Arrays are fixed-size, stack-allocated sequences. Size must be known at compile time.

    Explicit and Inferred Types

    You can define types explicitly or let the compiler infer them:

    // Explicit
    var a = int[3]{1, 2, 3};
    
    // Inferred
    const untyped = {1, 2, 3};
    

    Multi-dimensional Arrays

    const matrix = int[2][3] {
        int[3] {1, 2, 3},
        int[3] {1, 2, 3},
    };
    

    Pointers

    Cyrus pointers function similarly to C.

    var a: int = 10;
    var b: int* = &a;
    

    GEP and Decay

    Cyrus simplifies pointer access:

    1. GEP: You can use indexing on pointers directly (GetElementPtr semantics).

      var ptr: int* = malloc(8);
      ptr[0] = 10;
      ptr[1] = 20;
      
    2. Decay: Arrays automatically decay to pointers when assigned to a pointer type.

      const nums = int[3]{1, 2, 3};
      const ptr: int* = nums; // Equivalent to &nums[0]
      
    3. Pointer to Array:

      const nums = int[3]{1, 2, 3};
      var ptr: int[3]* = &nums;
      
      (*ptr)[0] = 10;
      

    Pointer Constness and Mutability

    Cyrus distinguishes between the mutability of the pointer itself and the mutability of the data it points to. If you take a reference to a const value, the resulting pointer is automatically a pointer to a constant (e.g., const int*), preventing mutation of the underlying value through that pointer.

    pub fn main() {
       const x = 10;
    
       // immut_ref is a mutable pointer to a constant integer (const int*)
       var immut_ref = &x;
    
       // ERROR: cannot modify a value through a 'const int*'
       *immut_ref = 20;
    
       printf("%d\n", *immut_ref);
    
       // However, the pointer itself can be reassigned:
       const y = 30;
       immut_ref = &y;
    }