Ritchie Programming Language Specification
Programming Language Name is Ritchie.
filename.ken .ken is Ritchie Source File.
There will be no module system, all is global.
All is public, no private and protected.
Compile-Time Metaprogramming Execution(CME):
#compile.time.code
// Executes logic strictly during compile-time resolution
#end.compile.time.code // also can #end
#compile.run.time.code
// Shared structural utilities visible inside compile and runtime phases
#end.compile.run.time.code // also can #end
#compile.time.create.code NAME //just plain text
// Automatically drops dynamic code blocks directly back into source
example
#compile.time.code
sub say_hello()
{
write_code("\"Hello World\"");
}
sub say_verbos(bool b)
{
sure b;
code = text.c"""
puts("verbos mode is active");
"""
write_code(code);
}
#end
#compile.time.create.code HELLO say_hello();
#compile.time.create.code VERBOS(B) say_verbos(B);
sub main()
{
puts(HELLO);
VERBOS(#false#)
}
comment: // single line , /* */ multi line
Preprocessor Directives
#end[.optional] // after #end is optional, like #end.if is as same #end
#header FOO_LIB
// Isolated compiler layout boundary
#end.header
#macro NAME
//like #define but multiline
#end.macro
#macro.define BASE_VAL 255
#if.defined VAL
// Conditional logic block
#end.if // also can be #end
#if.not.defined SOME_VALUE
#end.if.not // also can #end
#else.if.defined
#end.else.if.define
#else.not.defined
#end.else.not.defined
#macro.if #macro.else #macro.else.if #end.macro.if
#macro.error
#macro.warning
#file.add "system_io.h"
#file.add "lenna_rgba.hex" // just add text file
#file.binary core_blob, "firmware.bin" // Embeds raw image file asset cleanly
#macro.enable WIN32 // like #define
#macro.disable WIN32 == #macro.undefine WIN32 //like #undef
#header.import "math.ken" // all function and global data visiable
#header.include "sdl.ken" // add once(with gaurd act like c include
#macro.line line_num ["filename"]// Preprocessor emit line number for compiler
Compiler Pipeline:
1.compiler time code
2.Preprocessor
3.compiler
value types: true, false, null
index and error types: index_t and error_t
built in
type.define int index_t;
type.define int error_t;
default@index_t = -1
default@error_t = -1
Data Types:
int, bool, index_t , error_t ,int8_t i8 ,int16_t i16 ,int32_t i32, int64_t i64
uint, uint8_t byte_t u8 , uint16_t u16,uint32_t u32,uint64_t u64
float, double
char, wchar_t,
void,
size_t
Auto Bytes Order handling:
endian-aware data types:
i16le,i32le,i64le,
i16be,i32be,i64be,
u16le,u32le,u64le,
u16be,u32be,u64be,
f32le,
f32be,
example
i32le x = 65536;// 65536 is system endian int on need coverted to i32le
i32be y = x;// auto convert
u32 z = y; // convert if host system is litle endian
z = x;// convert if host host system is big endian
Control Flow and looping Keywords:
if , if.not , else, else.if, switch, case, default case.else ,
for, for.{a-z}, for.forever, while, do, break, continue
case.else keyword: same as default: in switch
if keyword:
same as c if keyword and if pointer only check by it its make valid in if scope.
if( x > y) // like c
int *? p;// optional pointer( nullable pointer)
if(p)
{
// auto valid.pointer@p = true in this scope
}
if.not keyword: like if(!(expr))
for keyword:
like c
int i;
for(i = 0; i < 10; i++)
//...
for.{variable name 1 char a-z} keyword: for.{1 char} max
for.a ... for.z like for.i , for.j , for.x , for.y
for.i 10
same as
int i;
for(i = 0; i < 10; i++)
for.forever keyword: loop
same as
while(1)
const keyword : for readonly function parameters, variable, pointers like c
keyword auto: auto keyword is optional its always enabled.
x = 10; // same as auto x = 10;
f = 3.14;
keywords Others:
align_of, type_of, count_of, pack_of, size_of
size_of: same as sizeof in c
default@typename: meta compiler default
builtin
default@int = 0
default@float = 0.0
default@bool = false
Default Arguments
Default Arguments (=): Assigns static fallback constants to function parameters that are automatically filled in at the call site.
sub foo(x = 10);
Default Arguments (skip parameter when calling function): default@typename
sub foo(x,y,z);
call it
foo(); // same as foo(0,0,0);
foo(1);//
meta compiler method@
like UFCS(Unified Function Call Syntax).
method@typename.method_name:
// Manual mapping assignment
sub void shift_coordinate(point *p, amount);
method@point.move = shift_coordinate;
Dot Notation (.) and (->) : object-style method calls
sub point_center(w,h);
sub foo(point * p,w,h)
{
p.center(w,h);// same as point_center(p,w,h);
point pt;// var
// auto mapping
pt->center(w,h);//same as point_center(&pt,w,h);// if we have var we have to use ->
}
note like p.center if no method@point.center = point_center is define Ritchie will do typename_{method_name}
field@ // look for field first
method@ // look after field
point * p;
point_t * pt;
p.action();// point_action(p);
pt.action();// point_action(p); auto detect _t in at end of point_t
type framebuffer_image_t
{
int w;
int h;
int pitch;// in pixels
pixel_t * pixels;
}
method.prefix@framebuffer_image_t = fi
sub fi_make_gray(framebuffer_image_t * fi);
//call
fi.make_gray();
[auto mode without @ need]
typename or typename_t ( _t auto remove):
typename
typename_method_name :
pointer.method_name var->method_name
typename_set_field_name,typename_get_field_name :
pointer.field_name var->field_name
meta compiler field@: field@ field.set@ field.get@
field@: Hooks property accessor functions (getters and setters) .
sub point_get_x(point *p);
sub void point_set_x(point *p,val);
field@point.x point_get_x, point_set_x
can also read only
field@point.x point_get_x
field.get@point.x = point_get_x
also write only
field@point.x ,point_set_x
field.set@point.x = point_set_x
[]@ : meta compiler array like access for types
[]@typename get_func,set_func;// read write
[]@typename get_func;// read
[]@typename , set_func;// write
example:
v = lst.get_at(0);
lst.set_at(0,0);
will become
v = lst[0];
lst[0]=0;
meta compiler valid@:
valid@typename:var_name expr
valid@index_t:var var >= 0
use
index_t i;
if(i) // same as if(i >= 0)
{
// code
}
sure i // sure can check for valid index
valid@error_t:var var == 0
same index_t now we can use with if and sure
keyword sub : subroutine , functions starting keyword.
sub return_type function_name(typename parameter_name);
sub foo(); // default return value is int
sub foo(x,y);// default parameter typename is int
sub<T>: Declares compile-time templated function.
sub<T> return_type function_name(T var_name);
sub<T> bool same(T * a , T * b);
sub main()
{
x = 10;
p = &x;
p2 = &x;
sure same<int>(p,p2);
}
naming for sub<t> :
same<int> will become same_int
if valid pointer * used it add _valid_pointer
sub<T> foo<T v);
foo<int*> will become foo_int_valid_pointer
if optional *? used it add _optional_pointer
foo<int*?> will become foo_int_optional_pointer
sub.thread:
run in thread
sub.thread void thread_function(x,y);
meta compiler valid.pointer@pointer
Valid Pointer : valid.pointer(scoped), *, *?
valid.pointer@point_name: for meta compiler
int * p;
valid.pointer@p = true
*? and *: *? is optional pointer and * is valid pointer(non null).
int *? px;//optional pointer
but we can make valid pointer by
valid.pointer@px = true
or
if(px) // will set valid.pointer@px = true in scope
sure keyword:
1. sure variable_name
2. sure expr
it like sure a > b become
if(!(a > b))
return;
3. sure pointer
if pointer is no null set valid.pointer@pointer = true
co thread:
co@function_name: create thread
work on hosted system like Windows and linux.
enable co like (enable by default on Windows and Linux)
system@co = create_thread
type.sub void * thread_function_f(void * ctx);
sub create_thread(thread_function_f function_pointer,void *? context_pointer);// how create_thread look like name it as you wish
example code:
sub void download_assets(const char* server_url, timeout_seconds);
sub main() {
url = "https://assets.quantis.io/pack01.pkg";
timeout = 30;
// Fire and forget: Runs download_assets in the background immediately
co@download_assets(url, timeout);
// Main thread execution continues instantly without blocking
print("Download dispatched. Initializing game loop...");
}
Transpiler Code Generation (Lowered C Output)
// 1. Transpiler automatically generates an argument carrier layout
typedef struct {
const char* server_url;
int timeout_seconds;
} _co_args_download_assets;
// 2. Transpiler generates a standard signature worker wrapper
void* _co_worker_download_assets(void* raw_payload) {
_co_args_download_assets* args = (_co_args_download_assets*)raw_payload;
// Executes your original function procedurally
download_assets(args->server_url, args->timeout_seconds);
// Cleans up the parameter carrier memory safely
free(args);
return NULL;
}
// 3. The lowered main function
void main() {
const char* url = "https://assets.quantis.io/pack01.pkg";
int timeout = 30;
// Transpiler packs your variables into the carrier
_co_args_download_assets* carrier = malloc(sizeof(_co_args_download_assets));
if(carrier){
carrier->server_url = url;
carrier->timeout_seconds = timeout;
create_thread(_co_worker_download_assets,carrier);
}
print("Download dispatched. Initializing game loop...");
}
create_thread will use CreateThread on Windows and pthread_create on Linux and other system.
return.ok keyword: helper fo defer.fail.safe if return.ok then defer.fail.safe will not run
defer keyword : Schedules a cleanup expression to automatically execute across all subsequent return pathways.
1. defer var_name
defer var_name // same as defer delete
2. defer expr
defer free(p) // free memory
defer fclose(f) // close file
defer.fail.safe keyword: only run if function failed
type buffer{ void * p; size_t len; }
sub buffer *? buffer_new(len)
{
buffer * r = (buffer*) malloc(size_of(buffer));
sure r;
defer.fail.safe free(r);
r->p = malloc(len);
sure r-p; // if malloc return null defer.fail.safe free(r) will run;
r->len = len;
// by return.ok any defer.fail.safe will be not called
return.ok r;// return.ok make pair with defer.fail.safe for ease confusion
}
keyword type.define: like c typedef but types not for functions
keyword type: is like c struct keyword.
type<T>: templated
keyword type.record : pack structure.
keyword type.enum: enum and enum<T> with optional typename and name
1. no name, no type , default type int, no namespace
enum{
FILE_SAVED // FILE_SAVED = 0
,FILE_NEED_SAVE // FILE_NEED_SAVE = 1
,FILE_IS_READ_ONLY = 10
}
used like
int save_state = FILE_IS_READ_ONLY;
2. with typename, no name , no namespace
type.define u32 pixel_t;
enum<pixel_t>
{
COLOR_BLACK = 0xFF000000;
COLOR_WHITE = 0xFFFFFFFF;
}
used like
pixel_t pix = COLOR_BLACK;
3. typename and name
enum<pixel_t> color
{
black = 0xFF000000;
white = 0xFFFFFFFF;
}
used like
pixel_t pix = color.black;
keyword type.union: union
type.union dynamic_arg_u
{
char ch;
int i;
uint u;
float f;
double d;
char * s;
void * p;
}
type dynamic_arg_t
{
int var_type;
dynamic_arg_t var;
}
type.enum dynamic_type
{
var_none,
var_char,
var_int,
var_uint,
var_float,
var_double,
var_string,
var_object
}
sub foo(dynamic_arg_t * dyn)
{
dyn->type = dynamic_type.var_int;
dyn->var.i = 10;
}
Dot Compiler Guide(DCG) .inlay: help for unions as field types
.inlay union_name optional_variable_name;
type dynamic_parameter
{
int pram_type;
.inlay dynamic_arg_t pram;
}
sub func(dynamic_parameter * dyn)
{
dyn->pram_type = dynamic_type.var_int;
dyn->i = 10;// same as dyn->parm.i = 10;
}
keyword type.union.inlay:
type.union.inlay [optional_name] { }
type parameter_for_dynamic_type
{
int parameter_type;
type.union.inlay
{
char ch;
int i;
uint u;
float f;
double d;
char * s;
void * p;
}
}
sub fun(parameter_for_dynamic_type * pram)
{
pram->parameter_type = dynamic_type.var_int;
pram->i = 10;
}
keyword type.sub: declare a function. type.sub return_type function_name(parameters);
type.sub is like c typedef but for function only
type.sub foo();
in c
typedef int (*foo)(void);
Dot Compiler Guide(DCG) list: Line Start With Dot(.)
.align
.offset
.extern
.register
.volatile
.static
.rom
.rom.volatile
.data
.data.volatile
.inlay
meta compiler volatile@:
.volatile and volatile@: keep variable in ram.
.volatile int x;
same as
int x;
volatile@x = true
two ways to ensure variable will placed in ram.
self keyword: implicit field scope, used as function parameter to indicate type function is working on.
typename * self
1. work only with pointer
2. self keyword can be used anywhere not just as first parameter
type recta { int x; int y; int w; int h;}
sub recta_make_half_size(recta * self)
{
w /= 2;// same as self->w /= 2;
h /= 2;// same as self->h /= 2;
}
sub recta_memset(val,recta * self)
{
x = val;
y = val;
w = val;
h = val;
}
keywords new and delete
meta compiler new@ and delete@ is used for new and delete.
keywords new :
use meta compiler new@typename = typename_new
let say we
type point
{
int x;
int y;
}
sub point *? point_new()
{
// code
}
new@point = point_new
can call using
sub foo()
{
p = new point();
sure p; //check for null pointer if its null return from function
defer p;// same as defer delete
}
keyword delete:
meta compiler delete@typename = typename_new
delete@point = point_delete
example for new and delete
type mem
{
void * ptr;
int len;
}
sub mem *? mem_new(size);
sub void mem_delete(mem * m);
new@mem = mem_new;
delete@mem = mem_delete;
sub main()
{
m = new mem(4096);
sure m;
defer m; // same as defer delete m; m is mem and its support delete so defer dectect that
// delete m; // auto by defer at every exit point
}
Raw Bits Bytes Access(R3A): bytes@variable_name, pointer.bytes@pointer_name , bits@variable_name, pointer.bits@pointer_name
bytes@: get set bytes
int x;
u = bytes@x[0]; // read first byte of int x
bytes@x[1] = 0; // write second
pointer.bytes@: same as bytes@ but for pointers
sub foo(int * p)
{
u = pointer.bytes[0];// read first byte from int * data it pointing to
}
bits@: get set bits
int x;
bits@x[0] = 0; // set bits
b = bits@x[0];// get bits
pointer.bits@: same as bits@ but for pointer
int x;
int * p = &x;
pointer.bits@p[0] = 0;
b = pointer.bits
typed<T>@: get set type
type loc { u8 x; u8 y;}
u32 x;
typed<loc>@x[0].x = 1; // set
v = typed<loc>@x[0].y;// get
pointer.typed<T>@: same for pointer
type wind { u8 w; u8 h;}
u16 w;
u16 * p;
pointer.typed<wind>@p[0].w = 10;// set
val = pointer.typed<wind>@p[0].h;// get
Context Function Pointer (CFP):
function_pointer_t<function_name_by_type_dot_sub,typename> var_name;
function_pointer<function_name_by_type_dot_sub,typename>(function_pointer,optional_pointer);
in context only pointer is allowed.
example:
type.sub foo(i,double * cxt);
sub func(i,double * cxt);
sub fun(function_pointer_t<foo,double> f)
{
f(13,f.context);
}
sub main()
{
d = 3.14;
f = function_pointer<foo,double>(func,&d);
}
function_pointer is keyword.
function_pointer_t is builtin datatype;
Wide Pointer: keyword wide_pointer and count_of
typename[] var_name
name = wide_pointer(raw_buffer,count)
count_of(wide_pointer)
// Wrapping standard dynamic heap segments
int* raw_buffer = (int*)malloc(sizeof(int) * 200);
int[] wide_buf = wide_pointer(raw_buffer, 200);
type __WidePointer_Internal {
typename * data;
size_t count;
}
example
// Wide pointer used as a parameter and a return type
sub int[] filter_positive_values(int[] input_data) {
size_t total = count_of(input_data);
if (total == 0) return input_data;
// Boundary validations are implicitly active during execution
for (size_t i = 0; i < total; i++) {
if (input_data[i] < 0) {
input_data[i] = 0;
}
}
return input_data
}
for.each keyword support wide pointer:
sub sum_ints(int[] vals)
{
int r = 0;
for.each(v in vals)
{
r += v;
}
return r;
}