1
Language Expressions
erick-alcachofa edited this page 2025-12-30 03:08:14 +00:00

Expressions & Operators

artichoke uses a Pratt-style expression parser supporting rich infix, prefix, and postfix syntax. This section summarizes the key behaviors currently implemented.

Literals

  • Numeric literals: 42, 3.14159, 10.
  • Character/boolean/null: 'a', true, false, null.
  • Strings follow double-quoted C-style syntax with escapes.

All literal tokens map to dedicated AST nodes (CharLiteral, NullLiteral, StringLiteral, FloatLiteral, IntegerLiteral, BooleanLiteral).

Identifiers and Module Access

  • Simple identifiers refer to variables or functions: x, meaning_of_life.
  • Namespaced access uses ::: Result::<void, i32>::Err, std::memory.

Function Calls and Methods

meaning_of_life();
scale(&point, 2);
block.initialize(2048);
  • Turbofish syntax applies at call sites when generics are involved.
  • Methods (declared with this) can be invoked as member calls (expr.method) or as regular functions (method(expr, ...)).

Operators and Precedence

artichoke uses Pratt parsing with the following precedence (lowest to highest):

  1. Assignment: =, +=, -=, *=, /=, %=
  2. Boolean OR: or, ||
  3. Boolean AND: and, &&
  4. Comparisons: ==, !=, <, >, <=, >=
  5. Bitwise OR/XOR/AND: |, ^, &
  6. Shifts: <<, >>
  7. Addition/Subtraction: +, -
  8. Multiplication/Division/Modulo: *, /, %
  9. Prefix: !, -, ~, &, *
  10. Postfix and suffix operators

The sample program demonstrates complex precedence:

let calculation = ~5 + 10 * 2 / (length - 1) % 4 << 2 >> 1;
let logic_check = (calculation >= 100 or !true) and (length != 0);

x = y = length += 10;
  • Assignment chains associate right-to-left.
  • Parentheses override precedence as expected.
  • Boolean aliases (or, and) behave like ||, &&.

Postfix Operators

  • slice[index] and slice[start:end] for indexing and slicing.
  • slice.* to retrieve the raw pointer.
  • slice.# to obtain length.
  • ptr.[len] to form a slice from pointer + length.
  • value.member, value->member for object and pointer member access.
  • value.@, Type::member.@attribute for reflection.
  • Type::<T>{ ... } for object literals (named initializers).

These suffixes can be chained, e.g., optional_ptr->slice[other.# - 1].member_func(list.*, 2).data[0].

Object Literals

Point::<T> {
  .x = lhs->x * rhs,
  .y = lhs->y * rhs
}
  • Named initializer syntax .field = expr is used consistently to emphasize readability and order independence.

Reflection

foo.@;
Point::<u32>::x.@alignment;
Point::<u32>.@size;
  • Reflection works on values, types, and struct members, returning metadata used by introspection tools.

Error Handling Expressions

  • Result values are constructed with variant initializers (Result::<void, i32>::Err{ -1 }).
  • Unwrapping happens in control-flow statements.

AST Rendering

  • ast::toString produces the Markdown AST dumps emitted by the CLI; these align with the structures implied by the example program.

These behaviors are reflected in the AST output produced by the parser.