From 11dc4b81935e3dfee997c421d8d6fa166edd7a05 Mon Sep 17 00:00:00 2001 From: dec05eba Date: Sun, 24 Feb 2019 02:10:58 +0100 Subject: Initial commit, Function declaration work somewhat --- doc/DESIGN.md | 251 +++++++++++++++++++++++++++++++++++++++++++++++++++++ doc/IMPLEMENTED.md | 2 + 2 files changed, 253 insertions(+) create mode 100644 doc/DESIGN.md create mode 100644 doc/IMPLEMENTED.md (limited to 'doc') 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 -- cgit v1.2.3