Skip to content

Instantly share code, notes, and snippets.

@kittech0
Last active June 18, 2023 08:54
Show Gist options
  • Select an option

  • Save kittech0/4e615e4e5df1cf355cb55a8c10297957 to your computer and use it in GitHub Desktop.

Select an option

Save kittech0/4e615e4e5df1cf355cb55a8c10297957 to your computer and use it in GitHub Desktop.
The Prismatica Programming Language idea

Welcome to the idea of language based around Kotlin and Rust!

Comments

Comments in this language use C-like syntax.

// One-liner
function(/* Insides */) // Description of it! 
/*
   Multiple lines!
*/

Variables and mutability

There are multiple ways of declaring variables in this language. By default, every variable is immutable, and you need to specify mutability. The syntax for declaring variables is Rust-like, with an optional let keyword. Example of an immutable variable:

variable: i32 = 2
let variable: i32 = 2 // `let` is optional and not required; it will work the same in the example above

Example of mutable variable:

mut variable: i32 = 2 //you just put `mut` before name!
let mut variable: i32 = 2 // same here but after `let`

There are also constant values, which are strictly immutable and only allow primitive values. They require the const keyword before the name. They are automatically inlined by the compiler.

const CONSTANT_VARIABLE: i32 = 2

Types

Uses rust-like types

  1. Signed integers: i8,i16,i32,i64,i128 and isize
  2. Unsigned integer: u8,u16,u32,u64,u128 and usize
  3. Floating-point numbers: f8,f16,f32,f64,f128 and fsize
  4. Characters: char (to create character use '' example: 'a')
  5. Boolean: bool (true or false)

Tuples

Tuples have a Rust-like syntax. They are groups with multiple types of values inside and have a fixed size. Tuples can be destructured. Example way of creating:

tuple: (fsize, u16, bool) = (1.0, 24, true)

Accessing values is different from Rust. Instead of tuple.i (where i is the index/place of the value in the tuple), it uses array-like syntax for accessing elements. Example way of accessing value:

value: fsize = tuple[0] //returns 1.0 of type fsize
// remember `tuple` variable is (1.0, 24, true)

You can also destructure tuples using a different variable syntax, which destructures the tuple into multiple variables. Example of destruction:

(float: fsize, number: u16, answer: bool) = tuple 
float //returns 1.0 with type fsize
number //returns 24 with type u16
answer //returns true with type bool 

Array

Arrays have a Kotlin-like syntax. They are groups of the same type and have a fixed size. Example way of creating:

array: char[5] = ['h','e','l','l','o']

The number inside char[5] defines the fixed size of the array, and char defines the type of values in the array. You can access values inside an array in the same way you would in a tuple. Example of accessing value:

letter: char = array[3] //returns `l` with type char

Lambda

Lambdas are a replacement for functions in this language. They use a different syntax from other languages. To create a lambda, you use ||. By default, they return nothing. Lambdas are executed like C functions. They also support compact one-line execution, similar to Kotlin. Example use of lambda in variable

lambda: || = something()

Lambdas can span multiple lines by using {}. Example use:

lambda: || = {
	something()
	something()
}

Lambdas can also have a return type, which is specified after ||, like || -> i32. Example use:

lambda: || -> i32 = 2 //will return `2`

You can also specify when the lambda should return, if required; otherwise, it will return the last statement in the block. Instead of using return as in other languages, you use <- to indicate a return. Example use:

lambda: || -> i32 = {
	2+2 //won't be returned
	<- 4+4 //will return 8 and stop lambda here
	5-5 //won't be reached
}

Lambdas also support arguments. Arguments are specified inside ||, similar to other languages' function syntax. Example use:

lambda: |x: i32| -> i32 = x^2 //if executed `lambda(2)` will return `4`
//You can also specify which argument you pass value by using `lambda(x=2)`

Arguments also support default values, as you would see in Kotlin. Example use:

lambda: |x: i32 = 2| -> i32 = x^2 //If not passed anything by doing `lambda()` it will return 4, if did for example `lambda(6)` it will return 36.

Lambdas can be used as arguments, and there is a shorthand syntax for it. Example use:

lambda: |lam: || | = lam()
//without shorting syntax
lambda(|| = std\println("Hello world!"))
//with shorting syntax
lambda || = std\println("hello world!")

When multiple arguments are used, the shorthand syntax can be applied to each argument. Example of a lambda with multiple arguments and shorthand syntax:

lambda: |x: i32, lam: |y: i32|| = lam(x)

lambda(32) |x| = std\println("Hello {x}") //you do exactly same thing but instead you add the value in `()`

Modules and Packages

This language supports creating modules and importing them. The standard library is included by default and can be used. Modules use a syntax similar to Rust, and the namespace specifier is \. Example module:

mod MyModule

pub powerMe: |x: i128| -> i128 = x^2 // Use `pub` keyword to make something public!
//to use it you would write MyModule\powerMe(2) (returns 4)

Structure

Structures are used to create more complex data types from existing types. The language combines Rust's structure syntax with Kotlin's implementation of function syntax. Example usage:

struct Person {
    mut name: std\String = "Jane" // To make a mutable variable in a structure, use `mut`
    pub age: u16 // By default, values in a structure are only available for implemented functions. Using `pub` makes them accessible internally and externally.
} // You can initialize it using `Person("Kittech", 20)` or `Person(age = 16)`

Person.sayHello: || = std\out.println("{$.name}: Hello!") // Implements a function for the structure
// To access values from inside the structure, use `$` (similar to `self` in Rust or `this` in Kotlin)

mut Person.setName: |name: std\String| = $.name = name // To mutate any value in the structure, the implemented lambda also needs to be mutable

|Person.new: |name: std\String, age: u16| -> it = it(name, age)
// This is a static variable on Person. You create it by putting `Person` between `||`.
// `it` is used for returning itself and only stores the constructor and static variables.
// Static variables are immutable and cannot be changed.

DSL

A DSL is a building pattern commonly found in Groovy or Kotlin. It makes it easy for developers to create builder functions, and for users to use them without problems. In this language, we can implement a builder using lambda-like syntax with some differences. Example implementation:

// Example structure
struct ExampleBuild {
    mut number: isize
}

mut ExampleBuild.addNumber: |num: isize| = $.number += num

// DSL builder implementation
builder: |num: isize, example: ExampleBuild.|| | = ExampleBuild(num).apply(example)
// `ExampleBuild.||` is similar to a lambda but provides DSL abilities

// Example usage 
builder(100) || = {
    $.addNumber(1)
    $.addNumber(100)
} // Returns ExampleBuild with `number` equal to 201

Every struct has an .apply function that can be called by passing the builder DSL lambda as an argument.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment