Skip to content

Greyrat7490/gamma-lang

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Gamma Programming Language

Fun Project to write my own language, to learn Go and to see how a good language would look like for me. So it will probably end up like a modern C or Rust

A statically and strongly typed programming language similar to Go and Rust.

Goals

  • fast
  • easy
  • compiled
  • statically and strongly typed
  • lightweigth
  • important build-in functions
  • general purpose language and good for low level tasks
  • crossplatform

Supported

  • Linux
  • MacOS
  • windows
  • x86_64
  • ARM

Examples

define var / const

v := 69         // infer type from value
v u32 := 64     // explicit type

c :: -64        // just change "=" to ":" to make it a const
c i64 :: -420

print

// print, println, eprint, eprintln
println("hello world!")
println(fmt("print a number {} or {}", 69, "somthing else"))
eprintln("ERROR") // write to stderr

vectors

v := [$]i32{ len: 1, cap: 6 }
v[0] = 0
v = append::<i32>(v, 2)
v = append::<i32>(v, 3)
println(vtos(v)) // vectors are not yet supported for 'fmt'

structs

struct Test {
    a i32,
    b u64
}

t1 := Test{ a: 1, b: 6 }
t2 := Test{ 1, 6 }        // omit field names -> go by order (will be changed later)

println(fmt("Test{ a: {}, b: {} }", t1.a, t1.b))

functions

fn func(a i32, b i32) {
    println(fmt("{}", a + b))
}

fn func(a i32, b i32) -> i32 {
    ret a + b
}

generic functions

fn func<T>(v [$]T) -> [$]T {
    for i u64, v.len {
        v[i] = i
    }
    ret v
}

// calling generic functions
v = func::<i32>(v)

interfaces

// define an interface
interface Number {
    fn add(a u64, b u64) -> u64
    fn inc(self) -> u64
    fn dec(*self) -> u64
}

struct Test {
    a u64
}

// implement an interface
impl Test :: Number {
    fn add(a u64, b u64) -> u64 {
        ret a + b
    }
                // optional: use explicitly Self type
                // optional: use explicitly actual Struct type
    fn inc(self) -> u64 {
        ret self.a + 1
    }
    
    fn dec(*self) -> u64 {
       self.a = self.a + 1
       ret self.a
    }
}

// call interface functions
res := Test::add(30, 39)

// call like methods
t := Test{ 64 }
res := t.inc()
res2 := t.dec()    // causes a side effect due to *self

// calling like a function is possible too
_ := Test::inc(t)
_ := Test::dec(&t)

methods

struct Test {
    a u64
}

// implement without an interface
impl Test {
    fn inc(self) -> u64 {
        ret self.a + 1
    }

    fn dec(*self) -> u64 {
       self.a = self.a + 1
       ret self.a
    }
}

t := Test{ 64 }
res := t.inc()
res2 := t.dec()
_ := Test::inc(t)
_ := Test::dec(&t)

enums

enum Test {
 // 0, 1, 2 (u64)
    A, B, C
}

           // optional id type (default is u64)
enum Test2 u8 {
    // enums are like tagged unions
    A(i64), B(str), C(bool)
}

a := Test::A
b := Test2::A(64)
b = Test2::B("string")

if a == Test::A {
    println("a == Test::A")
}

// unwrap b to get the string (creates a new var / not a reference)
if b : Test::B(s) {
    println("unwraped b contains: " + s)
}

const functions

// only tmp sytnax for funcs (will be changed)
cfn func(a i32, b i32) -> i32 {
    // non const stmts will cause an error (like "print")
    if a > b * 2 {
        ret b
    } else {
        ret a + b
    }
}

cfn func2(a i32) -> i32 {
    // vars are allowed
    res := 0
    for i i32, a {
        res = res + i
    }
    ret res
}

a :: 30
b :: 39
c := func(a, b)    // func will be executed at compile time and "69" will be "hardcoded"
d := 69
e := func(a, d)    // if one or more args are not const the func gets executed at runtime (like a normal func)

const function examples

cfn fib(i u64) -> u64 {
    ret $ i == {
        0, 1: 1 as u64
           _: fib(i-1) + fib(i-2)
    }
}
// check at compile time if your machine is little or big endian
cfn isBigEndian() -> bool {
    // even pointers (and dereferencing) are allowed (only addresses in the stack)
    word i16 := 0x0001
    ptr *bool := &word as u64 as *bool
    ret *ptr == false
}

switches

if {
    // cases only have one statement so use {} for multiple statements
    x == 0: {
        do_stuff()
        do_stuff()
    } 
    _: do_stuff()
}

if x == {
    0: do_stuff()
    1: do_stuff()
    2, 3, 4: do_stuff() 
    _: do_stuff()
}

// cases in one-line-switches are seperated with ";" 
if x == { 0: do_stuff(); _: do_stuff() }

xswitches (eXpression switch)

// same as a normal switch but with a $ instead of an "if"
res := $ {
    x == 0: -1     // only an expression is allowed as case body (statments are allowed later too)
    _: 69
}

// assign to one of vars depending on a condition
$ i <= { 1: v1; _: v2 } = 64

Get Started

compile a source file

$ go run gamma <source_file>

run tests

$ go test ./test -v

gamma usage

$ go run gamma --help
gamma usage:
  -ast
    	show the AST
  -r	run the compiled executable

run simple http server example

$ go run gamma -r ./examples/http.gma

run on http://localhost:6969
...

run rule110 example

$ go run gamma -r ./test/rule110.gma

                o
               oo
              ooo
             oo o
            ooooo
           oo   o
          ooo  oo
         oo o ooo
        ooooooo o
       oo     ooo
      ooo    oo o
     oo o   ooooo
    ooooo  oo   o
   oo   o ooo  oo
  ooo  oooo o ooo
 oo o oo  ooooo o
oooooooo oo   ooo
...

TODO:

  • generate assembly file
    • nasm
    • fasm (preferable!)
  • variables
  • functions
    • define/call
    • System V AMD64 ABI calling convention
    • lambda
    • const function
  • packages
    • import
    • import only once
    • detected import cycles
    • pub keyword
    • access by package name
  • stdlib
    • sockets
    • io
      • print
      • read/write files
  • arithmetics
    • unary ops
    • binary ops
      • parse by precedence
    • parentheses
  • controll structures
    • if, else, elif
    • while, for
    • switch
    • xswitch (expr switch)
  • pointer
    • define/assign
    • deref
    • get addr (via "&")
    • arithmetic
  • consts
    • define/use
    • compile time eval
  • arrays
    • define/use
    • multi-dimensionale
    • compile time eval
  • structs
    • define struct type
    • define object
    • access fields (read/write)
    • compile time eval
  • turing complete -> actual programming language
    • proof with Rule 110 programm
  • type checking
  • tests
  • examples
    • simple http server
    • game of life
    • doom
  • self-hosted
  • cross-platform

Releases

No releases published

Packages

No packages published

Languages