The basic idea of this change is to create a new `robot` type and use it to identify robots instead of `string` names. Internally, a `robot` value is just a (unique) `Int`.
Closes#212 .
This ended up turning into a sort of constellation of related changes.
- Add the `robot` type and change the type of various built-in functions which used to take a robot name so they now take a `robot` (`give`, `install`, `reprogram`, `view`, `upload`) and change `build` so it returns a `robot`.
- All internal data structures that store robots are now keyed by a unique (`Int`) robot ID rather than by name.
- Add a `setname` command for setting a robot's display name (which no longer needs to uniquely identify a robot).
- Import a big list of words which we can use to randomly pick names for robots, just for fun. This is why the diff says "+31,050 -265"; I did not write 31 thousand lines of code.
- Add constants `base`, `parent`, and `self` for getting a `robot` value referring to the base, one's parent, and one's self, respectively.
- Top-level binders like `r <- build {move}` now export a variable binding which can be used in later expressions entered at the REPL; additionally, unlike Haskell, a binder can now appear as the last statement in a block.
- Fix the pretty-printer for `Value` by doubling down on our current strategy of injecting `Value`s back into `Term`s and then pretty-printing the result. I am now convinced this is the Right Way (tm) to do this; it only required adding a couple additional kinds of `Term` which represent internal results of evaluation and cannot show up in the surface language (`TRef`, `TRobot`).
- Update the tutorial.
- While updating the tutorial, I noticed that #294 had introduced a bug, where the inventory display no longer updated when 0 copies of an entity are added to the inventory (as with `scan` + `upload`), so I fixed that by changing the way inventory hashes are computed.
I tried running the benchmarks both before & after this change. I was hoping that it might speed things up to be using `IntMap` and `IntSet` instead of looking things up by `Text` keys in a `Map` all the time. However, if I'm interpreting the results correctly, it seems like it didn't really make all that much difference, at least for the particular benchmarks we have.
The hash for an inventory is now the sum of the hashes of its contents. As discussed in #229 , the point of this is that inventory hashes can now be maintained incrementally, which could be a big win if there are robots with big inventories. It is less "secure" but we don't really care about that.
Closes#229.
Tuples are now parsed as parens containing terms separated by commas,
instead of just treating the comma as a binary infix operator. This
fixes#225 --- we now properly parse tuples containing lambdas.
Tuples bigger than pairs are treated as syntax sugar for right-nested
pairs, e.g. (1,2,3) is (1,(2,3)) (and also pretty-prints as the former).
Closes#241 .
This PR implements two changes:
- The error message window uses as much horizontal space as necessary now, wrapping lines when no further horizontal expansion is possible.
- The parser groups "built-in user functions" and "direction constants" under labels of the same names. This leads to more concise parse error messages.
- The user can now enter only whitespace (including comments) at the
REPL.
- A new file which is blank / only comments is no longer invalid from
the perspective of LSP.
Closes#275.
Players can ignore the return value until they have the capability to
deal with sum types. `scan` still has the effect of adding
information to one's inventory.
Closes#267.
- adds `editors` directory
- migrates [xsebek/swarm-vscode](https://github.com/xsebek/swarm-vscode) repo to `editors/`
- updates the highlighting (drill, sum types,...)
- adds some notes how to test and build the extension
- part of #100
- closes#123
- fixes#136
- changes the history file format to simple text line per `REPLEntry`
- refactors out a `REPLHistory` type and its pure functions
- adds tests for REPL logic (move to different previous entry,...)
Closes#269
- The parser now accepts `'` in a variable name as long as it does not start with `'` (to rule out potentially problematic variable names like `'a'`).
- Unit tests for this are added.
Closes#88.
Currently, these commands require no capability and no specific device (you already have an inventory, so why wouldn't you be able to look in it to see what you have?). However, that makes it impossible to discover these commands without reading the source or tutorial. Maybe we should make an "inventory" device? I'm not sure. Suggestions welcome. Or maybe once we implement #84 it won't matter since players can discover commands that way.
We used to call `initMachine` with `emptyStore` but this was wrong.
It meant that the store was reset every time you hit Enter on an
inventory item to `make` it. So e.g. if you had made a `def` and
executed it at least once, then made something from the inventory,
trying to execute the same definition again would yield a fatal
"reference to unknown memory cell" error.
The delay brackets mean the entire seed robot program simply becomes a
delayed value in a single step, and the seed robot then becomes
inactive, because it has successfully evaluated its program. This
took me an embarrassingly long time to figure out.
Fixes#264.
Make explicit in the type system when evaluation of a computation should be delayed. This gives the user fine-grained control over selective laziness (for example, once we have sum types and recursive types, one could use this to define lazy infinite data structures). It also allows us to guarantee that certain commands such as `build` and `reprogram` delay evaluation of their arguments, and lets the user e.g. define their own modified versions of `build` without compromising those guarantees.
- Delay is indicated by curly braces both at the value and type levels, that is, if `t : ty` then `{t} : {ty}`.
- `force : {ty} -> ty` is now exposed in the surface language.
- Change from a CEK machine to a CESK machine. Recursive `let` and `def` delay via allocating a cell in the store. For now, there is no other way to allocate anything in the store, but see discussion at #150 for some possible future directions.
- change the types of `build` and `reprogram` to require a delayed program, e.g. `build : string -> {cmd a} -> cmd string`
- `if` and `try` also require delayed arguments.
- don't elaborate Build and Reprogram with extra Delay wrappers since one is now required by the type
- Division by zero, negative exponents, and bad comparisons now throw exceptions.
Closes#150. Closes#226.
Resolves#228.
I've redefined the missing lens operators in `Utils.hs` in order to keep the diff of the function bodies minimal. Hopefully that will make merges and rebases less painful. Most of the type signatures are modified though, we can't avoid this.
Closes#180
Add `Integration.hs` which reads files from `example` folder and runs `processTerm` on the contents. The test passes if creating a term is successful.
Currently only one example i.e. `zigzag.sw` is failing.
Adds sum types (e.g. `int + bool`) along with constants `inl : a -> a + b`, `inr : b -> a + b`, and `case : a + b -> (a -> c) -> (b -> c) -> c`.
I considered whether to automatically wrap the arguments to `case` in `delay`, like the arguments to `if`, but they are already functions anyway so we get a lot of laziness for free. It would only make a difference if you wrote something like `case foo (let x = blah in \y. ...) (...)` in which case the `let x = blah` is going to be evaluated eagerly, *before* we know which branch we are going to take. I don't think it's worth bothering about. In the normal case that you write `case foo (\y. ...) (\z. ...)` then only one of the two functions gets run at all, without us having to do anything special with `delay`.
I also considered whether to make special syntax for case expressions, like `case foo of { inl x -> ... ; inr y -> ... }` but doing it as a simple built-in function is both easier to implement and feels like it fits better with the aesthetic of the language so far.
Closes#46 .
Since the base was not put into the active robots set, it never made
any progress on making the recipe.
Fixes#227. This just goes to prove @polux's point in #217.
There are still some things missing (e.g. operators) but this is a start. Some remaining issues:
* We should look into auto-generating the lists of keywords so we don't have to manually update every time we add new commands. Or (fancier) maybe the swarm executable can have a special flag to make it spit out lists of command names, so the emacs mode can dynamically find out what to highlight?
* I am not sure how to get it to highlight both single-line and multi-line comments at the same time. It must be possible since e.g. `java-mode` does it. We could also change the comment syntax, I really don't care that much.