plum
git clone https://git.pyrossh.dev/plum
A statically typed, imperative programming language inspired by rust, python
plum-examples/functions.plum
import std/Str
import std/Bool
import std/Number
fun addInts(a: Int, b: Int) -> Int =
a + b
fun greet() =
todo
fun withDefault(a: Int, step: Int = 1) -> Int =
a + step
fun sumAll(nums: ...Int) -> Int =
total := 0
for v := range nums
total = total + v
total
fun wrap(value: T) -> Bool =
True
fun pair(first: T, second: U) -> Bool =
True
fun useWrap() -> Bool =
wrap(5)
fun usePair() -> Bool =
pair(1, "x")
# ---- generics, variadics, and misc regression tests ----
fun factorial(x: Int) -> Int =
if x < 2
return 1
return x * factorial(x - 1)
# Regression test: `double(...)` (an all-lowercase, no-uppercase, no-underscore
# callee) used to fail to parse at all — `var_identifier` and `fn_identifier`
# both matched its text and the grammar's lexer would nondeterministically
# commit to `var_identifier`, breaking every such call site.
fun double(n: Int) -> Int =
n * 2
enum GenericBox[T] =
| GenericBox(value: T)
fun getIntValue() -> Int =
self.value
fun useGenericBox() -> Int =
b := GenericBox(value: 7)
b.getIntValue()
fun identity(value: T) -> T =
value
enum GenericBox2[T] =
| GenericBox2(value: T)
fun getValue() -> Int =
self.value
fun doubled(value: T) -> Int =
identity(value) + identity(value)
enum FnOption[T] =
| FnSome(T)
| FnNone
fun unwrapFnOptionOr(o: FnOption, default: Int) -> Int =
match o
FnSome(v) => v
FnNone => default
# `Str.length()` is not a real, working method — the point of this test is
# that `FnOption$Str` coexists with `FnOption$Int` and both run correctly, not
# string processing, so the Str arm returns a fixed literal.
fun unwrapFnOptionIntOr(o: FnOption, default: Int) -> Int =
match o
FnSome(v) => v
FnNone => default
fun unwrapFnOptionStrOr(o: FnOption, default: Int) -> Int =
match o
FnSome(v) => 4
FnNone => default
enum GenericBox3[T] =
| GenericBox3(value: T)
fun getBoxValue() -> Int =
self.value
fun sumBox(b: GenericBox3) -> Int =
b.getBoxValue()
fun combineVariadic(prefix: Int, rest: ...Int) -> Int =
prefix
test "factorial runs correctly"
assert factorial(5) == 120
test "lowercase single word function call runs correctly"
assert double(21) == 42
test "generic class specialized at two types does not alias"
assert useGenericBox() == 7
test "generic function called at multiple concrete types runs correctly"
assert identity(5) + identity(37) == 42
test "generic method on generic class runs correctly"
b := GenericBox2(value: 9)
assert b.getValue() == 9
test "transitively generic call chain runs correctly"
assert doubled(21) == 42
test "generic enum specialized and matched runs correctly"
assert unwrapFnOptionOr(FnSome(13), 0) == 13
test "generic enum multiple instantiations coexist and run correctly"
assert unwrapFnOptionIntOr(FnSome(13), 0) + unwrapFnOptionStrOr(FnSome("abcd"), 0) == 17
test "same bare generic enum param function called multiple times runs correctly"
assert unwrapFnOptionOr(FnSome(5), 0) + unwrapFnOptionOr(FnSome(37), 0) == 42
test "ordinary function with bare generic class param runs correctly"
assert sumBox(GenericBox3(value: 11)) == 11
test "variadic call with varying trailing arg counts runs correctly"
a := combineVariadic(10)
b := combineVariadic(20, 1)
c := combineVariadic(30, 1, 2, 3)
assert a + b + c == 60
test "sum all variadic int runs correctly"
assert sumAll(1, 2, 3, 4) == 10
test "sum all variadic int with zero args runs correctly"
assert sumAll() == 0