deimos-lang/TODO.md

4.0 KiB

TODO/Plans

General Pipeline

  • Transform a single file into a CompilationUnit AST node.
  • Gather all CompilationUnits 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<T> : Monad<List>[T] {}

impl ByteArray(fld raw_address: USize, fld count: USize) : Array<Byte> {

    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<T>

    pub fn <T> of(ts: ...T) = _of(ts)

}

std/core/hkt/monad.dm

ns std::core::hkt

pub hkt Monad<T = Self>[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<List>[Char]