Fixes#2007. After #1928, we handle exceptions a little differently, so it no longer works to simply set the base's CESK machine to an `Up` (exception) state no matter what. Instead we have to first check if the base is running, and if so set it to `Up` as before; if not, do nothing (except clear the REPL prompt).
Closes#1486.
I'm not entirely sure I understand why this is necessary but it seems like for anything with a brick `viewport` it's not enough to just rely on wrapping it in `clickable`. We have to actually set their focus explicitly depending on the identity of the clicked viewport.
In the implementation of #1826, I decided to preserve the old truncating behavior as the default. But after some consideration, there's no real use case for the old behavior, so let's take it out to simplify the code.
Adds a new primitive `imap`, aka index map, primitive to the world DSL. `imap` has type `World int -> World int -> World a -> World a`. Think of it like `(Coords -> Coords) -> World a -> World a`, i.e. given a coordinate mapping, it creates a new world by looking up the cell at the transformed coordinates in the given base world. However, since there are no lambdas we cannot directly give it that type; instead, the first `World int` represents a function `Coords -> int` which gives an x coordinate, and the second gives the y coordinate. All told, `imap wx wy wa` is like `\c -> wa (wx c, wy c)`. For example, `imap (-x) y w` is a reflection of `w` across the y-axis.
Adds a description of `imap` to the language reference, as well as adding a few examples.
Also removes the `rot` and `reflect` primitives, since they can now be simply implemented in terms of `imap`.
Depends on merging #1989 first. Closes#1584.
It turns out that the `hash` primitive was always computing the same deterministic hash of the coordinates regardless of the seed. This meant that *e.g.* any world features placed in a way that depended on the hash were always in the same locations, and if you created a world that only relied on `hash` and not on, say, Perlin noise, it would always look the same regardless of the seed. This does not seem desirable.
This PR fixes the DSL interpreter by passing the seed to the `murmur3` hash function (we used to always pass the constant seed 0). In theory, this does mean that all the "classic" worlds are now slightly different than what they used to be (except for seed 0). However, there's no way to tell the difference between one random placement and another. The only scenario where we really depend on the particular locations of entities for a particular seed is the `world101` tutorial, but that used seed 0 anyway, which did not change.
Depends on merging #1988 first.
The special variables `x` and `y` in the world DSL did not refer to the correct thing --- in the interpreter apparently I forgot to convert from `Coords` to `Location` and just used the row, column in `Coords` as the `x` and `y`. I have also fixed up all the scenarios which used `x` and `y` in their world description so that they now look identical to before, by replacing every use of `x` with `-y` and every use of `y` with `x` (though in some cases where the result would be algebraically equal I did not literally do this replacement, *e.g.* `(x + y) % 2` is equal to `((-y) + x) % 2`, so I left it alone).
Closes#1901
When switching description modals or info panel in the bottom left corner, the viewport used to retail the scrolled state.
This PR attempts to reset the scroll position when we switch modals.
Closes#1888. When we discovered a type mismatch, we were not fully substituting everything we had learned about the types (via `applyBindings`) before reporting the error. For example, in #1888 we had `2 : u1` and a unification constraint `u1 = Int -> u2`, but we were just reporting the type of `2` as `u1` rather than first substituting `Int -> u2` for `u1`.
I think we have had this problem for a while, but the recent rewrite of the unification engine possibly made the effects more noticeable.
This incidentally improved a couple more error messages in the test suite. =)
Closes#1948; see that issue for a much more in-depth discussion.
Depends on merging #1928 first.
A lot of this PR consists in deleting code that is either (1) ugly or (2) overly clever! 🥳
The short version is that the `Store` used to incorporate some laziness + memoization: when a cell was first allocated, it was an unevaluated thunk; it then got evaluated the first time it was referenced. However, this wasn't really needed to handle recursive definitions (which is the only thing we were using it for). Getting rid of it means we can get rid of a lot of weird ugly code needed to wrap free variables in extra calls to `force` and so on.
The new and improved `Store` just stores `Value`s, period. A special `VBlackhole` value was added, to be used while evaluating a recursive `let`.
Note that `VRef` is no longer really used, but I left it there for use in implementing #1660 . Once we have mutable references we can use them + delay/force to implement lazy cells.
The big idea of this PR is to add a new type of CESK machine state, `Suspended`, which is a state the base robot automatically goes into after completing execution of a program entered at the REPL. It is as if the base robot is still within the local context of any definitions etc. entered previously, just printed out an "intermediate result", and is now waiting to find out what the next term to be executed will be. This allows us to treat `def` as syntax sugar for `let` and results in a much cleaner way to manage the context of definitions, which in turn allows us to remove a whole lot of special cases and fixes several annoying bugs. See #1087 for more explanation and discussion.
Things that are **deleted** (!) by this PR:
- `TDef` (`def` is now just syntax sugar for `let`) (#997)
- `VResult` (we no longer need to return anything other than plain values)
- `FUnionEnv`, `FDiscardEnv`, `FLoadEnv` (we no longer need machinery to collect up definitions while evaluating terms)
- `ProcessedTerm` (just a plain `TSyntax` (i.e. `Syntax' Polytype`) is now enough)
- `Module` (it only existed to package up some contexts with typechecked terms, but we don't need them anymore)
- `RobotContext` and `topContext` (we don't need to store those things separately any more, they are just stored in the `CESK` machine where they belong)
Additions/changes:
- The `Requirement` module is split into `Requirements.Type` and `Requirements.Analysis` to avoid circular module imports
- New `Suspended` state for the CESK machine
- `def` and `tydef` are now allowed anywhere (even nested inside other definitions etc.) since `def x = y end; z` is just syntax sugar for `let x = y in z` (see #349)
- Code size decreased slightly for many programs using `def`, since `def` is now a synonym for `let`, and consecutive `def`s therefore do not require a `bind`.
Closes#1087. Fixes#681 (hence also #736, #1796). Fixes#1032. Closes#1047. Closes#997. Fixes#1900. Fixes#1466. Fixes#1424.
See also #636.
Currently, operator names are generated only for vscode only using the command `cabal run swarm:swarm-docs -- editors --code`.
With this PR, I intend to bring that behaviour to all the editors.
Changes include:
- `cabal run swarm:swarm-docs -- editors` command now supports `vim` as well.
- `operatorNames` can generate operator list catering to all the editors supporting Swarm.
- Update operator list in `swarm-mode.el`, `swarm.vim` and `swarm.tmLanguage.yaml`.
How to test emacs syntax:
- Open `editors/emacs/swarm-mode.el` in emacs.
- Then `M-x eval-buffer`
- Open up any of the `.sw` file under `examples`.
- Then `M-x swarm-mode`
How to test vim syntax:
- Copy swarm.vim to vim directory using `cp editors/vim/swarm.vim ~/.vim/syntax/sw.vim`
- Setup auto detect in vim. `echo 'autocmd BufRead,BufNewFile *.sw set filetype=sw' > ~/.vim/ftdetect/sw.vim`
- Open up any of the `.sw` files under `examples`. (Also ensure that you have syntax on in vim. `ESC :syntax on`)
Closes#1952. Whenever you type `(`, `[`, or `{` at the REPL, a matching close bracket is automatically inserted.
I suppose the next level would be to have it delete both brackets if you hit backspace immediately after inserting an open bracket, but I'll leave that for another PR. Doesn't seem that important anyway.
Includes tests for `prettyTextWidth` on type signatures. It should verify that line breaks are
introduced appropriately given number of allowed characters in a line.
Closes#1794
Changes include:
- Introduce `prettyTextWidth` that takes in number of allowed characters in a line as an argument.
- Introduce `pparens'` which is mostly similar to `pparens` except that it only encloses a document
in parantheses and does not do anything else.
- Make type signatures in renderers aware of the widget width.
- Replace usage of `hardline` with `softline` for multiline pretty printing.
Enforces that ever entry in the palette for a given (sub-)structure is used in its map.
Also in the PR, moved the `Coords` module to the `topography` sublibrary.
This refactoring makes structures parseable independently of `Entity` and `Robot `definitions.
We can define a `Palette` that maps to an arbitrary type, for example `RGBColor` instead of `Cell Entity`.
## Testing
```
scripts/test/run-tests.sh standalone-topography
```
I used to define functions with multiple clauses in a style like
```
f pat1 = ...
f pat2 = ...
f pat3 = ...
```
but since then have been convinced (by [this blog post](https://ro-che.info/articles/2014-05-09-clauses) and my own experience) that it is superior for multiple reasons to prefer using `case` (or `\case`), like
```
f = \case
pat1 -> ...
pat2 -> ...
pat3 -> ...
```
This PR refactors several functions that were still using the old style.
Fixes#1899. It turned out the problem was not specifically with infinite loop detection but simply any time an exception was thrown and bubbled up to the top level. After logging the exception the CESK machine returned `VUnit` and there was no way for the UI to tell the difference between a computation that ended successfully with value `VUnit` and one with an uncaught exception. This PR adds a new special value `VExc` to denote the result of a computation that threw an exception. The UI can then check for this and not set the `it` variable in that case.
I have seen the `479-atomic-race` integration test timeout several times recently (most recently in #1917). Increase the timeout for that test from the default 1s to 2s.
* Update VSCode plugin NPM package
* Update VSCode syntax
* Rewrite the `definition` rule to make it simpler and work with multiline types
* Use shared `#types` group with added support for `rec`
* Refactor groups to use ordered include `patterns` and unordered `repository` of named subgroups
* Add escape sequences to strings
* Fix a typo in a regular expression that broke syntax highlighting
* Generate the syntax JSON file from YAML
---
* Closes#1887
When I refactored requirements analysis during #1906 I didn't properly update the variable case: the code continued to look up the variable in `ctx` which used to be the name of the local context being passed around; after the refactoring, however, `ctx` was the name of the initial context passed to the top-level `requirements` function, and the local context was passed around as a `Reader` effect. Thus, the lambda case (for example) was correctly deleting the bound variable from the context, but then when checking the variable inside the body of the lambda we looked up its requirements in the initial, global context instead of the modified local one.
This PR fixes the issue and also adds some test cases, one of which was failing before this fix.
Fixes#1914.
When running on macOS, the integration tests open too many file handles,
even when you do not need to run any swarm file tests.
```sh
> cabal run -O0 swarm-integration -- -p editors
swarm-integration: data/scenarios/Challenges/_bucket-brigade/hauler.sw: openFile: resource exhausted (Too many open files)
```
The solution is to get the file paths only and safely open them as needed.
Surprisingly, this even makes the integration test code simpler.
* discovered while fixing failing tests in #1895
Towards #1907. For the most part, eschew the default To/FromJSON deriving in favor of `sumEncoding = ObjectWithSingleField`, which encodes `Constructor val` as something like `Constructor: val` instead of `{tag: Constructor, contents: val}`. Also omit empty `Comments` records.
In the context of #1907, this reduced the size of the generated JSON by about half.
Closes#1910
I'd argue that the code is behaving correctly and as intended. Snippets wrapped with backticks are/should be treated as regular texts with highlighting. Introducing line breaks inside a snippet should trigger add a newline character to the text before being rendered (which is what was happening in the first place).
This PR readjusts the description a bit to make sure that the snippets are in one line and do not have any line breaks in between.
Closes#1911. I understand the bug now: when inferring the type of a term, we also return a context of type alias definitions in the term. However, those type aliases might occur in types later in the term itself, so we need to pass those additional type aliases into the `requirements` function (which now looks at types and needs to be able to unfold type aliases).
(Once again, it's not really correct to be doing requirements analysis separately from type checking, and leads to bugs like this. See #231.)
What I am still really confused by is why the test suite did not catch this problem. The unit tests do in fact contain some terms like this, which contain a `tydef` followed by a use of the defined type. And the tests in `TestLanguagePipeline` call `processTerm` which seems like it should have triggered this...
Closes#1898. Adds the `hyperloop` device (recipe: `ADT calculator` + `strange loop`) which provides the ability to use recursive types (#1894). Also refactors requirements analysis code and adds the ability for types to trigger capability requirements.
Implements recursive types. Example:
```
tydef List a = rec l. Unit + a * l end
def nil : List a = inl () end
def cons : a -> List a -> List a = \x. \l. inr (x, l) end
def foldr : (a -> b -> b) -> b -> List a -> b = \f. \z. \xs.
case xs
(\_. z)
(\c. f (fst c) (foldr f z (snd c)))
end
def map : (a -> b) -> List a -> List b = \f.
foldr (\y. cons (f y)) nil
end
```
As discussed at #154, this uses the syntax `rec x. F(x)` to define the type `x` which is a solution to `x = F(x)`. However, unlike the discussion there, I ended up going with *equirecursive* types (so a recursive type is *equal to* its unfolding). For example, as you can see above, if we have a value of type `List a` (defined as `rec l. Unit + a * l`), then it actually has the equivalent type `Unit + a * List a`, so we can simply do a `case` on it, without having to `unroll` first. This actually turned out to be *easier* to implement (and it is cooler).
There are multiple built-in functions that conceptually return a list but currently do something different (like return a fold, or take an index and return a single element, etc.) We should consider changing them to actually return lists, but that should definitely be in a separate PR.
Closes#154.
At some point in the past a `welder` device and 50 `clock`s were added to the equipment and inventory, respectively, of the `base` robot in the `classic` scenario. This just updates the speedrun scenarios to match.