* feat: Add additional ignore macros
This commit adds two new ignore macros, ignore*, which wraps an
arbitrary number of forms in calls to `ignore` and ignore-do, which
wraps an arbitrary number of forms in ignore, then bundles the whole in
a do call, effectively executing each form only for side effects and
ignoring all results.
* docs: Update ignore* docs
Link to `ignore` doc
Co-authored-by: Veit Heller <veit@veitheller.de>
* fix: Call ignore* in ignore-do
ignore-all was an old name that no longer exists!
* test: Add test for ignore-do
Co-authored-by: Veit Heller <veit@veitheller.de>
* refactor: refactor concretize module
This commit primarily refactors the concretize module, breaking out the
local definitions for visit functions into top level functions that are
hopefully easier to change. I've also modified some monadic code in the
interest of terseness.
This commit adds some additional patterns for XObj forms as well.
* refactor: Only export called functions in Concretize
Adds an export list to Concretize so that the module encapsulates those
functions that are only used internally within the module.
* refactor: better names in concretize functions
Clarify the names of variables in visitor type functions.
* refactor: ensure findType returns a type
Adds an additional check to findType that ensures the retrieved binder
is in fact a type and not another object. This is necessary for certain
contexts like type concretization since modules may also be designated
by symbols that refer to types.
* fix: ensure nested polymorphic types are emitted
This commit fixes an issue whereby nested polymorphic types would not be
emitted by the compiler, even though their member functions were
emitted.
In order to support this, we need to update a couple of functions to
take the global environment (to find nested types, which live in
modules) in addition to the top level type environment. Additionally, we
had to update scoring to account for nested names.
fixes#1293
* test: add tests for nested polymorphic types
Adds regression tests to ensure nested polymorphic types are concretized
and emitted correctly.
* feat!: implemented Pattern.match which returns start and end indizes of the first match
* fix: Pattern.match now returns correct end index
* feat: moved Pattern.match-str and Pattern.find from C to Carp code
* chore: fix build after merges
* chore: fix build after merges
* feat: moved Pattern.find-all from C to Carp code
* feat: Pattern.global-match-str no longer relies on Pattern.global-match
* docs: updated for Pattern.global-match
* fix: moved str/prn functions into sub module
* fix: removed unused functions from carp_pattern.h (using cflow)
* feat!: renamed (Pattern.global-match) to (Pattern.match-all-groups)
* fix: unit test
* fix: some functions renamed to match Carp style
Co-authored-by: guberatsie <gunnar.bernhardt@siemens.com>
* feat: generalized (and) and (or) to handle any number of parameters
* feat!: removed (and*) and (or*) macros
* chore: worked around compiler issue for unit test
* fix: unit test in ./test/macro.carp
Co-authored-by: guberatsie <gunnar.bernhardt@siemens.com>
* feat!: implemented String.ascii-to-lower and String.ascii-to-upper
* fix: corrected docstrings
* fix: added unit test for ascii-to-lower and ascii-to-upper
* fix: moved tolower- and toupper from String to Byte module
Co-authored-by: guberatsie <gunnar.bernhardt@siemens.com>
* chore: Abuse deftemplate to get rid of Address
* chore: Avoid semicolon at end of define
* fix: address should be useable as an argument to a HOF
* chore: adapt examples to new address signature
* fix: Remove Address from typeOf
* fix: Remove more uses of Address
* fix: Remove more mentions of address in the Haskell code
* fix: Remove test that ensure you can't take the address of non-symbols
* refactor: Moved `address` to Pointer.carp
* refactor: Move address into Pointer module
Co-authored-by: Jorge Acereda <jacereda@gmail.com>
* chore: Re-format Haskell code
* fix: Unify aupdate and aupdate! with other update functions
* fix: Re-add comment
* fix: Also make StaticArray.aupdate! adhere to the normal update signature
* fix: Failing test
* test: Test for error when recursing using wrong nr of args
* test: Wrong type when recursing
* test: Defining function with def
* test: Using special symbol as binder
* test: Dynamic closures can refer to itself
* test: Avoid unification failure
* fix: Address feedback
* fix: don't expand inner module macros on first pass; privacy
This commit changes the behavior of expansions to avoid expanding module
expressions until we're actually processing the module in question.
Previously, the following form would be entirely expanded at the time of evaluating A:
```clojure
(defmodule A <- current environment
(some-macro) <- expand
(defmodule B
(some-macro f) <- expand, current env is A, *NOT* B.
so if this expands to
(private f)
(defn f ....)
the f of the expansion is added to *A*, and we have a duplicate
ghost binder.
)
(defn foo [] B.f) <- expand, B.f does not exist yet, any meta on the
binding will be ignored, permitting privacy errors since expansion
ignores undefined bindings, instead, we'll look this up at eval time,
and not check privacy as doing so would cause problems for legitimate
cases.
)
```
This meant that if the macro happened to have side-effects, e.g. calling
`meta-set!` we'd produce side-effects in the wrong environment, A,
resulting in duplicate bindings, missing bindings at evaluation time,
and other problems.
Now, we instead process the form as follows:
```clojure
(defmodule A <- current environment
(some-macro) <- expand
(defmodule B
(some-macro f) <- wait
)
(defn foo [] B.f)
)
;; step 2
(defmodule A
(foo-bar ) <- previously expanded macro
(defmodule B <- current environment
(some-macro f) <- expand
)
....
)
```
In general, this prevents the generation of a bunch of unintentional and
incorrectly added bindings when calling `meta-set!` from various macros.
Additionally, privacy constraints are now carried across nested modules:
```
(defmodule A
(defmodule B
(private f)
(defn f [] 0)
)
(defn g [] (B.f)) ;; Privacy error!
)
```
This change also fixed an issue whereby recursive functions with `sig`
annotations could trick the compiler. Again, this had to do with the
unintentionally added bindings stemming from expansion of nested module
expressions via meta-set.
Fixes#1213, Fixes#467
* fix: ensure we check privacy against the path of found binders
* 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: Groups Dynamic together in Macros.carp
* fix: Fixes doc for `hidden` referring to the wrong symbol
* feat: Adds defn- & def- macros
Adding these macros as a shortand for declaring a def or defn and making
them `hidden` and `private`, useful to keep things internal to a module.
* test: Adds expected error output tests for def- & defn-
* refactor: Changes position of Module and Interface section in LanguageGuide
Trying to introduce concepts in the same order they are referred to in
the examples: structs > modules > interfaces.
* docs: Adds private & hidden section in the LanguageGuide
* feat: a proper dynamic numeric tower
The following things were changed and/or added:
- `Dynamic.neg` was added
- `Dynamic.mod` was changed to work on float values
- `Dynamic.cxr` was changed to work with `0` instructions
- `Dynamic.=` was changed to ignore the type of the number
- `Dynamic.round` was added
- dynamic arithmetic was changed to respect the numeric type tower
- the instances of `Eq` and `Ord` for `Number` are no longer derived, so that they work across numeric types
- the instance of `Num` for `Number` was changed to work across numeric types
- `promoteNumber` was added as a type function to implement the numeric tower.
The numeric tower is as follows:
Byte -> Int -> Long -> Float -> Double
* test: add tests for cxr, neg, and =
* test: add tests for Dynamic.round
* fix: make set! work with dynamic args (thanks @hellerve)
Like `let` before it, we used to bind function arguments to their values
only, which wasn't accounted for in `set!` such that one could not
`set!` `i` in `defndynamic [i] ...`. To fix this for let bindings we
introduced a `LetDef` form for consistency with Def forms. This commit
renames `LetDef` to `LocalDef` and uses it as a value for function
arguments in addition to let bindings, ensuring `set!` works on function
arguments too. Big thanks to @hellerve for the suggestion!
* test: add regression test for set! on dynamic function args
* feat: quasiquotation
* test: add tests for quasiquotation
* fix: fix typo in call to doc
* fix: do not evaluate quasiquote too eagerly
* test: pull quasiquote test into macro
* docs: fix unquote example with better constant
* feat: add quasiquote literals
* refactor: simplify reader macros
* core: add derive
* fix: fix errors with set!
Notably, don't type check dynamic bindings (which can be set to
whatever) and eliminate a hang that resulted from not handling an error
at the end of the `set!` call. Also refactors some of the code in
efforts to make it a bit cleaner.
Also adds an error when `set!` can't find the variable one calls set!
on.
* feat: better derive
* test: add error test for derive
* document derive
* add derive to core documentation to generate
* core: add derive
* fix: fix errors with set!
Notably, don't type check dynamic bindings (which can be set to
whatever) and eliminate a hang that resulted from not handling an error
at the end of the `set!` call. Also refactors some of the code in
efforts to make it a bit cleaner.
Also adds an error when `set!` can't find the variable one calls set!
on.
* feat: better derive
* document derive
* feat: first completely working version of derive
* feat: make name of derivable customizable (thanks @scolsen)
* refactor: implement doc edits provided by @scolsen
* feat: change argument order for derive
* fix: change deriver error test
* test: add derive tests
* fix: change order of derive back
* docs: fix typo in derive document
Co-authored-by: scottolsen <scg.olsen@gmail.com>
* feat: add semigroup instance for Env and Context
Adds a semigroup instance for combining Envs and Contexts--this will be
necessary to ensure closure's are evaluated under the combination of the
context captured in the closure and the current global context during
evaluation.
The semigroup instances are left biased and will prefer bindings defined
in the left context/env argument in the case of conflicts (this is in
keeping with the implementation of `union` in Data.Map, the underlying
function powering this instance).
* fix: evaluate closures under the current context
Previously, closures were evaluated only under the context that was
stored during their creation. However, this can lead to issues where
closures do not resolve bindings to their latest definitions.
This commit leverages the semigroup instance of Context to evaluate
closures under the combination of the context captured during their
creation and the broader context during their evaluation/application,
preferring the context captured in the closure when bindings conflict.
This ensures that when we apply closures their local bindings still
resolve to definitions encapsulated in the closure, while other bindings
resolve to the definitions contained in the current overarching context
(instead of the old context captured by the closure).
* fix: fix bias for context env combinations in semigroup
Previously, the semigroup instance for Context was left-biased in all
the combinations of each context's environment. However, one usually
calls this function to combine some older context with a newer context,
intending to have the older context win *only* in the case of internal
environments.
This commit changes the behavior of the semigroup instance to better
reflect this use case. When one calls:
`c <> c'`
The envs in each context are combined as follows:
- internal: If conflicts occur, prefer the bindings of the context on
the LHS (the "older" context)
- global: If conflicts occur, prefer the bindings of the context on the
RHS ("newer" context)
- type: If conflicts occur, prefer the bindings of the context on the
RHS ("newer" context)
This ensures the resulting context uses the latest values in the chance
of conflicts in the global env/type env, and the older values in the
case of an internal env (a closure).
* test: add basic tests for closures
* refactor: rename test/closure -> test/dynamic-closure
Also updates the forms to test dynamic closures.
* feat: overwrite existing interface implementations
This commit alters the behavior of interfaces so that implementations
with the same type signature will overwrite previous implementations
with that signature--before this was a runtime error.
Previously, if a user defined two distinctly named implementations of an
interface that shared a type, Carp would panic and error at runtime if
the interface was called and resolved to the type, since it couldn't
decide which implementation to use from the type alone. After this
commit, we instead issue a warning and overwrite existing
implementations of the same type, so that defining:
```
(defn foo [] 0)
(implements zero foo)
```
will replace `Int.zero` in the `zero` interface's implementation path
list and won't result in a runtime error--instead `foo` will be called
when `zero` is called in a context in which it returns an int:
```
[WARNING] An implementation of the interface zero with type (Fn [] Int)
already exists: Int.zero. It will be replaced by the implementation:
foo.
This may break a bunch of upstream code!
```
test/interface.carp also has a concrete illustration of this case.
* chore: address hlint suggestions
* fix: don't print overridden interface implementations in info
This commit updates our handling of interface overrides to remove
interfaces from the implements meta of a function that was overridden by
a new implementation.
Similarly, this refactors primitiveInfo to prevent printing binders that
do not actually implement an interface.
* refactor: incorporate @TimDeve's error message suggestion
* fix: don't set the inner env to globals in type mods
Previously, we set the inner environment of a type generated module to
the global env in cases where the overarching context didn't have an
inner env. This leads to problems where by the recognition of modules is
inconsistent, and one can't use the names of types as submodules in
certain circumstances.
This commit fixes that issue.
* refactor: refactor primitiveDefmodule
This refactor fixes a issues with meta information on submodules, for
instance, sigs on submodule functions used to result in a compiler error
about ambiguous identifiers. This fixes that.
Unfortunately, I don't have a precise idea about what exactly was wrong
with the original definition of this function. My suspicion is that the
recursion originally altered submodule paths in the wrong way, but I'm
not certain. In any case it's fixed.
* fix: ensure macros are expanded in the correct module
Previously, macro expansions folded over all forms after the top level
form, without performing any context updates on encountered
`defmodules`. This created an issue in which macro calls that produced
new bindings, "meta stubs", were *hoisted* out of submodules and into
the top-level module, creating duplicate definitions.
This commit fixes that issue by adding a special case for defmodule in
macroExpand.
* fix: ensure submodules and globals don't conflict
Previously, our module lookups during new module definition always
eventually fell back to the global environment, which caused submodules
that happen to share a name with a global module to be confused with the
global module. This change fixes that, so now one can define both
`Dynamic` (global) and `Foo.Dynamic` without issue.
* fix: remove old prefixes from vector tests
Commit 7b7cb5d1e replaced /= with a generic function. However, the
vector tests still called the specific Vector variants of this function,
which were removed when the generic was introduced. After recent
changes, these calls are now (correctly) identified as erroneous. My
guess is that they only worked in the past because of problems with our
lookups.
* chore: format code
* feat!: support defining types in modules
This commit adds support for defining types (using deftype) in modules.
Previously, all types were hoisted to the top level of the type
environment. After this commit, the type environment supports defining
nested modules just like the value env, so, calling the following:
```
(defmodule Foo (deftype Bar Baz))
```
Adds the following to the type env:
```
Foo : Module = {
Bar : Type
}
```
and the following to the value env:
```
Foo : Module = {
Bar : Module = {
Baz : (Fn [] Foo.Bar)
copy : (Fn [(Ref Foo.Bar q)] Foo.Bar)
delete : (Fn [Foo.Bar] ())
get-tag : (Fn [(Ref Foo.Bar q)] Int)
prn : (Fn [(Ref Foo.Bar q)] String)
str : (Fn [(Ref Foo.Bar q)] String)
}
}
```
Such a type is *distinct* from any type defined at the top level that
happens to also have the name `Bar`.
This commit also updates info and tests to account for types in modules.
BREAKING CHANGE: This change is breaking since it alters the names of
types that were previously defined in modules. A good example of this is
the `Id` type in the `Color` module. Previously, one could refer to this
type by simply typing `Id` since it was hoisted to the top level. Now it
*must* be referred to by `Color.Id` since `Id` at the top level of the
type env and `Color.Id` (Id in the color module) are considered to be
distinct types.
* chore: format code
* refactor: use concat instead of intercalate
* chore: remove excess parentheses
* chore: Add todo to return IO () in printIfFound