BioLang operators are listed below from highest precedence (binds
tightest) to lowest . Within the same precedence level, operators are
left-associative unless noted otherwise.
Symbol Name Description Example
.Field access Access a record field or method variant.chrom
()Call Invoke a function or builtin gc_content(seq)
[]Index Index into a list, string, or sequence reads[0]
Symbol Name Description Example
**Power Raise to a power (right-associative) 2 ** 10 gives 1024
Symbol Name Description Example
-Negate Arithmetic negation -log2(fc)
!Logical NOT Boolean negation !is_snp(v)
notLogical NOT (word) Same as !, reads more naturally in predicates not is_indel(v)
~Bitwise NOT Bitwise complement ~flags
Symbol Name Description Example
*Multiply Arithmetic multiplication coverage * depth
/Divide Arithmetic division gc_count / len(seq)
%Modulo Remainder after division; useful for reading frame math pos % 3
Symbol Name Description Example
+Add Arithmetic addition; also concatenates strings start + kb(1)
-Subtract Arithmetic subtraction end - start
Symbol Name Description Example
asCast Convert between compatible types qual as Int
Symbol Name Description Example
..Range (exclusive) Half-open range; useful for genomic coordinates 0..len(seq)
..=Range (inclusive) Closed range 1..=22 for autosomal chromosomes
Symbol Name Description Example
<<Left shift Shift bits left 1 << 4
>>Right shift Shift bits right; useful for SAM flag decoding flags >> 8
Symbol Name Description Example
&Bitwise AND Test individual flag bits in BAM flags flags & 0x4 to check unmapped
Symbol Name Description Example
^Bitwise XOR Exclusive or a ^ b
Symbol Name Description Example
==Equal Structural equality variant_type(v) == "snp"
!=Not equal Structural inequality v.chrom != "chrM"
<Less than Numeric or lexicographic comparison v.qual < 30
>Greater than gc_content(seq) > 0.6
<=Less or equal len(seq) <= kb(1)
>=Greater or equal depth >= 10
~Regex match True if the left string matches the right pattern header ~ "^>chr[0-9]+"
Symbol Name Description Example
&&AND Short-circuiting logical and is_snp(v) && v.qual > 30
andAND (word) Same as &&, reads naturally in filters is_snp(v) and v.qual > 30
Symbol Name Description Example
||OR Short-circuiting logical or is_het(v) || is_hom_alt(v)
orOR (word) Same as || is_het(v) or is_hom_alt(v)
Symbol Name Description Example
??Null coalesce Use the right-hand value when the left is nil v.info["AF"] ?? 0.0
Symbol Name Description Example
|>Pipe Pass the left-hand value as the first argument to the right-hand function reads |> filter(|r| mean_phred(r.quality) > 30)
|>>Tap pipe Like pipe, but passes the value through unchanged; used for side effects reads |>> print |> len()
|> intoPipe bind Evaluate the left side, bind the result to a name, and return it data |> filter(|x| x > 0) |> into clean
The pipe operators are the idiomatic way to build multi-step analysis
pipelines in BioLang. The |> into variant lets you capture an intermediate
result without breaking left-to-right reading order — expr |> into name
is equivalent to let name = expr:
read_fastq("sample.fq")
|> filter(|r| mean_phred(r.quality) > 25)
|>> |reads| print("After QC: " + str(len(reads)) + " reads")
|> map(|r| {id: r.id, gc: gc_content(r.seq)})
|> write_csv("gc_report.csv")
Symbol Name Description Example
=Assign Bind a value to a name let gc = gc_content(seq)
+=Add-assign Increment in place count += 1
-=Subtract-assign Decrement in place remaining -= 1
*=Multiply-assign Multiply in place score *= weight
/=Divide-assign Divide in place total /= n
?=Nil-assign Assign only if the target is currently nil cache ?= compute()
These symbols appear in specific syntactic positions and do not participate
in general expression precedence.
Symbol Name Description Example
=>Fat arrow Separates patterns from bodies in match and given arms match v { "snp" => handle_snp() }
->Arrow Return type annotation in function signatures fn gc(seq: Dna) -> Float
BioLang uses newlines as statement terminators – there are no
semicolons. A newline ends the current expression unless it is suppressed.
A newline does not terminate a statement when it appears:
After a binary operator. The expression continues on the next line.
let total = a +
b +
c
After an opening delimiter ((, [, {). The expression continues
until the matching closing delimiter.
let record = {
chrom: "chr1",
start: 1000,
end: 2000
}
After a pipe operator (|> or |>>). The pipeline continues on the
next line.
reads
|> filter(|r| mean_phred(r.quality) > 30)
|> map(|r| r.seq)
After a comma inside argument lists, list literals, and record
literals.
let xs = [
1,
2,
3
]
After keywords that expect a continuation : then, else, do,
and, or.
These rules mean that multi-line pipelines and data structures work
naturally without any explicit continuation characters.
Blank lines (lines containing only whitespace) are ignored between
statements. Use them freely to organize code into logical sections.
Syntax Name Description
#Line comment Everything from # to end of line is ignored
##Doc comment Attached to the following declaration; extractable by documentation tools
# This is a regular comment
## Compute GC content for a DNA sequence.
## Returns a float between 0.0 and 1.0.
fn gc(seq: Dna) -> Float
gc_content(seq)
end
Doc comments (##) attach to the immediately following fn, let, or
type declaration and are preserved in the AST for tooling and
auto-generated documentation.