symbols

Version, currently 0.2.01 version
  • 0.2.0latestFeb 11, 2026

github.com/trans/symbol

Tacit Expression Language

0 stars
0 dependents
License: MIT

Installation

# Add this to your shard.yml
dependencies:
  symbols:
    github: trans/symbol
    version: ~> 0.2.0

Then run:

shards install

shard.yml

Crystal
>= 1.19.1
License
MIT
Author
Thomas Sawyer
Target
  • symbols from src/cli.cr

Dependencies

This version declares no dependencies.

README

SYMBOL

An APL-inspired tacit expression language written in Crystal.

SYMBOL uses reverse-reading postfix notation (RRPN) -- expressions are written left-to-right but evaluated right-to-left, with operators consuming arguments from the stack. It supports integer-preserving arithmetic, vectorized operations over arrays, structural operators, and multi-statement programs with assignment.

Installation

Add to your shard.yml:

dependencies:
  symbols:
    github: axiomatic/symbol

Then run shards install.

Usage

Single Expression

require "symbols"

result = SYMBOL.eval("2 + 3")
# => Resolved(5)

result = SYMBOL.eval("Σ [1, 2, 3, 4]")
# => Resolved(10)

result = SYMBOL.eval("2 * (3 + 4)")
# => Resolved(14)

Multi-Statement Programs

Use program: true to enable . statement separators and = assignment:

result = SYMBOL.eval("x = 4. x + 2.", program: true)
# => Resolved(6)

bindings = {} of String => SYMBOL::Tacit::TacitValue
SYMBOL.eval("x = 3. y = x * 2. y + 1.", bindings, program: true)
# => Resolved(7)
# bindings == {"x" => 3, "y" => 6}

Variable Bindings

bindings = {"k" => 5_i64.as(SYMBOL::Tacit::TacitValue)}
SYMBOL.eval("k + 1", bindings)
# => Resolved(6)

Inline Templates

Evaluate {{ expr }} expressions embedded in text:

SYMBOL.inline("The answer is {{ 2 + 3 }}.")
# => "The answer is 5."

bindings = {"name" => "world".as(SYMBOL::Tacit::TacitValue)}
SYMBOL.inline("Hello {{ name }}!", bindings)
# => "Hello world!"

Inline mode uses program semantics by default, so assignment works inside templates. Code spans and fences are respected as literal text.

REPL

$ symbols repl
SYMBOL v0.2.0
> 2 + 3
5
> Σ [1, 2, 3, 4]
10
> let x = 5
> x * x
25

CLI

symbols eval "2 + 3"        # Evaluate an expression
symbols repl                 # Start interactive REPL
symbols parse "2 + 3"       # Show AST
symbols tokenize "2 + 3"    # Show tokens

Operators

Arithmetic

OperatorDescriptionArity
+Add2
-Subtract2
*Multiply2
/Divide2
%Modulo2
^Power2
~Negate1

Integer types are preserved when possible. Division of integers that doesn't divide evenly produces a float.

Comparison

OperatorDescriptionArity
==Equal2
!= Not equal2
<Less than2
>Greater than2
<= Less or equal2
>= Greater or equal2

Logic / Bitwise

OperatorDescriptionArity
!Boolean NOT1
[+]OR (boolean or bitwise)2
[*]AND (boolean or bitwise)2
[-]XOR (boolean or bitwise)2
[~]NOT (boolean or bitwise)1

Wrapped operators dispatch by type: booleans get logical operations, integers get bitwise.

Aggregation

OperatorDescriptionArity
ΣSum1
ΠProduct1
#Count1
Ceiling (scalar) / Max (array)1
Floor (scalar) / Min (array)1

Structural

OperatorDescriptionArity
..Range (inclusive)2
><Concat2
<>Wrap (pair)2
+>Cons (prepend)2
<+Snoc (append)2
~>Zip (interleave)2
<~Piz (reverse interleave)2
->Remove from back2
<-Remove from front2
<->Remove from both ends2
Take2
Drop2
@Index (1-based)2
Reverse1

Vectorization

Binary arithmetic and comparison operators automatically vectorize over arrays:

[1, 2, 3] + 10             => [11, 12, 13]
[2, 3, 4] * [10, 20, 30]   => [20, 60, 120]

Multi-Statement Programs

When program: true is passed to eval:

  • . separates statements
  • = assigns to variables (left-hand side must be an identifier)
  • == is equality comparison
  • The result of the last statement is returned
  • Bindings are mutated in place
x = 3. y = x * 2. y + 1.

Trailing . is optional. Spaces between tokens are optional, except when a digit appears on both sides of a . separator (4.0 is always a float literal -- use 4 .0 + 1 to disambiguate).

License

MIT