plum

#treesitter#compiler#wasm

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