diff --git a/spec.md b/spec.md index 7c611fe..68debe6 100644 --- a/spec.md +++ b/spec.md @@ -409,28 +409,85 @@ Give fuzzy-matched suggestions for at the following things: ## Store as much debug in fromation as possible until type checking is done +# Compilation units + +Each file is a "compilation unit" + +When compiling a compilation unit, the following inputs have to be provided: +- any amount of files containing signatures of exported definitions. + only definitions of the compilation unit that are in one of the signature files will get exported. +- any amount of other files containing imported definitions + +Note that there is no practical difference between signature and source files. + +
+Example + +Export signature file `List.li`: +``` +type List[t] = 'End | 'Cons {head:t, tail:List[t]} + +# not providing a function body makes it a function signature definition +def [t] `a++b`(a: List[t], b: List[t]) -> List[t] +``` + +Import signature file `Option.li`: +``` +type Option[t] = 'None | 'Some t +``` + +Compilation unit `List.lu`: +``` +def [t] `a++b`(a: List[t], b: List[t]) -> List[t] { + # ... +} +``` + +
+ # Syntax Note that the order of syntax cases matter! ``` Identifier = { (* ( a-z | A-Z | 0-9 | _ | - | . | # ) TODO: cvt to ebnf *) }; + Partial Type = '?', Identifier; Union Type Case = '\'', Identifier, [ Type (*default to Unit*) ]; Union Type = Union Type Case, { '|', Union Type Case}; Record Type Field = Identifier, ':', Type; Record Type = '{', [Record Type Field, {',' Record Type Field }], [ '...', Partial Type ], '}'; -Type = Partial Type | Identifier | Union Type | Record Type | TODO; +With Type = 'with', Identifier, {',', Identifier}, ':', Type; +Recursive Type = '&', Identifier, Type; +Nested Type = '(', Type, ')'; +Multi Arg Type = '[', Type, {',', Type} ']', Type; +Auto Type = '_'; (* this only works as return type of signatures of func def, that also contain the impl *) +Type Part = Auto Type | Identifier | Partial Type | Union Type | Record Type | With Type | Recursive Type | Nested Type; +Type = {Type Part (* args *)}, Type Part; + ``` + + + + + + + + + + + + + + + + + + + + # OLD SPECIFICATION STARTING HERE -## automatic return types -``` -def add(a: Num, b: Num) -> _ { - a + b -} -``` - ## pattern matching ``` type Option[t] = 'None | 'Some t @@ -462,121 +519,7 @@ def example(li: List[Char]) -> {t:Token,rem:List[Char]} { } ``` -## recursive data types -``` -type List[t] = 'End | 'Cons {head:t, tail:List[t]} -# now you might notice an issue with this -# `type` defines non-distinct type alisases -# so what is the type of this... -# Introducing: type self references -# the above example is the same as this: -type List[t] = &a ('End | 'Cons {head:t, tail:a}) -# example 2: -# a List[List[t]] is just: -&b ('End | 'Cons {head: &a ('End | 'Cons {head:t, tail:a}), tail: b}) -``` - -Infinitely sized types are not allowed: -``` -&a {x:Num, y:a} -``` - -However, infinite types without size *are* allowed: -``` -&a {x:a} -``` - -This is *not* allowed: -``` -&a a -``` - -## module system -Each file is a "compilation unit" - -When compiling a compilation unit, the following inputs have to be provided: -- any amount of files containing signatures of exported definitions. - only definitions of the compilation unit that are in one of the signature files will get exported. -- any amount of other files containing imported definitions - -Note that there is no practical difference between signature and source files. - -### Example -Export signature file `List.li`: -``` -type List[t] = 'End | 'Cons {head:t, tail:List[t]} - -# not providing a function body makes it a function signature definition -def [t] `a++b`(a: List[t], b: List[t]) -> List[t] - -def [t] Match.`a++b`( - value: List[t], - l: List[t], - r: MatchUtil.Var[List[t]] -) -> Option[{ r: List[t] }] -``` - -Import signature file `Option.li`: -``` -type Option[t] = 'None | 'Some t -``` - -Compilation unit `List.lu`: -``` -def [t] `a++b`(a: List[t], b: List[t]) -> List[t] { - # ... -} - -def [t] Match.`a++b`( - value: List[t], - l: List[t], - r: MatchUtil.Var[List[t]] -) -> Option[{ r: List[t] }] { - # ... -} -``` - -### Notes -Each compilation unit gets compiled to implementation-specific bytecode. - -Templated functions can only be compiled partially during a compilation unit. This will impact compile speeds. - -Avoid templated functions wherever possible. - -## Hide record fields in module signatures -Signatue: -``` -type User = {name: List[Char], ...} - # the ... is used to indicate that this is a partial type definition - # User, as given here, can not be constructed, but name can be accessed -``` -Compilation unit: -``` -type User = {name: List[Char], password: List[Char]} -``` - -## Hide union variants in module signatures -Signature: -``` -type DType = 'Int | 'UInt | 'Byte | ... - # users of this can never do exhaustive pattern matching on this -``` -Compilation unit: -``` -type DType = 'Int | 'UInt | 'Byte - # this compilation unit can actually do exhaustive pattern matching on this -``` - -## Note on hidden union variants / record fields -To make these work, the following is legal: -``` -def example() -> 'Int | 'UInt | ... - -def example() -> 'Int | 'UInt | 'Byte | 'Char { - # ... -} -``` ## Extensible unions ``` @@ -589,17 +532,6 @@ extend Plan with 'WritelnPlan Unit # can only pattern match with the imported extensions ``` -## Any type -in the stdlib: -``` -extensible union Any - -type Any.LambdaCalc = 'Apply {fn: Any.LambdaCalc, arg: Any.LambdaCalc} - | 'Scope {idx: Uint} - | 'Abstr {inner: Any.LambdaCalc} -def Any.toLambda(a: Any) -> Any.LambdaCalc -``` -It gets automatically extended with every type ever used. ## Lenses In the stdlib: