* refactor: add type candidates for validation
This commit adds a new module and type, the TypeCandidate, which
represents a potentially valid or invalid type. We use it as the
input for both type validation routines and type binding generation. The
type also allows us to unify the structure of sum types and product
types in an xobj agnostic way, paving the way for future simplification
of binding generation for type definitions.
This commit also removes SumtypeCase.hs, since it's no longer needed.
* refactor: add template generators; update type templates
This commit builds on the TypeCandidate data structure further by
providing "template generators" that work on candidates. Using
generators, templates for type functions ("methods") can be written
almost completely declaratively. Generators also remove some of the
typical boilerplate involved in creating templates from lists of tokens
and enable us to unify several of the generic and concrete templates for
types.
Generators can act on type candidates or their fields (for
field-specific functions). In general, this approach makes the
generation of type templates more structured. A type candidate now
contains all the information a generator needs to create appropriate
templates, thus it is a single and well-defined input for validation and
generation of user defined types.
This commit also updates the Deftype templates to use template
generators.
* refactor: use template generators for sumtype templates
* feat: add box templates and box type
This commit adds an implementation of Boxes, memory manged heap
allocated values.
Boxes are implemented as C pointers, with no additional structure but
are treated as structs in Carp. To facilitate this, we need to add them
as a clause to our special type emissions (TypesToC) as they'd otherwise
be emitted like other struct types.
Co-authored-by: Veit Heller <veit@veitheller.de>
* fix: slight memory management fix for Box
Make sure we free the box!
* test: add tests for box (including memory checks)
* Revert "fix: Ignore clang nitpick"
This reverts commit 70ec6d46d4.
* fix: update example/functor.carp
Now that a builtin type named Box exists, the definitions in this file
cause a conflict. I've renamed the "Box" type in the functor example to
remove the conflict.
* feat: add Box.peek
Box.peek allows users to transform a reference to a box into a a
reference to the box's contained value. The returned reference will have
the same lifetime as the box. This function allows callers to manipulate
the value in a box without re-allocation, for example:
```clojure
(deftype Num [val Int])
(let-do [box (Box.init (Num.init 0))]
(Num.set-val! (Box.peek &box) 1)
@(Num.val (Box.peek &box)))
```
This commit also includes tests for Box.peek.
Co-authored-by: TimDeve <TimDeve@users.noreply.github.com>
Co-authored-by: Veit Heller <veit@veitheller.de>
Co-authored-by: Erik Svedäng <erik@coherence.io>
Co-authored-by: TimDeve <TimDeve@users.noreply.github.com>
* refactor: Mid-refactor save point.
* feat: Code compiles
* refactor: Remove unused imports
* refactor: Move functions out of massive `manageMemory` block
* refactor: Move out even more functions from `manageMemory`
* refactor: Made most patterns match on "head form" of each s-expression
e.g. (if a b c) matches on 'if', 'a', 'b' and 'c'
* refactor: Use the pattern synonyms in Memory
* refactor: Remove a little cruft
* refactor: whenOK function
* refactor: Use 'whenRight' functions to avoid directly matching on Either
* docs: Comment the 'getConcretizedPath' function
* refactor: Move functionFinding-functions into Polymorphism module
* refactor: major environment mgmt refactor
This big refactor primarily changes two things in terms of behavior:
1. Stores a SymPath on concretely named (non-generic) struct types;
before we stored a string.
2. The SymPath mentioned in (1.) designates where the struct is stored
in the current environment chain. Modules now carry a local type
environment in addition to their local value environments. Any types
defined in the module are added to this environment rather than the
global type environment.
To resolve a type such as `Foo.Bar` we now do the following:
- Search the *global value environment* for the Foo module.
- Get the type environment stored in the Foo module.
- Search for Bar in the Foo module's type environment.
Additionally, this commit eliminates the Lookup module entirely and
refactors the Env module to handle all aspects of environment management
in hopefully a more reusable fashion.
I also took the opportunity to refactor primitiveDeftype in Primitives
and qualifySym in Qualify, both of which were hefty functions that I
found difficult to grok and needed refactoring anyway as a result of
lookup changes (lookups now return an Either instead of a Maybe).
Subsequent commits will clean up and clarify this work further.
This does include one minor regression. Namely, an implementation of
`hash` in core/Color that was maximally generic now needs type casting.
* refactor: clean up recent Env changes
This commit removes some redundant functions, unifies some logic, and
renames some routines across the Env module in efforts to make it
cleaner. Call sites have been updated accordingly.
* chore: format code with ormolu
* fix: update lookup tests
Changes references to renamed functions in the Env module.
* refactor: style + additional improvements from eriksvedang@
- Rename arrayTy -> arrayTyA in ArrayTemplates.hs to disambiguate.
- Add maybeId util function.
- Remove commented code.
- Refactor a few functions for readability.
* fix: fix type inference regression
Recent commits introduced one minor regression whereby an instance of
type inference in core/Color.carp no longer worked and required
explicit type annotation. The problem ultimately had to do with
qualification:
- Prior to the recent changes, type inference worked because the call in
question was qualified to Color.Id.get-tag, fixing the type.
- Failing to copy over a local envs Use modules to function envs
resulted in finding more than just Color.Id.get-tag for this instance.
We now copy use modules over to function envs generated during
qualification to ensure we resolve to Use'd definitions before more
general cases.
Similarly, I made a small change to primitiveUse to support contextual
use calls (e.g. the `(use Id)` in Color.carp, which really means `(use
Color.Id)`)
* chore: Update some clarificatory comments
* chore: fix inline comment
* refactor: move primitive errors; refactor primtiveInfo
This commit is the first in what will hopefully be a series of helpful
primitive refactors. To start, we:
- Move some inline `evalError` strings into a `PrimitiveError` module,
(similar to the `TypeError`/`Types` module relationship
- Add `Reifiable` instances for String and Int types to take these
types to their XObj representation.
- Add info utility functions for converting Info data to an XObj
- Refactor the `info` primitive:
- Use monadic combinators + `maybe` instead of nested cases.
- Use helper lookup functions that take a *context*--nearly *all*
lookup calls currently extract some env, typically without doing
anything to it, to pass it to lookup. This is a sign the boundary is
incorrect and lookups should take the context instead--this will allow
us to eliminate a ton of local `globalEnv`, `typeEnv`, etc. bindings.
- Don't print hidden bindings
- Indent printed meta information.
- Color bindings blue
* chore: format code
* refactor: improve names for lookups that take a context
* feat: print hidden binders when calling info
Someone calling info might be interested in hidden binders as well, for
debugging purposes, etc. To enable this, we provide a version of show
for binders that prints hidden binders.
I've also made the printing of meta values in info more generic.
* refactor: Move constraints test to own module, create TestLookup module
* refactor: Extracted 'Env' module
* refactor: Extracted 'TypePredicates' module
* test: First, very simple test
* refactor: Extracted 'Managed' module
* refactor: Add 'lookupBinder' function that doesn't return an Env (often what we want)
* refactor: Move out more stuff from Lookup
* refactor: Use new 'lookupBinder' in tons of places (avoids tuple)
* refactor: Got rid of monolithic 'recursiveLookupInternal'
* refactor: Avoid boolean blindness
* refactor: Better names for some lookup functions
* refactor: More logical order in Lookup.hs
* style: Use correct version of ormolu (0.1.4.1)
* refactor: Slightly more consistent naming
* refactor: Address @scolsen:s feedback
* refactor: improve readability of interface functions
Also refactors the `define` function for readability.
The old definitions of these functions were quite unwieldy and difficult
to read. This refactor attempts to make the monadic contexts we're
juggling (often 3, Maybe, IO, Either) easier to spot.
* refactor: Add context env updaters; refactor prims
This commit contains a few more cleanups of the interface and define
functions in Primitives. It also defines a new context module for
holding functions that update context environments.
* Rename ty to xobjTy.
* Rename info to xobjInfo.
* Rename obj to xobjObj.
* Address name shadowing.
* Address name shadowing.
* Address name shadowing.
* Address name shadowing.
* Address name shadowing.
* Address name shadowing.
* Address name shadowing.
* Address name shadowing.
* Address name shadowing.
* Address name shadowing.
* Address name shadowing.
* Address name shadowing.
* Address name shadowing.
* Address name shadowing.
* Address name shadowing.
* Address name shadowing.
* Address name shadowing.
* Address name shadowing.
* Address name shadowing.
* Address name shadowing.
* Address name shadowing.
* Remove some primes.
* docs: Remove a lot of duplicated information and refer to webpages instead
* fix: Remove line about (help), it does not make sense anymore
* fix: Add open-browser to nix config
Co-authored-by: Erik Svedang <erik@Eriks-iMac.local>
Extends Carp's support for type reflection by returning types for
values as well as bindings.
`type` now also returns a valid Carp expression/s-expression and so its
output can be used as input to dynamic functions and macros (prior to
this commit, `type` printed the type to the REPL but did not return a
meaningful expression in Carp).
Here are a few illustrations of the behavior:
```
(def x 1)
;; type now returns an s-expression/symbol
(type x)
=> Int
;; It also works on values
(type 1)
=> Int
(type 2b)
=> Byte
(type "foo")
=> (Ref String <StaticLifetime>)
;; It works on more complex values as well
(type Maybe)
=> Module
(type Maybe.Just)
(Fn [a] (Maybe a) <StaticLifetime>)
;; reports honestly about polymorphism
(type (Maybe.Nothing))
=> (Maybe a)
(type (Pair.init 1 2))
=> (Pair Int Int)
;; What about the type of types?
(type (type 2))
=> Type
;; Or the type of types of types?
(type (type (type 2)))
=> ()
;; One more time!
(type (type (type (type 2))))
=> ()
;; so, () is the fixpoint of type, and is reached after two applications
(type zero)
;; the type of an interface is all of its implementations
=> (((Fn [] (Array a) <StaticLifetime>) (Fn [] Bool <StaticLifetime>) (Fn
[] Byte <StaticLifetime>) (Fn [] Char <StaticLifetime>) (Fn [] Double
<StaticLifetime>) (Fn [] Float <StaticLifetime>) (Fn [] Int
<StaticLifetime>) (Fn [] Int16 <StaticLifetime>) (Fn [] Int32
<StaticLifetime>) (Fn [] Int64 <StaticLifetime>) (Fn [] Int8
<StaticLifetime>) (Fn [] Long <StaticLifetime>) (Fn [] (Maybe a)
<StaticLifetime>) (Fn [] (Pair a b) <StaticLifetime>) (Fn [] (Quadruple
a b c d) <StaticLifetime>) (Fn [] String <StaticLifetime>) (Fn []
(Triple a b c) <StaticLifetime>) (Fn [] Uint16 <StaticLifetime>) (Fn []
Uint32 <StaticLifetime>) (Fn [] Uint64 <StaticLifetime>) (Fn [] Uint8
<StaticLifetime>)))
```
As shown in the example above, this change also includes a cosmetic
update to the representation of lifetime variables, which are surrounded
in <> to distinguish them from type variables.
This commit also adds a new `kind` primitive that reports on the kind of
a binding or value:
```
(def x 3)
(kind x)
=> Base
(kind 2)
=> Base
(kind Maybe.Just)
=> Higher
(kind (Maybe.Just 2))
=> Higher
```
`kind` and `type` both support interactive development in the repl, for
example, a user can rely on `kind` to check the kind of a type they plan
on using in an interface that demands a higher-kinded argument.
Likewise, they both also support developing macros based on type
information.
This PR moves interface handling code out of Primitives.hs and into its
own module. The actual primitives user's rely on to define and implement
interfaces still live in Primitives.hs, but now all the
registration/internal context mgmt code related to interfaces lives in
its own module.
Hopefully this will make it easier to modify and extend!
The Meta module does two things:
- Collects functions related to working with Carp MetaData in one place
- Hides the underlying implementation of MetaData
MetaData is backed by `Data.Map` previously, we'd alter MetaData by
getting the underlying map directly and calling Map functions to modify
the contents. The functions in the Meta module encapsulate this--now
callers may manipulate MetaData without having to know anything about
the underlying Map implementation. This should make it easier to swap
out the underlying representation in the future as well.
Unlike many of the other datatypes in Obj.hs, Info does not introduce
mutually recursive dependencies. Obj.hs is quite large and contains a
lot of different functionality, so I think it helps to move anything
that we can separate out into its own module in order to start
simplifying the Obj.hs and its responsibilities.