Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Expressions

This chapter describes the expression grammar fic actually parses. Expressions appear as:

  • the right-hand side of assignments inside event bodies;
  • the payload of a channel send (c!e);
  • the body of a guard ([b]);
  • arguments to calls, sub-process calls, and computation-event carriers.

One grammar (Expr) covers literals, variables, calls, sizeof, unary and binary operators, and field access. There’s no separate arithmetic vs. logical vs. boolean sub-grammar — a boolean-shaped subset of Expr is what’s required in guard position (see below), not a different grammar.

Expr    ::= Lit | ident | CExpr | 'sizeof' '(' Type ')'
          | UnOp Expr | Expr BinOp Expr
          | FieldBase '.' ident           -- field access
FieldBase ::= ident | CExpr | FieldBase '.' ident  -- var, call, or field chain

Lit     ::= int_lit | hex_lit | bool_lit
UnOp    ::= '-' | '!' | '~'
BinOp   ::= '+' | '-' | '*' | '/' | '%'
          | '==' | '!=' | '<' | '<=' | '>' | '>='
          | '&&' | '||'
          | '&' | '|' | '^' | '<<' | '>>'

Operator precedence

Loosest to tightest:

LevelOperators
1||
2&&
3|
4^
5&
6==, !=
7<, <=, >, >=
8<<, >>
9+, -
10*, /, %
11unary -, !, ~
12primary atoms

Call expressions (CExpr)

CExpr ::= ident '.' ident '(' (Expr (',' Expr)*)? ')'

A call expression invokes a function defined in an imported .c file, prefixed with the import alias chosen at the import declaration. The alias is required — there are no local callables in Fiducia, only externally-implemented functions reached through an alias.

The first ident is the alias; the second is the function name. No whitespace is permitted around the . or before the (:

eth.send_frame()                  // OK
eth.send_frame(pkt, len)          // OK — arguments are full Expr, comma-separated
drv .start()                      // rejected — whitespace before '.'
drv. start()                      // rejected — whitespace after '.'
drv.start ()                      // rejected — whitespace before '('

Guard expressions

A guard ([b] P) requires a boolean-shaped Expr — arithmetic like [a + b] is rejected at parse time, since a guard must denote a yes/no decision, not a value. Boolean-shaped means: a boolean literal, a variable, a call, a field access, a !-negated boolean-shaped expression, or a comparison/&&/|| combination of boolean-shaped expressions.

[a + b == c]              // OK — comparison of arithmetic is boolean-shaped
[eth.is_forward()]         // OK — call
[!flag && ready]           // OK — negation + conjunction
[true]                     // OK
[a + b]                    // rejected — arithmetic isn't boolean-shaped