aboutsummaryrefslogtreecommitdiff
path: root/doc
diff options
context:
space:
mode:
Diffstat (limited to 'doc')
-rw-r--r--doc/DESIGN.md251
-rw-r--r--doc/IMPLEMENTED.md2
2 files changed, 253 insertions, 0 deletions
diff --git a/doc/DESIGN.md b/doc/DESIGN.md
new file mode 100644
index 0000000..b8693f1
--- /dev/null
+++ b/doc/DESIGN.md
@@ -0,0 +1,251 @@
+# Amalgam design document
+Amalgam is a simple language with few keywords but at the same time is very powerful.
+All functions are closures. Assigning a closure to a variable is how you make regular functions.
+
+## Hello world
+```
+const main = () {
+ stderr.writeln("hello, world!");
+}
+```
+
+## Conditions
+```
+const main = () {
+ var value = 23 + 50;
+ if value < 23
+ stderr.writeln("less!");
+ else
+ stderr.writeln("more!");
+
+ while value > 0 {
+ stderr.writeln("value: {}", value);
+ value -= 1;
+ }
+}
+```
+
+## Data types
+```
+const main = () !void {
+ var v1: i32 = 50;
+ var v2: u32 = 50;
+
+ v1 = v2; // error, v2 can't be implicitly cast to v1 because i32 can't represent the same values as u32
+ v1 = @cast(i32, v2); // ok, explicitly cast u32 to i32
+
+ var str1 = "hello";
+ var str2 = "world";
+ var str3 = try str1 + " " + str2;
+ var str4 = try str1 + 20; // error, can't add number to string. Preferable use str.fmt or explicitly cast to string
+ var str5 = try str1 + str(20); // ok, number explicitly cast to string
+
+ const str6 = "hello";
+ const str7 = "world";
+ const str8 = str6 + " " + str7; // ok, all variable involved are const. They can be combined at compile-time
+
+ stderr.writeln("{}, {} | {}", str1, str2, str3); // prints hello world | hello world
+}
+```
+
+## Dynamic allocation (array)
+```
+const ArrayList = @import("std.array.ArrayList");
+
+const main = () !void {
+ var list = ArrayList(i32);
+ try list.add(23);
+ try list.add(50);
+ var value = list.get(40);
+
+ for val in list {
+ stdout.writeln("value: {}", val);
+ }
+}
+```
+
+## Structures and instances
+```
+struct User {
+ name: str,
+ age: i32,
+ level = 1 // default value is 1 and type is i32
+}
+
+const levelUp = (self: &User) {
+ self.level += 1;
+}
+
+const main = () {
+ const user1 = User {
+ name: "John",
+ age: 24
+ }
+
+ var user2 = User {
+ name: "Titor",
+ age: 50,
+ level: 100
+ }
+
+ levelUp(user2);
+ // syntax sugar for calling a function with the first argument as
+ // the variable before the dot (same thing as levelUp(user2))
+ user2.levelUp();
+}
+```
+
+## Named parameters
+Functions call be called with arguments in position that matches the parameters or by using the names of the parameters.
+```
+struct User {
+ name: str,
+ age: i32,
+ level: i32
+}
+
+const createUser = (name: str, age: i32, level: i32 = 1) User {
+ return User {
+ name: name,
+ age: age,
+ level: level
+ }
+}
+
+const main = {
+ createUser(name: "John", level: 30, age: 30);
+ createUser(age: 40, name: "Titor");
+}
+```
+
+## Closure
+```
+const apply = (func: () bool) {
+ const result = func();
+}
+
+const main = () {
+ // Return type is automatically deduces. If function returns multiple different types at different points, then you get an error and are required to specify the return type
+ apply((){
+ return true;
+ });
+
+ apply(() bool {
+ return true;
+ });
+
+ // Or store in a variable and use it
+ const func = () {
+ return true;
+ }
+ apply(func);
+}
+```
+
+## Generic programming
+```
+const add = (comptime T: type, a: T, b: T) !T {
+ return try a + b;
+}
+
+const main = () {
+ var numberValue = add(20, 40);
+ var stringValue = add("hello", "world");
+}
+```
+
+## Ownership
+Like Rust, Amalgam has a concept of ownership but with less cumbersome syntax.
+There is one issue with ownership and that is references to data that gets reallocated.
+Rust doesn't handle this but Amalgam does it using #reallocatable(instance).
+Reallocatable should be ignored if the reference that taken from the reallocatable memory
+doesn't change location after realloc, which would be the case for pointers.
+```
+const ArrayList = @import("std.array.ArrayList");
+
+struct User {
+ name: str,
+ level: i32
+}
+
+const addUserToList = (list: &ArrayList(User), user: User) {
+ // this is not actually needed for ArrayList because ArrayList uses #reallocatable internally for list.add and list.remove
+ @reallocatable list.add(move user);
+}
+
+const main = () {
+ var users = ArrayList(User);
+ users.add(User {
+ name: "John",
+ level: 34
+ });
+
+ const user1 = User {
+ name: "David",
+ level: 55
+ }
+ // error, addUserToList expects user1 to be moved or copied
+ // addUserToList(users, user1);
+
+ // addUserToList(users, clone user1); // ok, user1 has been copied to function scope
+ addUserToList(users, move user1); // ok, user1 has been moved to function scope
+
+ next(move users);
+}
+
+const getUserAtIndex = (list: &ArrayList(User), index: usize) User {
+ return list.get(index);
+}
+
+const next = (users: ArrayList(User)) {
+ const user = getUserAtIndex(users, 0);
+
+ // Reallocatable example:
+ addUserToList(users, User {
+ name: "John",
+ level: 34
+ });
+
+ // error, "user" can't be safely used because addUserToList on line XXX can reallocate "users" which "user" belongs to
+ stdout.writeln("user name: {}", user.name);
+}
+```
+
+## Table (inspired by lua)
+```
+const main = () {
+ const values = {
+ "name": "John",
+ "age": 42,
+ "dogs": [
+ "spot",
+ "doggy"
+ ]
+ }
+
+ printMap(values); // stdout.writeln("{}", values) can also be used directly as it supports tables
+}
+
+const printTable = (value: TableValue) {
+ switch @type(value) {
+ array => {
+ // value type is automatically cast to array here, same with other cases in the switch
+ for index, val in value {
+ stdout.write("[{}] = ", index);
+ printTable(val);
+ stdout.writeln(",");
+ }
+ }
+ map => {
+ stdout.writeln("{");
+ for key, val in value {
+ stdout.write("'{}': ", key);
+ printTable(val);
+ stdout.writeln(",");
+ }
+ stdout.writeln("}");
+ }
+ else => stdout.write(value);
+ }
+}
+``` \ No newline at end of file
diff --git a/doc/IMPLEMENTED.md b/doc/IMPLEMENTED.md
new file mode 100644
index 0000000..2583774
--- /dev/null
+++ b/doc/IMPLEMENTED.md
@@ -0,0 +1,2 @@
+const main = () {
+} \ No newline at end of file