From 7cbb1d3b52bc9025c0117d869948641934c83479 Mon Sep 17 00:00:00 2001 From: Valentin Knabel Date: Thu, 17 Feb 2022 20:55:11 +0100 Subject: [PATCH] stdlib: mark functions as internal and improved docs --- .gitignore | 1 + CHANGELOG.md | 19 +- info/globals.go | 2 +- stdlib/cmp.md | 29 ++- stdlib/cmp/comparables.lithia | 11 ++ stdlib/cmp/contravariant.lithia | 8 + stdlib/cmp/equatableFrom.lithia | 6 +- stdlib/cmp/numeric.lithia | 2 +- stdlib/controls.md | 16 +- stdlib/controls/_monad.lithia | 5 + stdlib/controls/contravariant.lithia | 2 + stdlib/controls/functor.lithia | 3 +- stdlib/docs.md | 116 +++++++----- stdlib/docs/inspect.lithia | 79 +++++++- stdlib/docs/internal/internal-markup.lithia | 79 ++++++++ stdlib/docs/markdown.lithia | 2 +- stdlib/docs/markup.lithia | 106 ++--------- stdlib/eq/contravariant.lithia | 1 + stdlib/fs.md | 19 +- stdlib/fs/shim.lithia | 7 + stdlib/lists.md | 13 ++ stdlib/lists/concat.lithia | 2 + stdlib/lists/functor.lithia | 2 + stdlib/lists/is-empty.lithia | 1 + stdlib/lists/monad.lithia | 4 + stdlib/markdown.md | 11 +- ...markdown.lithia => markdown-format.lithia} | 40 ++-- ...down_t.lithia => markdown-format_t.lithia} | 56 +++--- stdlib/markup.md | 174 +++++++++++++----- stdlib/markup/convenience.lithia | 21 ++- stdlib/markup/format.lithia | 31 ++++ stdlib/markup/nodes.lithia | 68 ++++++- stdlib/markup/serialize.lithia | 21 --- stdlib/optionals.md | 31 ++-- stdlib/optionals/equatable.lithia | 16 +- stdlib/optionals/functor.lithia | 9 +- stdlib/optionals/is-none.lithia | 5 +- stdlib/optionals/optional.lithia | 12 +- stdlib/optionals/or-default.lithia | 7 +- stdlib/os.md | 6 +- stdlib/os/shim.lithia | 2 + stdlib/prelude.md | 38 +++- stdlib/prelude/_shim.lithia | 35 ++++ stdlib/prelude/optional.lithia | 7 + stdlib/prelude/shim.lithia | 22 --- stdlib/prelude/when.lithia | 8 +- stdlib/ranges.md | 8 + stdlib/ranges/open-numbers.lithia | 8 + stdlib/results.md | 17 ++ stdlib/results/functors.lithia | 4 + stdlib/results/monads.lithia | 8 + stdlib/results/result.lithia | 1 + stdlib/rx.md | 2 + stdlib/rx/variable.lithia | 2 + stdlib/strings.md | 2 + stdlib/strings/strings.lithia | 3 + stdlib/tests.md | 7 +- stdlib/tests/basic.lithia | 48 +---- stdlib/tests/internal/test-cases.lithia | 46 +++++ 59 files changed, 931 insertions(+), 380 deletions(-) create mode 100644 stdlib/docs/internal/internal-markup.lithia rename stdlib/markdown/{markdown.lithia => markdown-format.lithia} (69%) rename stdlib/markdown/markdown_t/{markdown_t.lithia => markdown-format_t.lithia} (53%) create mode 100644 stdlib/markup/format.lithia delete mode 100644 stdlib/markup/serialize.lithia create mode 100644 stdlib/prelude/_shim.lithia delete mode 100644 stdlib/prelude/shim.lithia create mode 100644 stdlib/strings/strings.lithia create mode 100644 stdlib/tests/internal/test-cases.lithia diff --git a/.gitignore b/.gitignore index 68d92c2..d5562bc 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ *.dll *.so *.dylib +__debug_bin # Test binary, built with `go test -c` *.test diff --git a/CHANGELOG.md b/CHANGELOG.md index 895be63..ac73970 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,22 @@ # Changelog +## v0.0.15-next + +- stdlib: removed `docs.moduleMemberDocsToMarkup`, `docs.dataFieldDocsToMarkup` and `docs.enumCaseDocsToMarkup` and marked them as internal +- stdlib: renamed `markup.MarkupNode` to `markup.Markup` +- stdlib: renamed `markup.Serializer` to `markup.Format` +- stdlib: renamed `markup.SerializerWitness` to `markup.FormatWitness` +- stdlib: renamed `markup.serialize` to `markup.convert` +- stdlib: renamed `markdown.serializer` to `markup.format` +- stdlib: renamed `markdown.serialize` to `markup.convert` +- stdlib: removed `markdown.asMarkdown` +- stdlib: removed `optionals.Optional`. Use `prelude.Optional` instead +- stdlib: added `prelude.Maybe` as `prelude.Some`, `prelude.None` or `prelude.Any` +- stdlib: improved `optionals` functions to also support `prelude.Maybe` +- stdlib: removed `tests.testCases` and `tests.runTestCase` and marked them as internal +- fix: `docs` of `docs.ExternFunctionDocs` has always been empty +- docs: improved for all modules + ## v0.0.14 - lsp: fix jump to definition @@ -7,7 +24,7 @@ - lsp: fix logging too many errors - lsp: deleting files, deletes its diagnostics - fix: extern docs generation -- stdlib: new markup and markdown library +- stdlib: new `markup` and `markdown` library - stdlib: better docs generation ## v0.0.13 diff --git a/info/globals.go b/info/globals.go index 280e081..29e7ebc 100644 --- a/info/globals.go +++ b/info/globals.go @@ -1,3 +1,3 @@ package info -var Version = "0.0.14" +var Version = "0.0.15-next" diff --git a/stdlib/cmp.md b/stdlib/cmp.md index b3791e1..cf8972b 100644 --- a/stdlib/cmp.md +++ b/stdlib/cmp.md @@ -13,27 +13,33 @@ Defines comparision operations, ascending and descending of values. ## Ascending -_data_ +_data_ Indicates an ascending order of two values. +For example 1 and 2. ## Comparable -_data_ +_data_ Instances compare values regarding the order. +Witnesses are typically only defined for specific types. ### Properties -- `compare lhs, rhs` +- `compare lhs, rhs` - Compares two values. +@returns Order ## Descending -_data_ +_data_ Indicates an descending order of two values. +For example 2 and 1. ## Equal -_data_ +_data_ Both values are ordered equally. +In context of Order, it doesn't necessarily require equality. ## Order _enum_ +Represents the order of two values. ### Cases @@ -45,9 +51,20 @@ _enum_ _func_ `equatableFrom comparableWitness` -Creates an `eq.Equatable` +Creates an `eq.Equatable` from a `cmp.Comparable`. +`cmp.Equal` will result in `True`, +`cmp.Ascending` and `cmp.Descending` will be `False`. + +@returns eq.Equatable ## pullback _func_ `pullback f, witness` +Lifts an existing `cmp.Comparable` witness to a different type. +Can be used to pick a specific property of complex data. + +```lithia +let compareUsersById = cmp.pullback { user => user.id }, cmp.numeric +``` + diff --git a/stdlib/cmp/comparables.lithia b/stdlib/cmp/comparables.lithia index 22cd0dc..2fa695d 100644 --- a/stdlib/cmp/comparables.lithia +++ b/stdlib/cmp/comparables.lithia @@ -1,13 +1,24 @@ /// Defines comparision operations, ascending and descending of values. module cmp +/// Instances compare values regarding the order. +/// Witnesses are typically only defined for specific types. data Comparable { + /// Compares two values. + /// @returns Order compare lhs, rhs } +/// Represents the order of two values. enum Order { + /// Indicates an ascending order of two values. + /// For example 1 and 2. data Ascending + /// Both values are ordered equally. + /// In context of Order, it doesn't necessarily require equality. data Equal + /// Indicates an descending order of two values. + /// For example 2 and 1. data Descending } diff --git a/stdlib/cmp/contravariant.lithia b/stdlib/cmp/contravariant.lithia index 0f73c39..3351a05 100644 --- a/stdlib/cmp/contravariant.lithia +++ b/stdlib/cmp/contravariant.lithia @@ -2,12 +2,20 @@ module cmp import controls { Contravariant } +/// Lifts an existing `cmp.Comparable` witness to a different type. +/// Can be used to pick a specific property of complex data. +/// +/// ```lithia +/// let compareUsersById = cmp.pullback { user => user.id }, cmp.numeric +/// ``` func pullback { f, witness => Comparable { lhs, rhs => witness.compare f lhs, f rhs } } +/// A `controls.Contravariant` witness for `cmp.Comparable`. +/// Allows to lift comparision to different types. let contravariant = Contravariant pullback import tests { test } diff --git a/stdlib/cmp/equatableFrom.lithia b/stdlib/cmp/equatableFrom.lithia index 1e65f23..6989ed4 100644 --- a/stdlib/cmp/equatableFrom.lithia +++ b/stdlib/cmp/equatableFrom.lithia @@ -2,7 +2,11 @@ module cmp import eq -/// Creates an `eq.Equatable` +/// Creates an `eq.Equatable` from a `cmp.Comparable`. +/// `cmp.Equal` will result in `True`, +/// `cmp.Ascending` and `cmp.Descending` will be `False`. +/// +/// @returns eq.Equatable func equatableFrom { comparableWitness => eq.Equatable { lhs, rhs => with (comparableWitness.compare lhs, rhs), type Order { diff --git a/stdlib/cmp/numeric.lithia b/stdlib/cmp/numeric.lithia index 45e62a9..0da2bd2 100644 --- a/stdlib/cmp/numeric.lithia +++ b/stdlib/cmp/numeric.lithia @@ -1,6 +1,6 @@ module cmp -/// `Comparable` for numbers using < and >. +/// `Comparable` witness for numbers using < and >. /// Not safe for other types. let numeric = Comparable { lhs, rhs => if lhs < rhs, Ascending, ( diff --git a/stdlib/controls.md b/stdlib/controls.md index 395b5a0..784d670 100644 --- a/stdlib/controls.md +++ b/stdlib/controls.md @@ -138,19 +138,26 @@ flatMap repeat 2, lists.monad _func_ `contravariantFrom moduleWitness` +Creates a Contravariant from a given ContravariantWitness. + ## flatMap _func_ `flatMap f, witness, instance` +Flat map for a yet unknown witness and instance. +Can be used in generic contexts, where the witness will be curried. + ## functorFrom _func_ `functorFrom moduleWitness` +Creates a Functor from a given FunctorWitness. + ## map _func_ `map f, witness, value` -Transforms a wrapped value using a functor witness. +Transforms a wrapped value using a yet unknown functor witness and value. Essentially just uses the map of the given witness, but allows to defer the decision regarding the witness itself. @@ -165,11 +172,18 @@ map incr, lists, [1, 2, 3] _func_ `monadFrom monadWitness` +Creates a Monad from a given MonadWitness. + ## pullback _func_ `pullback f, witness` +pullback for a yet unknown witness. + ## pure _func_ `pure value, witness` +Creates a pure monad value from a yet unknown witness. +Can be used in generic contexts, where the witness will be curried. + diff --git a/stdlib/controls/_monad.lithia b/stdlib/controls/_monad.lithia index f6f3498..bb2285e 100644 --- a/stdlib/controls/_monad.lithia +++ b/stdlib/controls/_monad.lithia @@ -26,6 +26,7 @@ enum MonadWitness { Module } +/// Creates a Monad from a given MonadWitness. func monadFrom { monadWitness => with monadWitness, type MonadWitness { Monad: { witness => witness }, @@ -35,10 +36,14 @@ func monadFrom { monadWitness => } } +/// Creates a pure monad value from a yet unknown witness. +/// Can be used in generic contexts, where the witness will be curried. func pure { value, witness => (monadFrom witness).pure value } +/// Flat map for a yet unknown witness and instance. +/// Can be used in generic contexts, where the witness will be curried. func flatMap { f, witness, instance => (monadFrom witness).flatMap f, instance } diff --git a/stdlib/controls/contravariant.lithia b/stdlib/controls/contravariant.lithia index e1f9a89..fb7e42d 100644 --- a/stdlib/controls/contravariant.lithia +++ b/stdlib/controls/contravariant.lithia @@ -36,6 +36,7 @@ enum ContravariantWitness { Function } +/// Creates a Contravariant from a given ContravariantWitness. func contravariantFrom { moduleWitness => with moduleWitness, type ContravariantWitness { Contravariant: { witness => witness }, @@ -48,6 +49,7 @@ func contravariantFrom { moduleWitness => } } +/// pullback for a yet unknown witness. func pullback { f, witness => (contravariantFrom witness).pullback f } diff --git a/stdlib/controls/functor.lithia b/stdlib/controls/functor.lithia index c4176ba..043023e 100644 --- a/stdlib/controls/functor.lithia +++ b/stdlib/controls/functor.lithia @@ -40,6 +40,7 @@ enum FunctorWitness { Monad } +/// Creates a Functor from a given FunctorWitness. func functorFrom { moduleWitness => with moduleWitness, type FunctorWitness { Functor: { witness => witness }, @@ -56,7 +57,7 @@ func functorFrom { moduleWitness => } /** - * Transforms a wrapped value using a functor witness. + * Transforms a wrapped value using a yet unknown functor witness and value. * Essentially just uses the map of the given witness, * but allows to defer the decision regarding the witness itself. * diff --git a/stdlib/docs.md b/stdlib/docs.md index 47dd8a3..5dadae0 100644 --- a/stdlib/docs.md +++ b/stdlib/docs.md @@ -13,30 +13,41 @@ _module_ - _data_ [FunctionDocs](#FunctionDocs) - _data_ [ModuleDocs](#ModuleDocs) - _enum_ [TypeDocs](#TypeDocs) -- _func_ [dataFieldDocsToMarkup](#dataFieldDocsToMarkup) field - _func_ [docsToMarkdown](#docsToMarkdown) docs - _func_ [docsToMarkup](#docsToMarkup) -- _func_ [enumCaseDocsToMarkup](#enumCaseDocsToMarkup) case - _extern_ [inspect](#inspect) value -- _func_ [moduleMemberDocsToMarkup](#moduleMemberDocsToMarkup) ## ConstantDocs -_data_ +_data_ The documentation of a constant declaration. +If a constant resolves to a function, it can still be called. + +```lithia +/// The docs string +let constantName = 42 +``` ### Properties -- `name` -- `docs` +- `name` - The name of the constant declaration. +- `docs` - The docs as text. ## DataDocs -_data_ +_data_ The documentation of a data declaration. + +```lithia +/// The docs string +data DataName { +someFields with, params +orWithout +} +``` ### Properties - `name` - The name of the data declaration -- `docs` +- `docs` - The docs as text. - `fields` - A List of fields of DataFieldDocs ## DataFieldDocs @@ -46,8 +57,9 @@ _data_ Describes a field of a data type ### Properties - `name` - name of the data property -- `docs` -- `params` +- `docs` - The docs as text. +- `params` - A List of the data field's parameter names. +Can be treated as function if not Nil. ## EnumCaseDocs @@ -55,9 +67,9 @@ _data_ The documentation for a specific enum case. ### Properties -- `name` -- `docs` -- `type` +- `name` - The name of the enum case. +- `docs` - The docs as text. +- `type` - The underlaying type of the enum case. ## EnumDocs @@ -65,9 +77,9 @@ _data_ Contains all documentation information for a given enum. ### Properties -- `name` - Name of the enum -- `docs` -- `cases` +- `name` - Name of the enum. +- `docs` - The docs as text. +- `cases` - Each enum case as EnumCaseDocs. ## ExternFieldDocs @@ -76,48 +88,72 @@ _data_ Describes a field of a data type ### Properties - `name` - name of the data property -- `docs` -- `params` +- `docs` - The docs as text. +- `params` - A List of the extern field's parameter names. +Can be treated as function if not Nil. ## ExternFunctionDocs -_data_ +_data_ The documentation of an extern function declaration. + +```lithia +/// The docs string +extern externFunctionName params, asList +``` ### Properties -- `name` -- `docs` -- `params` +- `name` - The name of the external function. +- `docs` - The docs as text. +- `params` - A list of its paramter names. Can be treated as constant if Nil. ## ExternTypeDocs -_data_ +_data_ The documentation of an extern type declaration. + +```lithia +/// The docs string +extern ExternTypeName { +someFields with, params +orWithout +} +``` ### Properties -- `name` -- `docs` -- `fields` - a list of ExternFieldDocs +- `name` - The name of the external type. +- `docs` - The docs as text. +- `fields` - a list of ExternFieldDocs. ## FunctionDocs -_data_ +_data_ The documentation of a function declaration. + +```lithia +/// The docs string +func functionName { params => } +``` ### Properties -- `name` -- `docs` -- `params` +- `name` - name of the function. +- `docs` - The docs as text. +- `params` - A list of the function's parameter names. ## ModuleDocs -_data_ +_data_ The documentation of a module declaration. + +```lithia +/// The docs string +module internalModuleName +``` ### Properties - `name` - name of the module - `types` - all types declared in the module -- `docs` +- `docs` - The docs as text. ## TypeDocs @@ -135,10 +171,6 @@ All possible docs inspection values. - [ExternFunctionDocs](#ExternFunctionDocs) - [None](#None) -## dataFieldDocsToMarkup - -_func_ `dataFieldDocsToMarkup field` - ## docsToMarkdown _func_ `docsToMarkdown docs` @@ -147,16 +179,10 @@ _func_ `docsToMarkdown docs` _func_ `docsToMarkup` -## enumCaseDocsToMarkup - -_func_ `enumCaseDocsToMarkup case` - ## inspect +_func_ `inspect value` -_extern_ `inspect value` - -## moduleMemberDocsToMarkup - -_func_ `moduleMemberDocsToMarkup` +Inspects a given value for documentation. +@returns TypeDocs diff --git a/stdlib/docs/inspect.lithia b/stdlib/docs/inspect.lithia index c1cde49..ef09d8f 100644 --- a/stdlib/docs/inspect.lithia +++ b/stdlib/docs/inspect.lithia @@ -1,50 +1,116 @@ module docs +/// Inspects a given value for documentation. +/// @returns TypeDocs extern inspect value /// All possible docs inspection values. enum TypeDocs { /// Contains all documentation information for a given enum. data EnumDocs { - /// Name of the enum + /// Name of the enum. name + /// The docs as text. docs + /// Each enum case as EnumCaseDocs. cases } + + /// The documentation of a data declaration. + /// + /// ```lithia + /// /// The docs string + /// data DataName { + /// someFields with, params + /// orWithout + /// } + /// ``` data DataDocs { /// The name of the data declaration name + /// The docs as text. docs /// A List of fields of DataFieldDocs fields } + + /// The documentation of a module declaration. + /// + /// ```lithia + /// /// The docs string + /// module internalModuleName + /// ``` data ModuleDocs { /// name of the module name /// all types declared in the module types + /// The docs as text. docs } + + /// The documentation of a function declaration. + /// + /// ```lithia + /// /// The docs string + /// func functionName { params => } + /// ``` data FunctionDocs { + /// name of the function. name + /// The docs as text. docs + /// A list of the function's parameter names. params } + + /// The documentation of a constant declaration. + /// If a constant resolves to a function, it can still be called. + /// + /// ```lithia + /// /// The docs string + /// let constantName = 42 + /// ``` data ConstantDocs { + /// The name of the constant declaration. name + /// The docs as text. docs } + + /// The documentation of an extern type declaration. + /// + /// ```lithia + /// /// The docs string + /// extern ExternTypeName { + /// someFields with, params + /// orWithout + /// } + /// ``` data ExternTypeDocs { + /// The name of the external type. name + /// The docs as text. docs - /// a list of ExternFieldDocs + /// a list of ExternFieldDocs. fields } + + /// The documentation of an extern function declaration. + /// + /// ```lithia + /// /// The docs string + /// extern externFunctionName params, asList + /// ``` data ExternFunctionDocs { + /// The name of the external function. name + /// The docs as text. docs + /// A list of its paramter names. Can be treated as constant if Nil. params } + /// No docs available for the currently reflected type. None } @@ -52,7 +118,10 @@ enum TypeDocs { data DataFieldDocs { /// name of the data property name + /// The docs as text. docs + /// A List of the data field's parameter names. + /// Can be treated as function if not Nil. params } @@ -60,14 +129,20 @@ data DataFieldDocs { data ExternFieldDocs { /// name of the data property name + /// The docs as text. docs + /// A List of the extern field's parameter names. + /// Can be treated as function if not Nil. params } /// The documentation for a specific enum case. data EnumCaseDocs { + /// The name of the enum case. name + /// The docs as text. docs + /// The underlaying type of the enum case. type } diff --git a/stdlib/docs/internal/internal-markup.lithia b/stdlib/docs/internal/internal-markup.lithia new file mode 100644 index 0000000..fb88d1f --- /dev/null +++ b/stdlib/docs/internal/internal-markup.lithia @@ -0,0 +1,79 @@ +import markup +import strings + +import docs + +func moduleMemberDocsToMarkup { => + type docs.TypeDocs { + ModuleDocs: { d => + markup.inline [ + markup.i "module", + (markup.ref d.name, d.name) + ] + }, + EnumDocs: { d => + markup.inline [ + markup.i "enum", + (markup.ref d.name, d.name) + ] + }, + DataDocs: { d => + markup.inline [ + markup.i "data", + (markup.ref d.name, d.name) + ] + }, + FunctionDocs: { d => + markup.inline [ + markup.i "func", + (markup.ref d.name, d.name) + (strings.join ", ", d.params) + ] + }, + ConstantDocs: { d => + markup.inline [ + markup.i "let", + (markup.ref d.name, d.name) + ] + }, + ExternTypeDocs: { d => + markup.inline [ + markup.i "extern", + (markup.ref d.name, d.name) + ] + }, + ExternFunctionDocs: { d => + markup.inline [ + markup.i "extern", + (markup.ref d.name, d.name) + (strings.join ", ", d.params) + ] + }, + None: { _ => "" } + } +} + +func dataFieldDocsToMarkup { field => + let docsSuffix = if field.docs == "", "", strings.concat [" - ", field.docs] + let fieldText = with field.params, type List { + Cons: { params => + markup.inline [ + field.name, + (strings.join ", ", params) + ] + }, + Nil: { _ => field.name }, + } + markup.li [ + markup.pre fieldText, + docsSuffix + ] +} + +func enumCaseDocsToMarkup { case => + let docsSuffix = if case.docs == "", "", strings.concat [" - ", case.docs] + markup.li [ + (markup.ref case.name, case.type.name), + docsSuffix + ] +} diff --git a/stdlib/docs/markdown.lithia b/stdlib/docs/markdown.lithia index 1850512..99b96d9 100644 --- a/stdlib/docs/markdown.lithia +++ b/stdlib/docs/markdown.lithia @@ -3,5 +3,5 @@ module docs import markdown func docsToMarkdown { docs => - markdown.serialize docsToMarkup docs + markdown.convert docsToMarkup docs } diff --git a/stdlib/docs/markup.lithia b/stdlib/docs/markup.lithia index 918f2db..7be9c67 100644 --- a/stdlib/docs/markup.lithia +++ b/stdlib/docs/markup.lithia @@ -3,6 +3,7 @@ module docs import markup import lists import strings +import docs.internal func docsToMarkup { => type TypeDocs { @@ -13,7 +14,7 @@ func docsToMarkup { => markup.i "module", d.docs ]), - markup.ul (lists.map moduleMemberDocsToMarkup, d.types), + markup.ul (lists.map internal.moduleMemberDocsToMarkup, d.types), (lists.map docsToMarkup, d.types) ] }, @@ -22,7 +23,7 @@ func docsToMarkup { => Cons: { cons => markup.group [ markup.h3 "Cases", - markup.ul (lists.map enumCaseDocsToMarkup, d.cases) + markup.ul (lists.map internal.enumCaseDocsToMarkup, d.cases) ] }, Nil: { _ => "" } @@ -41,7 +42,7 @@ func docsToMarkup { => Cons: { cons => markup.group [ markup.h3 "Properties", - markup.ul (lists.map dataFieldDocsToMarkup, cons) + markup.ul (lists.map internal.dataFieldDocsToMarkup, cons) ] }, Nil: { _ => "" } @@ -90,7 +91,7 @@ func docsToMarkup { => Cons: { cons => markup.group [ markup.h3 "Properties", - markup.ul (lists.map dataFieldDocsToMarkup, cons) + markup.ul (lists.map internal.dataFieldDocsToMarkup, cons) ] }, Nil: { _ => "" } @@ -110,94 +111,25 @@ func docsToMarkup { => Cons: strings.join ", ", Nil: { _ => "" } } - markup.p [ + markup.group [ markup.h2 d.name, - markup.inline [ - markup.i "extern", - markup.pre [ - d.name, - " ", - params, + markup.p [ + markup.inline [ + markup.i "func", + markup.pre (markup.inline [ + d.name, + params, + ]), ], - d.docs, - ] - ] - }, - None: { _ => "" } - } -} - -func moduleMemberDocsToMarkup { => - type TypeDocs { - ModuleDocs: { d => - markup.inline [ - markup.i "module", - (markup.ref d.name, d.name) - ] - }, - EnumDocs: { d => - markup.inline [ - markup.i "enum", - (markup.ref d.name, d.name) - ] - }, - DataDocs: { d => - markup.inline [ - markup.i "data", - (markup.ref d.name, d.name) - ] - }, - FunctionDocs: { d => - markup.inline [ - markup.i "func", - (markup.ref d.name, d.name) - (strings.join ", ", d.params) - ] - }, - ConstantDocs: { d => - markup.inline [ - markup.i "let", - (markup.ref d.name, d.name) - ] - }, - ExternTypeDocs: { d => - markup.inline [ - markup.i "extern", - (markup.ref d.name, d.name) - ] - }, - ExternFunctionDocs: { d => - markup.inline [ - markup.i "extern", - (markup.ref d.name, d.name) - (strings.join ", ", d.params) + ], + (if d.docs == "", "", markup.p d.docs), ] + let params = with d.params, type List { + Cons: strings.join ", ", + Nil: { _ => "" } + } }, None: { _ => "" } } } -func dataFieldDocsToMarkup { field => - let docsSuffix = if field.docs == "", "", strings.concat [" - ", field.docs] - let fieldText = with field.params, type List { - Cons: { params => - markup.inline [ - field.name, - (strings.join ", ", params) - ] - }, - Nil: { _ => field.name }, - } - markup.li [ - markup.pre fieldText, - docsSuffix - ] -} - -func enumCaseDocsToMarkup { case => - let docsSuffix = if case.docs == "", "", strings.concat [" - ", case.docs] - markup.li [ - (markup.ref case.name, case.type.name), - docsSuffix - ] -} diff --git a/stdlib/eq/contravariant.lithia b/stdlib/eq/contravariant.lithia index 9998cc4..ccba8cf 100644 --- a/stdlib/eq/contravariant.lithia +++ b/stdlib/eq/contravariant.lithia @@ -13,4 +13,5 @@ func pullback { transform, witness => } } +/// The Contravariant over eq.Equatable. let contravariant = Contravariant pullback diff --git a/stdlib/fs.md b/stdlib/fs.md index 2c7f916..27555d6 100644 --- a/stdlib/fs.md +++ b/stdlib/fs.md @@ -10,26 +10,35 @@ _module_ ## delete +_func_ `delete atPath` -_extern_ `delete atPath` +Deletes a file or empty directory at a given path. +Returns a `result.Result`. ## deleteAll +_func_ `deleteAll atPath` -_extern_ `deleteAll atPath` +Deletes a file or any directory at a given path. +Returns a `result.Result`. ## exists +_func_ `exists atPath` -_extern_ `exists atPath` +Returns a Bool if a file or directory exists at a given path. ## readString +_func_ `readString fromPath` -_extern_ `readString fromPath` +Reads a file at a given path. +Returns `result.Result`. ## writeString +_func_ `writeString toPath, newContents` -_extern_ `writeString toPath, newContents` +Write a given string to a path. +Returns `results.Result`. diff --git a/stdlib/fs/shim.lithia b/stdlib/fs/shim.lithia index 448924e..00151bf 100644 --- a/stdlib/fs/shim.lithia +++ b/stdlib/fs/shim.lithia @@ -9,7 +9,14 @@ import results { /// Write a given string to a path. /// Returns `results.Result`. extern writeString toPath, newContents +/// Reads a file at a given path. +/// Returns `result.Result`. extern readString fromPath +/// Returns a Bool if a file or directory exists at a given path. extern exists atPath +/// Deletes a file or empty directory at a given path. +/// Returns a `result.Result`. extern delete atPath +/// Deletes a file or any directory at a given path. +/// Returns a `result.Result`. extern deleteAll atPath diff --git a/stdlib/lists.md b/stdlib/lists.md index 17e7597..73aa7f8 100644 --- a/stdlib/lists.md +++ b/stdlib/lists.md @@ -32,6 +32,8 @@ Appends an element to the end of a list. _func_ `concat nestedLists` +Concats a list of lists. + ## count _func_ `count list` @@ -80,6 +82,9 @@ When empty `Nil`, otherwise `Some`. _func_ `flatMap transform, list` +Transforms a list's values into a list of more values. +Concats these values into one single list while keeping their order. + ## foldr _func_ `foldr accumulator, initial` @@ -99,18 +104,26 @@ Returns last result or `prelude.Void`. _func_ `isEmpty list` +True if the given list is Nil. Otherwise False. + ## map _func_ `map transform, list` +Transforms the list values, while keeping their order. + ## prependList _func_ `prependList prefix, postfix` +Prepends a given prefix with another postfix list. + ## pure _func_ `pure value` +Creates a list with one single element. + ## reduce _func_ `reduce accumulator, initial` diff --git a/stdlib/lists/concat.lithia b/stdlib/lists/concat.lithia index ff8b62b..18d3bba 100644 --- a/stdlib/lists/concat.lithia +++ b/stdlib/lists/concat.lithia @@ -1,9 +1,11 @@ +/// Prepends a given prefix with another postfix list. func prependList { prefix, postfix => foldr { nextHead, postfix => Cons nextHead, postfix }, postfix, prefix } +/// Concats a list of lists. func concat { nestedLists => foldr { nextList, appendedLists => prependList nextList, appendedLists diff --git a/stdlib/lists/functor.lithia b/stdlib/lists/functor.lithia index 931fbda..7e02503 100644 --- a/stdlib/lists/functor.lithia +++ b/stdlib/lists/functor.lithia @@ -2,8 +2,10 @@ module lists import controls { Functor } +/// The Functor for lists. Allows transforming values, while keeping their order. let functor = Functor map +/// Transforms the list values, while keeping their order. func map { transform, list => with list, type List { Cons: { part => diff --git a/stdlib/lists/is-empty.lithia b/stdlib/lists/is-empty.lithia index d732b0c..ad029ee 100644 --- a/stdlib/lists/is-empty.lithia +++ b/stdlib/lists/is-empty.lithia @@ -1,5 +1,6 @@ module lists +/// True if the given list is Nil. Otherwise False. func isEmpty { list => with list, type List { Cons: { _ => False }, diff --git a/stdlib/lists/monad.lithia b/stdlib/lists/monad.lithia index ab23d63..562a361 100644 --- a/stdlib/lists/monad.lithia +++ b/stdlib/lists/monad.lithia @@ -2,12 +2,16 @@ module lists import controls { Monad } +/// The Monad witness of List. let monad = Monad pure, flatMap +/// Creates a list with one single element. func pure { value => Cons value } +/// Transforms a list's values into a list of more values. +/// Concats these values into one single list while keeping their order. func flatMap { transform, list => lists.concat (lists.map transform, list) } diff --git a/stdlib/markdown.md b/stdlib/markdown.md index 34d65a2..23d341d 100644 --- a/stdlib/markdown.md +++ b/stdlib/markdown.md @@ -1,10 +1,15 @@ # markdown _module_ +Implements the markdown format. +Currently only handles converting markup.Markup to markdown strings. +Planned to be able of parsing markdown strings to markup.Markup in the future. -- _func_ [asMarkdown](#asMarkdown) +- _func_ [convert](#convert) -## asMarkdown +## convert -_func_ `asMarkdown` +_func_ `convert` + +Converts markup.Markup to a markdown string. diff --git a/stdlib/markdown/markdown.lithia b/stdlib/markdown/markdown-format.lithia similarity index 69% rename from stdlib/markdown/markdown.lithia rename to stdlib/markdown/markdown-format.lithia index bb73586..ecf51a7 100644 --- a/stdlib/markdown/markdown.lithia +++ b/stdlib/markdown/markdown-format.lithia @@ -1,16 +1,22 @@ +/// Implements the markdown format. +/// Currently only handles converting markup.Markup to markdown strings. +/// Planned to be able of parsing markdown strings to markup.Markup in the future. +module markdown + import markup import strings import lists import ranges -let serializer = markup.Serializer asMarkdown -let serialize = asMarkdown +/// The default markup.Format to generate markdown from markup. +let format = markup.Format convert -func asMarkdown { => - type markup.MarkupNode { +/// Converts markup.Markup to a markdown string. +func convert { => + type markup.Markup { String: { str => str }, List: pipe [ - lists.map asMarkdown, + lists.map markdown.convert, strings.concat ], Heading: { hx => @@ -20,17 +26,17 @@ func asMarkdown { => strings.concat [ prefix, " ", - asMarkdown hx.child, + markdown.convert hx.child, "\n\n" ] }, Paragraph: { b => - let paragraph = with b.child, type markup.MarkupNode { + let paragraph = with b.child, type markup.Markup { List: pipe [ - lists.map asMarkdown, + lists.map markdown.convert, strings.join "\n" ], - Any: { _ => asMarkdown b.child } + Any: { _ => markdown.convert b.child } } strings.concat [ paragraph, @@ -40,21 +46,21 @@ func asMarkdown { => Italic: { n => strings.concat [ "_", - asMarkdown n.child, + markdown.convert n.child, "_", ] }, Bold: { n => strings.concat [ "**", - asMarkdown n.child, + markdown.convert n.child, "**", ] }, Link: { n => strings.concat [ "[", - asMarkdown n.child, + markdown.convert n.child, "]", "(", n.url, @@ -64,7 +70,7 @@ func asMarkdown { => Image: { n => strings.concat [ "![", - asMarkdown n.alt, + markdown.convert n.alt, "]", "(", n.url, @@ -74,12 +80,12 @@ func asMarkdown { => Code: { n => strings.concat [ "`", - asMarkdown n.text, + markdown.convert n.text, "`", ] }, CodeBlock: { n => - let language = with n.language, type Optional { + let language = with n.language, type Maybe { Some: { some => some.value }, None: { none => "" }, Any: { any => any } @@ -94,7 +100,7 @@ func asMarkdown { => }, UnorderedList: { n => let items = lists.map pipe [ - asMarkdown, + markdown.convert, "- ".append ], n.children @@ -107,7 +113,7 @@ func asMarkdown { => let items = lists.zipWith { i, child => strings.concat [ i, ". ", - asMarkdown child, + markdown.convert child, ] }, ranges.indices, n.children diff --git a/stdlib/markdown/markdown_t/markdown_t.lithia b/stdlib/markdown/markdown_t/markdown-format_t.lithia similarity index 53% rename from stdlib/markdown/markdown_t/markdown_t.lithia rename to stdlib/markdown/markdown_t/markdown-format_t.lithia index 86b5866..9aa19aa 100644 --- a/stdlib/markdown/markdown_t/markdown_t.lithia +++ b/stdlib/markdown/markdown_t/markdown-format_t.lithia @@ -4,86 +4,86 @@ import tests { test } -test "markdown.serialize string", { fail => +test "markdown.convert string", { fail => let m = "Hello World" - let actual = markdown.asMarkdown m + let actual = markdown.convert m unless actual == "Hello World", fail actual } -test "markdown.serialize list of strings", { fail => +test "markdown.convert list of strings", { fail => let m = ["Hello", " ", "World"] - let actual = markdown.asMarkdown m + let actual = markdown.convert m unless actual == "Hello World", fail actual } -test "markdown.serialize h1", { fail => +test "markdown.convert h1", { fail => let m = markup.Heading 1, "Hello World" - let actual = markdown.asMarkdown m + let actual = markdown.convert m unless actual == "# Hello World\n\n", fail actual } -test "markdown.serialize h2", { fail => +test "markdown.convert h2", { fail => let m = markup.Heading 2, "Hi" - let actual = markdown.asMarkdown m + let actual = markdown.convert m unless actual == "## Hi\n\n", fail actual } -test "markdown.serialize paragraph", { fail => +test "markdown.convert paragraph", { fail => let m = markup.Paragraph "Hi" - let actual = markdown.asMarkdown m + let actual = markdown.convert m unless actual == "Hi\n\n", fail actual } -test "markdown.serialize italic", { fail => +test "markdown.convert italic", { fail => let m = markup.Italic "Hi" - let actual = markdown.asMarkdown m + let actual = markdown.convert m unless actual == "_Hi_", fail actual } -test "markdown.serialize bold", { fail => +test "markdown.convert bold", { fail => let m = markup.Bold "Hi" - let actual = markdown.asMarkdown m + let actual = markdown.convert m unless actual == "**Hi**", fail actual } -test "markdown.serialize link", { fail => +test "markdown.convert link", { fail => let m = markup.Link "Lithia", "https://github.com/vknabel/lithia" - let actual = markdown.asMarkdown m + let actual = markdown.convert m unless actual == "[Lithia](https://github.com/vknabel/lithia)", fail actual } -test "markdown.serialize image", { fail => +test "markdown.convert image", { fail => let m = markup.Image "./assets/lithia.png", "lithia logo" - let actual = markdown.asMarkdown m + let actual = markdown.convert m unless actual == "![lithia logo](./assets/lithia.png)", fail actual } -test "markdown.serialize code", { fail => +test "markdown.convert code", { fail => let m = markup.Code "example" - let actual = markdown.asMarkdown m + let actual = markdown.convert m unless actual == "`example`", fail actual } -test "markdown.serialize code block with no language", { fail => +test "markdown.convert code block with no language", { fail => let m = markup.CodeBlock None, "example" - let actual = markdown.asMarkdown m + let actual = markdown.convert m unless actual == "```\nexample\n```\n\n", fail actual } -test "markdown.serialize code block with empty language", { fail => +test "markdown.convert code block with empty language", { fail => let m = markup.CodeBlock "", "example" - let actual = markdown.asMarkdown m + let actual = markdown.convert m unless actual == "```\nexample\n```\n\n", fail actual } -test "markdown.serialize code block with some language", { fail => +test "markdown.convert code block with some language", { fail => let m = markup.CodeBlock Some "lithia", "example" - let actual = markdown.asMarkdown m + let actual = markdown.convert m unless actual == "```lithia\nexample\n```\n\n", fail actual } -test "markdown.serialize code block with string language", { fail => +test "markdown.convert code block with string language", { fail => let m = markup.CodeBlock "lithia", "example" - let actual = markdown.asMarkdown m + let actual = markdown.convert m unless actual == "```lithia\nexample\n```\n\n", fail actual } diff --git a/stdlib/markup.md b/stdlib/markup.md index 6b20977..78825b6 100644 --- a/stdlib/markup.md +++ b/stdlib/markup.md @@ -1,22 +1,25 @@ # markup _module_ +A generalized data format to represent human readable contents. +Though it is not meant to represent HTML nodes. - _data_ [Bold](#Bold) - _data_ [Code](#Code) - _data_ [CodeBlock](#CodeBlock) +- _data_ [Format](#Format) +- _enum_ [FormatWitness](#FormatWitness) - _data_ [Heading](#Heading) - _data_ [Image](#Image) - _data_ [Italic](#Italic) - _data_ [Link](#Link) -- _enum_ [MarkupNode](#MarkupNode) +- _enum_ [Markup](#Markup) - _data_ [OrderedList](#OrderedList) - _data_ [Paragraph](#Paragraph) -- _data_ [Serializer](#Serializer) -- _enum_ [SerializerWitness](#SerializerWitness) - _data_ [UnorderedList](#UnorderedList) - _func_ [b](#b) - _func_ [code](#code) +- _func_ [convert](#convert) markup, targetFormatWitness - _func_ [from](#from) witness - _func_ [group](#group) list - _func_ [h1](#h1) @@ -34,73 +37,115 @@ _module_ - _func_ [p](#p) child - _func_ [pre](#pre) - _func_ [ref](#ref) child, name -- _func_ [serialize](#serialize) markup, witness - _func_ [text](#text) str - _func_ [ul](#ul) child ## Bold -_data_ +_data_ A bold portion of inline text. + +> Bold **"text"** ### Properties -- `child` +- `child` - At least one child of type Markup. ## Code -_data_ +_data_ Some preformatted inline code. + +> `Code text` ### Properties -- `text` +- `text` - Some text. Markup not supported. ## CodeBlock -_data_ +_data_ A block of preformatted multiline code. + +> ```lithia +> CodeBlock "lithia", "text" +> ``` ### Properties -- `language` -- `text` +- `language` - Maybe the language as string. +Implementations must support Some, None and String. +- `text` - The text itself as String. + +## Format + +_data_ A specific markup format to convert to. + +### Properties + +- `convert markup` - Converts given markup to this format. + +## FormatWitness + +_enum_ +A more generalized form of a markup.Format. +Allows to use plain functions and whole modules as format. + +### Cases + +- [Format](#Format) +- [Module](#Module) +- [Function](#Function) ## Heading -_data_ +_data_ A heading of a specific nesting level. + +> ##### Heading 5, "title" ### Properties -- `level` -- `child` +- `level` - The level of nesting. +An Int, typically in the range of one to six. +- `child` - At least one child of type Markup. ## Image -_data_ +_data_ An embedded image. + +> Image ![url](https://github.com/vknabel/lithia/blob/main/assets/lithia.png), alt ### Properties -- `url` -- `alt` +- `url` - The url of the image. +Markup not supported. +- `alt` - Alternatively displayed text in case the image can't be loaded or for accessibility. +Markup not supported. ## Italic -_data_ +_data_ An italic portion of inline text. + +> Italic _"text"_ ### Properties -- `child` +- `child` - At least one child of type Markup. ## Link -_data_ +_data_ A link to a resource. + +> [Link child, url](https://github.com/vknabel/lithia) ### Properties -- `child` -- `url` +- `child` - At least one child of type Markup. +Used to display the link. +- `url` - The url to point to. +Markup not supported. -## MarkupNode +## Markup _enum_ +A recursive enum of markup nodes. ### Cases @@ -119,62 +164,75 @@ _enum_ ## OrderedList -_data_ +_data_ An ordered list. Requires a list of children. + +> OrderedList [ +> 1. item +> 2. another +> +> ] ### Properties -- `children` +- `children` - A list of Markup children. ## Paragraph -_data_ - -### Properties - -- `child` - -## Serializer +_data_ A paragraph with some blank lines around. -_data_ +> Paragraph [ +> "First", +> "Second" +> ] ### Properties -- `serialize markup` - -## SerializerWitness - -_enum_ - -### Cases - -- [Serializer](#Serializer) -- [Module](#Module) -- [Function](#Function) +- `child` - At least one child of type Markup. ## UnorderedList -_data_ +_data_ An unordered list. Requires a list of children. + +> UnorderedList [ +> - item +> - another +> +> ] ### Properties -- `children` +- `children` - A list of Markup children. ## b _func_ `b` +**bold** text + ## code _func_ `code` +A Code block. + +## convert + +_func_ `convert markup, targetFormatWitness` + +Converts some markup to a target format. + ## from _func_ `from witness` +Creates a Format from a given FormatWitness. + ## group _func_ `group list` +A list of markup for better readbility. + ## h1 _func_ `h1` @@ -203,47 +261,65 @@ _func_ `h6` _func_ `i` +_italic_ text + ## img _func_ `img` +An image with url and alt. + ## inline _func_ `inline list` +Some inline text. Ignores empty elements. Adds spaces. + ## li _func_ `li item` +A list item for better readability. + ## link _func_ `link` +A link with title and url. + ## ol _func_ `ol child` +An ordered list. Ignores empty lines. + ## p _func_ `p child` +A paragraph. Ignores empty lines. + ## pre _func_ `pre` +Preformatted inline code. + ## ref _func_ `ref child, name` -## serialize - -_func_ `serialize markup, witness` +An internal ref to a heading. ## text _func_ `text str` +Constant text for better readbility. + ## ul _func_ `ul child` +An unordered list. Ignores empty lines. + diff --git a/stdlib/markup/convenience.lithia b/stdlib/markup/convenience.lithia index 6eaf334..2e6014d 100644 --- a/stdlib/markup/convenience.lithia +++ b/stdlib/markup/convenience.lithia @@ -9,44 +9,59 @@ func h4 { => Heading 4 } func h5 { => Heading 5 } func h6 { => Heading 6 } +/// _italic_ text func i { => Italic } +/// **bold** text func b { => Bold } +/// A blank line. let br = Paragraph "" +/// A paragraph. Ignores empty lines. func p { child => - let filtered = with child, type MarkupNode { + let filtered = with child, type Markup { List: (lists.filter { n => n != "" && n != " " && n != Nil }), Any: { node => node } } Paragraph filtered } +/// Preformatted inline code. func pre { => Code } +/// A Code block. func code { => CodeBlock } +/// An image with url and alt. func img { => Image } +/// A link with title and url. func link { => Link } +/// An internal ref to a heading. func ref { child, name => Link child, "#".append name } +/// An unordered list. Ignores empty lines. func ul { child => - let filtered = with child, type MarkupNode { + let filtered = with child, type Markup { List: (lists.filter { n => n != "" && n != " " && n != Nil }), Any: { node => node } } UnorderedList filtered } +/// An ordered list. Ignores empty lines. func ol { child => - let filtered = with child, type MarkupNode { + let filtered = with child, type Markup { List: (lists.filter { n => n != "" && n != " " && n != Nil }), Any: { node => node } } OrderedList filtered } +/// A list item for better readability. func li { item => item } +/// Constant text for better readbility. func text { str => str } +/// A list of markup for better readbility. func group { list => list } +/// Some inline text. Ignores empty elements. Adds spaces. func inline { list => type List { Cons: pipe [ diff --git a/stdlib/markup/format.lithia b/stdlib/markup/format.lithia new file mode 100644 index 0000000..641aa83 --- /dev/null +++ b/stdlib/markup/format.lithia @@ -0,0 +1,31 @@ +/// A generalized data format to represent human readable contents. +/// Though it is not meant to represent HTML nodes. +module markup + +/// A specific markup format to convert to. +data Format { + /// Converts given markup to this format. + convert markup +} + +/// A more generalized form of a markup.Format. +/// Allows to use plain functions and whole modules as format. +enum FormatWitness { + Format + Module + Function +} + +/// Creates a Format from a given FormatWitness. +func from { witness => + with witness, type FormatWitness { + Format: { s => s }, + Module: { m => Format m.serialize }, + Function: { f => Format f }, + } +} + +/// Converts some markup to a target format. +func convert { markup, targetFormatWitness => + (from targetFormatWitness).convert markup +} diff --git a/stdlib/markup/nodes.lithia b/stdlib/markup/nodes.lithia index a70ebf6..23adb8d 100644 --- a/stdlib/markup/nodes.lithia +++ b/stdlib/markup/nodes.lithia @@ -1,39 +1,105 @@ -enum MarkupNode { +/// A recursive enum of markup nodes. +enum Markup { + /// A plain string. String + // a list of markup.Markup nodes. List + /// A heading of a specific nesting level. + /// + /// > ##### Heading 5, "title" data Heading { + /// The level of nesting. + /// An Int, typically in the range of one to six. level + /// At least one child of type Markup. child } + /// A paragraph with some blank lines around. + /// + /// > Paragraph [ + /// > "First", + /// > "Second" + /// > ] data Paragraph { + /// At least one child of type Markup. child } + /// An italic portion of inline text. + /// + /// > Italic _"text"_ data Italic { + /// At least one child of type Markup. child } + /// A bold portion of inline text. + /// + /// > Bold **"text"** data Bold { + /// At least one child of type Markup. child } + /// A link to a resource. + /// + /// > [Link child, url](https://github.com/vknabel/lithia) data Link { + /// At least one child of type Markup. + /// Used to display the link. child + /// The url to point to. + /// Markup not supported. url } + /// An embedded image. + /// + /// > Image ![url](https://github.com/vknabel/lithia/blob/main/assets/lithia.png), alt data Image { + /// The url of the image. + /// Markup not supported. url + /// Alternatively displayed text in case the image can't be loaded or for accessibility. + /// Markup not supported. alt } + /// Some preformatted inline code. + /// + /// > `Code text` data Code { + /// Some text. Markup not supported. text } + /// A block of preformatted multiline code. + /// + /// > ```lithia + /// > CodeBlock "lithia", "text" + /// > ``` data CodeBlock { + /// Maybe the language as string. + /// Implementations must support Some, None and String. language + /// The text itself as String. text } + /// An unordered list. Requires a list of children. + /// + /// > UnorderedList [ + /// > - item + /// > - another + /// > + /// > ] data UnorderedList { + /// A list of Markup children. children } + /// An ordered list. Requires a list of children. + /// + /// > OrderedList [ + /// > 1. item + /// > 2. another + /// > + /// > ] data OrderedList { + /// A list of Markup children. children } } diff --git a/stdlib/markup/serialize.lithia b/stdlib/markup/serialize.lithia deleted file mode 100644 index cd7845d..0000000 --- a/stdlib/markup/serialize.lithia +++ /dev/null @@ -1,21 +0,0 @@ -data Serializer { - serialize markup -} - -enum SerializerWitness { - Serializer - Module - Function -} - -func from { witness => - with witness, type SerializerWitness { - Serializer: { s => s }, - Module: { m => SerializerWitness m.serialize }, - Function: { f => SerializerWitness f }, - } -} - -func serialize { markup, witness => - (from witness).serialize markup -} diff --git a/stdlib/optionals.md b/stdlib/optionals.md index a318caf..b2f9aab 100644 --- a/stdlib/optionals.md +++ b/stdlib/optionals.md @@ -2,40 +2,49 @@ _module_ -- _enum_ [Optional](#Optional) - _func_ [equalFor](#equalFor) someWitness, lhs, rhs - _func_ [equatableFor](#equatableFor) someWitness +- _func_ [from](#from) maybe - _func_ [isNone](#isNone) - _func_ [map](#map) transform - _func_ [orDefault](#orDefault) default -## Optional - -_enum_ -An optional value. Either some value or none. - -### Cases - -- [Some](#Some) -- [None](#None) - ## equalFor _func_ `equalFor someWitness, lhs, rhs` +Creates an equal function, that understands optionals and maybes for a given witness. + ## equatableFor _func_ `equatableFor someWitness` +Creates an Equatable witness for Optionals on top of an existing witness. + +## from + +_func_ `from maybe` + +Creates an optional from a Maybe-value. + ## isNone _func_ `isNone` +True if None. Otherwise False. + ## map _func_ `map transform` +Transforms Some value to a new one. +Keeps None as-is. +Any other values will still be mapped, but not wrapped. + ## orDefault _func_ `orDefault default` +Returns a default, if None given. +Otherwise unwraps Some value or keeps Any as-is. + diff --git a/stdlib/optionals/equatable.lithia b/stdlib/optionals/equatable.lithia index 0596fcc..f273526 100644 --- a/stdlib/optionals/equatable.lithia +++ b/stdlib/optionals/equatable.lithia @@ -2,10 +2,11 @@ module optionals import eq +/// Creates an equal function, that understands optionals and maybes for a given witness. func equalFor { someWitness, lhs, rhs => - type Optional { + type Maybe { Some: { lsome => - type Optional { + type Maybe { Some: { rsome => someWitness.equal lsome, rsome }, @@ -13,14 +14,15 @@ func equalFor { someWitness, lhs, rhs => } rhs }, None: { _ => - type Optional { + type Maybe { Some: { _ => False }, None: { _ => True } } - } - } lhs + }, + } optionals.from lhs } +/// Creates an Equatable witness for Optionals on top of an existing witness. func equatableFor { someWitness => Equatable equalFor someWitness } @@ -40,7 +42,7 @@ func equatableFor { someWitness => // it "some and some delegate equality to values" { expect => // expect numbers, (Some 1), (Some 1) -// expect eq.negated numbers (Some 1) (Some 2) -// expect eq.negated numbers (Some 2) (Some 1) +// expect eq.negated numbers, (Some 1), (Some 2) +// expect eq.negated numbers, (Some 2), (Some 1) // } // } diff --git a/stdlib/optionals/functor.lithia b/stdlib/optionals/functor.lithia index df13355..4f48cd9 100644 --- a/stdlib/optionals/functor.lithia +++ b/stdlib/optionals/functor.lithia @@ -3,12 +3,17 @@ module optionals import booleans import controls { Functor } +/// A Functor instance for Optional. let functor = Functor map +/// Transforms Some value to a new one. +/// Keeps None as-is. +/// Any other values will still be mapped, but not wrapped. func map { transform => - type Optional { + type Maybe { Some: { some => transform some.value }, - None: { _ => None } + None: { _ => None }, + Any: { any => transform any } } } diff --git a/stdlib/optionals/is-none.lithia b/stdlib/optionals/is-none.lithia index 2e43b3f..083097f 100644 --- a/stdlib/optionals/is-none.lithia +++ b/stdlib/optionals/is-none.lithia @@ -2,10 +2,11 @@ module optionals import booleans +/// True if None. Otherwise False. func isNone { => type Optional { - Some: { _ => False }, - None: { _ => True } + None: { _ => True }, + Any: { _ => False } } } diff --git a/stdlib/optionals/optional.lithia b/stdlib/optionals/optional.lithia index 28e70ce..8ae7231 100644 --- a/stdlib/optionals/optional.lithia +++ b/stdlib/optionals/optional.lithia @@ -1,9 +1,8 @@ module optionals +/// Implements some helpers around prelude.Optional and prelude.Maybe. import prelude -let Optional = prelude.Optional - // describe "optional", { it => // it "can have some value", { _ => // Some 41 @@ -13,3 +12,12 @@ let Optional = prelude.Optional // None // } // } + +/// Creates an optional from a Maybe-value. +func from { maybe => + type Maybe { + Some: { _ => maybe }, + None: { _ => maybe }, + Any: { _ => Some maybe }, + } maybe +} diff --git a/stdlib/optionals/or-default.lithia b/stdlib/optionals/or-default.lithia index e42eadc..00e5d8b 100644 --- a/stdlib/optionals/or-default.lithia +++ b/stdlib/optionals/or-default.lithia @@ -1,8 +1,11 @@ module optionals +/// Returns a default, if None given. +/// Otherwise unwraps Some value or keeps Any as-is. func orDefault { default => - type Optional { + type Maybe { Some: { some => some.value }, - None: { none => default } + None: { none => default }, + Any: { any => any }, } } diff --git a/stdlib/os.md b/stdlib/os.md index 067eaa3..aba142a 100644 --- a/stdlib/os.md +++ b/stdlib/os.md @@ -7,11 +7,13 @@ _module_ ## env +_func_ `env name` -_extern_ `env name` +Returns an Optional value of the environment variable. ## exit +_func_ `exit code` -_extern_ `exit code` +Exits the whole program with the given exit code. diff --git a/stdlib/os/shim.lithia b/stdlib/os/shim.lithia index 994b5d0..c3b31e7 100644 --- a/stdlib/os/shim.lithia +++ b/stdlib/os/shim.lithia @@ -1,2 +1,4 @@ +/// Exits the whole program with the given exit code. extern exit code +/// Returns an Optional value of the environment variable. extern env name diff --git a/stdlib/prelude.md b/stdlib/prelude.md index d5d0ecf..5a43b3f 100644 --- a/stdlib/prelude.md +++ b/stdlib/prelude.md @@ -14,6 +14,7 @@ Will always be imported implicitly. - _extern_ [Function](#Function) - _extern_ [Int](#Int) - _enum_ [List](#List) +- _enum_ [Maybe](#Maybe) - _extern_ [Module](#Module) - _enum_ [Never](#Never) - _data_ [Nil](#Nil) @@ -37,6 +38,7 @@ Will always be imported implicitly. ## Any _extern_ +Any value that exists. ## Bool @@ -52,6 +54,7 @@ Typically used for conditionals and flags. ## Char _extern_ +A single character of a string. ## Cons @@ -70,18 +73,22 @@ _data_ A constant to represent invalid conditions. ## Float _extern_ +A base type for floating point numbers like 13.37. ## Function _extern_ +A function that may be called. ### Properties -- `arity` +- `arity` - The minimum arity of the function. +If it returns another function, the actual arity might be higher. ## Int _extern_ +A base type for non-fractional numbers like -1, 0, 1 and 2. ## List @@ -100,9 +107,21 @@ lists.reduce { l, r => l + r }, 0, myList - [Cons](#Cons) - [Nil](#Nil) +## Maybe + +_enum_ +An uknown value. Might be an optional, the value itself or None. + +### Cases + +- [Some](#Some) +- [None](#None) +- [Any](#Any) + ## Module _extern_ +A module. Either from an import or by a module-declaration. ## Never @@ -139,11 +158,12 @@ _data_ ## String _extern_ +Represents text like "hello world". ### Properties -- `length` -- `append str` +- `length` - The length of the string. +- `append str` - Allows to append another string. ## True @@ -168,8 +188,9 @@ Always returns the first argument. ## debug +_func_ `debug message` -_extern_ `debug message` +Prints a debug message to stdout. ## identity @@ -197,17 +218,24 @@ The first function is applied to the value, the second to the result of the firs ## print +_func_ `print message` -_extern_ `print message` +Prints a message to stdout. ## unless _func_ `unless condition, then` +Only if a condition is False, the right side will be executed and returned. +Otherwise Void. + ## when _func_ `when condition, then` +Only if a condition is True, the right side will be executed and returned. +Otherwise Void. + ## with _func_ `with value, body` diff --git a/stdlib/prelude/_shim.lithia b/stdlib/prelude/_shim.lithia new file mode 100644 index 0000000..46b7e2d --- /dev/null +++ b/stdlib/prelude/_shim.lithia @@ -0,0 +1,35 @@ +/** + * Implements the most basic data types. + * Espcially those needed for built-in functionality and for the compiler. + * Will always be imported implicitly. + */ +module prelude + +/// Prints a message to stdout. +extern print message +/// Prints a debug message to stdout. +extern debug message + +/// A base type for non-fractional numbers like -1, 0, 1 and 2. +extern Int +/// A base type for floating point numbers like 13.37. +extern Float +/// Represents text like "hello world". +extern String { + /// The length of the string. + length + /// Allows to append another string. + append str +} +/// A single character of a string. +extern Char +/// A function that may be called. +extern Function { + /// The minimum arity of the function. + /// If it returns another function, the actual arity might be higher. + arity +} +/// A module. Either from an import or by a module-declaration. +extern Module +/// Any value that exists. +extern Any diff --git a/stdlib/prelude/optional.lithia b/stdlib/prelude/optional.lithia index ea93890..52e59e1 100644 --- a/stdlib/prelude/optional.lithia +++ b/stdlib/prelude/optional.lithia @@ -5,3 +5,10 @@ enum Optional { data Some { value } data None } + +/// An uknown value. Might be an optional, the value itself or None. +enum Maybe { + Some + None + Any +} diff --git a/stdlib/prelude/shim.lithia b/stdlib/prelude/shim.lithia deleted file mode 100644 index bf2b32d..0000000 --- a/stdlib/prelude/shim.lithia +++ /dev/null @@ -1,22 +0,0 @@ -/** - * Implements the most basic data types. - * Espcially those needed for built-in functionality and for the compiler. - * Will always be imported implicitly. - */ -module prelude - -extern print message -extern debug message - -extern Int -extern Float -extern String { - length - append str -} -extern Char -extern Function { - arity -} -extern Module -extern Any diff --git a/stdlib/prelude/when.lithia b/stdlib/prelude/when.lithia index 0a579c4..67cbf31 100644 --- a/stdlib/prelude/when.lithia +++ b/stdlib/prelude/when.lithia @@ -1,15 +1,19 @@ module prelude +/// Only if a condition is True, the right side will be executed and returned. +/// Otherwise Void. func when { condition, then => with condition, type Bool { True: { _ => then }, - False: { _ => } + False: { _ => Void } } } +/// Only if a condition is False, the right side will be executed and returned. +/// Otherwise Void. func unless { condition, then => with condition, type Bool { - True: { _ => }, + True: { _ => Void }, False: { _ => then } } } diff --git a/stdlib/ranges.md b/stdlib/ranges.md index 8a17476..b649ba2 100644 --- a/stdlib/ranges.md +++ b/stdlib/ranges.md @@ -1,6 +1,8 @@ # ranges _module_ +An early concept of ranges. +Might change largely in future. - _func_ [indices](#indices) - _func_ [numbersFrom](#numbersFrom) n @@ -9,7 +11,13 @@ _module_ _func_ `indices` +An infinite list of all numbers greater than or equal 0. +e.g. [0, 1, 2, 3, 4, ...] + ## numbersFrom _func_ `numbersFrom n` +An infinite list of all numbers greater than or equal a given one. +e.g. [n, n+1, n+2, n+3, n+4, ...] + diff --git a/stdlib/ranges/open-numbers.lithia b/stdlib/ranges/open-numbers.lithia index b6ed082..ec3ff4d 100644 --- a/stdlib/ranges/open-numbers.lithia +++ b/stdlib/ranges/open-numbers.lithia @@ -1,5 +1,13 @@ +/// An early concept of ranges. +/// Might change largely in future. +module ranges + +/// An infinite list of all numbers greater than or equal 0. +/// e.g. [0, 1, 2, 3, 4, ...] func indices { => numbersFrom 0 } +/// An infinite list of all numbers greater than or equal a given one. +/// e.g. [n, n+1, n+2, n+3, n+4, ...] func numbersFrom { n => Cons n, numbersFrom (n+1) } diff --git a/stdlib/results.md b/stdlib/results.md index 07d5e81..bc8171c 100644 --- a/stdlib/results.md +++ b/stdlib/results.md @@ -1,6 +1,7 @@ # results _module_ +The results module is all about failable operations. - _data_ [Failure](#Failure) - _enum_ [Result](#Result) @@ -57,31 +58,47 @@ _data_ Represents a successful result with a value. _func_ `flatMapSuccess transform, result` +When successful, attempts another operation by transforming the result. + ## flatMapFailure _func_ `flatMapFailure transform, result` +When failed, attempts another operation by transforming the error. + ## flatMapSuccess _func_ `flatMapSuccess transform, result` +When successful, attempts another operation by transforming the result. + ## mapSuccess _func_ `mapSuccess transform, result` +Transorms only successful results. + ## mapFailure _func_ `mapFailure transform, result` +Transorms only failed results. + ## mapSuccess _func_ `mapSuccess transform, result` +Transorms only successful results. + ## pureFailure _func_ `pureFailure error` +Creates a pure failure value. + ## pureSuccess _func_ `pureSuccess value` +Creates a pure succcess value. + diff --git a/stdlib/results/functors.lithia b/stdlib/results/functors.lithia index 8eb2e81..e7fa5be 100644 --- a/stdlib/results/functors.lithia +++ b/stdlib/results/functors.lithia @@ -6,6 +6,7 @@ import controls /// In contrast to failureFunctor, implemented to map Success values. let successFunctor = controls.Functor mapSuccess +/// Transorms only successful results. func mapSuccess { transform, result => with result, type Result { Success: { success => Success transform success.value }, @@ -17,6 +18,7 @@ func mapSuccess { transform, result => /// In contrast to successFunctor, implemented to map Failure errors. let failureFunctor = controls.Functor mapFailure +/// Transorms only failed results. func mapFailure { transform, result => with result, type Result { Success: { success => success }, @@ -27,4 +29,6 @@ func mapFailure { transform, result => /// The default witness for controls.Functor for results.Result. /// Is equal to successFunctor. let functor = successFunctor +/// The default map for results.Result. +/// Is equal to successFunctor. let map = mapSuccess diff --git a/stdlib/results/monads.lithia b/stdlib/results/monads.lithia index 8212f6d..6bbf40b 100644 --- a/stdlib/results/monads.lithia +++ b/stdlib/results/monads.lithia @@ -6,10 +6,12 @@ import controls /// In contrast to failureMonad, implemented to map Success values. let successMonad = controls.Monad pureSuccess, flatMapSuccess +/// Creates a pure succcess value. func pureSuccess { value => Success value } +/// When successful, attempts another operation by transforming the result. func flatMapSuccess { transform, result => with result, type Result { Success: { success => transform success.value }, @@ -22,10 +24,12 @@ func flatMapSuccess { transform, result => /// In contrast to successMonad, implemented to map Failure errors. let failureMonad = controls.Monad pureFailure, flatMapFailure +/// Creates a pure failure value. func pureFailure { error => Failure error } +/// When failed, attempts another operation by transforming the error. func flatMapFailure { transform, result => with result, type Result { Success: { success => success }, @@ -33,5 +37,9 @@ func flatMapFailure { transform, result => } } +/// The default witness for controls.Monad for results.Result. +/// Is equal to successMonad. let monad = successMonad +/// The default flatMap for results.Result. +/// Is equal to flatMapSuccess. let flatMap = flatMapSuccess diff --git a/stdlib/results/result.lithia b/stdlib/results/result.lithia index 10562e5..587f4ad 100644 --- a/stdlib/results/result.lithia +++ b/stdlib/results/result.lithia @@ -1,3 +1,4 @@ +/// The results module is all about failable operations. module results /// A result of a failable operation. diff --git a/stdlib/rx.md b/stdlib/rx.md index 6c02783..0c71560 100644 --- a/stdlib/rx.md +++ b/stdlib/rx.md @@ -1,6 +1,8 @@ # rx _module_ +A very early concept of implementing functional reactive programming. +Currently only used to provide mutability. - _extern_ [Variable](#Variable) diff --git a/stdlib/rx/variable.lithia b/stdlib/rx/variable.lithia index ceb4df0..2468afa 100644 --- a/stdlib/rx/variable.lithia +++ b/stdlib/rx/variable.lithia @@ -1,3 +1,5 @@ +/// A very early concept of implementing functional reactive programming. +/// Currently only used to provide mutability. module rx /// Holds a value and enables replacing it. diff --git a/stdlib/strings.md b/stdlib/strings.md index 58b43ce..641aa41 100644 --- a/stdlib/strings.md +++ b/stdlib/strings.md @@ -1,6 +1,8 @@ # strings _module_ +Provides convenience functions around the basic String type. +Currently pretty limited. - _func_ [concat](#concat) listOfStrings - _func_ [join](#join) separator, listOfStrings diff --git a/stdlib/strings/strings.lithia b/stdlib/strings/strings.lithia new file mode 100644 index 0000000..372db68 --- /dev/null +++ b/stdlib/strings/strings.lithia @@ -0,0 +1,3 @@ +/// Provides convenience functions around the basic String type. +/// Currently pretty limited. +module strings \ No newline at end of file diff --git a/stdlib/tests.md b/stdlib/tests.md index 7a7ea0c..ab23308 100644 --- a/stdlib/tests.md +++ b/stdlib/tests.md @@ -23,13 +23,12 @@ In case you really need expectations, writing a wrapper around tests should be p - _data_ [TestCase](#TestCase) - _data_ [TestSummary](#TestSummary) -- _func_ [runTestCase](#runTestCase) summary, testCase - _func_ [runTests](#runTests) - _func_ [test](#test) case, function ## TestCase -_data_ +_data_ Represents a buffered test case. ### Properties @@ -47,10 +46,6 @@ _data_ The prinatble summary of all tests. - `notOk` - How many tests have been not ok. - `failedTests` - List of failed test numbers. -## runTestCase - -_func_ `runTestCase summary, testCase` - ## runTests _func_ `runTests` diff --git a/stdlib/tests/basic.lithia b/stdlib/tests/basic.lithia index c2b9267..cc17d58 100644 --- a/stdlib/tests/basic.lithia +++ b/stdlib/tests/basic.lithia @@ -26,8 +26,9 @@ import strings import os import rx -let testCases = rx.Variable Nil +import tests.internal +/// Represents a buffered test case. data TestCase { /// The title of the test case for the logs. title @@ -66,7 +67,7 @@ let enabled = with os.env "LITHIA_TESTS", type Optional { * ``` **/ func test { case, function => - testCases.accept (lists.append (TestCase case, function), testCases.current) + internal.testCases.accept (lists.append (TestCase case, function), internal.testCases.current) } /// Runs all test cases, that have been buffered by now. @@ -74,10 +75,10 @@ func runTests { => print "TAP version 13" print strings.concat [ "1..", - lists.count testCases.current + lists.count internal.testCases.current ] - let summary = (lists.reduce runTestCase, (TestSummary 0, 0, Nil), testCases.current) + let summary = (lists.reduce internal.runTestCase, (TestSummary 0, 0, Nil), internal.testCases.current) with summary.failedTests, type List { Cons: { _ => @@ -105,42 +106,3 @@ func runTests { => } } } - -func runTestCase { summary, testCase => - let eagerlyRunPreviousTests = summary.failedTests - eagerlyRunPreviousTests - - let testNumber = summary.ok + summary.notOk + 1 - let failure = rx.Variable None - testCase.impl { message => - let combined = with failure.current, type Optional { - Some: { previous => Some strings.concat [previous.value, "; ", message] }, - None: { _ => Some message } - } - failure.accept combined - } - - with failure.current, type Optional { - Some: { some => - print strings.concat [ - "not ok ", - testNumber, - " - ", - testCase.title - ] - print " ---" - print " message: ".append some.value - print " severity: fail" - TestSummary summary.ok, summary.notOk+1, (lists.append testNumber, summary.failedTests) - }, - None: { _ => - print strings.concat [ - "ok ", - testNumber, - " - ", - testCase.title - ] - TestSummary (summary.ok+1), summary.notOk, summary.failedTests - } - } -} diff --git a/stdlib/tests/internal/test-cases.lithia b/stdlib/tests/internal/test-cases.lithia new file mode 100644 index 0000000..fb64080 --- /dev/null +++ b/stdlib/tests/internal/test-cases.lithia @@ -0,0 +1,46 @@ +import tests + +import lists +import strings +import rx + +let testCases = rx.Variable Nil + +func runTestCase { summary, testCase => + let eagerlyRunPreviousTests = summary.failedTests + eagerlyRunPreviousTests + + let testNumber = summary.ok + summary.notOk + 1 + let failure = rx.Variable None + testCase.impl { message => + let combined = with failure.current, type Optional { + Some: { previous => Some strings.concat [previous.value, "; ", message] }, + None: { _ => Some message } + } + failure.accept combined + } + + with failure.current, type Optional { + Some: { some => + print strings.concat [ + "not ok ", + testNumber, + " - ", + testCase.title + ] + print " ---" + print " message: ".append some.value + print " severity: fail" + tests.TestSummary summary.ok, summary.notOk+1, (lists.append testNumber, summary.failedTests) + }, + None: { _ => + print strings.concat [ + "ok ", + testNumber, + " - ", + testCase.title + ] + tests.TestSummary (summary.ok+1), summary.notOk, summary.failedTests + } + } +}