A programming language whose keywords, whose type system, and whose own compiler are written in Sanskrit।
Vāk takes Pāṇini's analysis of a sentence — that meaning comes from the role each participant plays, not from where it sits — and makes it a type system. Every stage of the language is written in the language itself.
# कारकाणि — a parameter declares the role it plays in the action
कार्यम् छानय(अपादानम् सूची संग्रहः, करणम् कार्यम् परीक्षा) : सूची {
सूची फलम् = []।
प्रत्येकम् (अङ्गम् अन्तः संग्रहः) {
यदि (परीक्षा(अङ्गम्)) { योजय(फलम्, अङ्गम्)। }
}
प्रत्यागच्छ फलम्।
}
मुद्रय छानय(करणम्: समः, अपादानम्: [१, २, ३, ४, ५, ६])।१
स्थापनाInstalling Vāk
There is no package to install and nothing to configure. Pick whichever of these four suits you — they run the same language.
१ The standalone binary nothing else required
वाक्.exe ships in the repository. It is the whole toolchain —
lexer, parser, analyser, compiler and machine — compiled to one file, and it
needs neither Python nor anything else. Copy it where you like and run it:
वाक्.exe प्रोग्राम.vakThe binary in the repository is built for 64-bit Windows. On Linux or macOS, build your own — see Building the binary below; the C sources are platform-neutral.
२ With pip Python 3.10 or newer
Vāk pulls in no third-party packages. A standard Python is all it needs; it was developed on 3.13.
pip install vak-lang
vaak प्रोग्राम.vakThree names, and they differ on purpose. The distribution is
vak-lang, the command and the import name are vaak.
vak on PyPI is an unrelated bioacoustics package, and shadowing
it would let pip overwrite one install with the other.
This gives you the interpreter, the bytecode virtual machine, the native back
end, the REPL and the standard library, and the vak command works
from any directory.
३ From a clone everything a wheel does not carry
Clone it for the C runtime, the Vāk-written toolchain behind
--self, the documentation generators and the editor extension:
git clone https://github.com/vidyadheeshp/vak.git
cd vak
python -m vaak examples/01_namaste.vakWorking from a clone, stay in the repository root.
python -m vaak finds the package only because you are standing in
the directory that contains it; from anywhere else you will get
No module named vak. Installing with pip avoids this entirely.
To run from elsewhere without installing, put the root on the module
path:
# bash / zsh
PYTHONPATH=/path/to/vak python -m vaak ~/प्रोग्राम.vak
# PowerShell
$env:PYTHONPATH = "C:\path\to\vak"; python -m vaak प्रोग्राम.vakOn Windows the two launchers in the repository do this and set UTF-8 for you:
.\vaak.ps1 examples/01_namaste.vak # PowerShell
vaak.cmd examples/01_namaste.vak # cmd.exe४ In a browser nothing installed at all
The playground is this same toolchain compiled to WebAssembly. It runs entirely in the page — your program is not uploaded, and nothing you type leaves your machine. Use it to try the language before deciding whether to install anything.
Checking that it works
python -m vaak --version # वाक् (Vāk) 0.12.1
python -m vaak --builtins # the 39 built-in functions
python -m vaak # संवादः — the interactive sessionThen a program of one line. Put this in परीक्षा.vak and run
it — if you see the greeting, everything works:
मुद्रय "नमस्ते जगत्"।A terminal that can show Devanagari
Two separate things have to be right: the console must be in UTF-8, and the font must contain Devanagari.
- Windows. The CLI reconfigures its own output, so Devanagari
normally works in Windows Terminal. If you see boxes, the font is the
problem, not the encoding — choose Nirmala UI or
Noto Sans Devanagari. The older
conhostconsole may also needchcp 65001. - Linux and macOS. A UTF-8 locale is the default almost everywhere;
localewill confirm it. Most terminal fonts fall back to a system Devanagari face automatically.
You do not have to type Devanagari at all. Every keyword has an ASCII spelling and ASCII numerals work everywhere, so a complete Vāk program can be written on a plain keyboard. The switch at the top of this page shows any example either way.
Building the binary
The native back end turns a program into C and hands it to gcc, so a C compiler is the only extra requirement. On Windows, w64devkit is the one Vāk looks for by default; on Linux and macOS the system compiler is already there.
python -m vaak --native प्रोग्राम.vak # produce an executable
python -m vaak --run-native प्रोग्राम.vak # build it and run itIf no compiler is found, Vāk says so rather than failing obscurely.
The editor extension
Copy the vscode-vak folder from the repository into your VS Code
extensions directory and reload the window:
# Windows
%USERPROFILE%\.vscode\extensions\vscode-vak
# macOS and Linux
~/.vscode/extensions/vscode-vakThen point it at whichever toolchain you installed — set
vak.executable to your वाक्.exe, or leave that empty
and set vak.pythonPath so it uses python -m vaak. You
get highlighting, the .vak file icon, romanised typing that becomes
Devanagari, and the analyser's diagnostics as you save — the same ones listed in
दोषसूची.
२
चालनम्Running Vāk
Three ways to run a program, all producing identical output. The first needs Python; the last needs nothing at all.
python -m vaak प्रोग्राम.vak # the tree-walking interpreter
python -m vaak --vm प्रोग्राम.vak # compile to bytecode, run on the SanskritVM
./वाक्.exe प्रोग्राम.vak # the self-hosted toolchain, no PythonTwo more you will want early — the first analyses without running, the second starts a REPL:
./वाक्.exe --परीक्षा प्रोग्राम.vak # report problems, run nothing
python -m vaak # संवादः — the REPLThe संवादः remembers. What you type is kept in
~/.vaak_history and read back next time, so the up arrow reaches
yesterday's session. This needs Python's readline, which is not
in the standard library on Windows — there the REPL works exactly as before
and simply forgets between sessions.
The full set of options, read from the argument parser itself. Four carry a Sanskrit alias:
| विकल्पः | संस्कृतम् | what it does |
|---|---|---|
--tokens | | print the token stream and stop |
--ast | | print the syntax tree and stop |
--check | | run the semantic analyser and stop, without executing |
--no-check | | skip the semantic analyser and run the program directly |
--vm | | compile to bytecode and run on the SanskritVM |
--bytecode | --vyakhya | disassemble the compiled bytecode and stop |
--self | --svayam | compile with the Vāk-written toolchain, then run on the VM |
--self-vm | --svayam-yantram | lex, parse, compile AND run entirely in Vāk |
--native | --deshiya | compile to a standalone native executable (needs gcc) |
--run-native | | compile natively and run the result |
--builtins | | list the built-in functions |
--karakas | | list the kāraka roles |
--version | | print the version and stop |
An editor. The vscode-vak extension in the repository
gives Vāk syntax highlighting, the .vak file icon, romanised
typing that becomes Devanagari as you write, and live diagnostics from the
real analyser — the same messages listed in
दोषसूची.
Fonts. No monospace coding font contains Devanagari, so an editor
falls back to a proportional face and columns drift. Setting
editor.fontFamily to a chain ending in Nirmala UI or
Noto Sans Devanagari fixes the rendering, though nothing makes
Devanagari truly monospaced. Installation is covered in
स्थापना.
३
वाक्यानिStatements and the danda
A statement ends with a danda — । — the full stop
Sanskrit has used since manuscripts. ॥, the double danda, ends a
section. A semicolon means the same thing and is easier to type.
मुद्रय "नमस्ते जगत्"।
मान क = ५;
मुद्रय क॥मुद्रय prints its arguments separated by a space. Comments run
from # to the end of the line.
४
चराःVariables and numerals
मान declares a variable, ध्रुव a constant. A type
may be written in place of मान, and then it binds — the analyser
and every engine hold you to it.
मान नाम = "वाक्"।
ध्रुव पाई = ३.१४१५९।
पूर्णाङ्कः वर्षम् = २०२६।
शब्दः अभिवादनम् = "नमस्ते"।
वर्षम् += १।
मुद्रय नाम, वर्षम्, पाई।Devanagari and ASCII numerals are the same numbers — २०२६ and
2026 are one value, and you may mix them freely. Output uses
whichever form the value was written in where that is knowable, and
देवनागरी() converts on demand.
५
प्रवाहःControl flow
यदि and अन्यथा branch. Parentheses around the
condition are optional; the braces are not.
यदि (अङ्कः > १००) {
मुद्रय "महान्"।
} अन्यथा यदि (अङ्कः > १०) {
मुद्रय "मध्यमः"।
} अन्यथा {
मुद्रय "अल्पः"।
}Four loops, because four different things are worth saying.
यावत् repeats while a condition holds, कुरु does the
same but asks afterwards, आवृत्तिः repeats a fixed number of times,
and प्रत्येकम् … अन्तः walks a collection.
यावत् (क < १०) { क += १। }
कुरु { क += १। } यावत् (क < १०)।
आवृत्तिः (३) { मुद्रय "ॐ"। }
प्रत्येकम् (अङ्कः अन्तः [१, २, ३, ४]) {
यदि (अङ्कः == ३) { अनुवर्त। }
मुद्रय अङ्कः।
}विरम leaves a loop, अनुवर्त starts its next turn.
कुरु · asking after, not before
कुरु is the imperative — do! — and it opens the one loop
whose body runs before anything is asked. The test that follows is written with
यावत्, so the pair reads as a single sentence: do this, as long
as that.
कुरु {
उत्तरम् = पठ("नाम? ")।
} यावत् (दीर्घता(उत्तरम्) == ०)।अनुवर्त inside a कुरु jumps to the test rather than
back to the top of the body, since the body has already had its turn.
It needs no instruction of its own. A यावत् loop already
compiles to a conditional jump out and an unconditional jump back;
कुरु is those same two in the other order, which is why every
engine — the C runtime included — understood it the day it was added.
विकल्पः · Choosing among alternatives
Where a chain of अन्यथा यदि only compares one value over and over,
विकल्पः says it once. The word is Pāṇini's own: a vikalpa is
an optional alternative in a rule. Each alternative is introduced by
पक्षे — the locative, “in this case” — matching
दोषे, the locative Vāk already uses for catch.
कार्यम् वासरनाम(कर्म पूर्णाङ्कः वारः) : शब्दः {
विकल्पः (वारः) {
पक्षे १: प्रत्यागच्छ "सोमवासरः"।
पक्षे २, ३: प्रत्यागच्छ "मङ्गलः बुधः वा"।
पक्षे ६, ७: प्रत्यागच्छ "सप्ताहान्तः"।
अन्यथा: प्रत्यागच्छ "अज्ञातः"।
}
}One पक्षे may carry several values, separated by commas.
अन्यथा is the fallback, and it is the fallback wherever it is
written. The subject is evaluated once.
पक्षाः do not fall through. The alternative that matches is the only
one that runs, so nothing has to be written to stop it. That frees
विरम to keep its ordinary meaning: inside a विकल्पः it leaves the
enclosing loop, not the विकल्पः — and outside a loop it is an error,
exactly as it always was.
The analyser reports a पक्षः whose type could never match the subject, and
a value given twice — neither could ever run. A विकल्पः without an
अन्यथा is only advice, not an error, but it does mean an
unmatched subject does nothing at all.
A विकल्पः also counts as returning on every path, so long as it has an
अन्यथा and every पक्षः returns — which is why the function above
needs no closing प्रत्यागच्छ.
६
कार्याणिFunctions
कार्यम् defines a function. A return type after the colon is
optional and binding. Functions are values: pass them, return them, close over
their surroundings.
कार्यम् क्षेत्रफलम्(पूर्णाङ्कः दैर्घ्यम्, पूर्णाङ्कः विस्तारः) : पूर्णाङ्कः {
प्रत्यागच्छ दैर्घ्यम् * विस्तारः।
}
कार्यम् योजकः(आधारः) : कार्यम् {
प्रत्यागच्छ कार्यम्(क) : पूर्णाङ्कः { प्रत्यागच्छ आधारः + क। }।
}
मान दश = योजकः(१०)।
मुद्रय क्षेत्रफलम्(६, ७), दश(५)।Functions are hoisted: a function may call one defined later in the same block.
A parameter may carry a default, which must be written out — a number, a
string, सत्य, असत्य or शून्य. Nothing is
computed at the call, so the value cannot be shared between calls and the
mutable-default trap familiar from Python cannot arise.
कार्यम् अभिवादय(शब्दः नाम, शब्दः वचनम् = "नमस्ते") : शब्दः {
प्रत्यागच्छ वचनम् + ", " + नाम + "।"।
}
मुद्रय अभिवादय("रामः")। # नमस्ते, रामः।
मुद्रय अभिवादय("रामः", "स्वागतम्")। # स्वागतम्, रामः।Where the parameters are unmarked, a default may not sit before a parameter that has none — position is all the call has to go on. Where every parameter declares its kāraka, that restriction lifts.
प्रयुज् · applying a call you did not write
Sometimes the arguments are computed rather than written out.
प्रयुज् — prayuj, “to yoke, to apply” — takes a
कार्यम् and either a सूची, which fills the parameters
in order, or a कोशः whose keys are kāraka names, which fills them
by role:
प्रयुज्(योगः, [१, २, ३])। # योगः(१, २, ३)
प्रयुज्(लिखतु, {"कर्ता": "कालिदासः", "कर्म": "मेघदूतम्"})।This is what a wrapper needs — a function standing in front of another without knowing how many arguments it takes:
कार्यम् गणयित्वा(कार्यम् क, सूची अर्घाः) {
मुद्रय "आह्वानम्:", दीर्घता(अर्घाः)।
प्रत्यागच्छ प्रयुज्(क, अर्घाः)।
}प्रयुज् becomes a single instruction, because the number of
arguments is only known once the program is running. That has one consequence
worth stating plainly: it must be called, and cannot be passed around
as a value. All five engines refuse the indirect form rather than three
allowing it and two not.
लक्षणम् · what a कार्यम् declares
Lakṣaṇa is the grammarians' word for a defining characteristic — the
mark by which a thing is known. A function's mark is its parameters, and
लक्षणम् hands them back as an ordinary कोशः:
कोशः ल = लक्षणम्(छानय)।
मुद्रय ल.नाम, ल.प्राचलसंख्या, ल.प्रतिफलप्रकारः।
प्रत्येकम् (प्रा अन्तः ल.प्राचलाः) {
मुद्रय प्रा.कारकम्, प्रा.प्रकारः, प्रा.नाम, प्रा.मूलमस्ति।
}The two are meant to be used together: read the roles a function wants, then build the call from them.
कोशः अर्घाः = {}।
प्रत्येकम् (प्रा अन्तः लक्षणम्(लिखतु).प्राचलाः) {
यदि (न प्रा.मूलमस्ति) { अर्घाः[प्रा.कारकम्] = मूल्यम्_आनय(प्रा.कारकम्)। }
}
प्रत्यागच्छ प्रयुज्(लिखतु, अर्घाः)।For a built-in, प्रतिफलप्रकारः comes back as
किमपि. That is the analyser's knowledge rather than the
runtime's, and two of the five engines have no way to reach it — reporting it
from the three that can would be a divergence.
७
संग्रहाःLists and dictionaries
सूची is an ordered list, कोशः a dictionary —
literally a treasury, the word Sanskrit uses for a lexicon. Negative
indices count from the end.
मान अङ्काः = [१, २, ३, ४, ५]।
मुद्रय अङ्काः[०], अङ्काः[-१], दीर्घता(अङ्काः)।
योजय(अङ्काः, ६)।
मान छात्रः = { "नाम": "रामः", "वयः": २० }।
मुद्रय छात्रः.नाम, छात्रः["वयः"]।
छात्रः.नगरम् = "काशी"।A dictionary key may be reached with a dot or with brackets; the dot form is the same lookup written more quietly.
८
प्रकाराःTypes
Typing is gradual. Write no type and nothing is checked; write one and it is
enforced everywhere — at declaration, at assignment, at every call, and on the
way out of a function. किमपि flows both ways, so only a provable
mismatch is an error.
| प्रकारः | what it holds |
|---|---|
पूर्णाङ्कः | whole number — pūrṇāṅkaḥ, “complete-numbered” |
दशांशः | a number with a fractional part — daśāṃśaḥ, “tenth-part” |
अङ्कः | either kind of number |
शब्दः | text — śabdaḥ, the word for word |
सत्यता | truth — सत्य or असत्य |
सूची | a list |
कोशः | a dictionary |
कार्यम् | a function |
किमपि | anything at all — kimapi, “whatever” |
शून्यम् | nothing — śūnyam, the zero India gave the world |
पूर्णाङ्कः आयुः = २५।
आयुः = "पञ्चविंशतिः"। # प्रकारदोषः — शब्दः दीयते, पूर्णाङ्कः अपेक्षितः९
कारकाणिKāraka roles
This is the part of Vāk that exists nowhere else.
Pāṇini analysed a sentence not by word order but by kāraka — the role each participant plays in the action. Vāk lets a parameter declare its role, and then checks the grammar of your function the way Pāṇini checked the grammar of a sentence.
| कारकम् | विभक्तिः · what the role means |
|---|---|
कर्ता | प्रथमा (nominative) — the agent, who acts |
कर्म | द्वितीया (accusative) — the patient, what the action most wants |
करणम् | तृतीया (instrumental) — the means by which it is done |
सम्प्रदानम् | चतुर्थी (dative) — the recipient it is given to |
अपादानम् | पञ्चमी (ablative) — the source it departs from |
अधिकरणम् | सप्तमी (locative) — the locus it happens in |
कार्यम् छानय(अपादानम् सूची संग्रहः, करणम् कार्यम् परीक्षा) : सूची {
सूची फलम् = []।
प्रत्येकम् (अङ्गम् अन्तः संग्रहः) {
यदि (परीक्षा(अङ्गम्)) { योजय(फलम्, अङ्गम्)। }
}
प्रत्यागच्छ फलम्।
}Because the roles are marked, the arguments carry their own labels and the order stops mattering — exactly the freedom case marking gives a Sanskrit sentence. All three of these calls are the same call:
छानय(अङ्काः, समः)।
छानय(अपादानम्: अङ्काः, करणम्: समः)।
छानय(करणम्: समः, अपादानम्: अङ्काः)।अनुक्तम् कारकम् — the role that goes unsaid
Sanskrit does not require every kāraka to appear. देवदत्तः पचति — “Devadatta cooks” — is a whole sentence, and it states neither what is cooked nor by what means. Those roles exist; this sentence does not name them.
A parameter with a default says exactly that. The role is part of the action, and this call leaves it unexpressed.
कार्यम् छानय(अपादानम् सूची संग्रहः, करणम् किमपि परीक्षा = शून्य) : सूची {
यदि (परीक्षा == शून्य) { प्रत्यागच्छ संग्रहः। }
सूची फलम् = []।
प्रत्येकम् (अङ्गम् अन्तः संग्रहः) {
यदि (परीक्षा(अङ्गम्)) { योजय(फलम्, अङ्गम्)। }
}
प्रत्यागच्छ फलम्।
}
छानय(अपादानम्: अङ्काः)। # करणम् अनुक्तम् — everything comes back
छानय(करणम्: समः, अपादानम्: अङ्काः)। # both stated, in the other orderBecause the roles are named rather than counted, a default may sit anywhere in the parameter list — not only at the end, as a language with positional arguments must insist. A call names the roles it supplies and says nothing about the rest:
कार्यम् लिखतु(कर्ता शब्दः लेखकः,
करणम् शब्दः साधनम् = "लेखन्या",
कर्म शब्दः ग्रन्थः) : शब्दः {
प्रत्यागच्छ लेखकः + " '" + ग्रन्थः + "' " + साधनम् + " लिखति"।
}
लिखतु(कर्ता: "कालिदासः", कर्म: "मेघदूतम्")। # साधनम् अनुक्तम्A role that is neither supplied nor defaulted is an error, and the message
names it — न्यूनाः प्राचलाः: कर्म — because with the order free, a
position would tell the reader nothing about which role is missing.
What gets checked. Pāṇini's rule that an action has one agent and one
patient is enforced: two कर्ता parameters, or two
कर्म, is an error. A label that names no declared role is an
error, and so is giving the same role twice. Word order is deliberately
not enforced — that is the whole point of marking the roles.
Softer observations come back as सूचनाः rather than errors: a
करणम् that is not a means, an अपादानम् that is not a
collection, a function with a कर्म that returns nothing.
१०
अर्थविश्लेषकःThe semantic analyser
Before anything runs, the analyser walks the syntax tree and reports what it
can prove wrong: undefined names, type mismatches, assignments to constants,
wrong argument counts, विरम outside a loop, kāraka violations,
unreachable code, a declared return type some path does not satisfy.
$ ./वाक्.exe --परीक्षा प्रोग्राम.vak
अर्थदोषः (Semantic Analysis) — 2 दोषाः, 0 सूचनाः
दोषः [ध्रुवदोषः] प्रोग्राम.vak:6 — ध्रुवः 'सीमा' न परिवर्तनीयः / cannot reassign the constant 'सीमा'
6 | सीमा = ११।
दोषः [नामदोषः] प्रोग्राम.vak:7 — अपरिभाषितम् नाम 'अज्ञातम्' / undefined name 'अज्ञातम्'
7 | मुद्रय बाह्यम्(), अज्ञातम्।Every message is bilingual, and every diagnostic carries a Sanskrit code —
नामदोषः, प्रकारदोषः, कारकदोषः,
ध्रुवदोषः, प्राचलदोषः, प्रवाहदोषः. Errors
stop the program; सूचनाः are advice and do not.
The analyser exists twice: once in Python and once written in Vāk itself. The two are compared on sixty-five files — every example, the standard library, forty deliberately broken programs, and the toolchain's own source — and must produce identical diagnostics, in the same order, with the same wording.
११
दोषनिग्रहःExceptions
प्रयत्नः is the attempt, दोषे the locative — “in
the event of an error” — and अन्ततः what happens at the end
regardless. उत्सृज throws.
प्रयत्नः {
यदि (हरः == ०) {
उत्सृज { "प्रकारः": "गणितदोषः", "सन्देशः": "शून्येन भागः" }।
}
मुद्रय अंशः / हरः।
} दोषे (द) {
मुद्रय "दोषः प्राप्तः:", द.प्रकारः, "—", द.सन्देशः।
} अन्ततः {
मुद्रय "समाप्तम्"।
}The caught value is an ordinary कोशः carrying at least
प्रकारः and सन्देशः. Runtime failures from the
language itself arrive in the same shape, so one handler catches both.
१२
प्रदानम्Reading from the user
पठ reads one line from the user and hands it back as a
शब्दः. Give it an argument and that is printed first, as a
prompt.
शब्दः नाम = पठ("नाम किम्? ")।
मुद्रय "नमस्ते,", नाम + "!"।
पूर्णाङ्कः वयः = संख्या(पठ("वयः? "))।
मुद्रय "आगामिवर्षे भवतः वयः", वयः + १, "भविष्यति।"।What comes back is always text, even when it looks like a number, so wrap it
in संख्या when you want arithmetic. A line that cannot be read as a
number raises a catchable कार्यकालदोषः:
प्रयत्नः {
पूर्णाङ्कः क = संख्या(पठ("अङ्कम् लिखतु: "))।
मुद्रय "वर्गः:", क * क।
} दोषे (द) {
मुद्रय "सः अङ्कः न आसीत् —", द.सन्देशः।
}At the end of input पठ returns the empty string rather
than failing, in every engine. So a program that reads until there is nothing
left tests for it:
यावत् (सत्य) { शब्दः पं = पठ()। यदि (दीर्घता(पं) == ०) { विरम। } … }
That does mean an empty line and the end of input look alike. If you need to tell them apart, read the whole of standard input another way.
In the playground there is no terminal to type
into, so the box under the editor is what पठ reads — one line per
call.
१३
आनयModules and files
आनय — bring — imports. A module is any
.vak file; whatever it declares at the top level is what it
exports.
आनय "गणितम्"। # गणितम्.वर्गः(...)
आनय "गणितम्" इति ग। # ग.वर्गः(...)
आनय "गणितम्" तः वर्गः, क्रमगुणितम्। # वर्गः(...)Modules run once and are cached; a circular import is reported rather than hung on. Files are read and written with the built-ins:
शब्दः विषयम् = सञ्चिकापठ("काव्यम्.txt")।
सञ्चिकालिख("फलम्.txt", विषयम्)।
यदि (सञ्चिकास्ति("फलम्.txt")) { मुद्रय निर्देशिका(".")। }१४
पुस्तकालयःThe standard library
Two modules ship with Vāk, and both are written in Vāk — they are
ordinary .vak files you can read, and a fair sample of what the
language looks like in use. Bring one in with आनय:
आनय "गणितम्"।
मुद्रय गणितम्.क्रमगुणितम्(५)। # १२०
आनय "शब्दाः" तः विलोमः_वा।
मुद्रय विलोमः_वा("नयन")। # सत्यEvery signature below is printed from the module's own source, so it is exactly what the file declares — including the kāraka role each parameter takes.
आनय "गणितम्"। Mathematics — two constants and sixteen functions.
| गणितम् | what it does |
|---|---|
दशांशः पाई | π, to fifteen places |
दशांशः ई | e, the base of the natural logarithm |
वर्गः(अङ्कः क) : अङ्कः | क squared |
घनः(अङ्कः क) : अङ्कः | क cubed |
निरपेक्षम्(अङ्कः क) : अङ्कः | the absolute value of क |
चिह्नम्(अङ्कः क) : पूर्णाङ्कः | the sign of क — १, ०, or -१ |
क्रमगुणितम्(पूर्णाङ्कः न्) : पूर्णाङ्कः | न् factorial |
वर्गमूलम्(अङ्कः क) : दशांशः | the square root of क, by Newton's method |
मसाभा(पूर्णाङ्कः अ, पूर्णाङ्कः ब) : पूर्णाङ्कः | the greatest common divisor of अ and ब |
लसागु(पूर्णाङ्कः अ, पूर्णाङ्कः ब) : पूर्णाङ्कः | the least common multiple of अ and ब |
अभाज्यः_वा(पूर्णाङ्कः न्) : सत्यता | whether न् is prime |
अभाज्याः_यावत्(पूर्णाङ्कः सीमा) : सूची | every prime up to सीमा, as a list |
माध्यम्(अपादानम् सूची अङ्काः) : अङ्कः | the arithmetic mean of the list |
मध्यमा(अपादानम् सूची अङ्काः) : अङ्कः | the median of the list |
घातः(अङ्कः आधारः, पूर्णाङ्कः घाताङ्कः) : अङ्कः | आधारः raised to the power घाताङ्कः |
बहुलकः(अपादानम् सूची अङ्काः) : अङ्कः | the most frequent value; the smaller one when two tie |
विचरणम्(अपादानम् सूची अङ्काः) : दशांशः | the population variance — the mean squared deviation |
प्रमाणविचलनम्(अपादानम् सूची अङ्काः) : दशांशः | the population standard deviation |
आनय "शब्दाः"। Strings — thirteen functions over शब्दः.
| शब्दाः | what it does |
|---|---|
आदौ_अस्ति(अधिकरणम् शब्दः पूर्णः, कर्म शब्दः आदिः) : सत्यता | whether पूर्णः begins with आदिः |
अन्ते_अस्ति(अधिकरणम् शब्दः पूर्णः, कर्म शब्दः अन्तः_) : सत्यता | whether पूर्णः ends with अन्तः_ |
पुनरावृत्तिः(कर्म शब्दः स, पूर्णाङ्कः वारम्) : शब्दः | स repeated वारम् times |
पूरय(कर्म शब्दः स, पूर्णाङ्कः दैर्घ्यम्, शब्दः अक्षरम्) : शब्दः | स padded with अक्षरम् until it reaches दैर्घ्यम् |
अक्षरसूची(कर्म शब्दः स) : सूची | स as a list of its characters |
विलोमः_वा(कर्म शब्दः स) : सत्यता | whether स reads the same in both directions |
गणय_अक्षरम्(कर्म शब्दः अक्षरम्, अधिकरणम् शब्दः वाक्यम्) : पूर्णाङ्कः | how many times अक्षरम् occurs in वाक्यम् |
शब्दगणना(अधिकरणम् शब्दः वाक्यम्) : कोशः | a dictionary of each word in वाक्यम् and its count |
रिक्तम्_वा(कर्म शब्दः अ) : सत्यता | whether अ is a space, tab, newline or carriage return |
आदौ_छिन्द(कर्म शब्दः स) : शब्दः | स with leading whitespace removed |
अन्ते_छिन्द(कर्म शब्दः स) : शब्दः | स with trailing whitespace removed |
छिन्द(कर्म शब्दः स) : शब्दः | स with whitespace removed from both ends |
प्रतिस्थापय(अधिकरणम् शब्दः वाक्यम्, कर्म शब्दः पुरातनम्, करणम् शब्दः नूतनम्) : शब्दः | वाक्यम् with every पुरातनम् replaced by नूतनम् |
१५
यन्त्रम्How Vāk runs
The point of the project is a language that does not depend on a host language.
A Vāk program can be executed by any of five engines, and all five are held to byte-identical output on every example:
- The tree-walking interpreter, in Python — the reference, the definition of what a program means.
- The SanskritVM, in Python — a stack machine over bytecode whose every instruction has a Sanskrit name.
- The SanskritVM written in Vāk — the machine's semantics, expressed in the language it runs.
- The SanskritVM in C — the native runtime, ~2,600 lines.
- वाक्.exe — the whole Vāk-written toolchain compiled natively. No Python anywhere.
The front end is entirely self-hosted. Lexer, parser, analyser, compiler and virtual machine all exist written in Vāk, and each is checked against its Python counterpart at the finest granularity that stage allows — the lexer on every token's kind, lexeme, value and line; the parser on the whole syntax tree node for node; the analyser on every diagnostic's code, line and wording; the compiler on every instruction, constant and line number.
python -m vaak --self प्रोग्राम.vak # compiled by Vāk, run on the Python VM
python -m vaak --self-vm प्रोग्राम.vak # lexed, parsed, compiled AND run by Vāk
python -m vaak --native प्रोग्राम.vak # a standalone executable (needs gcc)
python -m vaak --bytecode प्रोग्राम.vak # disassemblePython is used to build वाक्.exe once, exactly as a C compiler is
used once to build a self-hosting C compiler. After that the language stands on
its own.
Where it runs. The Python implementation is portable as it stands.
The native runtime is C11; the few places that need the operating system —
the command line, opening a file by a Devanagari path, listing a directory —
have both a Windows branch and a POSIX one, chosen by a single switch that
every file shares. Building with VAK_POSIX=1 forces the POSIX
branch, so the code Linux and macOS will run can be exercised anywhere.
And it runs in a browser: the same C machine, compiled to WebAssembly, is what the playground executes. Nothing is sent anywhere — the lexer, parser, analyser, compiler and VM are all in the page.
१६
दोषसूचीEvery diagnostic
The analyser reports 6 kinds of error and 6 kinds of warning. A दोषः stops the program from running; a सूचना is printed and the program runs anyway. Every one carries its Sanskrit name, so a message can be looked up here.
| सङ्केतः | kind | what it means |
|---|---|---|
कारकदोषः | दोषः | a kāraka role is repeated — Pāṇini allows one agent and one patient |
ध्रुवदोषः | दोषः | an assignment to a ध्रुव constant |
नामदोषः | दोषः | a name is used that was never declared |
प्रकारदोषः | दोषः | a value does not match the declared प्रकारः |
प्रवाहदोषः | दोषः | विरम or अनुवर्तस्व outside a loop |
प्राचलदोषः | दोषः | a call passes the wrong number of arguments |
अगम्यदोषः | सूचना | a statement after प्रत्यागच्छ that can never run |
अप्रयुक्तसूचना | सूचना | a variable declared and never read — a leading underscore says it is deliberate |
कारकसूचना | सूचना | some parameters carry kāraka roles and some do not |
पुनर्घोषणा | सूचना | a name declared twice in the same scope |
प्रतिफलसूचना | सूचना | a function promises a return type but has a path that returns nothing |
प्रवाहसूचना | सूचना | a विकल्पः with no अन्यथा — an unmatched value does nothing |
Separately, an error caught by दोषे carries its kind in
प्रकारः. These are the 4 values it can
hold:
| प्रकारः | raised by |
|---|---|
दोषः | Error |
अक्षरदोषः | Lexical Error |
व्याकरणदोषः | Syntax Error |
कार्यकालदोषः | Runtime Error |
प्रयत्नः {
मुद्रय संख्या("न अङ्कः")।
} दोषे (त्रुटिः) {
यदि (त्रुटिः.प्रकारः == "कार्यकालदोषः") {
मुद्रय "गणने दोषः / a runtime error"।
}
}Each one, happening
A list of diagnostics teaches less than watching one fire. Below is the shortest program that provokes each, and the message the analyser actually gives — both taken from the test suite and regenerated whenever this page is built, so a reworded message changes here too.
अगम्यदोषः
कार्यम् क() : पूर्णाङ्कः { प्रत्यागच्छ १। मुद्रय "अगम्यम्"। }
मुद्रय क()।
इदम् वाक्यम् कदापि न चलति / unreachable code after Return on line 1
अप्रयुक्तसूचना
कार्यम् क() { मान अ = ५। मुद्रय "अ इति न प्रयुक्तम्"। }
क()।
'अ' घोषितम् किन्तु न प्रयुक्तम् / 'अ' is declared but never used
कारकदोषः
कार्यम् क(अ) { मुद्रय अ। }
क(कर्म: १)।
क: कर्म इति कारकम् नास्ति / declares no कर्म parameter
कारकसूचना
कार्यम् क(कर्ता अ, ब) { मुद्रय अ। }
क: केचन प्राचलाः कारकयुक्ताः, केचन न / only 1 of 2 parameters carry a कारकम्
ध्रुवदोषः
ध्रुव क = ५। क = ६।
ध्रुवः 'क' न परिवर्तनीयः / cannot reassign the constant 'क'
नामदोषः
अज्ञातम् = ५।
अपरिभाषितम् नाम 'अज्ञातम्' — प्रथमम् 'मान' इति उपयुज्यताम् / undefined name 'अज्ञातम्'
पुनर्घोषणा
मान क = १। मान क = २।
'क' अस्मिन् एव परिवेशे पुनः घोष्यते / 'क' is redeclared in the same scope
प्रकारदोषः
मुद्रय -"अ"।
'-' अङ्कम् इच्छति, शब्दः दत्तः / unary '-' needs a number, got शब्दः
प्रतिफलसूचना
कार्यम् क(अ) : पूर्णाङ्कः { यदि (अ) { प्रत्यागच्छ १। } }
क: पूर्णाङ्कः इति प्रतिज्ञातम्, किन्तु मार्गः अस्ति यत्र किमपि न प्रत्यागच्छति / declared पूर्णाङ्कः but some path returns nothing
प्रवाहदोषः
विरम।
'विरम' पाशस्य बहिः / 'विरम' outside a loop
प्रवाहसूचना
मान क = १।
विकल्पः (क) {
पक्षे १: मुद्रय "अ"। मुद्रय अज्ञातम्।
पक्षे २: विरम।
}
विकल्पे 'अन्यथा' नास्ति — अमिलितः विषयः किमपि न करोति / no अन्यथा, so a subject that matches nothing does nothing
प्राचलदोषः
मुद्रय दीर्घता(१, २, ३)।
दीर्घता: 1 प्राचलाः अपेक्षिताः, 3 दत्ताः / expected 1 argument(s), got 3
१७
पदकोशःEvery keyword
Each keyword may be written in Devanagari, in IAST transliteration, or in plain ASCII. They are the same word — the lexer holds all three spellings, so 28 keywords are what there is to learn.
Where a cell lists two Devanagari words joined by ·, they are
synonyms for the identical token, not different keywords:
दोषे and गृहाण both begin a catch block. 10
constructs have such a pair.
| देवनागरी | IAST · ASCII | meaning |
|---|---|---|
मान | māna · mana | declare a variable |
ध्रुव | dhruva | declare a constant |
कार्यम् · कार्य | kāryam · kārya · karyam · karya | define a function |
प्रत्यागच्छ · प्रतिदा | pratyāgaccha · pratidā · pratyagaccha · pratida | return from a function |
मुद्रय | mudraya | |
यदि | yadi | if |
अन्यथा | anyathā · anyatha | else |
यावत् · यावत | yāvat · yavat | while |
आवृत्तिः · आवृत्ति | āvṛttiḥ · avrttih | repeat a fixed number of times |
प्रत्येकम् · प्रत्येकम | pratyekam | for each |
विकल्पः · विकल्प | vikalpaḥ · vikalpah | choose among alternatives |
पक्षे | pakṣe · pakshe | in this case |
अन्तः | antaḥ · antah | of the collection |
विरम | virama | leave the loop |
अनुवर्त | anuvarta | next turn of the loop |
प्रयत्नः · प्रयत्न | prayatnaḥ · prayatnah | attempt |
दोषे · गृहाण | doṣe · gṛhāṇa · doshe · grihana | in the event of an error |
अन्ततः · अन्ते | antataḥ · antatah | at the end, regardless |
उत्सृज · क्षिप | utsṛja · kṣipa · utsrja · kshipa | throw |
आनय | ānaya · anaya | import |
इति | iti | under the name |
तः | taḥ · tah | taking from |
सत्य | satya | true |
असत्य | asatya | false |
शून्य | śūnya · shunya · sunya | nothing |
च | ca | and |
वा | vā · va | or |
न | na | not |
१८
अन्तर्निहितानिThe 48 built-ins
Available everywhere without an import. Two more —
गणितम् and शब्दाः — are libraries written in Vāk and
brought in with आनय.
| नाम | roman | what it does |
|---|---|---|
लिख | likh | मुद्रयति / print values |
दोषलिख | doshalikh | दोषप्रवाहे मुद्रयति / print to the error stream |
प्रतिच्छेदः | pratichchhedah | कणशः संयोगः / bitwise and |
संयोगः | samyogah | कणशः विकल्पः / bitwise or |
वियोगः | viyogah | कणशः भेदः / bitwise exclusive or |
पूरकः | purakah | कणशः निषेधः / bitwise not |
वामसारः | vamasarah | वामतः सारणम् / shift left |
दक्षिणसारः | dakshinasarah | दक्षिणतः सारणम् / shift right |
पठ | patha | उपयोक्तुः पङ्क्तिम् पठति / read a line |
प्रकार | prakara | मूल्यस्य प्रकारः / type of a value |
संख्या | sankhya | अङ्कः करोति / convert to number |
शब्द | shabda | शब्दः करोति / convert to string |
देवनागरी | devanagari | देवनागरी-अङ्काः / Devanagari digits |
दीर्घता | dirghata | दीर्घता / length |
सूची | suchi | सूचीम् रचयति / build a list |
परास | parasa | अङ्कपरासः / numeric range |
योजय | yojaya | सूच्याम् योजयति / append |
निष्कास | nishkasa | अपनयति / remove an item |
अस्ति | asti | अस्ति वा / membership test |
कुञ्जिकाः | kunjika | कोशस्य कुञ्जिकाः / keys of a dict |
मूल्यानि | mulyani | कोशस्य मूल्यानि / values of a dict |
क्रम | krama | क्रमबद्धा सूची / sorted copy |
विपर्यय | viparyaya | विपरीतक्रमः / reversed |
अक्षराणि | aksharani | शब्दस्य अक्षराणि / syllables of a string |
संकेतः | sanketa | अक्षरस्य संकेतः / code point of a character |
वर्णः | varna | संकेतस्य वर्णः / character for a code point |
अंशः | amsha | शब्दस्य सूच्याः वा अंशः / a slice |
विभज | vibhaja | शब्दम् विभजति / split a string |
संयोज | samyoja | सूचीम् संयोजयति / join a list |
योग | yoga | योगफलम् / sum |
न्यूनतम | nyunatama | न्यूनतमम् / minimum |
अधिकतम | adhikatama | अधिकतमम् / maximum |
मूल | mula | वर्गमूलम् / square root |
पूर्ण | purna | पूर्णाङ्कः / truncate to integer |
यादृच्छिक | yadrcchika | यादृच्छिकः अङ्कः / random number |
काल | kala | कालः / current time in seconds |
प्राचलाः | prachalah | आदेशपङ्क्त्याः प्राचलाः / command-line arguments |
प्रयुज् | prayuj | कार्यम् सूच्या कोशेन वा प्रयुङ्क्ते / apply a function to computed arguments |
लक्षणम् | lakshanam | कार्यस्य प्राचलाः कारकाणि च / a function's parameters and their roles |
खण्डम्_चालय | khandam_chalaya | संकलितम् खण्डम् चालयति / run a compiled chunk |
दोष | dosha | दोषम् उत्पादयति / raise an error |
सञ्चिकापठ | sanchikapatha | सञ्चिकाम् पठति / read a whole file |
सञ्चिकापङ्क्तयः | sanchikapanktayah | सञ्चिकायाः पङ्क्तयः / read a file as lines |
सञ्चिकालिख | sanchikalikh | सञ्चिकाम् लिखति / write a file |
सञ्चिकायोजय | sanchikayojaya | सञ्चिकायाम् योजयति / append to a file |
सञ्चिकास्ति | sanchikasti | सञ्चिका विद्यते वा / does the path exist |
सञ्चिकानाशय | sanchikanashaya | सञ्चिकाम् नाशयति / delete a file |
निर्देशिका | nirdeshika | निर्देशिकायाः सूची / list a directory |