Thanks to visit codestin.com
Credit goes to github.com

Skip to content

ostanton/opl

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

15 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

OPL

Oliver's Programming Language is based on scopes. Value scopes (essentially lambdas) and type scopes (structs). Examples so far found below:

// Fundamental types
u8, u16, u32, u64,
i8, i16, i32, i64,
f32, f64, bool

// Names can be either a value (fundamental type), or a value scope (lambda)
a: f32 = 5; // value
b := () {}; // empty lambda, type of "scope"
// b: scope = () {};

// Anonymous lambda
() {};

// Calling anonymous lambda
() {} ();

// Naming anonymous lambda
my_name := () {};

// Calling named lambda
my_name(); // equivalent to () {} ();

// Called lambdas can have their local names accessed
num: f32 = () { x: f32 = 5; } ().x;

// Named lambdas therefore support this
length := (x: f32, y: f32) {
    result := std.sqrt(x * x, y * y).result;
};
len := length(2, 5).result;

// Called lambdas can be cached (with ":>") so they're only evaluated once
add := (a: u8, b: u8) {
    result := a + b;
};
add_alias :> add(1, 1); // "add" is evaluated here even though no locals are accessed
num := add_alias.result; // add_alias (and therefore add(1, 1)) is not re-evaluated
num2 := add_alias.result * 2; // again, the "result" value is got from a cache not re-evaluated

// Parameterless lambdas can be cached immediately to create namespaces or enum-like values
my_enum :> () {
    first := 0;
    second := 1;
    third := 2;
} ();
val := my_enum.first;

// So far only value scopes (lambdas) have been discussed
// Type scopes are used instead of fundamental types or the "value_scope" type
Point: {
    x: f32 = 0;
    y: f32 = 0;
};
p: Point = {}; // Equivalent to p: {x: f32 = 0; y: f32 = 0;} = {};
// = {} is required otherwise p is an alias of the "Point" type scope instead of a value scope name
// the empty value scope makes p use Point's default values. Note that the value scope is NOT a lambda.
// It serves as the structural equivalent to a literal value (1, "", false, etc.)

// It is worth noting that OPL is duck-typed. Two Point structures that are defined in different places
// will compare for equality successfully

// Type scopes act like an array of different types
// Their local names are available in their assigned value scope
p: Point = {
    x = 55; // x and y are available from the Point type scope
    y = x * 2;
};
// Because names require assignment or else they become type aliases, value names in type scopes
// can be left un-assigned in their value scopes because they have an initial value already
p: Point = {
    x = y * 2; // y was assigned 0 in the Point type scope already
};

// Note that type scopes cannot have parameters
Point: () {}; // error!

// It's possible they could in the future for compile-time things, like Zig's functions
Point: (T: type) { // no idea what the "type" would be here
    x: T = 0;
    y: T = 0;
};
p: Point(f32) = {};

// Type scopes cannot have their local names accessed like value scopes allow
Point.x; // error! Type scopes must be instantiated first
p.x = 5; // OK, value comes from a variable instance

// Only fields which come from a type scope are mutable outside a value scope
maths :> () {
    pi := 3.1415;
} ();
maths.pi = 5; // error! pi is const!

// Type scopes can have other type scopes defined within
Box: {
    pos: Point = {}; // = {} is required otherwise "pos" is a type scope instead of a value scope name
    size: {
        w: f32 = 0;
        h: f32 = 0;
    } = {};

    // This is not cached as the inner values can change between calls, so acts more like a normal function
    bottom_right := () {
        result: Point = {
            x = pos.x + size.w;
            y = pos.y + size.h;
        };
    };
};
b: Box = {
    size.w = 24;
    size.h = 24;
    // could do value scope initialisation - size = {w = 24; h = 24;};
};
br := b.bottom_right().result; // br == Point {x = 24; y = 24;};

// Taking a lambda as a function input
func: scope = (pred: scope) {
    if (pred().result) {} // etc.
};
// There is no signature for the scope parameter, which leads to unknown signatures if not documented
// Not sure how this would be solved, or if it can. Named scopes can equal anything, a signature is not part of the type!
f: scope = (x: f32) {result := x * 2;};
f(5); // == 10
f = {};
f(); // nothing
/**
 * I don't think this is much of a problem though. Scopes already have pretty hidden names that the user
 * is expected to know (like the typical "result"), so this isn't hugely different. Just a quirk of the language.
 */

About

Oliver's Programming Language

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages