Skip to content

peterdelevoryas/ono

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

95 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Overview

This language is approximately equal to C, but with some essential modern features:

  • Modern syntax
  • Type inference
  • Local variable shadowing
  • Stronger typing (explicit casting required)
  • Auto-deref: ptr.field implicitly becomes (*ptr).field
  • bool type
  • Tuples
  • First-class () type and value replaces void
  • Compile-time constants (replacing macros or static data)
  • Sum types (like Rust enum's)
  • Pattern matching (if let ...)

Some more features that I want to add, but haven't finished implementing yet:

  • Generics
  • Fat pointer primitive (ptr + len): []T, like Rust &[T] slice type
  • Module system
  • SIMD primitive types
  • Uniform function call syntax
  • match expression (like Rust)

The filetests/ directory contains examples of all language features, below some are reproduced with added comments.

// Explicit libc namespace import.

import libc;

function main() -> i32 {
  let p = libc.malloc(64);
  libc.printf("ptr = %p\n", p);
  return 0;
}
// Hello world

import libc;

function main(argc: i32, argv: **i8) -> i32 {
  libc.printf("hello world\n");
  return 0;
}
// Local variable declaration

import libc;

function main(argc: i32, argv: **i8) -> i32 {
  // Basic local variable declaration.
  let x: i32 = 1;

  // Type annotation is optional, and shadowing is allowed.
  let x = 2;
  libc.printf("%d\n", x); // 2

  return 0;
}
// Parse compiler args

import libc;

// Returns (filename, -)
function parse_args(argc: i32, argv: **i8) -> (*i8, bool) {
  let file: *i8 = null;
  let help = false;
  for let i = 1; i < argc; i += 1 {
    let arg = argv[i];
    if libc.strcmp(arg, "-h") == 0 {
      help = true;
      continue;
    }
    file = arg;
  }
  return (file, help);
}

function main(argc: i32, argv: **i8) -> i32 {
  let (file, help) = parse_args(argc, argv);
  libc.printf("help = %d, file = %s\n", help, file);
  if help {
    libc.printf("usage: ono [-h] <file>\n");
    return 1;
  }
  if file == null {
    libc.printf("missing file argument\n");
    return 1;
  }
  return 0;
}
// 4x4 Matrix multiplication

import libc;

type Mat4 = [4][4]f32;

function matmul(a: Mat4, b: Mat4) -> Mat4 {
  let xx = a[0][0] * b[0][0] + a[0][1] * b[1][0] + a[0][2] * b[2][0] + a[0][3] * b[3][0];
  let xy = a[0][0] * b[0][1] + a[0][1] * b[1][1] + a[0][2] * b[2][1] + a[0][3] * b[3][1];
  let xz = a[0][0] * b[0][2] + a[0][1] * b[1][2] + a[0][2] * b[2][2] + a[0][3] * b[3][2];
  let xw = a[0][0] * b[0][3] + a[0][1] * b[1][3] + a[0][2] * b[2][3] + a[0][3] * b[3][3];

  let yx = a[1][0] * b[0][0] + a[1][1] * b[1][0] + a[1][2] * b[2][0] + a[1][3] * b[3][0];
  let yy = a[1][0] * b[0][1] + a[1][1] * b[1][1] + a[1][2] * b[2][1] + a[1][3] * b[3][1];
  let yz = a[1][0] * b[0][2] + a[1][1] * b[1][2] + a[1][2] * b[2][2] + a[1][3] * b[3][2];
  let yw = a[1][0] * b[0][3] + a[1][1] * b[1][3] + a[1][2] * b[2][3] + a[1][3] * b[3][3];

  let zx = a[2][0] * b[0][0] + a[2][1] * b[1][0] + a[2][2] * b[2][0] + a[2][3] * b[3][0];
  let zy = a[2][0] * b[0][1] + a[2][1] * b[1][1] + a[2][2] * b[2][1] + a[2][3] * b[3][1];
  let zz = a[2][0] * b[0][2] + a[2][1] * b[1][2] + a[2][2] * b[2][2] + a[2][3] * b[3][2];
  let zw = a[2][0] * b[0][3] + a[2][1] * b[1][3] + a[2][2] * b[2][3] + a[2][3] * b[3][3];

  let wx = a[3][0] * b[0][0] + a[3][1] * b[1][0] + a[3][2] * b[2][0] + a[3][3] * b[3][0];
  let wy = a[3][0] * b[0][1] + a[3][1] * b[1][1] + a[3][2] * b[2][1] + a[3][3] * b[3][1];
  let wz = a[3][0] * b[0][2] + a[3][1] * b[1][2] + a[3][2] * b[2][2] + a[3][3] * b[3][2];
  let ww = a[3][0] * b[0][3] + a[3][1] * b[1][3] + a[3][2] * b[2][3] + a[3][3] * b[3][3];

  return [[xx, xy, xz, xw],
      [yx, yy, yz, yw],
      [zx, zy, zz, zw],
      [wx, wy, wz, ww]];
}

function print(a: Mat4) {
  for let i = 0; i < 4; i += 1 {
    for let j = 0; j < 4; j += 1 {
      libc.printf("%10.4f  ", a[i][j] as f64);
    }
    libc.printf("\n");
  }
}

function main() -> i32 {
  let a = [[ 1.0,  9.0,  3.0,  4.0],
      [ 2.0, -4.0,  5.0,  0.5],
      [-3.0,  1.0,  6.0, -3.0],
      [ 6.0, 10.0, 11.0,  1.0]];
  let b = matmul(a, a);
  print(a);
  print(b);
  return 0;
}
// Structs and auto-deref

import libc;

type Vec3 = struct {
  x: f32,
  y: f32,
  z: f32,
};

function print(v: Vec3) {
  let x = v.x as f64;
  let y = v.y as f64;
  let z = v.z as f64;
  libc.printf("%f %f %f\n", x, y, z);
}

// Field accesses on pointers to structs are auto-deref'd.
function dot(x: *Vec3, y: *Vec3) -> f32 {
  return x.x * y.x + x.y * y.y + x.z * y.z;
}

function main(argc: i32, argv: **i8) -> i32 {
  let a: Vec3 = { x: 1.0, y: 2.0, z: 3.0, };
  let b: Vec3 = { x: 2.0, y: 3.0, z: 4.0, };
  print(a);
  print(b);

  let ab = dot(&a, &b);
  libc.printf("dot a, b = %f\n", ab as f64);

  return 0;
}
// Pattern matching with `if let`

import libc;

type Expr = enum {
  Int(i32),
  String(*i8),
};

function print(e: Expr) {
  if let Int(i) = e {
    libc.printf("%d\n", i);
  }
  if let String(s) = e {
    libc.printf("%s\n", s);
  }
}

function main() -> i32 {
  let e = Expr.Int(1);
  print(e);

  e = Expr.String("hello world");
  print(e);

  return 0;
}

About

Oh-no, not another programming language

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors