Specification
Wawk Language Specification
Version 1.2.0 — A complete reference for the Wawk language: POSIX AWK fundamentals plus Wawk extensions. Every section includes a runnable example where noted. Edit the code and press Run to execute it as real WebAssembly in your browser.
Part 1: POSIX AWK
Part 2: Wawk Extensions
Part 1 — POSIX AWK
Patterns
Every AWK program consists of pattern-action pairs. A pattern selects which input lines to process. An action executes when the pattern matches. If no pattern is given, the action runs for every line.
Syntax
/regex/ { action }
expression { action }
pattern1, pattern2 { action } # range
{ action } # every line
Try It
stdout
Press Run to execute
Fields & Records
AWK splits each input line (record) into fields automatically. $1 is the first field, $2 the second, and so on. $0 is the entire line. NF holds the number of fields, NR the record number.
Syntax
$1 # first field
$NF # last field
$0 # entire record
NF # field count
NR # record number
FS # input field separator (default: space)
OFS # output field separator (default: space)
Try It
stdout
Press Run to execute
Variables & Assignment
AWK variables are dynamically typed. They hold numbers or strings depending on context. Variables are initialized to 0 or empty string automatically.
Syntax
x = 42 # numeric
name = "Alice" # string
x = x + 1 # increment
$1 = toupper($1) # modify field
Try It
stdout
Press Run to execute
Regular Expressions
AWK uses extended regular expressions. Patterns between /.../ are regex matches against $0. The ~ and !~ operators test specific fields.
Syntax
/^[A-Z]/ # starts with uppercase
/error|warn/ # alternation
$1 ~ /^[0-9]+$/ # field matches digits
$2 !~ /tmp/ # field does not match
Try It
stdout
Press Run to execute
BEGIN & END
BEGIN runs once before any input is read. END runs once after all input is processed. Use them for initialization, headers, summaries, and final calculations.
Syntax
BEGIN { # init, print header }
/pattern/ { # process each line }
END { # summary, print footer }
Try It
stdout
Press Run to execute
Associative Arrays
AWK arrays are hash maps. Indices can be any string. Use for (key in array) to iterate. Common patterns: word count, group-by, frequency analysis.
Syntax
arr[key] = value # set
arr[key]++ # increment
key in arr # test membership
delete arr[key] # remove element
for (k in arr) ... # iterate
Try It
stdout
Press Run to execute
Built-in Functions
Wawk provides all POSIX AWK built-in functions plus Wawk extensions for type inspection, bitwise operations, time handling, and advanced string processing.
String Functions
length(s) # string length (or $0 if omitted)
substr(s, start, len) # substring of s starting at position start
index(s, t) # position of t in s (0 if not found)
split(s, arr, fs) # split s into array by separator fs
sub(r, t, s) # substitute first match of regex r with t
gsub(r, t, s) # substitute all matches of regex r with t
match(s, r) # position of first match of regex r in s
sprintf(fmt, ...) # format string (like printf but returns string)
toupper(s) / tolower(s) # case conversion
patsplit(s, arr, pat) # split by pattern matches into array (gawk ext)
Math Functions
int(x) # truncate to integer (toward zero)
sqrt(x) # square root
exp(x) # exponential (e^x)
log(x) # natural logarithm
sin(x) # sine (x in radians)
cos(x) # cosine (x in radians)
atan2(y,x) # arctangent of y/x (in radians)
rand() # random number in [0, 1)
srand(n) # seed for rand() (returns previous seed)
abs(x) # absolute value (Wawk extension)
Try It
stdout
Press Run to execute
User-Defined Functions
Define custom functions with the function keyword. Functions can take parameters and return values. Local variables are declared as extra parameters (convention).
Syntax
function name(params) {
# body
return value
}
# Local variables: extra params
function max(a, b, _tmp) {
return (a > b) ? a : b
}
Try It
stdout
Press Run to execute
Control Flow
AWK supports if/else, while, for, and do-while loops. break and continue work as expected. The ternary operator is available for inline conditionals.
Syntax
if (cond) stmt
if (cond) stmt else stmt
while (cond) stmt
for (init; test; incr) stmt
do stmt while (cond)
break / continue
cond ? val1 : val2
Try It
stdout
Press Run to execute
Output & Formatting
print outputs fields separated by OFS, followed by ORS (newline). printf gives C-style formatting. Output can be redirected to files or pipes within AWK.
Syntax
print expr # print with ORS
print a, b, c # separated by OFS
printf fmt, args # formatted output
print > "file" # redirect to file
print | "cmd" # pipe to command
Try It
stdout
Press Run to execute
Part 2 — Wawk Extensions
PropertyTree: Universal Data Model
Wawk extends AWK with PropertyTree — a universal structured data model that serves as the core representation for all structured input formats. Input is automatically detected and parsed into PropertyTree regardless of format: JSON (priority 10), XML (30), YAML (40), or CSV (50). Access object fields with $.field notation, array elements with $1, $2 positional access, and construct new structured data with object/array literals.
Syntax
# JSON is auto-detected — no import needed
# Access nested fields with chained dot-notation
{ print $.customer.name, $.customer.address.city }
# Array element access with bracket indexing
{ print $.items[0].product, $.items[0].price }
# Positional access for top-level arrays
$1, $2, $3 # array element by position
print # auto-serializes PropertyTree back to JSON
Try It
stdout
Press Run to execute
Multi-Format: Same Syntax, Any Input
The same $.field syntax works regardless of whether input is JSON, XML, YAML, or CSV. PropertyTree abstracts away the format — write once, process anything. Navigate nested structures with chained dot-access: $.address.city. Use typeof() to inspect value types at runtime. Each input record is parsed independently — for XML, use one element per line.
Format-Agnostic Code
# This code works with JSON, XML, YAML, or CSV input:
{ print $.customer.name, $.customer.address.city }
# Array bracket indexing works in all formats
$.items[0].product # JSON: {"items":[{"product":"Laptop"}]}
# XML: <items><product>Laptop</product></items>
# Object literal output — construct new JSON from extracted fields
{ print {name: $.customer.name, city: $.customer.address.city} }
# Type introspection on nested fields
{ print typeof($.customer.name), typeof($.items) }
Try It — XML Input
stdout
Press Run to execute
@include Directive
@include "file.awk" expands included files inline, enabling code reuse across scripts (gawk-compatible, max 16 levels nesting, circular include protection). For plugin loading via @plugin, see the Plugin page.
Syntax
@include "utils.awk" # inline-expand file at this point
@include "lib/math.awk" # relative or absolute path
# Max 16 levels of nested includes
# Circular includes are detected and rejected
Try It
stdout
Press Run to execute
typeof() & Literal Syntax
Wawk adds a typeof() function and literal syntax for structured data construction. These extensions allow AWK programs to work natively with typed values and build PropertyTree values inline.
typeof() Function
typeof(expr) # Returns one of: "number", "string", "array",
# "object", "boolean", "null", "undefined"
# Examples:
typeof(42) # "number"
typeof("hello") # "string"
typeof(true) # "boolean"
typeof(null) # "null"
typeof([1,2,3]) # "array"
typeof({"a": 1}) # "object"
Boolean & Null Literals
true / false # Boolean literals
null # Null literal
x = true
if (x == true) print "yes"
print typeof(null) # "null"
Object & Array Literals
# Object literal (creates PropertyTree::Object)
person = {"name": "Alice", "age": 30, "active": true}
print person.name # "Alice"
print typeof(person) # "object"
# Array literal (creates PropertyTree::Array)
scores = [95, 87, 72, 63]
print scores[0] # 95
print typeof(scores) # "array"
# Nested construction
data = {
"users": [{"name": "Alice"}, {"name": "Bob"}],
"count": 2
}
print data.users[0].name # "Alice"
Try It
stdout
Press Run to execute
I/O: print, printf & getline
print outputs fields separated by OFS, followed by ORS. printf provides C-style formatted output. getline reads the next record from input or from a pipe/file. Output can be redirected to files or piped to commands.
Syntax
print expr # print with ORS (default: newline)
print a, b, c # separated by OFS (default: space)
printf "%-10s %5d\n", name, val # C-style formatting
print expr > "file" # redirect output to file
print expr | "cmd" # pipe output to command
getline # read next record from stdin
getline var < "file" # read from file into var
Format specifiers
| Specifier | Meaning |
| %s | String |
| %d | Integer |
| %f | Floating point |
| %o | Octal |
| %x | Hexadecimal |
| %e/%g | Scientific / shortest float |
| %% | Literal % |
Complete Function Reference
All built-in functions available in Wawk. POSIX functions work identically to standard AWK. Functions marked ext are Wawk extensions.
String Functions
| Function | Description | Example |
| length(s) | Length of string s (or $0 if omitted) | length("hello") → 5 |
| substr(s, m, n) | Substring of s starting at position m, length n | substr("hello", 2, 3) → "ell" |
| index(s, t) | Position of t in s (0 if not found) | index("hello", "ll") → 3 |
| split(s, a, fs) | Split s into array a by separator fs | split("a:b:c", x, ":") → 3 |
| sub(r, t, s) | Substitute first match of r with t in s (or $0) | sub(/o/, "0", "foo") → "f0o" |
| gsub(r, t, s) | Substitute all matches of r with t in s (or $0) | gsub(/o/, "0", "foo") → "f00" |
| match(s, r) | Position of first match of regex r in s (0 if none) | match("abc123", /[0-9]+/) → 4 |
| sprintf(fmt, ...) | Format string (like printf but returns string) | sprintf("%03d", 7) → "007" |
| tolower(s) | Convert to lowercase | tolower("HELLO") → "hello" |
| toupper(s) | Convert to uppercase | toupper("hello") → "HELLO" |
| patsplit(s, a, p, [s]) | Split by pattern matches ext | patsplit("a1b2", x, /[0-9]/) → 2 |
Math Functions
| Function | Description |
| int(x) | Truncate to integer (toward zero) |
| sqrt(x) | Square root |
| exp(x) | Exponential (e^x) |
| log(x) | Natural logarithm |
| sin(x) | Sine (x in radians) |
| cos(x) | Cosine (x in radians) |
| atan2(y, x) | Arctangent of y/x (in radians) |
| rand() | Random number in [0, 1) |
| srand(n) | Seed for rand() (returns previous seed) |
| abs(x) ext | Absolute value |
I/O Functions
| Function | Description |
| print ... | Print arguments separated by OFS, terminated by ORS |
| printf fmt, ... | Formatted output (C-style) |
| getline [var] < file | Read next record from file into var (or $0) |
| close(file) | Close open file or pipe |
| fflush([file]) | Flush output buffer for file (or all files) |
| system(cmd) | Execute shell command, return exit status |
Type & Conversion Functions ext
| Function | Description |
| typeof(val) | Returns "number", "string", "boolean", "null", "object", "array", or "undefined" |
| is_null(val) | Returns 1 if val is null, 0 otherwise |
| is_object(val) | Returns 1 if val is an object, 0 otherwise |
| to_json(val) | Serialize any value to JSON string |
| from_json(str) | Parse JSON string into PropertyTree value |
Bitwise Functions ext
| Function | Description |
| and(a, b) | Bitwise AND |
| or(a, b) | Bitwise OR |
| xor(a, b) | Bitwise XOR |
| compl(a) | Bitwise complement (NOT) |
| lshift(a, n) | Left shift a by n bits |
| rshift(a, n) | Right shift a by n bits |
Time Functions ext
| Function | Description |
| systime() | Current time as Unix timestamp |
| strftime(fmt [, ts]) | Format timestamp using C strftime format (default: now) |
| mktime(datespec) | Parse "YYYY MM DD HH MM SS" to Unix timestamp |
Array Functions
| Function | Description |
| delete arr[key] | Remove element from array |
| delete arr | Delete entire array |
| (key in arr) | Test if key exists in array |
Built-in Variables
Wawk provides built-in variables that control input/output behavior and provide information about the current processing state.
| Variable | Description | Default |
| $0 | Current record (entire line) | — |
| $1..$NF | Individual fields | — |
| NF | Number of fields in current record | — |
| NR | Total number of records processed | 0 |
| FNR | Record number in current file | 0 |
| FS | Input field separator | " " (whitespace) |
| OFS | Output field separator | " " (space) |
| RS | Input record separator | "\n" (newline) |
| ORS | Output record separator | "\n" (newline) |
| FILENAME | Name of current input file | "" (stdin) |
| ARGV | Command-line arguments array | — |
| ARGC | Number of command-line arguments | — |
| ENVIRON | Environment variables (read-only associative array) | — |
| RSTART | Start position of last match() (1-based) | 0 |
| RLENGTH | Length of last match() | -1 |
| SUBSEP | Subscript separator for multi-dimensional arrays | "\034" |
Extended I/O
Wawk extends POSIX I/O with append redirection, command piping, nextfile to skip to the next input file, and fflush() to flush output buffers.
I/O Extensions
print "data" >> "file.log" # append to file
print "cmd" | "sort" # pipe output to command
getline line < "input.txt" # read from file
nextfile # skip remaining records in current file
fflush() # flush all open output files
fflush("file.log") # flush specific file
close("file.log") # close file or pipe
ERRNO # set on I/O failures
Extended Variables & Operators
Beyond POSIX variables (NR, NF, FS, OFS, RS, ORS, FILENAME), Wawk adds several built-in variables and operators.
Additional Built-in Variables
| Variable |
Description |
| FNR | Record number within current file (reset per file) |
| ENVIRON | Associative array of environment variables (read-only) |
| FPAT | Field pattern: regex describing field content (gawk extension) |
| CONVFMT | Conversion format for numbers (default "%.6g") |
| OFMT | Output format for numbers (default "%.6g") |
| RSTART | Start index of string matched by match() |
| RLENGTH | Length of string matched by match() |
| SUBSEP | Subscript separator for multi-dimensional arrays (default "\034") |
| ERRNO | Set on I/O failures, plugin errors (Wawk extension) |
| ARGV / ARGC | Command-line arguments and count |
| true / false / null | Boolean and null literals (Wawk extension) |
Extended Operators
x ** y # exponentiation (same as x ^ y)
x ? a : b # ternary conditional
!x # logical NOT
++x, x++ # pre/post increment
--x, x-- # pre/post decrement
expr ~ /re/ # regex match
expr !~ /re/ # regex not-match
String Escapes & Hex Literals
Wawk supports the full range of C-style string escape sequences and hexadecimal number literals.
\n newline \t tab \r carriage return
\\ backslash \" double quote \a alert/bell
\b backspace \f form feed \v vertical tab
\xNN hex escape (1-2 hex digits, e.g. \x41 = "A")
\OOO octal escape (1-3 octal digits, e.g. \101 = "A")
0xFF # hex number literal (255)
0x1A # hex number literal (26)
Reference
Security Features
Wawk includes comprehensive security limits to prevent resource exhaustion and denial-of-service attacks. All limits are enforced at the engine level and apply across all platforms.
| Limit | Value | Purpose |
| Output size | 64 MB | Prevents unbounded output generation |
| Record size | 64 MB | Prevents memory exhaustion from large records |
| Array size | 1,000,000 | Maximum entries per associative array |
| Object key limit | 10,000 | Maximum keys per PropertyTree object |
| Nesting depth | 64 | Maximum levels for structured data parsing |
| Field limit | 100,000 | Maximum fields per record |
| Open files | 256 | Maximum simultaneous file targets |
| Recursion depth | 256 | Maximum nested function calls |
| Loop iterations | 100M | Prevents infinite loops |
| Audit log cap | 1,024 | Prevents audit bomb attacks |
| Regex cache | 512 | LRU eviction for compiled regex patterns |
| Printf width/precision | 10,000 | Caps format string width and precision |
Additional security measures: NFA-based regex engine (no ReDoS vulnerability), Wasm sandbox isolation (no network, filesystem, or system command access from plugins), safe UTF-8 conversion (no unsafe blocks in hot paths), field index clamping (prevents overflow from very large f64 values), and configurable execution timeout with amortized checks.