Klik tombol di atas, lalu pilih "Save as PDF" pada dialog print
Path Object Notation (PON) adalah sebuah format data terstruktur yang dirancang untuk menjadi sederhana, ekspresif, dan human-friendly. PON menggabungkan kemudahan penulisan dengan kekuatan type safety dan default values yang terintegrasi.
PON lahir dari kebutuhan akan format data yang dapat:
💡 Inti PON dalam satu baris:
/path:type = value;
Sederhana, namun mampu merepresentasikan struktur data yang sangat kompleks.
PON dirancang dan dikembangkan pertama kali oleh Muhammad Arif Budianto sebagai solusi atas keterbatasan format data yang ada. Perjalanan pengembangan PON didasari oleh pengalaman panjang dalam bekerja dengan berbagai format data di berbagai proyek.
| Format | Masalah Utama | Dampak |
|---|---|---|
| XML | Terlalu verbose, tag berulang, ukuran file besar | Sulit dibaca, mahal untuk transfer data |
| JSON | Tidak ada tipe data eksplisit, array 1 elemen ambigu | Kesalahan parsing, boilerplate validasi |
| YAML | Bergantung pada indentasi yang rawan error | Sering terjadi kesalahan konfigurasi |
| CSV | Tidak support hierarki, tidak ada tipe data | Tidak cocok untuk data kompleks |
| Table Data | Hanya untuk data tabular, tidak fleksibel | Sulit untuk data yang tidak seragam |
Dari pengalaman inilah Muhammad Arif Budianto merancang PON sebagai format data yang menjawab semua masalah tersebut dengan pendekatan yang sederhana namun powerful.
"Menjadi format data pelengkap yang memudahkan developer dalam menulis, membaca, dan memahami data terstruktur."
Penulisan data terstruktur tanpa alat bantu
Pembacaan data kompleks dengan jelas
Data hierarkis dan tabular dalam satu format
⚠️ PENTING UNTUK DIPAHAMI:
PON dibuat BUKAN untuk menggantikan format data modern yang sudah ada seperti XML, JSON, YAML, CSV, atau format lainnya.
"Kami tidak datang untuk menggantikan, kami datang untuk melengkapi. Setiap format memiliki keunggulannya masing-masing. PON hadir sebagai pilihan tambahan ketika Anda menginginkan kesederhanaan, kejelasan, dan kemudahan tanpa mengorbankan kekuatan."
— Muhammad Arif Budianto, Perancang PON
PON dibangun di atas empat pilar filosofi yang menjadi landasan setiap keputusan desain:
| Pilar | Makna | Implementasi |
|---|---|---|
| 🎯 Sederhana | Sintaks minimalis, tidak berlebihan | Hanya 9 simbol dasar, 1 format utama: /path:type = value; |
| 🔍 Eksplisit | Tipe data dan path jelas terlihat | :type dan /path selalu eksplisit di setiap level |
| 🔄 Konsisten | Satu cara untuk satu tujuan | Aturan yang sama untuk semua level hierarki |
| 👤 Human-Friendly | Mudah dibaca dan ditulis manusia | Sintaks natural, error messages jelas, self-documenting |
Sintaks minimalis tanpa kurung kurawal berlebihan.
Cukup /path:type = value;
Hierarki jelas dengan path, tipe data eksplisit, dan format yang natural.
20+ tipe data dengan alias, menghindari ambiguitas seperti di JSON/XML.
Nilai default terintegrasi, mengurangi boilerplate code untuk validasi data.
Support array 1D, 2D, multidimensi, dan jagged dengan sintaks yang natural.
Dapat dikonversi ke XML, JSON, CSV, YAML, dan format lainnya dengan mudah.
Struktur dan tipe data terlihat jelas dari formatnya, tanpa dokumentasi terpisah.
Ukuran file 70-90% lebih kecil dari XML, parsing lebih cepat.
| Simbol | Nama | Fungsi | Contoh |
|---|---|---|---|
/ |
Path | Hierarki data | /root/user |
@ |
Atribut | Metadata | /user/@id |
: |
Tipe Data | Type annotation | :string, :int |
[] |
Array | Koleksi data | :int[], :float[2,3] |
() |
Non-Array | Object | (nama:string) |
, |
Separator | Pemisah nilai | 1,2,3 |
; |
Terminator | Akhir statement | value; |
# |
Komentar | Dokumentasi | # komentar |
= |
Assignment | Memberi nilai | = "Budi" |
; (terminator). Ini memudahkan parsing dan mencegah ambiguitas.
# Format dasar PON /path:type = value; # Contoh-contoh /nama:string = "Budi Santoso"; /umur:int = 25; /aktif:bool = true; /gaji:decimal = 15000000.50; /tanggal_lahir:date = "1990-05-15";
PON memiliki 24 tipe data yang mencakup berbagai kebutuhan:
| Kategori | Tipe | Alias | Contoh |
|---|---|---|---|
| Boolean | bool |
boolean |
true, false |
char |
wchar, char16 |
'A', '\u0041;' |
|
| String | string |
- | "Hello World" |
| DateTime | datetime |
- | "2024-01-15T14:30:00Z" |
date |
- | "2024-01-15" |
|
time |
- | "14:30:00" |
|
unixtime |
- | 1705314600 |
|
| Variant | object |
variant, any |
"string" atau 123 atau true |
| Integer | byte |
sbyte, int8, i8 |
100 (-128 sd 127) |
ubyte |
uint8, u8 |
200 (0 sd 255) |
|
short |
int16, i16 |
1000 (-32768 sd 32767) |
|
ushort |
uint16, u16 |
50000 (0 sd 65535) |
|
integer |
int, int32, i32 |
100000 (-2^31 sd 2^31-1) |
|
uinteger |
uint, uint32, u32 |
3000000000 (0 sd 2^32-1) |
|
long |
int64, i64 |
10000000000 (-2^63 sd 2^63-1) |
|
ulong |
uint64, u64 |
18000000000000000000 (0 sd 2^64-1) |
|
| Floating | float |
single, float32, f32 |
3.14 (7 digit presisi) |
double |
float64, f64 |
3.141592653589793 (15-16 digit) |
|
decimal |
decimal128, currency |
15000000.50 (28-29 digit) |
# Numerik → double (paling aman) /nilai = 12345; # → double # Leading zero → string (mempertahankan format) /kode = 0123456789; # → string /telepon = 08123456789; # → string # Boolean → bool /aktif = true; # → bool /nonaktif = false; # → bool # String dengan quote → string /nama = "Budi"; # → string /alamat = 'Jakarta'; # → string
_) dibolehkan/nama /nama_lengkap /_internal /user_name /nama123 /user_profile /alamat_rumah
/123nama # Diawali angka /nama/user # Mengandung / /nama@user # Mengandung @ /nama:user # Mengandung : /nama,user # Mengandung , /nama;user # Mengandung ; /nama#user # Mengandung #
/root ├── perusahaan │ ├── nama │ └── alamat │ ├── kota │ └── kode ├── karyawan[] # Array of objects │ ├── [0] │ │ ├── @id │ │ ├── nama │ │ └── umur │ └── [1] │ ├── @id │ ├── nama │ └── umur └── barang[] # Array of primitives
# Root level /root = value; # Level 1 /root/user = value; # Level 2 /root/user/profile = value; # Level 3 /root/user/profile/address = value; # Level n (maksimum rekomendasi: 5-7 level) /root/a/b/c/d/e = "deep";
Object di PON menggunakan () untuk mengelompokkan fields
menjadi satu entitas.
# Single object sederhana
/root/karyawan(
nama:string = "Budi Santoso";
umur:int = 25;
aktif:bool = true
);
# Object dengan atribut
/root/karyawan(
@id:int = 1;
@department:string = "IT";
nama:string = "Budi Santoso";
umur:int = 25
);
# Nested object (object di dalam object)
/root/karyawan(
nama:string = "Budi Santoso";
alamat(
jalan:string = "Jl. Merdeka No. 10";
kota:string = "Bandung";
kode:string = "40123"
)
);
# Object dengan array di dalamnya
/root/karyawan(
nama:string = "Budi Santoso";
hobi:string[] = "coding","gaming","reading";
nilai:int[] = 85,90,78
);
# Array dinamis (ukuran tidak tetap) /root/nilai:int[] = 85,90,78,92; /root/nama:string[] = "Budi","Siti","Andi"; # Array dengan ukuran tetap /root/nilai:int[3] = 85,90,78; # Array kosong /root/kosong:int[] = ; # Array dengan default (ukuran tetap) /root/nol:int[5] = ; # [0,0,0,0,0]
# Matrix 2x3 /root/matrix:float[2,3] = 1,2,3; 4,5,6; # Visual mapping: # [2,3] → 2 baris, 3 kolom # 1,2,3; → Baris 1 # 4,5,6; → Baris 2 # Matrix 3x3 /root/matrix:int[3,3] = 1,2,3; 4,5,6; 7,8,9; # 3D Array (cube) /root/cube:float[2,2,2] = 1,2; 3,4; 5,6; 7,8; # Jagged array (array of arrays, baris bisa beda panjang) /root/jagged:double[][] = 1,2,3; 4,5; 6,7,8,9;
# Array of objects dengan skema
/root/karyawan[
@id:int = 0;
nama:string;
umur:int = 0;
alamat/kota:string = "";
alamat/kode:string = ""
] =
1,"Budi Santoso",25,"Bandung","40123";
2,"Siti Rahayu",23,"Jakarta","10220";
3,"Andi Wijaya",,"Bandung"; # umur default 0
# Array of objects dengan nested object
/root/karyawan[
@id:int;
nama:string;
alamat(
kota:string;
kode:string
)
] =
1,"Budi Santoso",("Bandung","40123");
2,"Siti Rahayu",("Jakarta","10220");
Default values di PON memungkinkan Anda menentukan nilai fallback jika data tidak tersedia atau kosong.
# Deklarasi default di skema
/root/karyawan[
@id:int = 0; # Default 0 jika tidak ada
nama:string; # Required (tidak ada default)
umur:int = 0; # Default 0
aktif:bool = true; # Default true
alamat/kota:string = ""; # Default string kosong
alamat/kode:string = "" # Default string kosong
]
# Data yang menggunakan default
= 1,"Budi Santoso",,"Jakarta"; # umur → 0 (default)
= 2,"Siti Rahayu",, ,"40123"; # umur → 0, kota → "" (default)
= 3,"Andi Wijaya",,; # umur → 0, kota → "", kode → ""
# file: data.pon /root/nama:string = "Budi Santoso"; /root/umur:int = 25; /root/aktif:bool = true; /root/gaji:decimal = 15000000.50;
/root/karyawan(
@id:int = 1;
nama:string = "Budi Santoso";
alamat(
kota:string = "Bandung";
kode:string = "40123"
)
);
/root/karyawan[
@id:int;
nama:string;
umur:int
] =
1,"Budi Santoso",25;
2,"Siti Rahayu",23;
3,"Andi Wijaya",30;
/root/perusahaan(
nama:string = "PT Teknologi Maju";
alamat(
kota:string = "Jakarta";
kode:string = "10220"
);
karyawan[
@id:int;
nama:string;
jabatan:string;
gaji:decimal = 0;
alamat(
kota:string;
kode:string
);
aktif:bool = true
] =
1,"Budi Santoso","Manager",15000000,("Jakarta","10220"),true;
2,"Siti Rahayu","Developer",12000000,("Bandung","40123"),true;
3,"Andi Wijaya","Staff",8000000,("Surabaya","60111"),false
);
/root/users[
@id:int;
username:string;
email:string;
password:string = "";
active:bool = true;
last_login:datetime = "";
roles:string[] = "user"
] =
1,"budi","budi@mail.com","hash123",true,"2024-01-15T14:30:00Z",("user","admin");
2,"siti","siti@mail.com","hash456",true,"2024-01-14T10:00:00Z",("user");
3,"andi","andi@mail.com","hash789",false,,("user");
/root/products[
@id:int;
name:string;
price:decimal = 0;
stock:int = 0;
category:string = "General";
tags:string[] = ;
variants[
@id:int;
name:string;
price:decimal;
stock:int
] = ;
active:bool = true
] =
1,"Laptop Pro",15000000,10,"Electronics",("laptop","premium","gaming"),
[(1,"8GB RAM",15000000,5),(2,"16GB RAM",17000000,3),(3,"32GB RAM",19000000,2)],true;
2,"Mouse Wireless",250000,50,"Accessories",("mouse","wireless","ergonomic"),
[(1,"Black",250000,30),(2,"White",250000,20)],true;
3,"Keyboard Mechanical",500000,20,"Accessories",("keyboard","mechanical","rgb"),[],true;
Untuk memahami keunggulan PON, mari kita bandingkan dengan format data lain yang umum digunakan.
<root>
<nama>Budi</nama>
<umur>25</umur>
<aktif>true</aktif>
</root>
<root>
<karyawan id="1">
<nama>Budi</nama>
<umur>25</umur>
</karyawan>
<karyawan id="2">
<nama>Siti</nama>
<umur>23</umur>
</karyawan>
</root>
/root/nama:string = "Budi"; /root/umur:int = 25; /root/aktif:bool = true;
/root/karyawan[
@id:int;
nama:string;
umur:int
] =
1,"Budi",25;
2,"Siti",23;
{
"root": {
"user": {
"name": "Budi",
"age": 25,
"active": true,
"address": {
"city": "Bandung",
"zip": "40123"
}
}
}
}
/root/user/name:string = "Budi"; /root/user/age:int = 25; /root/user/active:bool = true; /root/user/address/city:string = "Bandung"; /root/user/address/zip:string = "40123";
root:
user:
name: Budi
age: 25
active: true
address:
city: Bandung
zip: 40123
/root/user/name:string = "Budi"; /root/user/age:int = 25; /root/user/active:bool = true; /root/user/address/city:string = "Bandung"; /root/user/address/zip:string = "40123";
id,nama,umur,kota 1,Budi,25,Bandung 2,Siti,23,Jakarta 3,Andi,30,Bandung
/root/karyawan[
@id:int;
nama:string;
umur:int;
alamat/kota:string
] =
1,"Budi",25,"Bandung";
2,"Siti",23,"Jakarta";
3,"Andi",30,"Bandung";
+----+-------+------+----------+ | id | nama | umur | kota | +----+-------+------+----------+ | 1 | Budi | 25 | Bandung | | 2 | Siti | 23 | Jakarta | | 3 | Andi | 30 | Bandung | +----+-------+------+----------+
/root/karyawan[
@id:int;
nama:string;
umur:int;
alamat/kota:string
] =
1,"Budi",25,"Bandung";
2,"Siti",23,"Jakarta";
3,"Andi",30,"Bandung";
Berikut adalah padanan struktur dasar PON (single type, array, dan object) dengan berbagai bahasa pemrograman.
| PON | C# | Contoh |
|---|---|---|
/nama:string = "Budi" |
string |
string nama = "Budi"; |
/umur:int = 25 |
int |
int umur = 25; |
/nilai:float = 3.14 |
float |
float nilai = 3.14f; |
/aktif:bool = true |
bool |
bool aktif = true; |
/data:int[] = 1,2,3 |
int[] |
int[] data = {1,2,3}; |
/user( nama:string = "Budi"; umur:int = 25 ) |
class |
class User { string Nama {get;set;} int Umur {get;set;} } |
// PON
/root/karyawan[
@id:int;
nama:string;
umur:int;
aktif:bool = true
] =
1,"Budi",25,true;
2,"Siti",23,true;
// C# Class
public class Karyawan
{
public int Id { get; set; }
public string Nama { get; set; }
public int Umur { get; set; }
public bool Aktif { get; set; } = true;
}
// List of objects
List<Karyawan> karyawan = new List<Karyawan>
{
new Karyawan { Id = 1, Nama = "Budi", Umur = 25, Aktif = true },
new Karyawan { Id = 2, Nama = "Siti", Umur = 23, Aktif = true }
};
| PON | VB.NET | Contoh |
|---|---|---|
/nama:string = "Budi" |
String |
Dim nama As String = "Budi" |
/umur:int = 25 |
Integer |
Dim umur As Integer = 25 |
/aktif:bool = true |
Boolean |
Dim aktif As Boolean = True |
/data:int[] = 1,2,3 |
Integer() |
Dim data() As Integer = {1,2,3} |
/user(nama:string = "Budi"; umur:int = 25) |
Class |
Class User Public Property Nama As String ... |
' VB.NET Class
Public Class Karyawan
Public Property Id As Integer
Public Property Nama As String
Public Property Umur As Integer
Public Property Aktif As Boolean = True
End Class
' List of objects
Dim karyawan As New List(Of Karyawan) From {
New Karyawan With {.Id = 1, .Nama = "Budi", .Umur = 25, .Aktif = True},
New Karyawan With {.Id = 2, .Nama = "Siti", .Umur = 23, .Aktif = True}
}
| PON | Java | Contoh |
|---|---|---|
/nama:string = "Budi" |
String |
String nama = "Budi"; |
/umur:int = 25 |
int |
int umur = 25; |
/aktif:bool = true |
boolean |
boolean aktif = true; |
/data:int[] = 1,2,3 |
int[] |
int[] data = {1,2,3}; |
/user(nama:string = "Budi"; umur:int = 25) |
class |
class User { String nama; int umur; } |
// Java Class
public class Karyawan {
private int id;
private String nama;
private int umur;
private boolean aktif = true;
// Constructor, getters, setters
}
// List of objects
List<Karyawan> karyawan = Arrays.asList(
new Karyawan(1, "Budi", 25, true),
new Karyawan(2, "Siti", 23, true)
);
| PON | Python | Contoh |
|---|---|---|
/nama:string = "Budi" |
str |
nama = "Budi" |
/umur:int = 25 |
int |
umur = 25 |
/aktif:bool = true |
bool |
aktif = True |
/data:int[] = 1,2,3 |
list |
data = [1,2,3] |
/user(nama:string = "Budi"; umur:int = 25) |
dict / dataclass |
{"nama": "Budi", "umur": 25} |
# Python Dataclass
from dataclasses import dataclass
@dataclass
class Karyawan:
id: int
nama: str
umur: int
aktif: bool = True
# List of objects
karyawan = [
Karyawan(id=1, nama="Budi", umur=25, aktif=True),
Karyawan(id=2, nama="Siti", umur=23, aktif=True)
]
| PON | JavaScript | Contoh |
|---|---|---|
/nama:string = "Budi" |
string |
const nama = "Budi"; |
/umur:int = 25 |
number |
const umur = 25; |
/aktif:bool = true |
boolean |
const aktif = true; |
/data:int[] = 1,2,3 |
Array |
const data = [1,2,3]; |
/user(nama:string = "Budi"; umur:int = 25) |
Object |
{ nama: "Budi", umur: 25 } |
// JavaScript Object
class Karyawan {
constructor(id, nama, umur, aktif = true) {
this.id = id;
this.nama = nama;
this.umur = umur;
this.aktif = aktif;
}
}
// Array of objects
const karyawan = [
new Karyawan(1, "Budi", 25, true),
new Karyawan(2, "Siti", 23, true)
];
| PON | Rust | Contoh |
|---|---|---|
/nama:string = "Budi" |
String |
let nama = String::from("Budi"); |
/umur:int = 25 |
i32 |
let umur: i32 = 25; |
/aktif:bool = true |
bool |
let aktif: bool = true; |
/data:int[] = 1,2,3 |
Vec<i32> |
let data = vec![1,2,3]; |
/user(nama:string = "Budi"; umur:int = 25) |
struct |
struct User { nama: String, umur: i32 } |
// Rust Struct
#[derive(Debug)]
struct Karyawan {
id: i32,
nama: String,
umur: i32,
aktif: bool,
}
// Vector of objects
let karyawan = vec![
Karyawan { id: 1, nama: String::from("Budi"), umur: 25, aktif: true },
Karyawan { id: 2, nama: String::from("Siti"), umur: 23, aktif: true }
];
Berikut adalah spesifikasi formal PON dalam format EBNF (Extended Backus-Naur Form) dan ANTLR (Another Tool for Language Recognition).
(* ============================================================
PON - Path Object Notation
Spesifikasi Formal EBNF
Versi 1.0 - 29 Juli 2026
============================================================ *)
(* Dokumen PON terdiri dari kumpulan statement *)
PONDocument = { Statement };
(* Statement = komentar opsional + deklarasi + terminator *)
Statement = [Comment] Declaration Terminator;
(* Komentar dimulai dengan # sampai akhir baris *)
Comment = "#" { Character - "\n" };
(* Terminator adalah titik koma *)
Terminator = ";";
(* Deklarasi = path + tipe opsional + struktur opsional + assignment opsional *)
Declaration = Path [Type] [Structure] [Assignment];
(* Path = / diikuti oleh key dan sub-path *)
Path = "/" Key { "/" Key };
(* Key = huruf, angka, underscore (tidak diawali angka) *)
Key = Letter { Letter | Digit | "_" };
(* Type = : diikuti nama tipe dan spesifikasi array opsional *)
Type = ":" TypeName [ArraySpec];
(* TypeName = salah satu dari daftar tipe data *)
TypeName = "bool" | "boolean" | "char" | "wchar" | "char16" |
"string" | "datetime" | "date" | "time" | "unixtime" |
"object" | "variant" | "any" |
"byte" | "sbyte" | "int8" | "i8" |
"ubyte" | "uint8" | "u8" |
"short" | "int16" | "i16" |
"ushort" | "uint16" | "u16" |
"integer" | "int" | "int32" | "i32" |
"uinteger" | "uint" | "uint32" | "u32" |
"long" | "int64" | "i64" |
"ulong" | "uint64" | "u64" |
"float" | "single" | "float32" | "f32" |
"double" | "float64" | "f64" |
"decimal" | "decimal128" | "currency";
(* ArraySpec = dimensi dalam [] *)
ArraySpec = "[" [ Number { "," Number } ] "]" |
"[" "]" |
"[" "]" { "[" "]" };
(* Structure = object fields dalam () *)
Structure = "(" Field { ";" Field } ")";
(* Field = path + tipe opsional + default opsional *)
Field = Path [Type] [Default];
(* Default = = Value *)
Default = "=" Value;
(* Assignment = = Value *)
Assignment = "=" Value;
(* Value = berbagai tipe nilai *)
Value = Primitive | Array | Object | ArrayOfObjects;
(* Primitive = number, string, boolean, datetime, null *)
Primitive = Number | String | Boolean | DateTime | "null";
(* Number = integer atau float *)
Number = [ "-" ] Digit { Digit } [ "." Digit { Digit } ];
(* String = dalam quote (" atau ') *)
String = '"' { Character | Escape } '"' |
"'" { Character | Escape } "'";
(* Boolean = true atau false *)
Boolean = "true" | "false";
(* DateTime = ISO 8601 format *)
DateTime = "'" DatePattern [ "T" TimePattern [ "Z" | TimeZone ] ] "'";
(* Array = nilai-nilai dipisahkan koma *)
Array = Value { "," Value };
(* Object = field assignments dalam () *)
Object = "(" FieldAssignment { ";" FieldAssignment } ")";
(* FieldAssignment = path + tipe opsional + = value *)
FieldAssignment = Path [Type] "=" Value;
(* ArrayOfObjects = skema [] = data object *)
ArrayOfObjects = "[" Field { ";" Field } "]" "=" ObjectData;
(* ObjectData = object atau beberapa object dipisahkan ; *)
ObjectData = Object { ";" Object };
(* Escape sequences *)
Escape = "\"" | "\'" | "\\" | "\n" | "\r" | "\t" | Unicode;
Unicode = "\u" HexDigit HexDigit HexDigit HexDigit ";" |
"\" Number ";";
(* Token dasar *)
Letter = "A" | "B" | ... | "Z" | "a" | "b" | ... | "z";
Digit = "0" | "1" | ... | "9";
HexDigit = Digit | "A" | "B" | "C" | "D" | "E" | "F" | "a" | "b" | "c" | "d" | "e" | "f";
// ============================================================
// PON - Path Object Notation
// Spesifikasi Formal ANTLR v4
// Versi 1.0 - 29 Juli 2026
// ============================================================
grammar PON;
// ========================
// Parser Rules
// ========================
ponDocument: statement+;
statement: comment? declaration terminator;
terminator: SEMICOLON;
comment: HASH ~[\r\n]*;
declaration: path (type)? (structure)? (assignment)?;
path: SLASH key (SLASH key)*;
key: IDENTIFIER;
type: COLON typeName arraySpec?;
typeName: BOOL | BOOLEAN | CHAR | WCHAR | CHAR16
| STRING | DATETIME | DATE | TIME | UNIXTIME
| OBJECT | VARIANT | ANY
| BYTE | SBYTE | INT8 | I8
| UBYTE | UINT8 | U8
| SHORT | INT16 | I16
| USHORT | UINT16 | U16
| INTEGER | INT | INT32 | I32
| UINTEGER | UINT | UINT32 | U32
| LONG | INT64 | I64
| ULONG | UINT64 | U64
| FLOAT | SINGLE | FLOAT32 | F32
| DOUBLE | FLOAT64 | F64
| DECIMAL | DECIMAL128 | CURRENCY;
arraySpec: LBRACK (number (COMMA number)*)? RBRACK
| LBRACK RBRACK (LBRACK RBRACK)*;
structure: LPAREN field (SEMICOLON field)* RPAREN;
field: path (type)? (defaultValue)?;
defaultValue: EQUALS value;
assignment: EQUALS value;
value: primitive | array | object | arrayOfObjects;
primitive: number | string | boolean | datetime | NULL;
number: MINUS? DIGIT+ (DOT DIGIT+)?;
string: DOUBLE_QUOTE (ESC_SEQ | ~["\\])* DOUBLE_QUOTE
| SINGLE_QUOTE (ESC_SEQ | ~['\\])* SINGLE_QUOTE;
boolean: TRUE | FALSE;
datetime: SINGLE_QUOTE datePattern (T timePattern (Z | timeZone)?)? SINGLE_QUOTE;
array: value (COMMA value)*;
object: LPAREN fieldAssignment (SEMICOLON fieldAssignment)* RPAREN;
fieldAssignment: path (type)? EQUALS value;
arrayOfObjects: LBRACK field (SEMICOLON field)* RBRACK EQUALS objectData;
objectData: object (SEMICOLON object)*;
// ========================
// Lexer Rules
// ========================
// Keywords - Type Names
BOOL: 'bool';
BOOLEAN: 'boolean';
CHAR: 'char';
WCHAR: 'wchar';
CHAR16: 'char16';
STRING: 'string';
DATETIME: 'datetime';
DATE: 'date';
TIME: 'time';
UNIXTIME: 'unixtime';
OBJECT: 'object';
VARIANT: 'variant';
ANY: 'any';
BYTE: 'byte';
SBYTE: 'sbyte';
INT8: 'int8';
I8: 'i8';
UBYTE: 'ubyte';
UINT8: 'uint8';
U8: 'u8';
SHORT: 'short';
INT16: 'int16';
I16: 'i16';
USHORT: 'ushort';
UINT16: 'uint16';
U16: 'u16';
INTEGER: 'integer';
INT: 'int';
INT32: 'int32';
I32: 'i32';
UINTEGER: 'uinteger';
UINT: 'uint';
UINT32: 'uint32';
U32: 'u32';
LONG: 'long';
INT64: 'int64';
I64: 'i64';
ULONG: 'ulong';
UINT64: 'uint64';
U64: 'u64';
FLOAT: 'float';
SINGLE: 'single';
FLOAT32: 'float32';
F32: 'f32';
DOUBLE: 'double';
FLOAT64: 'float64';
F64: 'f64';
DECIMAL: 'decimal';
DECIMAL128: 'decimal128';
CURRENCY: 'currency';
// Boolean values
TRUE: 'true';
FALSE: 'false';
// Null
NULL: 'null';
// Punctuation
SLASH: '/';
COLON: ':';
SEMICOLON: ';';
COMMA: ',';
LBRACK: '[';
RBRACK: ']';
LPAREN: '(';
RPAREN: ')';
HASH: '#';
EQUALS: '=';
MINUS: '-';
DOT: '.';
DOUBLE_QUOTE: '"';
SINGLE_QUOTE: '\'';
// Identifier
IDENTIFIER: LETTER (LETTER | DIGIT | '_')*;
// Number
DIGIT: [0-9]+;
// Escape Sequence
ESC_SEQ: '\\' [btnrf\"'\\]
| '\\u' HEX HEX HEX HEX ';'
| '\\' DIGIT+ ';';
// Whitespace (skip)
WS: [ \t\r\n]+ -> skip;
// Fragments
fragment LETTER: [a-zA-Z];
fragment HEX: [0-9a-fA-F];
// Pattern helpers
datePattern: DIGIT DIGIT DIGIT DIGIT '-' DIGIT DIGIT '-' DIGIT DIGIT;
timePattern: DIGIT DIGIT ':' DIGIT DIGIT ':' DIGIT DIGIT ('.' DIGIT+)?;
timeZone: (PLUS | MINUS) DIGIT DIGIT ':' DIGIT DIGIT;
PLUS: '+';
# ============================================================
# FILE: app-config.pon
# KONFIGURASI APLIKASI MyApp v3.0
# ============================================================
/root/app(
@version:string = "3.0.0";
@environment:string = "production";
# ---- Server Configuration ----
server(
host:string = "0.0.0.0";
port:int = 8080;
workers:int = 4;
max_connections:int = 1000;
timeout:int = 60;
ssl:bool = false
);
# ---- Database Configuration ----
database(
default[
driver:string = "postgresql";
host:string = "localhost";
port:int = 5432;
name:string = "myapp_db";
username:string = "app_user";
password:string = "";
pool_size:int = 10
];
cache[
driver:string = "redis";
host:string = "redis.example.com";
port:int = 6379;
ttl:int = 3600
]
);
# ---- Logging Configuration ----
logging(
level:string = "info";
console:bool = true;
file[
enabled:bool = true;
path:string = "/var/log/myapp/app.log";
max_size:int = 104857600; # 100MB
format:string = "json"
]
);
# ---- Feature Flags ----
features[
@id:string;
enabled:bool = true;
description:string = ""
] =
"dark_mode",true,"Dark theme support";
"beta_features",false,"Beta features preview";
"analytics",true,"Analytics tracking"
);
# ============================================================
# FILE: master-karyawan.pon
# DATA MASTER KARYAWAN PT TEKNOLOGI MAJU
# ============================================================
/root/perusahaan(
@id:int = 1;
nama:string = "PT Teknologi Maju";
established:date = "2010-01-01";
alamat(
kota:string = "Jakarta Selatan";
kode:string = "10220";
negara:string = "Indonesia"
);
kontak(
telepon:string = "021-1234567";
email:string = "info@teknologimaju.com"
)
);
/root/karyawan[
@id:int;
@status:string = "active";
# Personal
nama_lengkap:string;
jenis_kelamin:char = 'M';
tempat_lahir:string;
tanggal_lahir:date;
kewarganegaraan:string = "Indonesia";
# Contact
alamat(
jalan:string;
kota:string;
kode:string;
negara:string = "Indonesia"
);
kontak(
telepon_seluler:string;
email_pribadi:string;
email_kantor:string = ""
);
# Employment
nip:string;
jabatan:string;
department:string;
tanggal_bergabung:date;
status_kepegawaian:string = "Permanent";
# Financial
gaji_pokok:decimal = 0;
rekening(
bank:string;
nomor:string;
atas_nama:string
);
# Education
pendidikan[
@tingkatan:string;
institusi:string;
jurusan:string = "";
tahun_lulus:int;
ipk:float = 0
] = ;
# Skills
skill[
@kategori:string;
nama:string;
level:string;
years:int = 0
] = ;
# Family
keluarga[
@hubungan:string;
nama:string;
jenis_kelamin:char;
pekerjaan:string = "";
tanggungan:bool = false
] = ;
created_by:int;
created_at:datetime
] =
1,"active","Budi Santoso",'M',"Jakarta","1990-05-15","Indonesia",
("Jl. Merdeka No. 10","Bandung","40123","Indonesia"),
("08123456789","budi@mail.com","budi@teknologimaju.com"),
"EMP-001","Senior Developer","IT","2018-06-01","Permanent",
15000000,("BCA","1234567890","Budi Santoso"),
[("S1","Universitas Indonesia","Ilmu Komputer",2018,3.75)],
[("Technical","C#","Expert",5),("Technical","SQL","Expert",5)],
[("Spouse","Siti Rahayu",'F',"Dokter",true)],
1,"2018-06-01T08:00:00Z";
2,"active","Siti Rahayu",'F',"Bandung","1992-08-20","Indonesia",
("Jl. Diponegoro No. 5","Jakarta","10220","Indonesia"),
("08129876543","siti@mail.com","siti@teknologimaju.com"),
"EMP-002","Developer","IT","2021-03-15","Permanent",
12000000,("Mandiri","2345678901","Siti Rahayu"),
[("S1","Universitas Gadjah Mada","Ilmu Komputer",2020,3.68)],
[("Technical","Python","Expert",4),("Technical","Django","Advanced",3)],
[("Spouse","Andi Wijaya",'M',"Data Scientist",true)],
1,"2021-03-15T09:00:00Z";
3,"active","Andi Wijaya",'M',"Bandung","1988-12-01","Indonesia",
("Jl. Ahmad Yani No. 10","Bandung","40132","Indonesia"),
("08123456788","andi@mail.com","andi@teknologimaju.com"),
"EMP-003","Senior Developer","IT","2019-06-01","Permanent",
18000000,("BNI","3456789012","Andi Wijaya"),
[("S1","ITB","Teknik Informatika",2014,3.45),("S2","ITB","Ilmu Komputer",2016,3.92)],
[("Technical","Java","Expert",6),("Technical","Spring","Expert",4)],
[("Spouse","Rina Lestari",'F',"Dokter",true)],
1,"2019-06-01T08:00:00Z"
);
# ============================================================
# PON CHEAT SHEET - REFERENSI CEPAT
# ============================================================
# ===== SINTAKS DASAR =====
/path:type = value;
/root/name:string = "Budi";
/root/age:int = 25;
/root/active:bool = true;
# ===== TIPE DATA =====
bool, boolean # Boolean
char, wchar, char16 # Karakter 16-bit
string # String
datetime, date, time, unixtime # Tanggal/Waktu
object, variant, any # Any type
byte, ubyte, short, ushort, integer, uinteger, long, ulong # Integer
float, double, decimal # Floating point
# ===== ARRAY =====
# Array 1D
/values:int[] = 1,2,3,4;
/names:string[3] = "A","B","C";
# Array 2D (Multidimensi)
/matrix:float[2,3] = 1,2,3; 4,5,6;
# Jagged Array
/jagged:int[][] = 1,2,3; 4,5; 6,7,8,9;
# ===== OBJECT (NON-ARRAY) =====
/object(field1:type = value1; field2:type = value2);
# ===== ARRAY OF OBJECTS =====
/objects[
field1:type = default1;
field2:type = default2
] =
value1,value2;
value3,value4;
# ===== ATTRIBUTE =====
/@attribute:type = value;
# ===== COMMENT =====
# Ini komentar
# ===== DEFAULT VALUES =====
/objects[
id:int = 0; # Default 0
name:string; # Required
active:bool = true # Default true
] =
1,"Budi"; # active default true
2,"Siti",; # active default true
3,"Andi",false; # active override
| Tipe | Alias | Ukuran | Contoh |
|---|---|---|---|
bool | boolean | 1 bit | true, false |
char | wchar, char16 | 16-bit | 'A' |
string | - | Variable | "Hello" |
datetime | - | 64-bit | "2024-01-15T14:30:00Z" |
date | - | 32-bit | "2024-01-15" |
time | - | 32-bit | "14:30:00" |
unixtime | - | 64-bit | 1705314600 |
object | variant, any | Variable | "string" atau 123 |
byte | sbyte, int8, i8 | 8-bit | 100 |
ubyte | uint8, u8 | 8-bit | 200 |
short | int16, i16 | 16-bit | 1000 |
ushort | uint16, u16 | 16-bit | 50000 |
integer | int, int32, i32 | 32-bit | 100000 |
uinteger | uint, uint32, u32 | 32-bit | 3000000000 |
long | int64, i64 | 64-bit | 10000000000 |
ulong | uint64, u64 | 64-bit | 18000000000000000000 |
float | single, float32, f32 | 32-bit | 3.14 |
double | float64, f64 | 64-bit | 3.141592653589793 |
decimal | decimal128, currency | 128-bit | 15000000.50 |
Berikut adalah ringkasan spesifikasi lengkap PON:
PON Document = { Statement }
Statement = [Comment] Declaration Terminator
Comment = "#" text
Declaration = Path [Type] [Structure] [Assignment]
Path = "/" Key { "/" Key }
Key = Letter { Letter | Digit | "_" }
Type = ":" TypeName [ArraySpec]
TypeName = ( "bool" | "boolean" | "char" | "wchar" | "char16" |
"string" | "datetime" | "date" | "time" | "unixtime" |
"object" | "variant" | "any" |
"byte" | "sbyte" | "int8" | "i8" |
"ubyte" | "uint8" | "u8" |
"short" | "int16" | "i16" |
"ushort" | "uint16" | "u16" |
"integer" | "int" | "int32" | "i32" |
"uinteger" | "uint" | "uint32" | "u32" |
"long" | "int64" | "i64" |
"ulong" | "uint64" | "u64" |
"float" | "single" | "float32" | "f32" |
"double" | "float64" | "f64" |
"decimal" | "decimal128" | "currency" )
ArraySpec = "[" [ Number { "," Number } ] "]" | "[" "]" | "[" "]" { "[" "]" }
Structure = "(" Field { ";" Field } ")"
Field = Path [Type] [ Default ]
Assignment = "=" Value
Value = Primitive | Array | Object | ArrayOfObjects
Primitive = Number | String | Boolean | DateTime | null
String = '"' { Character | Escape } '"' | "'" { Character | Escape } "'"
Number = [ "-" ] Digit { Digit } [ "." Digit { Digit } ]
Boolean = "true" | "false"
DateTime = ISO 8601 format
Array = Value { "," Value }
Object = "(" FieldAssignment { ";" FieldAssignment } ")"
FieldAssignment = Path [Type] "=" Value
ArrayOfObjects = "[" Field { ";" Field } "]" "=" ObjectData
ObjectData = Object { ";" Object }
Terminator = ";"
# ============================================================
# FILE: app-config.pon
# KONFIGURASI APLIKASI SEDERHANA
# ============================================================
/root/app(
@version:string = "1.0.0";
@environment:string = "development";
server(
host:string = "localhost";
port:int = 3000;
debug:bool = true
);
database(
host:string = "localhost";
port:int = 5432;
name:string = "myapp_dev";
username:string = "dev_user";
password:string = ""
)
);
# ============================================================
# FILE: master-data.pon
# DATA MASTER SEDERHANA
# ============================================================
/root/users[
@id:int;
username:string;
email:string;
active:bool = true;
roles:string[] = "user"
] =
1,"budi","budi@mail.com",true,("user","admin");
2,"siti","siti@mail.com",true,("user");
3,"andi","andi@mail.com",false,("user");
/root/products[
@id:int;
name:string;
price:decimal = 0;
stock:int = 0;
category:string = "General"
] =
1,"Laptop Pro",15000000,10,"Electronics";
2,"Mouse Wireless",250000,50,"Accessories";
3,"Keyboard",500000,0,"Accessories";
Pengembang & Perancang: Muhammad Arif Budianto
Lisensi: MIT License
© 2026 - PON Project
🏆 Dikembangkan Pertama Kali oleh Muhammad Arif Budianto
⚠️ PON dibuat BUKAN untuk menggantikan format data modern yang sudah ada