Language Specification

This document defines the syntax and semantics of the Meow programming language.

Meow is a cat-themed programming language that transpiles to Go. Source files use the .nyan extension and are encoded in UTF-8.

Notation

This specification uses Extended Backus-Naur Form (EBNF) for grammar productions:

Production  = name "=" Expression "." .
Expression  = Term { "|" Term } .
Term        = Factor { Factor } .
Factor      = name | literal | "(" Expression ")" | "[" Expression "]" | "{" Expression "}" .
  • [ ... ] denotes optional (0 or 1).
  • { ... } denotes repetition (0 or more).
  • " ... " denotes terminal symbols.

Source Code Representation

Source code is UTF-8 encoded text in .nyan files. Newlines serve as statement terminators (semicolons are not used). The compiler processes a single .nyan file at a time.

Lexical Elements

Comments

Two forms of comments:

LineComment  = "#" { any_char } newline .
BlockComment = "-~" { any_char } "~-" .

Line comments start with # and extend to the end of the line. Block comments start with -~ and end with ~-, and may span multiple lines. Comments are treated as whitespace by the parser.

Keywords

The following 19 identifiers are reserved as keywords:

nyan      meow      bring     sniff     scratch
purr      paw       nya       lick      picky
curl      peek      hiss      nab       flaunt
catnap    yarn      hairball  kitty

Type Keywords

The following 6 identifiers are reserved as type keywords:

int    float    string    bool    furball    litter

Identifiers

identifier = letter { letter | digit | "_" } .
letter     = "a" ... "z" | "A" ... "Z" | "_" .
digit      = "0" ... "9" .

Identifiers name variables, functions, types, and struct fields. By convention, all user-facing identifiers use snake_case.

Integer Literals

int_lit = digit { digit } .

Integer literals are sequences of decimal digits representing 64-bit signed integers.

Float Literals

float_lit = digit { digit } "." digit { digit } .

Float literals contain a decimal point and represent 64-bit IEEE 754 floating-point numbers.

String Literals

string_lit = '"' { char | escape } '"' .
escape     = "\" ( '"' | "\" | "n" | "t" | "r" ) .

String literals are enclosed in double quotes. Supported escape sequences: \", \\, \n, \t, \r.

Operators and Delimiters

Operators:
  +    -    *    /    %
  =    ==   !=   <    >    <=   >=
  &&   ||   !
  |=|  ~>   .    ..   =>

Delimiters:
  (    )    {    }    [    ]    ,    :

Types

Meow uses a gradual type system. Values are dynamically typed at runtime (boxed as Value), but optional static type annotations enable compile-time checking and optimized code generation.

Primitive Types

TypeDescriptionExamples
int64-bit signed integer42, -7, 0
float64-bit floating-point3.14, -0.5
stringUTF-8 text"hello", ""
boolBooleanyarn (true), hairball (false)

Special Types

TypeDescription
furballError value carrying a message string
catnapThe nil/null value (singleton)

Composite Types

TypeDescriptionSyntax
litterOrdered collection of values[1, 2, 3]
MapString-keyed dictionary{"key": value}
kittyUser-defined structkitty Name { field: type }

Type Annotations

Type annotations are optional but recommended. They appear after identifiers:

TypeExpr = "int" | "float" | "string" | "bool" | "furball" | "litter" .

Variable declaration with type:

VarStmt = "nyan" identifier [ TypeExpr ] "=" Expr .

Function with typed parameters and return type:

FuncStmt = "meow" identifier "(" [ ParamList ] ")" [ TypeExpr ] Block .
ParamList = Param { "," Param } .
Param = identifier [ TypeExpr ] .

Go-style grouped types propagate right-to-left: in (a, b int), both a and b receive type int.

Expressions

Literal Expressions

IntLit     = int_lit .
FloatLit   = float_lit .
StringLit  = string_lit .
BoolLit    = "yarn" | "hairball" .
NilLit     = "catnap" .
ListLit    = "[" [ Expr { "," Expr } [ "," ] ] "]" .
MapLit     = "{" [ MapEntry { "," MapEntry } [ "," ] ] "}" .
MapEntry   = StringLit ":" Expr .

Identifier Expression

Ident = identifier .

Evaluates to the value bound to the identifier in the current scope.

Unary Expressions

UnaryExpr = ( "-" | "!" ) Expr .
  • - negates an int or float.
  • ! inverts truthiness.

Binary Expressions

BinaryExpr = Expr op Expr .

Arithmetic operators (+, -, *, /, %) require operands of the same type. + also concatenates strings.

Comparison operators (<, >, <=, >=) work on int and float. Equality operators (==, !=) work on all types.

Logical operators (&&, ||) use short-circuit evaluation. && returns the left operand if falsy, otherwise the right. || returns the left operand if truthy, otherwise the right.

Call Expression

CallExpr = Expr "(" [ Expr { "," Expr } ] ")" .

Calls a function, lambda, or built-in. Also used to construct kitty instances by calling the type name.

Lambda Expression

LambdaExpr = "paw" "(" [ ParamList ] ")" "{" Expr "}" .

Creates an anonymous function. The body is a single expression (not a block of statements).

paw(x int) { x * 2 }

Index Expression

IndexExpr = Expr "[" Expr "]" .

Accesses a list element by zero-based index.

Member Expression

MemberExpr = Expr "." identifier .

Accesses a field on a kitty instance, or calls a function in an imported package.

Pipe Expression

PipeExpr = Expr "|=|" Expr .

Passes the left expression as the first argument to the right expression. If the right side is a function call, the left value is prepended to its arguments:

x |=| f(y)    # equivalent to f(x, y)
x |=| f       # equivalent to f(x)

Catch Expression

CatchExpr = Expr "~>" Expr .

If the left expression panics, the right side is used as a fallback. If the right side is a function, it receives the Furball error as its argument:

risky() ~> 0                    # fallback value
risky() ~> paw(err) { handle(err) }  # handler function

Match Expression

MatchExpr = "peek" "(" Expr ")" "{" { MatchArm } "}" .
MatchArm  = Pattern "=>" Expr [ "," ] .
Pattern   = LitPattern | RangePattern | WildcardPattern .
LitPattern      = Expr .
RangePattern    = Expr ".." Expr .
WildcardPattern = "_" .

Evaluates the subject and tests it against each pattern in order. Returns the body of the first matching arm.

peek(n) {
  0 => "zero",
  1..10 => "low",
  _ => "other"
}

Statements

Variable Declaration

VarStmt = "nyan" identifier [ TypeExpr ] "=" Expr newline .

Declares a variable and binds it to a value.

nyan x int = 42
nyan name = "Nyantyu"

Reassignment

AssignStmt = identifier "=" Expr newline .

Rebinds an existing variable to a new value.

Function Declaration

FuncStmt = "meow" identifier "(" [ ParamList ] ")" [ TypeExpr ] Block .
Block    = "{" { Stmt } "}" .

Declares a named function. Functions that don’t explicitly bring a value implicitly return catnap.

meow greet(name string) string {
  bring "Hello, " + name + "!"
}

Return Statement

ReturnStmt = "bring" [ Expr ] newline .

Returns a value from the enclosing function.

Conditional Statement

IfStmt = "sniff" "(" Expr ")" Block [ "scratch" ( IfStmt | Block ) ] .

Evaluates the condition. If truthy, executes the body. Optional scratch provides else/else-if branches.

sniff (x > 0) {
  nya("positive")
} scratch sniff (x == 0) {
  nya("zero")
} scratch {
  nya("negative")
}

Loop Statement

RangeStmt = "purr" identifier "(" RangeExpr ")" Block .
RangeExpr = Expr [ ".." Expr ] .

Two forms:

  • Count form: purr i (n) — iterates i from 0 to n-1.
  • Range form: purr i (a..b) — iterates i from a to b (inclusive).
purr i (5) { nya(i) }         # 0, 1, 2, 3, 4
purr i (1..5) { nya(i) }     # 1, 2, 3, 4, 5

Nab Statement

NabStmt = "nab" string_lit newline .

Imports a standard library package. Available packages: "file", "http", "testing".

nab "http"

Kitty Statement

KittyStmt  = "kitty" identifier "{" { KittyField } "}" .
KittyField = identifier ":" TypeExpr [ "," ] newline .

Defines a struct type with named, typed fields. A constructor function with the same name is automatically created.

kitty Point {
  x: int
  y: int
}

nyan p = Point(3, 7)
nya(p.x)   # => 3

Expression Statement

ExprStmt = Expr newline .

Any expression can appear as a statement. The result is discarded.

Built-in Functions

I/O

FunctionSignatureDescription
nyanya(args...)Print values (space-separated) with trailing newline

Error Handling

FunctionSignatureDescription
hisshiss(args...)Raise error — panics with "Hiss! ..."
gaggag(fn) → value | furballCall fn(); recover from panic, return Furball on error
is_furballis_furball(v) → boolCheck if v is a Furball error value

Type Conversion

FunctionSignatureDescription
to_intto_int(v) → intConvert float, bool, or int to int
to_floatto_float(v) → floatConvert int to float
to_stringto_string(v) → stringConvert any value to its string representation

Collections

FunctionSignatureDescription
lenlen(v) → intLength of string or list
headhead(list) → valueFirst element of a list
tailtail(list) → listAll elements except the first
appendappend(list, value) → listNew list with value appended

Functional Operations

FunctionSignatureDescription
licklick(list, fn) → listMap: apply fn to each element
pickypicky(list, fn) → listFilter: keep elements where fn returns truthy
curlcurl(list, init, fn) → valueReduce: fold list with accumulator

Error Model

Errors in Meow use a panic/recover model:

  1. Raising errors: hiss("message") panics with the message "Hiss! message". Error messages are suffixed with ", nya~" when raised from runtime functions.

  2. Error values: When a panic is caught, it becomes a Furball — a value that carries the error message string.

  3. Catching errors: Three mechanisms:

    • gag(fn) — calls fn() and catches panics, returning a Furball on error.
    • expr ~> fallback — evaluates expr; if it panics, uses fallback instead.
    • expr ~> paw(err) { ... } — evaluates expr; if it panics, calls the handler with the Furball.
  4. Checking errors: is_furball(v) returns yarn if v is a Furball, hairball otherwise.

Program Structure

A Meow program is a single .nyan file containing a sequence of top-level statements. The generated Go code follows this structure:

package main

import meow "github.com/135yshr/meow/runtime/meowrt"
import meow_file "github.com/135yshr/meow/runtime/file"    // from nab "file"
import meow_http "github.com/135yshr/meow/runtime/http"    // from nab "http"
import meow_testing "github.com/135yshr/meow/runtime/testing" // from nab "testing"

// user-defined functions

func main() {
    // top-level statements
}

Truthiness

All values have a truthiness used by sniff conditions and logical operators:

ValueTruthy?
yarnyes
hairballno
catnapno
0 (int)no
0.0 (float)no
"" (empty string)no
non-zero int/floatyes
non-empty stringyes
empty list []no
non-empty listyes
empty map {}no
non-empty mapyes
kittyyes
furballno
funcyes