diff --git a/TODO.md b/TODO.md new file mode 100644 index 0000000..a942599 --- /dev/null +++ b/TODO.md @@ -0,0 +1,140 @@ +# TODO/Plans + +## General Pipeline +- Transform a single file into a `CompilationUnit` AST node. +- Gather all `CompilationUnit`s and determine which modules need to be built. + - A module corresponds to one syntactical namespace `ns`, but not its children! + - For a namespace to be used as a top-level grouping in a file, it must be declared like so: + ``` + decl pub ns std { + decl pub ns core, http, json + decl ns internal + } + ``` + Here, `decl` indicates that the namespace is declared for top-level usage in other files. `pub` indicates that the + namespace may be read from other namespaces. `std` here is the identifier for the namespace, and the contents + inside its brackets are child namespaces. The list of child namespaces are all nested insided `std`, so are + referenced like `std::core`, `std::http`, etc. The non-`pub` namespace `internal` is readable from within the + namespace `std`, but not from outside of it. + - A namespace inside a file but not `decl` (declared) can only have members *in that file*. It cannot be used as a + top-level namespace in another file. However, the accessibility rules are similar to top-level namespaces: + ``` + ns std::core + + pub fn foo() = bar::baz() + + ns bar { + fn baz = hello() + prv fn hello = println("Hello, World!") + } + ``` + In this example, the namespace `bar` is accesible from the rest of the file, but not outside of it. The function + `bar::baz` can be called by within `foo`, but `hello`, being private to `bar`, can only be called by `baz`. +- Once the namespaces to be compiled have been computed, create a `DmModule` for each namespace. +- For each `CompilationUnit`, associate it to the correct `DmModule`, and transform its declarations into the + appropriate objects, such as `DmInterface`, `DmImplementation`, `DmFunction`, or `DmConstant`. +- Thus, a `DmModule` is a single-file containing all the code for one namespace, but not its child namespaces. Using + the above examples, the following DmModules would be created, with their appropriate contents: + - `pub ns std`: *no contents, only metadata.* + - `pub ns std::core`: + - `pub fn std::core::foo` + - `ns std::core::bar` + - `fn std::core::bar::baz` + - `prv fn std::core::bar::hello`: only accessible inside `std::core::bar`. + +## More Namespace Rules + +Top-level namespace declaration: +``` +decl pub ns std +``` + +Nested namespace declaration and members: +``` +ns std::core // indicates that all members of this file are in the std::core namespace + +// Indicates that array is a nested namespace in std::core, and is referencable by std::core::array +pub ns array { + pub int SomeInterface + pub cls SomeClass : SomeInterace + pub fn associated_fn() {} +} +``` + +## Example of std lib would be coded + +std/std.dm +``` +decl pub ns std { + decl pub ns core, http, json + decl ns internal // only accessible to members of std +} +``` + +std/core/core.dm +``` +ns std + +/* This declaration is merged with the one in std.dm */ +decl pub ns core { + decl pub ns hkt +} +``` + +std/core/array.dm +``` +ns std::core + +use std::core::hkt::Monad + +pub int Array : Monad[T] {} + +impl ByteArray(fld raw_address: USize, fld count: USize) : Array { + + impl fn map(fab) { + let mut rs = List(count) // dynamic list? + for (let i in 0..count) { + rs << fab(std::internal::mem::get_byte(raw_address + i)) + } + rs + } + + impl fn flat_map(fab) { + let mut rs = [] + for (let i in 0..count) { + rs << fab(std::internal::mem::get_byte(raw_address + i)) + } + rs.flatten() + } + +} + +pub ns array { + + extern fn _of(ts: ...T): Array + + pub fn of(ts: ...T) = _of(ts) + +} +``` + +std/core/hkt/monad.dm +``` +ns std::core::hkt + +pub hkt Monad[a] { + fn [b] map(fab: a -> b) -> T[b] + fn [b] flat_map(fab: a -> T[b]) -> T[b] + + def op fn pipe(fab: a -> b) -> T[b] = map(fab) + def op fn pipe(fab: a -> T[b]) -> T[b] = flat_map(fab) +} +``` + +std/core/string.dm +``` +ns std::core + +pub int String : Monad[Char] +``` +