SNlang is a programming language created from scratch by Asish Kumar Sharma. I took on the challenge of creating a programming language from scratch in just 7 days, and this is what I finally accomplished - completing it in just 5 days, which was fun to learn!
SNlang holds the distinction of being the first programming language created in India to be built entirely from scratch in ARM64 assembly, natively targeting Apple Silicon (macOS ARM64). It was designed, implemented, and completed solely by Asish Kumar Sharma in 5 days.
The core motive behind SNlang is to make programming natively fast while remaining incredibly simple to write. It was born out of a desire to eliminate repetitive boilerplate code and unnecessary syntax, like the semicolon (;), when they aren't actually needed.
SNlang is designed to give you:
- The speed and structuring of C (but better looking and easier to use).
- The simplicity of Golang.
- The feel and readability of Python.
- Zero boilerplate, removing the verbose overhead of Java (like
Class obj = new Class();).
To achieve this clarity, SNlang strips away confusing and misleading legacy keywords:
classis replaced withblueprint.extendsis replaced withfrom.- Pointers don't use confusing
*syntax; they use a readableref<T>approach. - Cumbersome input methods like
scanforSystem.inare replaced with a simpleinput(). - Function return types use a clear arrow syntax, like
-> intor-> str, making the code actually readable.
It is a natively compiled language that is fast enough to be broadly used, providing the raw performance of native execution without sacrificing the developer experience.
snc is a small programming language compiler written in ARM64 assembly.
It reads .sn source code and emits ARM64 assembly that can be assembled with clang.
The source includes a platform macro layer for ARM64 Mach-O output and is currently validated for:
- macOS on ARM64
The compiler is split by responsibility:
src/main.s- entry point, argument handling, source file loadingsrc/lexer.s- cursor movement, whitespace, and comment skippingsrc/parser.s- statements, expressions, conditions, and blockssrc/vars.s- variable storage, constants, assignment, and print recordssrc/codegen.s- generated ARM64 assembly outputsrc/utils.s- string matching, error reporting, and write helperssrc/data.s- shared messages, keywords, buffers, and compiler state
The old single-file version is archived at archive/snc.monolith.s.
Today, SNlang is a compiled language with a working core for:
- typed variables and constants
All critical infrastructure is complete and functional:
Core Language Features:
- typed variables and constants
- Arithmetic and comparisons
- Control flow (
if,while,for,for in) - Function definitions, parameters, returns
- String methods (
.length(),.slice(),.contains(),.replace(),.split(),.upper(),.lower()) - Collections (
list<T>,map<K, V>) - Error handling (
try/catch,throw) - Pointers (
ref<T>,alloc(),free()) - Pattern matching (
match)
Module System:
- Module imports and exports (
use module) - Module qualified access (
module.func()) - Selective imports (
use module only func1, func2) - Cross-file function calls
- Module search paths
Performance:
- Benchmark: 829ms for 100M iterations (comparable to C without optimization)
- Native ARM64 assembly generation
- No garbage collector - manual memory management
brew tap asish231/snlang
brew install snlang fn main() {
int a = 10
int b = 4
int total = a + b * 3
print(total)
print(total - 2)
print((a + b) * 3)
bool ready = true
str name = "Asish"
str greeting = "Hello {name}!" // String interpolation
print(greeting)
if (total >= 20) {
print(1)
} else {
print(0)
}
}
SNlang supports basic module imports:
use math
use utils.string
fn main() {
print("Modules loaded successfully")
}
Current module system status:
use module.pathsyntax parsing- Single and multiple module imports work
- Dotted module paths
- Module file loading and parsing
- Imported functions callable from importing file
- Duplicate
usehandled safely - Module search paths (
.andstdlibby default) - Function index adjustment for imported modules
- Function body emission
- Qualified access (
module.func()) - Selective imports (
use module only func1, func2)
Embed variables and expressions in strings:
fn main() {
str name = "World"
int count = 42
str msg = "Hello {name}! Count: {count}"
print(msg) // Prints: Hello World! Count: 42
}
Supported today:
fn main() { ... }int name = expressionlet name = expression;legacy syntaxprint(expression)printn(expression)(print without newline)print expression;legacy syntax- integer numbers
- variables
- arithmetic with
+,-,*,/, and% - parentheses for grouped expressions
- comparisons with
==,!=,>,<,>=, and<= if (...) { ... } else { ... }else if (...) { ... }while (...) { ... }- counted
for (...) { ... } for (item in list) { ... }stopskipbool,true, andfalsebytestrstring variablesconst strdec(X)declarations and decimal arithmetic paths- string literals in
print(...) input("prompt")forstrdeclarations/assignments (first-cut runtime path)use module.pathsyntax (basic module loading)- string interpolation with
"Hello {name}!" match (...) { ... default { ... } }- runtime slots for
int/booldeclarations and assignments - runtime slots for decimal values
- runtime
print(var)loads forint/bool - runtime arithmetic for
print(var op number)whereopis+ - * / % - runtime arithmetic for
x = x op numberwhereopis+ - * / % - runtime arithmetic for
print(var op var)whereopis+ - * / % - runtime arithmetic for
x = x op varwhereopis+ - * / % - runtime target assignments like
out = x + yandout = x + 7 - compound assignments
+=,-=,*=,/=, and%=for supported types - exponent with
** const intandconst bool- reassignment with
= - functions with parameters and return values
- nested and forward function calls
- partial
list<T>literals andfor initeration none, nullable?declarations, andotherwise- default parameters
- logical
and,or, andnot - pointers (
ref<T>), memory allocation (alloc(),free()), and dereferencing (value(),set()) // line comments/* block comments */
SNlang is now self-hosting capable in the practical sense that you can start
writing a compiler in SNlang today and bootstrap it with the current snc.
That means:
- language/runtime baseline is stable enough on macOS for compiler-work
- core module, map runtime store, cast, and slice paths are validated
SNlang provides a simple yet powerful object system inspired by Go and Java.
Define custom types with blueprint:
blueprint Point {
int x
int y
fn print() {
print("(" + self.x + ", " + self.y + ")")
}
}
| Type | Syntax | Variable Type |
|---|---|---|
| Heap | new Point p(x: 10, y: 20) |
ref<Point> |
| Stack | Point p(x: 10, y: 20) |
Point (value) |
new Point p(x: 10, y: 20) // Heap allocation
p.print() // Heap objects use . directly
Point q(x: 5, y: 15) // Stack allocation
q.print() // Same syntax, auto-cleanup
Define interfaces with contract, implement with follows:
contract Drawable {
fn draw()
}
blueprint Circle follows Drawable {
fn draw() { print("Drawing Circle") }
}
blueprint Square follows Drawable {
fn draw() { print("Drawing Square") }
}
Use from for single inheritance:
blueprint Animal {
str species
fn describe() { print("I am a " + self.species) }
}
blueprint Dog from Animal {
str breed
fn bark() { print("Woof!") }
}
| Modifier | Scope |
|---|---|
open |
Public (default) |
closed |
Private (blueprint only) |
guarded |
Protected (blueprint + children) |
Simple built-in concurrency primitives.
spawn {
for (i in 0..1000) {
print("Working: " + i)
}
}
print("Main continues immediately")
chan<int> numbers
spawn {
for (i in 0..10) {
numbers.send(i)
}
numbers.close()
}
spawn {
while (numbers.open) {
print("Received: " + numbers.receive())
}
}
lock counterLock
int counter = 0
fn increment() {
lock(counterLock) {
counter += 1
}
}
spawn increment()
spawn increment()
print(counter) // Output: 2
async fn fetchData(str url) -> str {
result = await httpGet(url)
return result
}
fn main() {
data = async fetchData("https://api.example.com")
print("Fetching...")
result = await data
print("Got: " + result)
}
blueprint Box<T> {
T value
fn get() -> T { return self.value }
}
new Box<int> intBox(value: 42)
new Box<str> strBox(value: "Hello")
print(intBox.get()) // 42
print(strBox.get()) // Hello
fn divide(int a, int b) -> int {
if (b == 0) {
throw("Division by zero")
}
return a / b
}
fn safeDivide() {
result = try divide(10, 0)
catch (e) {
print("Error: " + e)
return 0
}
return result
}
fn printName(&str name) { // Borrow
print(name)
}
fn consume(str s) { // Takes ownership
print(s)
}
fn main() {
str name = "Asish"
printName(&name) // Borrow: name still valid
move consume(name) // Move: ownership transferred
}
Write a .sn file, then run snc to emit ARM64 assembly.
Example:
fn main() {
int total = 0
for (i in [1, 2, 3, 4, 5]) {
if (i == 3) {
skip
}
if (i == 5) {
stop
}
total += i
}
print(total)
}
Compile it to assembly:
./snc your_file.sn > out.sThen assemble and link it with clang on an ARM64-capable setup:
clang out.s -o out
./outYou can also use the example programs in examples/ to probe features that already
exist, including:
examples/functions.snexamples/for_loop.snexamples/for_in_control.snexamples/function_scope_shadowing.snexamples/decimals.snexamples/test_combined.sn
Build the compiler:
makeOn PowerShell, you can also build without make:
./build.ps1Emit assembly for the example:
make runCompile and run the example program:
make exampleRun the current language checks:
make testCompile your own program:
./snc your_file.sn > /tmp/out.s
clang /tmp/out.s -o /tmp/out
/tmp/outOn Windows ARM64, the generated assembly now expects COFF/Windows-style symbol
resolution and printf naming automatically when the assembler target is
Windows.
SNlang produces native ARM64 machine code - no VM, no interpreter, just direct CPU instructions.
| Test | Time | Performance |
|---|---|---|
| 1M loop iterations | 0.4s | ~2.5M ops/sec |
| Compilation (typical file) | 4ms | ~250 files/sec |
- Native code: Compiles to ARM64 assembly → direct CPU execution
- No runtime: Uses standard C library (_printf, _malloc, _open)
- No GC overhead: Simple stack allocation, no garbage collector
- Tight loops: Compiled loops are direct CPU instructions
| Language | Relative Speed |
|---|---|
| C/C++/Rust/Go | 1x |
| SNlang | ~1x (native code) |
| JavaScript | ~20x slower |
| Python | ~100x slower |
For details on performance theory, see THEORY.md.
Built with ❤️ in ARM64 assembly by Asish Kumar Sharma