-
Notifications
You must be signed in to change notification settings - Fork 40
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[ideas] Some other ideas for packages and traits
- Loading branch information
Showing
2 changed files
with
300 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
/* | ||
Ideas for Virgil packages | ||
----------------------------- | ||
|
||
Goals: | ||
- add namespacing capabilities for Virgil | ||
- x86-linux constants vs x86-64-linux, etc | ||
- v3.util.Vector | ||
- better build system | ||
- more ergonomic simple programs | ||
- faster builds | ||
|
||
Example packages: | ||
- v3c.magic - Virgil compiler magic | ||
- v3c.x86-linux - target-specific magic | ||
- v3c.x86 - CPU-specific magic | ||
- v3c.wasm - Wasm-specific magic | ||
- v3rt.magic - runtime magic | ||
- v3rt.gc | ||
- v3rt.code | ||
- v3rt.safety | ||
- v3.cli - command-line utilities (env, etc) | ||
- v3.util - data structures and strings | ||
- v3.io - I/O | ||
- v3.net - networking | ||
- v3.file.macho | ||
- v3.file.elf - ELF processing | ||
- v3.file.jar - JAR | ||
- v3.file.zip - ZIP files | ||
- v3.file.class - Java class files | ||
- v3.file.wasm | ||
- v3.file.gpx | ||
- v3.kernel.linux - Linux kernel constants and layouts | ||
- v3.kernel.darwin - Darwin kernel constants | ||
- v3.kernel.wali | ||
- v3.kernel.zephyr | ||
- aeneas.ir | ||
- aeneas.ssa | ||
- aeneas.mach | ||
.x86 | ||
.x86-64 | ||
.arm | ||
.arm64 | ||
.wasm | ||
.jvm | ||
- aeneas.os | ||
.darwin | ||
.linux | ||
.none | ||
- aeneas.tools | ||
- aeneas.main | ||
- aeneas.test | ||
- aeneas.ast | ||
|
||
Usage: | ||
*/ | ||
|
||
//#File: lib/util/package.v3 | ||
//---------------------------------------- | ||
package v3.lib; | ||
private XYZ; | ||
add *.v3; | ||
target x86-linux: add f*.x86*.v3 | ||
target jvm: add f*.jvm*.v3 | ||
using v3.lib; | ||
|
||
//#File: lib/util/StringBuilder.v3 | ||
//---------------------------------------- | ||
// Copyright | ||
class StringBuilder { ... } | ||
|
||
//#File: MyFile.v3 | ||
//---------------------------------------- | ||
using v3.lib; | ||
|
||
var map = Strings.newMap() with { | ||
["foo"] = bar, | ||
["foo1"] = bar2, | ||
["foo2"] = bar3, | ||
}; | ||
var b = StringBuilder.new() with { | ||
.resize(44), | ||
.puts("things"), | ||
.putd(48), | ||
.x = 99 | ||
} | ||
System.puts(Arrays.reverse("Hello World!")); | ||
|
||
/* | ||
==================================== | ||
Index files: transparently cache modules/packages | ||
Binary format, easy to mmap + parse header | ||
package v3.lib | ||
<versioning information> | ||
<hash index> | ||
name:offset, name:offset, name:offset | ||
<reachability cache> | ||
<bytecode> | ||
<machine code?> | ||
<source at end> | ||
*/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,199 @@ | ||
// Idea: traits are constraints on type parameters, analogous to Haskell Type Classes or C++ concepts. | ||
|
||
type Value { | ||
case I32(val: i32); | ||
case I64(val: i64); | ||
} | ||
|
||
// An trait for boxable things, {Boxable} requires a type to have a method for boxing a {T} into a {Value}. | ||
// The {T} binds a type parameter so that signatures of methods can refer to the type that {Boxable} constrains. | ||
trait<T> Boxable { | ||
def box(t: T) -> Value; | ||
} | ||
|
||
// An trait for unboxable things, {Boxable} requires a type to have a method for unboxing a {Value} into a {T}. | ||
// The {T} binds a type parameter so that signatures of methods can refer to the type that {Unboxable} constrains. | ||
trait<T> Unboxable { | ||
def unbox(v: Value) -> T; | ||
} | ||
|
||
// An trait is used to limit what type arguments can be supplied at a given point. | ||
// A polymorphic method to search an array for a given element type {T}. Given a range of boxed values, search | ||
// through the range, unboxing and checking each value. | ||
def find<T: Unboxable>(vs: Range<Value>, elem: T) -> int { | ||
for (i < vs.length) if (T.unbox(vs[i]) == elem) return i; | ||
return -1; | ||
} | ||
|
||
adapt i32 { | ||
Boxable { | ||
def box(t: i32) -> Value { return Value.I32(t); } | ||
} | ||
Unboxable { | ||
def unbox(v: Value) -> i32 { return Value.I32.!(v).val; } | ||
} | ||
} | ||
|
||
adapt i64 { | ||
Boxable { | ||
def box(t: i64) -> Value { return Value.I64(t); } | ||
} | ||
Unboxable { | ||
def unbox(v: Value) -> i64 { return Value.I64.!(v).val; } | ||
} | ||
} | ||
|
||
// Define the union of traits. | ||
trait<T: Boxable&Unboxable> Boxed { | ||
} | ||
|
||
trait<T> group { | ||
def one: T; // multiplicative identity | ||
|
||
def "*"(a: T, b: T) -> T; // multiply operation | ||
|
||
require(v: T) v == one * v; // strength-reduce multiply | ||
require(a: T, b: T) (a * b) == (b * a); // commutative | ||
require(a: T, b: T, c: T) a * (b * c) == (a * b) * c; // associative | ||
} | ||
|
||
|
||
trait<T> ring { | ||
def zero: T; // additive identity | ||
def one: T; // multiplicative identity | ||
|
||
def inverse(a: T) -> T; | ||
def "+"(a: T, b: T) -> T; // add operation | ||
def "*"(a: T, b: T) -> T; // multiply operation | ||
|
||
def "-"(a: T, b: T) => a + inverse(b); // define subtract operation | ||
|
||
require(v: T) v == inverse(inverse(v)); // invertable | ||
require(v: T) v == zero + v; // strength-reduce add | ||
require(v: T) v == one * v; // strength-reduce multiply | ||
|
||
require(a: T, b: T) (a + b) == (b + a); // commutative addition | ||
require(a: T, b: T, c: T) (a + b) + c == a + (b + c); // associative addition | ||
require(a: T, b: T) (a * b) == (b * a); // commutative multiplication | ||
require(a: T, b: T, c: T) (a * b) * c == a * (b * c); // associative multiplication | ||
|
||
require(a: T, b: T, c: T) (a - b) - c == a - (b + c); // reassociative subtraction | ||
require(a: T, b: T, c: T) (a - b) + c == a - (c - b); // reassociative subtraction | ||
|
||
require(a: T, b: T, c: T) a * (b + c) == (a * b) + (a * c); // distributive multiplication | ||
require(a: T, b: T, c: T) (b + c) * a == (b * a) + (c * a); // distributive multiplication | ||
} | ||
|
||
type Vec2<T>(x: T, y: T) #unboxed { | ||
def unop(f: T -> R) => Vec2<R>(f(this.x), f(this.y)); | ||
def binop(that: Vec2<T>, f: (T, T) -> T) => Vec2<T>(f(this.x, that.x), f(this.y, that.y)); | ||
} | ||
|
||
type Vec3<T>(x: T, y: T, z: T) #unboxed { | ||
def unop(f: T -> R) => Vec3<R>(f(this.x), f(this.y), f(this.z)); | ||
def binop(that: Vec3<U>, f: (T, U) -> R) => Vec3<R>(f(this.x, that.x), f(this.y, that.y), f(this.z, that.z)); | ||
} | ||
|
||
// For any T that implements ring, Vec2<T> can implement ring. | ||
implements<T: ring> Vec2<T> { | ||
ring { | ||
def zero = Vec2<T>(T.zero, T.zero); | ||
def one = Vec2<T>(T.one, T.one); | ||
|
||
def inverse(a: Vec2<T>) => a.unop(T.inverse); | ||
def "+"(a: Vec2<T>, b: Vec2<T>) => a.binop(b, T.+); | ||
def "*"(a: Vec2<T>, b: Vec2<T>) => a.binop(b, T.*); | ||
} | ||
} | ||
|
||
// For any T that implements ring, Vec3<T> can implement ring. | ||
implements<T: ring> Vec3<T> { | ||
ring { | ||
def zero = Vec3<T>(T.zero, T.zero, T.zero); | ||
def one = Vec3<T>(T.one, T.one, T.one); | ||
|
||
def inverse(a: Vec3<T>) => a.unop(T.inverse); | ||
def "+"(a: Vec3<T>, b: Vec3<T>) => a.binop(b, T.+); | ||
def "*"(a: Vec3<T>, b: Vec3<T>) => a.binop(b, T.*); | ||
} | ||
} | ||
|
||
// For any two A and B that implement ring, (A, B) will also implement ring. | ||
implements<A: ring, B: ring> (A, B) { | ||
ring { | ||
def zero = (A.zero, B.zero); | ||
def one = (A.zero, B.zero); | ||
|
||
def inverse(v: (A, B)) => (A.inverse(v.0), B.inverse(v.1)); | ||
def "+"(a: (A, B), b: (A, B)) => (a.0 + b.0, a.1 + b.1); | ||
def "*"(a: (A, B), b: (A, B)) => (a.0.binop(b.0, A.*), (a.1.binop(b.1, B.*))); | ||
} | ||
} | ||
|
||
trait<T: equal> integral { | ||
def zero: T; | ||
def max: T; | ||
def min: T; | ||
|
||
def "+"(a: T, b: T) -> T; | ||
def "-"(a: T, b: T) -> T; | ||
def "*"(a: T, b: T) -> T; | ||
def "/"(a: T, b: T) -> T; | ||
def "%"(a: T, b: T) -> T; | ||
def "<"(a: T, b: T) -> T; | ||
|
||
def ">"(a: T, b: T) => b < a; | ||
def "<="(a: T, b: T) => a < b || a == b; | ||
def ">="(a: T, b: T) => a > b || a == b; | ||
|
||
def "<<"(a: T, b: shiftor) -> T; | ||
def ">>"(a: T, b: shiftor) -> T; | ||
def ">>>"(a: T, b: shiftor) -> T; | ||
} | ||
|
||
trait<T> Closeable { | ||
def T.close(); | ||
} | ||
|
||
class File implements Closeable { | ||
def revoke() -> this; | ||
def flush() -> this; | ||
def close() => flush().revoke(); | ||
} | ||
|
||
def run<R: Closeable>(resource: R) { | ||
computeStuff(); | ||
resource.close(); | ||
} | ||
|
||
trait<T, I, E> Indexable<I, E> { | ||
def [index: I] -> E; | ||
def [index: I] = val: E; | ||
} | ||
|
||
def search<M: Indexable<Key, Value>>(map: M) -> Value { | ||
for (key in allKeys) { | ||
var v = map[key]; | ||
if (v == null) return map[key] = Value.new(); | ||
return v; | ||
} | ||
} | ||
|
||
def linearSearch<M: Indexable<int, Value>>(map: M, max: int) -> Value { | ||
for (i < max) { | ||
var v = map[i]; | ||
if (v == null) return map[i] = Value.new(); | ||
return v; | ||
} | ||
} | ||
|
||
class HashMap<K, V> implements Indexable<K, V> { } | ||
|
||
trait<T, V> Stack<V> { | ||
def isEmpty() -> bool; | ||
def push(v: V) -> this; | ||
def pop() -> V?; | ||
} | ||
|
||
class ArrayStack<E> implements Stack<E> { ... } | ||
class ListStack<E> implements Stack<E> { ... } |