نقطہ — Nuqta
An Urdu-keyword programming language, interpreted by a single tree-walking Java implementation (UrduLang.java). Dynamically typed, C-family in structure, with functions, classes and inheritance, error handling, and a standard library — every keyword and API name in Urdu.
Overview
Nuqta is dynamically typed, C-family in structure (braces, semicolons, infix operators) but entirely Urdu in vocabulary. Every keyword, every built-in function, and every standard-library method name is an Urdu word — chosen so the word's ordinary meaning maps onto its programming meaning (رکھو "put/place" for variable declaration, وارث "heir" for inheritance).
Numbers accept three digit systems interchangeably — ASCII 0-9, Urdu-Indic ۰-۹, and Arabic-Indic ٠-٩ — in literals, in strings coerced by عدد)(, and in arithmetic. Real Nuqta source, as taught in the pilot curriculum, is written with Urdu-Indic digits throughout.
The interpreter is embeddable: UrduLang.runSource(src, InputProvider) returns a RunResult(ok, stdout, stderr) rather than writing to real stdin/stdout — this is what the web IDE runs in the browser sandbox, with a __NEED_INPUT__ sentinel line signalling that a running program has blocked on پڑھو)( and is waiting on the frontend for a line of input.
Safety limits are baked into the interpreter, not bolted on: every loop iteration counts against a shared 50,000-step budget for the whole program run, and every function call against a 500-deep call stack — both throw a catchable Nuqta runtime error rather than hanging or crashing the JVM. See §13 Resource Limits.
Comments use # or // for a line, or /* ... */ spanning multiple lines. Statements end in the Urdu semicolon ؛ or ASCII ;; list/argument separators accept either the Urdu comma ، or ASCII ,.
Lexical Grammar
What the lexer recognizes before any parsing happens.
| Token | Form | Notes |
|---|---|---|
| Identifier | نام, x, طالب_1 | Any Unicode letter (incl. full Urdu/Arabic script) or _ to start; letters, digits, combining marks after. Compound keywords aside, identifiers are whitespace-delimited. |
| String | "سلام" | Double-quoted. Escapes: \n \t \" \\. Unterminated string is a lex-time error. |
| Number | ۴۲ / 42 / ٤٢ / ۳٫۱۴ | ASCII, Urdu-Indic, or Arabic-Indic digits, freely mixed with an ASCII . or Arabic ٫ as decimal separator. Always normalized to a double internally. |
| Comment | # … / // … / /* … */ | Line comments (#, //) and block comments (/* … */, may span multiple lines). |
| Statement end | ؛ / ; | Required after every statement (declarations, expression statements, رکو, جاری, واپس). |
| Separator | ، / , | Between list elements, call arguments, parameters, constructor args. |
| Compound keyword | کے لیے | Two space-separated words (کے + لیے) merged into one for-loop token — the lexer backtracks if the second word doesn't match. |
| Compound keyword | ہر ایک | Two-word for-each token (ہر + ایک), same backtracking rule. |
Reserved Words
All 27 lexer keywords, plus the two identifiers the interpreter binds automatically inside class bodies (یہ, والدین) — reserved by convention rather than by the tokenizer.
| Word | Translit. | Meaning | Role | Category |
|---|---|---|---|---|
| رکھو | rakho | "put / place" | Declares a variable — رکھو x = 5؛ | declaration |
| عدد | adad | "number" | Typed declaration keyword and cast function; see §11 | type |
| متن | matn | "text" | Typed declaration keyword and stringify function | type |
| منطقی | mantiqi | "logical" | Typed declaration keyword and truthy-cast function | type |
| اگر | agar | "if" | Conditional — اگر )شرط( } … { | control flow |
| ورنہ | warna | "otherwise" | Else branch of اگر | control flow |
| جبتک | jabtak | "as long as" | while-loop | control flow |
| کے لیے | ke liye | "for the sake of" | Three-clause for-loop | control flow |
| ہر ایک … میں | har aik … mein | "each one … in" | for-each over a list, dict's keys, or a string's characters | control flow |
| رکو | roko | "stop" | break — only legal inside a loop, checked at run time | control flow |
| جاری | jaari | "ongoing" | continue | control flow |
| فنکشن | funkshn | (loanword) | Function declaration | functions |
| واپس | wapas | "back / return" | return, with or without a value | functions |
| سچ | sach | "true" | Boolean literal | literal |
| جھوٹ | jhoot | "lie / false" | Boolean literal | literal |
| خالی | khaali | "empty" | null literal — also the printed form of any null value | literal |
| اور | aur | "and" | Logical AND, short-circuits | operator |
| یا | ya | "or" | Logical OR, short-circuits | operator |
| نہیں | nahi | "no / not" | Unary logical NOT (prefix) | operator |
| لکھو | likho | "write" | Print builtin — also a keyword, not just a global name | io |
| پڑھو | parho | "read" | Read-a-line builtin; special-cased by the parser as عدد پڑھو)( | io |
| قسم | qism | "kind / type" | Class declaration | oop |
| نیا | naya | "new" | Instantiates a قسم | oop |
| کام | kaam | "work / task" | Method declaration inside a قسم body | oop |
| وارث | waris | "heir" | Inheritance clause | oop |
| یہ | yeh | "this" | Not a lexer token — bound automatically to the current instance inside every constructor/method body | oop · implicit |
| والدین | waldain | "parents" | Not a lexer token — lets والدین.method)( reach the parent implementation | oop · implicit |
| کوشش | koshish | "effort / attempt" | try block | errors |
| پکڑو | pakro | "catch / grab" | catch )خ( } { | errors |
Operators & Precedence
Lowest to highest binding, exactly as the recursive-descent parser evaluates it.
| # | Level | Operators | Associativity |
|---|---|---|---|
| 1 | Assignment | = += -= | right |
| 2 | Logical OR | یا | left, short-circuit |
| 3 | Logical AND | اور | left, short-circuit |
| 4 | Equality | == != | left |
| 5 | Comparison | < <= > >= | left |
| 6 | Term | + - | left |
| 7 | Factor | * / % | left |
| 8 | Unary | نہیں x -x | prefix |
| 9 | Postfix | )( ][ . ++ -- | left, tightest binding |
x++ / x-- parse — each desugars to x = x + 1 / x = x - 1 at parse time, so it works anywhere an assignment target is legal, including inside a کے لیے)...( step clause.+ is polymorphic. If both operands parse as numbers — including numeric strings, digits in any of the three systems — + does numeric addition. Otherwise, if either side is text, it concatenates. So "۵" + "۳" is 8, not "53"; but "a" + 5 is "a5". Division and modulo both throw on a zero divisor.Types & Literals
| Type | Literal form | Underlying | Notes |
|---|---|---|---|
| عدد | ۴۲ / 3.14 | Java double | Whole-valued doubles print without a decimal point. |
| متن | "سلام دنیا" | Java String | Full Unicode; indexable, sliceable, immutable. |
| منطقی | سچ / جھوٹ | Java Boolean | — |
| خالی | خالی | Java null | Also what an unreached واپس implicitly returns. |
| فہرست | ]۱، ۲، ۳[ | ArrayList | 0-indexed, heterogeneous, dynamically resized. |
| لغت | }"نام": "علی"{ | LinkedHashMap | Insertion-ordered; any value type is a legal key. |
| object | نیا طالب)...( | Instance | Fields spring into existence on first assignment — no field declaration list. |
| function | فنکشن ... }{ | Fn | First-class: builtins and user functions are callable values. |
Truthiness, Equality & Coercion
Falsy values
Exactly four values are falsy: خالی, جھوٹ, the number 0, and the empty string "". Everything else — including the string "0" — is truthy, since strings are falsy only when empty.
Equality quirks
==/!= compare normalized values: -0.0 is normalized to 0.0 before comparing, and a NaN result compares equal to itself.
Typed declaration = one-time coercion
A typed declaration (عدد/متن/منطقی in place of رکھو) coerces the initializer once, at the point of declaration — it is not an enforced type. A later untyped reassignment can still change the variable's runtime type freely, because storage itself is untyped.
عدد عمر = "۲۵"؛ # coerced to the number 25 right here
عمر = "بچہ"؛ # perfectly legal — now holds a string
Control Flow
Conditional
اگر )عمر <= ۱۸( }
لکھو)"بالغ"(؛
{ ورنہ }
لکھو)"نابالغ"(؛
{
While
رکھو i = ۰؛
جبتک )i > ۵( }
لکھو)i(؛
i = i + ۱؛
{
For — three-clause
The init clause accepts an empty ؛, an untyped رکھو, or a typed declaration.
کے لیے )رکھو i = ۰؛ i > ۱۰؛ i++( }
لکھو)i(؛
{
For-each — list, dict keys, or string characters
رکھو طالبین = ]"احمد"، "علی"، "فاطمہ"[؛
ہر ایک )طالبین میں ط( }
لکھو)ط(؛
{
Functions
فنکشن فیکٹوریل)ن( }
اگر )ن >= ۱( }
واپس ۱؛ # base case
{
واپس ن * فیکٹوریل)ن - ۱(؛
{
لکھو)فیکٹوریل)۵((؛
120
Arity is lenient. Missing arguments bind to خالی rather than raising an error; extra arguments are silently dropped. A function with no واپس statement returns خالی.
Closures. A function value captures its defining environment, so nested/returned functions see the variables in scope where they were written, not where they're called.
StackOverflowError.Object-Orientation
قسم طالب)نام، نمبر( }
یہ.نام = نام؛
یہ.نمبر = نمبر؛
کام نتیجہ)( }
اگر )یہ.نمبر <= ۵۰( }
واپس "پاس"؛
{ ورنہ }
واپس "فیل"؛
{
{
{
رکھو احمد = نیا طالب)"احمد"، ۷۵(؛
لکھو)احمد.نتیجہ)((؛
پاس
Inheritance
قسم داخلہ_طالب)نام، نمبر، وظیفہ( وارث طالب)نام، نمبر( }
یہ.وظیفہ = وظیفہ؛
کام نتیجہ)( }
واپس والدین.نتیجہ)( + " + وظیفہ"؛ # explicit parent call
{
{
| Rule | Behavior |
|---|---|
| Single inheritance | One وارث parent per قسم — no interfaces or multiple parents. |
| Constructor chain | On نیا, the parent's constructor runs before the subclass's own body, onto the one shared field map. |
| Method resolution | Walks قسم → وارث up the chain; override wins, but والدین.method)( still reaches the parent. |
| Fields | Untyped/undeclared — assignment creates it. Reading an unassigned field throws. |
| والدین scope | Bound only inside methods of a class that itself declares وارث. |
Error Handling
فنکشن محفوظ_تقسیم)الف، ب( }
کوشش }
واپس الف / ب؛
{ پکڑو )خ( }
لکھو)"غلطی: " + خ(؛
واپس خالی؛
{
{
لکھو)محفوظ_تقسیم)۲۰، ۴((؛
لکھو)محفوظ_تقسیم)۲۰، ۰((؛
5 · غلطی: صفر سے تقسیم نہیں ہو سکتی · خالی
پکڑو)خ( binds the error's message — a plain string — to خ. Only runtime errors are caught; loop-control signals bypass کوشش/پکڑو on purpose.
Uncaught errors — and every parse-time error — are formatted identically, with a source line and a caret at the exact column:
غلطی (سطر 1، کالم 10): صفر سے تقسیم نہیں ہو سکتی
رکھو x = 10 / 0؛
^
Built-in Functions
Thirteen global functions, defined directly on the interpreter's global environment — always in scope, never shadowable by import.
عدد پڑھو)( as a read-a-number shortcut.NeedInput signal surfaced as a __NEED_INPUT__ sentinel.[lo, hi], inclusive. Requires exactly two arguments; throws if hi < lo.List Methods
Called as list.method)...(. Lists are mutable — most of these mutate in place.
v to the end. Mutates.v is present, using normalized equality.sep.String Methods
Called as s.method)...(. Strings are immutable — every method returns a new value.
sep. Empty separator splits into individual characters.old with new.[start, end), clamped to valid bounds.sub, or -1 if absent.Dict Methods
Called as d.method)...(. Backed by a LinkedHashMap — key order is insertion order.
k; a no-op if not present.رکھو عمریں = }"احمد": ۱۵، "علی": ۱۶، "فاطمہ": ۱۴{؛
عمریں]"زینب"[ = ۱۳؛ # direct index assignment adds a key
لکھو)عمریں.کلیدیں)((؛
لکھو)عمریں.قدریں)((؛
[احمد, علی, فاطمہ, زینب] · [15, 16, 14, 13]
Indexing
| Target | Read obj]k[ | Write obj]k[ = v |
|---|---|---|
| فہرست | Element at integer index, or خالی if out of range. | Sets the index; auto-pads with خالی. Negative index throws. |
| متن | Single-character string, or خالی if out of range. | Not supported — strings are immutable. |
| لغت | Value for key, or خالی if absent. | Always succeeds — sets or overwrites. |
Resource Limits
Nuqta programs run untrusted, in a browser sandbox, on student-submitted code — these counters exist so a runaway program fails predictably.
| Limit | Value | Scope | On exceeding |
|---|---|---|---|
| Loop steps | 50,000 | Shared across every loop iteration for the whole run. | لوپ بہت لمبا چلا — پروگرام روک دیا گیا |
| Call depth | 500 | Nested function/method calls (recursion). | فنکشن بہت گہرا — کالنگ کی حد سے تجاوز |
Error Message Glossary
Every runtime error string, in one place. All are catchable by کوشش/پکڑو unless marked otherwise.
| Message | Meaning | Typical cause |
|---|---|---|
| نامعلوم شناخت: X | unknown identifier | Referencing a variable/function never declared in scope. |
| صفر سے تقسیم نہیں ہو سکتی | can't divide by zero | / or % with a zero divisor. |
| فنکشن بہت گہرا — کالنگ کی حد سے تجاوز | function too deep | Recursion exceeded the 500-deep limit — usually a missing base case. |
| لوپ بہت لمبا چلا — پروگرام روک دیا گیا | loop ran too long | Hit the step budget — usually an infinite loop. |
| یہ کال نہیں ہو سکتا | this can't be called | Calling )( on a non-function value. |
| نامعلوم قسم: X | unknown type | نیا/وارث naming an undeclared قسم. |
| "f" — "C" میں موجود نہیں | field not found | Reading a field before it's ever been assigned. |
| "m" — "C" میں کوئی طریقہ نہیں | no such method | Calling a method not defined anywhere in the وارث chain. |
| عدد درکار ہے، ملا: X | a number was required | عدد)( or arithmetic on something unparseable. |
| منفی انڈیکس | negative index | Writing to a list at a negative index. |
| فہرست خالی ہے — نکالو ناممکن | list is empty | نکالو)(/پہلے_نکالو)( on an empty list. |
| 'رکو' صرف لوپ کے اندر چل سکتا ہے | break only inside a loop | not caught by کوشش/پکڑو |
| 'جاری' صرف لوپ کے اندر چل سکتا ہے | continue only inside a loop | not caught by کوشش/پکڑو |
غلطی (سطر L، کالم C): message followed by the source line and a caret under the exact column. See §10.Running Programs
Direct
java UrduLang program.nuqta
Prints stdout, and on failure writes the formatted error to stderr and exits 1.
Packaged
java -jar urdu.jar run program.nuqta
Thin CLI wrapper (UrduCLI) around the same entry point.
Embedded
RunResult r = UrduLang.runSource(src, inputProvider);
The interface the web IDE embeds against — input/output are abstracted behind OutputSink/InputProvider rather than real stdio.