4dbe761574c65a616a50b66ed5c7923381868332 — Martin Angers 8 months ago ad37f0e
start experimenting with qbe syntax
4 files changed, 122 insertions(+), 6 deletions(-)

A .gitignore
A codegen/add_one.ssa
A codegen/hello.ssa
M syntax/overview.snow
A .gitignore => .gitignore +5 -0
@@ 0,0 1,5 @@
+# qbe compiled assembly
+*.s
+
+# compiled binary
+*.out

A codegen/add_one.ssa => codegen/add_one.ssa +14 -0
@@ 0,0 1,14 @@
+data $fmt = { b "%d\n", b 0 }
+
+function w $add(w %arg) {
+@start
+  %val =w add 1, %arg
+  ret %val
+}
+
+export function w $main() {
+@start
+  %val =w call $add(w 42)
+  call $printf(l $fmt, w %val)
+  ret 0
+}

A codegen/hello.ssa => codegen/hello.ssa +9 -0
@@ 0,0 1,9 @@
+# Define the string constant.
+data $str = { b "hello world", b 0 }
+
+export function w $main() {
+@start
+        # Call the puts function with $str as argument.
+        %r =w call $puts(l $str)
+        ret 0
+}

M syntax/overview.snow => syntax/overview.snow +94 -6
@@ 17,14 17,16 @@ import http, json, "github.com/some3rdparty/other"
 var s str
 
 # A block can be started after most keywords (`var`, `let`, `import`,
-# `type`, etc.) and the included statements all have that keyword apply, so the
+# `struct`, etc.) and the included statements all have that keyword apply, so the
 # following declares 4 variables.
-var {
+#
+# OR parens, because curly braces introduce a scope, which isn't the case here?
+var (
   x i8
   y i32
   z u64
   b bool
-}
+)
 
 # `let` declares a read-only "variable" or constant. It must be assigned
 # before use, and can only be assigned once.


@@ 36,18 38,22 @@ let pi = 3.1415
 # i8, i16, i32, i64 => signed integers
 # f32, f64 => floating-point numbers
 # bool => boolean (true, false)
+# void => no type
 
 # The array is a built-in aggregate data type. It holds values of the same type.
 var ar [4]u8 = [1, 2, 3, 4]
 
 # The struct is another built-in aggregate data type. It holds a pre-defined number
-# of values of possibly different types. A new data type is introduced by the
-# `type` keyword.
-type Person struct {
+# of values of possibly different types. A new struct is introduced by the
+# `struct` keyword.
+struct Person {
   # fields of a struct can be mutable or not.
   var age i8
   let id u32
 
+  # var is optional, it is the default for a struct field.
+  alive bool
+
   # methods are defined by implementing a function inside the struct block.
   # There is an implicit `self` argument, but it is seldom required to type
   # because unknown variables are automatically resolved by looking at the


@@ 56,3 62,85 @@ type Person struct {
     printf("person: {}, age {}", id, age)
   }
 }
+
+# `enum` introduces an enumeration. By default, it implicitly takes integer
+# values from 0. Specific values can be explicitly set.
+enum HttpCode {
+  success = 200
+  not_found = 404
+  # etc.
+}
+
+# Enumerations can have associated values. Combined with generics, this allows
+# avoiding nulls and elegant error-handling.
+enum Optional {
+  some $T
+  none void
+
+  fn is_some() bool {
+    # ... using pattern matching
+  }
+}
+
+enum Result {
+  ok $T
+  err $E
+}
+
+# lambdas and closures
+fn main(args []str) {
+  # short lambda syntax (types might be inferred by context)
+  let add = |x, y i32| i32 => x + y
+  let pi = 3.14
+  # longer syntax
+  let math = fn (r i32) f32 {
+      return pi * r
+  }
+}
+
+# protocol: the polymorphism / dynamic dispatch story, can also be used
+# to restrict generic types. Defines the "structure" a type must have,
+# and predefined protocols exist for built-in types.
+protocol Hashable {
+  fn hash() u64
+}
+
+# protocols are satisfied implicitly, no need to declare that a struct
+# "implements" a protocol.
+protocol User {
+  let id i32      # types with a var id i32 satisfy this
+  var salary u64  # types with let salary u64 do not satisfy this
+  fn name() str
+
+  # protocol extensions can be implemented too, so any type that
+  # satisfies the extension can also use those extensions, provided
+  # the type is "type-checked" as the protocol. Much like structs,
+  # a `self` argument is implicit.
+  fn format() str {
+    return fmt.printf("{} {}", id, name())
+  }
+}
+
+# TBD: strings, slices/vectors/etc., maps/hashes/dicts.
+
+# dynamic arrays or vectors or slices are not really part of the language,
+# built in the runtime module but have some compiler magic and syntax sugar.
+var ar vec($int) ???
+
+# dictionaries also are built in the runtime and have syntax sugar/literals.
+var lookup [str:int] = [:]
+
+# anonymous structs (tuples) can be created from syntax literals
+var point {i32, i32} = {1, 32}
+let emptyTuple = {}
+let emptyDict = [:]
+let emptySlice = []
+
+# there is no tuple type, but anonymous structs can be created easily.
+var x struct { a i32, b u64 } = { a: 1, b: 3 }
+# as special shortcut, field names can be omitted and can be referenced
+# as .0, .1, etc.
+var x struct { i32, u64 } = { 1, 3 }
+x.0 = 2
+x.1 = 6
+