- Add
std:builtin
module containing language builtins, for better discoverability. - Add
std:fs:read-link
to read symbolic link targets.
- Remove the force operator (
!
) and change evaluation semantics.- Value identities are no longer eagerly computed, but instead are delayed.
- Changing to non-eager identities removes a lot of pitfalls with forced expressions, particularly with regard to recursively-defined modules which access each other's entries with an index operator.
- It is now possible in the runtime to indicate that a value should be
evaluated to compute an accurate identity (thus using the result of
evaluation, like
!
used to do).- This is how the features that used to be achieved with
!
will be able to be implemented. While reasoning about evaluation may be a little more difficult, this ensures the correctness of identities and so generally users won't need to reason about things as much.
- This is how the features that used to be achieved with
- Value identities are no longer eagerly computed, but instead are delayed.
- Add an lsp server.
- Supports syntax highlighting and document formatting.
- Add support for script formatting.
- This is still fairly simplistic, and will only do whitespace and separator
(
,
and;
) formatting.
- This is still fairly simplistic, and will only do whitespace and separator
(
- Change the executable to be multi-functional, with shortcuts for subcommands
based on the executable name.
- Supports
evaluate
(old behavior),lsp
, andformat
subcommands.
- Supports
- Change library lookup to look in the sibling
lib/ergo
directory (rather thanshare/ergo/lib
). - Package with an installer to simplify and streamline installation.
- Improve the CLI markdown rendering for documentation.
- Disambiguate set and get operators.
- Rather than using context to determine whether
:
means get or set, we change gets to use$
.
- Rather than using context to determine whether
- Change the string interpolation operator from
^
to$
. - Indirect get expressions are no longer supported. Get expressions must be with a string.
- Remove pattern commands as a syntax feature. Functions that should do something different should be renamed.
- Remove
pat
and the function version ofindex
. - Change the syntax for
{ a }
expanding to{ :a = :a }
: it is now{ :a }
. - Change Maps and keyed arguments to always be evaluated, and always evaluate values when indexing. This avoids a lot of potential confusion when using maps, as you may try to insert a key or index with a value that's not a constant, but in the overwhelming majority the intention is to use the result of those expressions. If someone does want a key to incorporate an unevaluated value, it is as simple as nesting it (for instance, in another Map or Array).
- Allow
Unset
types to be persisted. - Change the value binding fallback behavior such that the bound value is
evaluated prior to comparing identities. This, for example, makes matching on
nested values much more intuitive:
std:match [a b c, d e f] [ [string,other-string] -> ... ]
will evaluatea b c
andd e f
to see whether the result matchesstring
andother-string
, respectively, where before they would not be evaluated so it would never match. The prior behavior had very few and obscure use cases. - Add a built-in
id
function to change the identity of a value. - Fix a bug with
Iter
types where very large iterators would cause a stack overflow (which occurred when the value was dropped). - Remove the
--detect-deadlock
argument. Deadlock detection is now done automatically with no meaningful performance implications. - Remove the internal
store
interface from the runtime context, opting for a much simpler strategy that just provides the project working directory. - Add a new syntax for setting keyed arguments (
~key
/~key=value
) and disallow merging strings. - Change the merge operator (
^
) to imply a get when followed by a string literal. Thus,^$something
can be simply^something
. - Add
doc:raw
to get the raw documentation metadata. - Change
doc:value
anddoc:path
to be values rather than functions. - Add a
Functor
trait for mapping a function over inner values. - Refactor Values to accomodate the concept of late binding (which is far less
error-prone than dynamic binding).
- This includes syntax for late binding (
$?BINDING
) and the built-inlate-bind
function.
- This includes syntax for late binding (
- Allow merging
Unset
values in Commands/Blocks/Arrays (as a no-op). This is convenient for conditionally merging values. - Rename
ergo
toload
, and remove the ability to call the result with additional arguments.
- Any use of
!
should be replaced with equivalent code. - Change any
:value
get expressions to use$value
instead. - Change any
^...
(string interpolation) in quoted strings to be$...
, and change^^
to^
and any$
literals to$$
. - Any indirect get expressions need to be replaced with indexing or explicit matching.
- The overloading of a function to be used in pattern and normal contexts is no longer allowed (as pattern contexts don't exist). Separate the bindings to distinct names.
- Anything using
pat
should be changed tofn
and/or bound to a new name. - Anything using
index :a b
as a function rather thana:b
can use the latter:a:b
is now lazily evaluated. - Any
{ a, b, c }
in what used to be a pattern context should be changed to{ :a, :b, :c }
. - Change
^key
to~key
, and optionally change(key=value)
keyed args to~key=value
. - Change
doc:value ()
anddoc:path ()
todoc:value
anddoc:path
, respectively. - Change
ergo
toload
, and if it has additional arguments, change the call appropriately (e.g.ergo script arg1 arg2
=>load script |> arg1 arg2
).
- Identity calculation doesn't handle circular dependencies well. Ideally this
would "just work", however instead a deadlock occurs. Be careful with values
that are
eval_for_id
instd:recurse
, for example.std:recurse
could set the identity appropriately for the recursive value, but for now it is left to the user. - Index expressions (
a:b
) will be eagerly evaluated (if all captures are present) when an identity is needed. This is detrimental when, for instance, your expression is something likestd:cache (std:exec a b c):success
. In this case, the intention is forstd:cache
to gate the actualstd:exec
call occurring, but sincestd:cache
needs an identity,std:exec
will be evaluated to get thesuccess
result due to the aforementioned behavior. In this case, the expression can be rewritten asstd:cache { std:exec a b c; () }
or (more generally)std:cache <| std:bind (std:exec a b c) (index success)
, though it is ugly.
- Fix a bug where
std:net:http
would still try to download the file when present in theERGO_NET_CACHE
(but would still return the cached result). - Allow multiple tasks to correctly be suspended when awaiting the same task.
- Allow
Unset
values in theenv
map ofstd:exec
.
- Add
std:Iter:partition
to partition iterators into a Map of Arrays. - Add
std:Iter:chunks
to iterate over consecutive chunks of a given size. - Add
std:Iter:new
to create an iterator from a generator function. - Add
std:Iter:true
as a convenience to filter values to those that convert to true (useful in combination withstd:Iter:map
as a filter map). - Add
std:Iter:item
to get the next item from an iterator. - Add a
Type
type, and refactor how script types work in general.- You can now get the type of any value as a runtime value.
- Add
std:trait
, which allows access to built-in traits (Bind
,Into
,Stored
,Functor
, andDisplay
) as well as creating custom traits withnew
. - Add the
std:Type:or
function (which was already in the last release but was mistakenly not exported). - Add
std:Type:name
to get the name of a type. - Add
std:Type:get
to get the Type of arbitrary values. - Add
std:Type:basic
to get a basic version of a type suitable for comparison. - Extend
std:doc:module
to handleType
s too. - Add
std:Iter:unzip
to handle what used to be done withstd:zip
in pattern expressions. - Add
std:fs:file-size
to get the size of a file in bytes. - Add
std:fs:rename
to rename files and directories. - Add
std:fs:lock
to get advisory locks on files. - Add
std:env:concurrent-tasks
to provide the runtime task concurrency. - Add
std:env:project-dir
to get the project working directory. - Add
std:env:temp-dir
to get the system temporary directory. - Add
std:env:process-id
to get the ergo process id. - Add
std:env:process-dir
to get the process working directory. - Add
std:Cache
to create caches (both in-memory and persisted to disk).- Caches now use sqlite to store values.
- Add
std:once
to add values to an in-memory cache. - Add
std:Path:owned
to mark a path as owned, which will delete the path when the value is no longer used. The cache takes ownership of these paths. - Add
std:Path:for
, which is very similar to the previousstd:Path:with-output
but is doing something slightly different, so it's worthwhile to have a new name. - Add
std:index
to get indices of a value. It is similar tostd:import
but doesn't support recursive indexing and doesn't error on Unset results. - Add an
all
keyed argument tostd:Iter:zip
to replace missing values withUnset
rather than ending the iterator. - Add
std:optargs
as a convenient way to add optional arguments to a function. - Add
std:dynamic:bind
to deeply bind dynamic bindings in values. This is preferable tostd:dynamic:eval
as it leads to fewer mistakes when working with dynamic bindings. - Add
std:Unset:or
to return the first non-Unset value. - Add
std:Unset:index
to deeply index a value, possibly returning Unset if any intermediate index is Unset. - Add
std:load-lazy
to lazily load a file (causing the identity of the expression to not rely on the loaded file value). - Add
std:backtrace
to log a backtrace of the current evaluation. - Add
std:next
to evaluate a value once and bind the result. - Add
std:eval-id
to fully evaluate a value when the identity is calculated.
- Removed the
std:by-content
function, as one shouldn't be reinterpreting value identities. - Change
std:meta:eval
to return a map with the evaluated value and the metadata value (if any). This also allows binding the map so that the evaluation occurs immediately, which is often the intention (since forcing evaluation is no longer supported syntactically). - Remove
std:eval
in favor ofstd:Type:any
. - Rename
std:String:format
tostd:String:match
(making it only valid to match strings rather than creating strings). - Rename various functions in
std
to be consistent. See Migration for details. - Remove
std:default
behavior in normal (as previously designated) expressions. - Allow converting
ExitStatus
toNumber
.- If the process exited as the result of a signal,
-1
is returned.
- If the process exited as the result of a signal,
- Change
std:exec
in a number of ways:- Remove the
stdin
keyed argument; stdin is passed with a function. - Print all information of the command in logs/errors, including env variables and working directory.
- Return a new
Child
type which supports:stdin
index - a function to pass data to the child process stdinstdout
index - aByteStream
of the process stdout (as before)stderr
index - aByteStream
of the process stderr (as before)exit
index - aExitStatus
(renamed from the previousexit-status
)success
index - runs the process until completion, requiring success and producing an error with the exit status, stdout, and stderr on error (renamed and improved from the previouscomplete
)- conversion to
Bool
,Number
,String
, andByteStream
- Remove the
- Remove
std:env:get
in favor ofstd:env:vars
, which is aMap
of all of the process's environment variables. - Rename
std:env:user-cache
andstd:env:system-cache
tostd:env:user-dir
andstd:env:system-dir
. - Remove the
no-persist
option fromstd:cache
(usestd:once
). - Support caching top-level errors in
std:cache
by setting theallow-error
keyed argument totop
. - Remove
std:Path:new
andstd:Path:with-output
. - Improve
std:import
to not evaluate values when binding keys. - Generalize
std:Function:recursive
tostd:recurse
, which allows creating arbitrary recursive values. Use with caution! - Support merging
Args
instd:merge
. - Improve
std:fs:copy
to allow non-existentfrom
paths if making a symbolic link. - Rename
std:ergo-remote
tostd:load-remote
. - Remove
std:variable
since the builtinid
does the same thing.
- Remove the use of
std:by-content
. If it was being used to compare nested structures, some other means should be used (like binding in astd:match
). - Change
std:meta:eval
calls to properly get the value. You likely want to bind the result so that the evaluation occurs immediately, e.g.{ result, metadata-value } = std:meta:eval KEY :value
- Replace
std:eval
calls withstd:Type:any
. In patterns, they are interchangeable. In normal expressions,std:eval :v
can be converted to{std:Typed :v = :v; :v}
, though you may no longer needstd:eval
semantics at all. - Anything using a custom
std:type:new
type will need to be rewritten for the new API. This includes changing anybind
keyed argument to instead callstd:trait:Bind:impl
, and adding associated functions usingstd:Type:modify
. - Any type checks as normal (as previously designated) function calls will need to be rewritten or wrapped.
- Change
std:String:format ...
to equivalent formatted strings"..."
in normal (as previously designated) expressions, and tostd:String:match
in pattern expressions. - Change
std:Iter:zip
in pattern (as previously designated) expressions tostd:Iter:unzip
. - Change
std:default X as Y
in normal (as previously designated) expressions tostd:Unset:or X Y
. - Rename the following functions:
std:Any
->std:Type:pass
std:Typed
->std:Type:any
std:Array:Values
->std:Array:values
std:Array:Of
->std:Array:of
std:Map:Values
->std:Map:values
std:Map:Of
->std:Map:of
std:env:user-cache
->std:env:user-dir
std:env:system-cache
->std:env:system-dir
- Update the use of
std:exec
, passingstdin
with the returned function and changingexit-status
toexit
andcomplete
tosuccess
. - Change
std:env:get ENV_VAR
tostd:env:vars:ENV_VAR
. - Change
std:cache ^no-persist :value
tostd:once :value
. - Replace uses of
std:Path:new
andstd:Path:with-output
withstd:Path:for
, which will produce deterministic paths. - Change
std:Function:recursive <| fn :self ...
tostd:recurse <| :self -> fn ...
and change any use ofself
in the function body to not passself
as the first argument. - Change
std:ergo-remote
tostd:load-remote
. - Replace
std:variable ~depends=DEPS VALUE
withid ~set=DEPS VALUE
.
- Properly remove previously-set keys when a key is set to
unset
.- With the recent modification to how unset values are removed this case was missed.
- No changes.
- Remove
Unset
keyed arguments to commands just like they are removed from maps. - Ensure shebangs will parse correctly. They used to parse correctly when
#
was a line comment. Now with#
being a tree comment, they actually do generally parse such that they won't fail, however to be fully correct we now have a special case to tokenize shebangs at the start of a file. Tokenizing them is useful to fully preserve the content of the source script. - Change storage behavior to store value identities with values. This ensures that deserialized values have the same identities as the original values that were serialized.
- Improve diagnostic aggregation to properly remove duplicates.
- Add
std:io:is-terminal
to check whether a stream is connected to a terminal. - Add
std:fs:file-type
to get the file type of a path. - Change
std:cache
to not cache errors by default.- One can use the
allow-error
flag to cache errors if that behavior is intended.
- One can use the
- Change
std:net:unarchive
to show network errors prior to unarchiving.
- Parallelize store implementations for Array, Map, and Iter.
- Improve type errors that involve an Error type.
- Previously these would mention the type error and then the error itself, but in practice this is just extra noise and the type error should be ignored.
- Fix a minor bug in doc comment leading whitespace removal.
- Improve error message printing and information.
- Improve terminal UI rendering behavior.
- Add support for tree comments.
- If a comment token (
#
) is followed by whitespace it is a line comment, otherwise it is a tree comment. A tree comment will comment out the following syntax tree.
- If a comment token (
- Automatically cache results of values that access dynamic bindings based on
the binding value identities.
- Previously, values simply checked whether they access any dynamic bindings and, if so, would always re-evaluate. This caching is more efficient and is more in line with how values which don't access dynamic bindings are cached.
- Remove default doc metadata (which was present for most of the script
primitive types).
- Now the only doc metadata is that explicitly introduced by users.
- Improve runtime task prioritization.
- Previously priorities were only used when a task began, but now they are used at any await points in tasks.
- Format markdown output in the terminal when
--doc
is used. - Change
doc:write
output to be HTML rather than markdown. - Remove the
:
suffix operator for no-arg function calls. While no-arg function calls are still possible withf ^[]
, idiomatically it is recommended that no-arg calls are done by accepting a single()
argument.doc:path
has been changed to take a single()
argument.workspace
andstd
no longer require binding; you can access them as if they were loaded values (e.g.,std:import { Path } = :std
rather than... = std:
).- To be idiomatic, if a function is returned as the final value of a CLI call,
it will be called with a
()
argument rather than with no arguments as was previously done.
- Overhaul string literals.
- Change interpolation in strings (previously just doc strings) to use
^<expr>
rather than{{ <block> }}
. - Allow quoted strings to have expression interpolation.
- This potentially replaces almost all cases of
std:String:format
.
- This potentially replaces almost all cases of
- Remove raw quoted strings in favor of string blocks.
- Similar to
## ...
blocks for doc comments, string blocks look like
They also support string interpolation, but none of the escapes that quoted strings do.' multiline ' string
- Similar to
- Change interpolation in strings (previously just doc strings) to use
- Add support for attributes.
- These look like
##<expr>
. They apply to the following value (if unambiguous), and will always result in an expression which binds the following value to the attribute value and returns the result. This is especially useful for adding metadata to values in an unobtrusive way.
- These look like
- Add
user-configuration-directory/lib
folder as a load path. - Change doc comments to use a dynamic binding (returned by the
doc:value
function) rather than the specialself
binding. - Change
doc:child
to return both the path and the doc content.
- If you had any line comments without a space, a space will need to be added to
retain the original meaning now that tree comments have been added. E.g.,
#hello world
becomes# hello world
. doc:path
calls must be changed todoc:path()
.workspace:
andstd:
must be changed to:workspace
and:std
, respectively. Other uses of the bindings ought to work as they did before.- If a workspace
command
or script that was intended to be called from the command line returns a function, be sure that the no-argument case now is translated to something taking a()
argument. - Doc comment strings are more strict. They must always start with
##
(note the single trailing space), and leading whitespace is no longer normalized based on the first line. - Doc comment strings with
{{ ... }}
must instead use^(...)
. - Any doc comment or quoted strings with a literal
^
will have to use^^
to escape the string interpolation. - Raw string literals should be replaced with either block strings or quoted strings. In the latter case, be sure to properly escape the string content.
- Any doc comments using
self
should instead usedoc:value()
. - The
doc:child
return type is now a map; to make equivalent calls use the returnedpath
key.
- Add
std:Error:display
to convert Errors into Strings. - Add
std:test
module.- Add
std:test:run
as a basic way to nicely run tests and display the results.
- Add
- Add
fallback
keyed argument tostd:match
.- This is more ergonomic for cases where the final case may error (but that error should be returned).
- Add the
std:sync
module for synchronizing concurrent evaluation. - Add
std:Iter:count
. - Add ordering utilities:
std:Order
- ordering constantsstd:Number:compare
- compare numbersstd:String:compare
- compare stringsstd:Iter:order
- order an iterator according to an ordering function
- Add
std:Path:from
, and allow Strings to be converted to Paths. - Add
std:merge
to deeply merge maps and arrays. - Add basic math operators (
+
,-
,*
,/
, and%
) tostd:Number
. - Add
std:equal
to compare two values by identity. - Add
std:Bool
functions:not
for complementsand
for conjunctionor
for disjunction
- Add
std:net:url-encode
for url-encoding strings. - Add a
pretty
keyed argument tostd:json:stringify
to make the output string nicely formatted. - Add
std:meta:eval
to evaluate a value until a metadata key is present. - Add
std:env:config
which evaluates to the configuration directory. - Add
std:net:cache-dir
to return the specified network cache directory, if any. - Add
std:net:http-defaults
to return the user defaults. - Rework the
std:doc
module to use attributes and automatically document module contents. - Add
std:Typed
. It will evaluate the value and reject any Errors. - Add
std:Function:module
to improve the process of creating functions that also act as modules (with indices).
- Do not cache
std:net:unarchive
results, to make the standard library purely functional. - Cache
std:ergo-remote
, as that is an appropriate place for caching of the downloaded libraries andstd:net:unarchive
no longer caches things. - Allow all
std:net:http
arguments to be used withstd:ergo-remote
. - Allow
std:fs:copy
to copy symlinks rather than follow them by default.- Add a
follow-symlinks
keyed argument to change this behavior.
- Add a
- Improve
std:Path:or-source
to error when non-Path values are passed. - Change
std:doc:functions
to generate per-function doc children. - No-arg functions are changed to take a single
()
argument to be idiomatic. - Change type functions to use the
@
index for binding construction/destruction. - Add
else
keyword andelse if
additional cases tostd:if
. - Change
std:match
to reject Errors by default, and add anallow-error
flag to allow errors (matching the old behavior). - Support an
enter
keyed argument tostd:net:unarchive
to return the inner path if the unarchived content has exactly one top-level entry. - Support an
ERGO_NET_CACHE
environment variable for caching any body content (by url) downloaded withstd:net:http
. - Support user-configurable http defaults in
std:net:http
to allow e.g. user-specific per-endpoint authentication. - Allow
Unset
andUnit
values to be passed as arguments tostd:exec
. They will be ignored.
- Fix error return values when using
std:eval
. - Fix the
std:fs:glob
relative directory.- It was mistakenly using the call site script path rather than the parent directory.
- Fix the behavior of
std:require
when a value is Unset, and ensure that documentation is carried over throughstd:import
uses. - Correctly capture network client errors in the runtime.
std:String:format
patterns would match string prefixes rather than whole strings; this has been fixed.
- Change the following functions from
function:
tofunction ()
:std:Path:new
std:io:stdin
- Change all type construction/destruction to use
Type:@
rather thanType:
.- This includes all types in
std
as well as any types created withstd:type
functions.
- This includes all types in
- Add an
else
keyword tostd:if
calls when necessary. - Add
^allow-error
tostd:match
calls where matching errors is intentional (there probably aren't many cases of this). - Any documentation using
std:doc
must change to use the new functions (attributes). Existing documentation likely can take advantage of the new features as well.
Most of the changes listed below are breaking changes, so there is no separate section for those. They also could all probably be considered as new features or improvements, so no such distinction is made.
- The runtime has been completely refactored and rewritten, with many lessons learned from prior version. This refactor results in different semantics for the scripting language, which are described below. A number of syntax changes were made as well, but in general the syntax is almost identical to before.
- Removed the
BindEqual
parsed expression type, as it was barely ever used and prevented other more intuitive use cases (and could be implemented as a function). - Removed the
If
andIfBind
parsed expression types, as they can be implemented as functions now.- The reason they were parsed was so that the condition expressions could have delayed evaluation; now that everything has delayed evaluation, this is unnecessary.
- Parsing was changed to make bind statements (note the nomenclature: not
expressions as before) only valid in blocks and commands.
- You can no longer bind values in arrays. They do not have their own binding scope.
- A merge of an unbound value in a function pattern (e.g. the
rest
infn :a ^:rest -> ...
) will now be bound with anArgs
- orPatternArgs
-typed value, which captures both the positional and keyed arguments that remain. If more than one is present, the first gets the keyed arguments, whereas positional arguments are grouped and matched as before. This is far more elegant than the priorfn a ^:rest ^{^:kw}
forms. - The
Args
andPatternArgs
types support indexing withpositional
andkeyed
to get theArray
andMap
of arguments, respectively. They also supportInto<Array>
andInto<Map>
, where unhandled keyed or positional arguments (respectively) will cause an error. - A merge of a
String
-typed value in a command or a block will bind the item to a unit value, e.g.a b ^c
will be the same asa b (c=())
, and{ ^v }
will be the same as{ v = () }
. This is useful shorthand for toggle flags. - Blocks are now used to sequence values/operations (see
Evaluation Semantics
) since evaluation is delayed. - A merge of an
Array
-typed value into a block will sequence the items in the array as if they were items in the block inserted at the merge point. - Raw quoted strings are supported. Some number of repeated single quotes are
used to open a raw quoted string, and the same number will close one. They do
not interpret any escape sequences.
- For example:
'my raw \quoted\nstring'
,''This has a literal ' in it.''
- For example:
- Quoted and raw quoted strings simply change the tokenizer mode, such that if
they follow eachother or normal string tokens without spaces, they will be
considered part of the same evaluated string.
- For example:
e"="mc'^'2
evaluates to the stringe=mc^2
.
- For example:
- Directories will now only resolve to
dir.ergo
when being loaded (workspace.ergo
is now strictly used for workspace resolution rather than also being used in directory resolution). <|
now has lower precedence than|
/|>
, as it is used much more in practice and this is the more useful behavior.- Dynamically-scoped bindings are supported by the runtime. These are bindings which are present for any values which are evaluated after they are set. The runtime does not account for these when calculating value identities, so care must be taken to use them correctly based on the intended semantics.
- All script evaluation happens concurrently as tasks on the thread pool (with a fixed, high priority).
- A new
Number
type has been added to the runtime, supporting arbitrarily large rational numbers. - Add support for arbitrary escaped unicode characters in quoted strings.
- This looks like
"\u{123456}"
, where you can have from 1 to 6 hex digits.
- This looks like
- Do not cache value results if the dynamic scope is accessed when the value is
evaluated.
- This reduces surprise when using dynamic bindings in scripts (and makes those always correct semantically).
- Always pass command-line arguments as Strings to faithfully preserve shell/OS
semantics.
- The first argument is treated a little specially, interpreting any
:
as index operations into the loaded value. - If
--expression
is used, arguments are passed as-is (and may have operators, other script types, etc).
- The first argument is treated a little specially, interpreting any
- Add a
--detect-deadlock
flag and functionality to detect deadlocks while evaluating scripts. - Add a
bind
builtin function for binding values explicitly. - Add an
unset
builtin value that is an Unset-typed value. - Change the
index
builtin to also support function calls, whereindex :a b
is the same asa:b
.- This is useful to force a delayed index when otherwise an index operator would cause an expression to be captured (and thus evaluated ASAP).
- Add lints for unused bindings and unnecessary force expressions, and improve linting for string/binding conflicts.
- Add lint levels, defaulting to "on" when set without a level, and supporting more aggressive (but less accurate) lints with "aggressive".
- Only apply the syntax sugar that expands a string in a block/map to a set/get expression to unquoted strings; quoted strings will be parsed as a normal string.
- Allow
PatternArgs
types to be bound toArgs
types for convenience.- Otherwise, you'd have to use
bind (fn ^:pat-args -> ()) :args
, which is awkward.
- Otherwise, you'd have to use
- Add a
--backtrace
argument to turn on evaluation backtrace context for errors.
The new evaluation semantics and data model are a drastic simplification over the old runtime. Now, all syntactic evaluation is delayed. What this means is that, for example, if you have a script with the following:
f = fn :a -> std:String:format "Hello, {}" :a
f World
When you load this script, a dynamically-typed value is returned which
represents the execution of the top-level block. When that is evaluated (once),
it binds :f
to a dynamic value that will evaluate to the function as written,
and then returns a dynamic value which will apply f
on World
. Once that
value is evaluated again, it will bind World
to :a
in the function, and
return a dynamic value that will apply std:String:format
, and finally when
evaluated again format
will be called and a String
-typed value will be
returned.
Importantly, throughout all of this evaluation the runtime tracks subexpression captures such that the dynamically-typed values have identities that are derived from (parts of) the literal syntax and the bound values. The implication is that value identities still accurately and uniquely represent the value that would be returned if the expression is fully evaluated to a typed value.
The !
symbol is no longer an evaluation-level operator. It is instead a
syntax-level operator, indicating that the following expression should be
evaluated as soon as possible rather than being delayed in a value. The old
runtime implementation made !
very confusing to use (but often necessary).
Now, it should be much clearer when to use it. In particular, !
should only
be used to affect a dependent identity (because the identity of the evaluated
value will be used), or to make some side-effect happen at a certain time. As
soon as possible pertains to binding availability: fn :a -> !std:log:debug :a
will evaluate std:log:debug :a
as soon as the function is called (normally it
would simply return a delayed value which would later perform the log).
Generally, !
will be less prevalent, and it should be somewhat obvious when to
use it. You also should never really need to use it when writing many classes of
functions where resulting identities of delayed values are not that relevant (or
more accurately, only depend on inputs), e.g. data-manipulation functions. These
can be considered pure functions with regard to value identity, in the sense
that the output identity strictly depends on the input identities.
Values have changed in the runtime such that a dynamically-typed value can be
evaluated to return a new (possibly dynamically-typed) value, and typed values
represent a value which cannot be further evaluated (though a typed value can
contain other values which can then be evaluated, e.g. items in an Array
-typed
value). This change was made to both simplify runtime semantics but also to
allow runtime errors to be lifted to first-class types. Previously in the
runtime, a typed value might still need to be evaluated to get the value data,
however that evaluation could result in an error, and there would be no way to
transform a value typed as one type to an Error
-typed value. Changing typed
values to strictly not have any further evaluation necessary allows for the
moments where you do evaluate values (which would have to be
dynamically-typed) to produce Error
-typed values representing any errors.
The new Error
type behaves just like other types. In the future it will also
support persisting so that you can cache error results as well. The type
supports Into<Bool>
, always converting to a false
value (just like Unset
).
Types and traits still exist as before and operate in the same ways.
- Add
std:env:arch
to get the host architecture. std:log
uses theDisplay
ergo trait to write values, which is far more useful than requiring aString
argument.std:dynamic
has been removed as all expressions are dynamically-typed, however a new (unrelated)std:dynamic
module has been added, supporting interaction with dynamic bindings.std:typed
has been renamed tostd:eval
, since getting a typed version of a value is the same as evaluating the value.std:seq
is removed as sequencing values is a syntax-level feature.std:error
is removed as errors are first-class types.std:script
is removed as the runtime no longer supports getting script paths in this way.- Add
std:if
, which works the same as the old built-in (though without equivalent IfBind support). - Add
std:source
module to get/manipulate source information of values.path
returns the source path, if available.dir
returns the parent of the source path, if available.copy
copies the source information of one value to another.map
maps a function on a value but retains the original value's source.
- Add
std:net:http
, which is mostly HTTP-feature-complete.std:net:download
still exists, but is implemented usingstd:net:http
and now supports all keyed argments thatstd:net:http
does.
- Support
ByteStream
values instd:fs:unarchive
. - Add
std:fs:archive
for creating archives (opposite ofstd:fs:unarchive
). - Add
std:json
module withparse
andstringify
functions to convert json strings to ergo values and visa versa. - Add
std:String:chars
to get the characters in a string. - Support using
std:String:format
as a pattern command to do simple destructuring of strings. - Add
std:getopt
andstd:getopt:fn
to support simple conversion of string arguments containing long getopt-style flags toArgs
. - Add
std:identity
to get the identity of a value. - Optimize the behavior of
std:fs:track
to share results throughout a single execution (and not block calling threads), and add aforce-check
flag to allow forcing a file to be checked regardless of whether it was already checked (in case the file changed while scripts were executing). - Add
std:Iter:no-errors
to check for error values in an iterator. - Add
std:Unset:map
to easily map functions on Unset values. - Add a
bind
module withand
andor
functions, to help with binding multiple cases. - Add
std:type:Or
to create types which can be multiple other types.
std:match
now takes an array of cases rather than using the remaining arguments as the cases.- It was basically always used with a merged array anyway.
std:log
has an interface like other modules, using indexing forsublog
,debug
,info
,warn
, anderror
rather than taking them as the first argument to the command.- All functions have new implementations taking into account the new runtime semantics. In particular, when they are applied to arguments they will execute the function immediately rather than returning a value which will execute the function as before.
- Add
std:Error
to handle Errors as first-class types. Allow construction of errors with an explicit source location with the optionalsource
keyed argument. - Add a
priority
keyed argument totask
, which allows setting a priority between 1 and 1000 for a task. - Updated numeric arguments of functions to take the new
Number
type. std:net:http
will use the system native certificates rather than the mozilla webpki set.std:fs:copy
now supports ashallow
keyed argument, which may be used to make shallow copies rather than actual file copies.
- Renamed the
task-count
keyed argument oftask
tocount
. - Renamed
Iter:map-all
toIter:map
(that should be preferred), andIter:map
toIter:map-lazy
. - Reordered
std:fs:unarchive
parameters to make more convenient to use with pipe operators. - Changed
std:env:path-search
to returnUnset
rather thanError
if no binary is found. std:fs:copy
now defaults to making actual copies rather than hard links.- Reordered
std:meta:{get,set}
parameters to put the value last, aligning better with other function signatures. - Removed the
std:Unset:
function in favor of the builtin:unset
. - Rename
std:net:unarchive-remote
tostd:net:unarchive
.
std:match
cases should be passed as an array.std:log
should be accessed with an index operation.- Language semantics have changed, so the use of value-level functions (like
std:dynamic
,std:typed
, etc) should be examined. std:seq
should be replaced with a syntax block.std:error:throw
should be replaced withstd:Error:
.std:error:catch
should be replaced withstd:match
with astd:Error
case.std:script
functions should be replaced with different means to get path information.- Use
std:if
in place of oldif
expressions. If theif
expression was using a binding, usestd:match
. - Use
count
rather thantask-count
in keyed arguments totask
. std:Iter:map
should be replaced withstd:Iter:map-lazy
, andstd:Iter:map-all
should be replaced withstd:Iter:map
.- You should also review whether you really want
map-lazy
; in general (if you will eventually use all values)map
is preferred.
- You should also review whether you really want
- Flip arguments to
std:fs:unarchive
.
- Evaluate scripts concurrently to avoid stack overflows.
- More efficiently calculate type/trait uuids at runtime.
- No changes!
- Make indexing a distinct operation (as opposed to being syntax sugar).
- Indexing (infix
:
) is now a distinct operation, binding anIndex
value. In scripts, you may match this withindex :v
. Maps and arrays have been changed to useIndex
rather thanArgs
to get values.
- Indexing (infix
- Add
Unset
type and use it when map indexing fails, patterns are unmatched, or map pattern keys are unmatched.- This allows for cleanly dealing with missing/optional map keys.
- Add a global
std
function as shorthand for(ergo std)
. - Change how workspaces are loaded.
- There is no special
prelude
key anymore, and it is not specially loaded. - A global
workspace
function is shorthand for(ergo path/to/ancestor/workspace.ergo)
, and the workspace should be accessed through this. - The
command
key is still special in the workspace, however only because the command-line invocation ofergo
will useworkspace:command <args>
ifergo <args>
does not resolve to a file. Otherwise,ergo
(the load command) will only load a file based on its path and the load path. Previously, it encapsulated the workspace fallback behavior, but this is no longer the case.
- There is no special
- Support negative indices in array indexing (which will index from the end of the array).
- Add
-E
/--error-limit
flag and default to 3 frames of error context. Pretty-print error tracebacks rather than relying on the error display implementations. - Add
--doc-write
flag to output documentation to markdown files. - Add a built-in
doc
function to get documentation of a value, supporting the following additional indexes:doc:write
to write out documentation for a value,doc:child
to write child documentation (ifdoc:write
is being used), anddoc:path
to get the current output location for documentation, if any.
- Support expressions in doc comments.
{{ ... }}
in doc comments (possibly spanning multiple lines) will evaluate the content as a block, with scope that is shared throughout the doc comment. The result of the block is displayed inline in the final comment.
- Add
Iter
type for iterators.
- Improve doc comment parsing by not requiring a space after the initial
##
. - Change parsing of parentheses to be purely grouping.
- Previously, parentheses implied commands. Now they are strictly for
grouping, e.g.
(a)
anda
parse identically. Commands are inferred based on the presence of arguments. To call a command with no arguments, use the trailing colon, e.g.a:
. - This makes things work better especially with regard to pipe operators,
where you can now use parentheses as the limits of the pipe operator without
need for calling a command. For instance,
a b |>:d | e
parses the same ase ((a b):d)
, and if parentheses imply a call, then it ends up calling the result of(a b):d
, which is likely not what is desired. Now, that is equivalent toe (a b):d
, as the extra parentheses around the single value are superfluous. - The interpretation of values within parentheses is now identical to those
without; if the value is a single value, it is the result, otherwise if
there is more than one value, the first is bound to an
Args
containing the rest to get the result.
- Previously, parentheses implied commands. Now they are strictly for
grouping, e.g.
- Improve parsing of the pipe operators (
|>
,|
, and<|
) to make them truly rewrite macros. Previously they were parsed as recursive descent binary operators, which had limitations and special code for certain situations. For instance,a b |>:<| c d
would not work as expected (but now does). - Change command-line parsing to stop parsing flags at the first non-flag
argument.
- This is more convenient than using
--
to end the parsed arguments, and generally makes more sense.
- This is more convenient than using
- Make pattern errors more accurate. Previously any error while executing pattern expressions were considered pattern errors, but this shouldn't be the case.
- Do not use
-F
with less on mac for paging; mac has an old, buggy version of less where this doesn't work.more
does work with this flag on mac (and actually is less), but usingless
as the default is still probably more useful. - Improve error messages a little to decrease ambiguity/repetitiveness.
- Allow
ByteStream
types to be displayed. This was a nuisance; initially the idea was that there would be aUtf8Stream
type to specifically capture such a stream that's appropriate for display, but we sanitize the bytes inByteStream
when converting to aString
, so there's no reason to not do the same to implementDisplay
. - Release the load cache when no other load calls are present, to correctly drop lifetimes of values.
- Make
if
returnUnset
if the false case is not provided and the condition evaluates to that case.
- Fix incorrect parsing of indexing in e.g.
a |>:b:c
. - Fix incorrect parsing of trailing colon in e.g.
a b:c:
.
Syntax has changed in the following breaking ways:
- Parentheses are purely grouping, and do not imply a command call. Thus, if you
were calling a command with no arguments as
(function)
, it must be changed tofunction:
. - Indexing is a distinct operation (
a:b
is no longer syntax sugar for(a b)
). If you were using:
on values that were not arrays or maps, that must be changed to be parenthesized. If you were using a function call to get map/array values (map :key
), that must be changed to use the infix:
instead. - Pipe operators are parsed directly after bind expressions. Previously, they
were parsed after function (
a -> b
) expressions. This means that you can use the pipe operators to group a function, however you must be careful if using the rightward operators (|
and|>
) in the body of a function, as now that will group things regardless of the->
(arrow has higher precedence now). For example,:a -> a b |> c
used to parse the same as:a -> (a b) c
, but now it will parse as(:a -> a b) c
. - Workspace access no longer relies on
prelude
. In any script, if you use the globalworkspace
function (whether indexing or calling), it will load the nearest ancestor workspace and then index/call it with the arguments (if any). This means anything using values from aprelude
will now have to either load the prelude explicitly in the scripts (^workspace:prelude
, for instance), or will have to access values directly in theworkspace
.- This was done to make workspace use more obvious and simple.
- Workspace fallback behavior (with
command
) is now only a special behavior of the command-line invocation. If you were relying on such behavior in scripts, useworkspace:command <args>
explicitly in the script.
Semantics have changed in the following breaking ways:
()
(unit-typed values) now convert to true (rather than false) if converted to aBool
. This means the logic of some things that relied on this behavior needs to be updated. In particular, all values now convert to true if there is no other override, andUnset
values convert to false. You can (and should) use the standard library to explicitly createBool
instances.if
returnsUnset
for the false case if it is not provided. Previously, it returned()
.
- The standard library has been restructured into a more consistent hierarchy (see the documentation or the migration guide for details).
- Add
type:enum
andtype:struct
for common cases. - Add
Map:Values
,Map:Of
,Array:Values
, andArray:Of
to check the contents of arrays and maps. - Add
net:unarchive-remote
function for fetching and caching a remote archive, andergo-remote
convenience function for loading a remote archive. - Add a number of support features for interacting with
Unset
types:- The
Unset
function to match the type. optional
andrequired
predicates, allowing/disallowingUnset
in patterns.default
to specify default values forUnset
values.
- The
- Add
import
to easily use a map of keys to bind to indexed values. - Add
Function:pass
convenience function, namely for use inmatch
cases. - Add
Function:recursive
to create recursive functions. - Add
Function:partial
to partially apply functions. - Add
Function:memoize
to cache function results based on arguments. - Add
match:value
convenience function. - Add
Path:with-output
to make output paths from commands more ergonomic. - Add
String:join
to join iterators of strings. - Add
MapEntry
type for iterators ofMap
. type:new
accepts abind
keyword argument to dictate how value instances can bind. If unspecified, uses thebind
behavior of whatever inner type is returned by the compose function.- Add
Bool
type as well asBool:true
,Bool:false
, andBool:from
to create and convert bool values. - Add
fs:append
for appending to a file. - Add
env:user-cache
andenv:system-cache
to get the user and system cache paths. - Add
env:os
to get the OS running ergo. - Add
Iter
type for iterators, with the following support functions:from
to convert values to iterators,fold
to fold an iterator into a value,filter
to filter values in an iterator,flatten
to flatten an iterator of iterators,map
to map values in an iterator,map-all
to concurrently map values in an iterator,skip
to skip a number of values in an iterator,skip-while
to skip values based on a predicate in an iterator,split
to split an iterator into two after a number of values,take
to take a number of values in an iterator,take-while
to take values based on a predicate in an iterator,unique
to deduplicate values in an iterator,zip
to zip/unzip iterators into array iterators.
- Add
Array:from
andMap:from
(mainly for conversion from iterators). - Add
typed
function to evaluate a value to a typed value.
- Allow
env:path-search
to take Paths, and simply forward them as the returned value for convenience. - Make
value:cache
also serve as a runtime cache, and add ano-persist
option to make it only serve as a runtime cache. - Add
pattern
option toerror:throw
to indicate the error is a pattern error (which may be ignored by something likematch
). value:meta:get
andenv:get
returnUnset
rather than()
if a return is not available.- Make
type:new
produce a value that behaves exactly like all other type functions for consistency (calls check types, call with no args returns a function to compose types). - Allow
value:cache
to drop values early when they are present in the cache. This mainly makes things like atask
value not count toward the pending work. - Remove
collection
in favor of iterators and array-/map-specific functions.
- Fix an issue where
match
incorrectly detected bind errors when a binding in the body of a case failed. - Fix a panic when
script:path
is called when no path is available (now it will be a runtime error).
- Values produced by
type:new
(custom script types) will now behave like other types in the standard library, meaning that calling the produced types merely checks the type (without (de)composing it as the previous behavior was). This means that anywhere where these types are used must be changed fromtoMyType :x :y :z
where calling the type with no arguments returns the compose/decompose function. Since previously this was always the behavior, it will be sufficient (though not using the new features here) to change all calls of the custom types by adding a trailing colon as above.MyType: :x :y :z
- Anything previously using functions in
collection
will have to be convert to iterator functions:collection:map :f :v
->Array:from <| Iter:map :f :v
collection:fold :f :orig :v
->Iter:fold :f :orig :v
collection:entries :v
->Iter:from :v | Iter:map (fn :entry -> {key = entry:key, value = entry:value}) | Array:from
collection:get
andcollection:has
are no longer necessary (useUnset
return type checking). Note that the above are directly equivalent conversions, but with the new iterator functions you can probably have better functionality not constrained as before.
- Functions/modules in the
value
module have been moved to the top level. value:doc
has been removed as the builtindoc
is sufficient.- Type-related functions are now indexed off the type checking function:
- Values in the
string
module are now accessed withString
. - Values in the
path
module are now accessed withPath
.
- Values in the
- Fix some bugs and improve output UI.
- Don't count/display abort errors.
- Fix rendering reset.
- Don't count prelude load errors.
- Don't allow ctrl-C to affect child processes.
- Don't echo stdin in fancy formatting.
- Correct closure lookup.
- When a closure-bound value evaluated to a string in command position, it was looked up twice (incorrectly).
- Support doc comments (starting with
##
). - Major syntax and runtime updates:
- Remove use of
pom
, opt for a custom parser. - Remove
match
as a built-in parsed expression (it will be added tostd
). - Remove patterns as an AST concept. Everything is parsed as expressions,
including bind targets (
[target] = ...
and[target] -> ...
). - In bind targets:
a = b
is parsed as a bind equality (which will bind a value to botha
andb
),!a
will causea
to be parsed like a normal expression,:a
is parsed as a set expression (which will then bind to a value)
- Support calling a function with no arguments using a trailing
:
:a:
is the same as(a)
. - Commands and arrays now correctly create new scopes, just like blocks.
- Support setting keyword arguments in commands with bindings:
cmd (:kw = something)
- Support bind expressions as
if
conditionals (if (:a = b) :a other
), where the branch is chosen based on if the binding succeeds. - Change function definition to be generalized to any bindings, and
fn
is just a function which will binds to call arguments. - Add
pat
as a function which will bind to bind-call arguments (i.e. arguments from within a binding context):versusa = pat :v -> ... # Now we can use `a` within a binding. a :x = 1
a = fn :v -> ... # The following will error. a :x = 1
- Merge expressions are always immediate (previously array merges produced delayed values).
- Remove use of
- Apply linting while executing values.
- Remove
script-dir
andload-path
.
The syntax changes should not require too much effort to enact. In particular:
- In patterns,
a = ...
is a shortcut for:a = ...
, so this simple case need not be changed in scripts. - In patterns, any nested bindings will need a preceding
:
now. This will affect nested array and map patterns:[a,b]
should now be[:a,:b]
.{a}
is still fine (and is the same as{:a = :a}
), and likewise because of the above shortcut{a = b}
in a pattern can be changed to either{:a = :b}
or{a = :b}
.
- Important: Nested array and map patterns used to be delayed (i.e., the
source array/map value wouldn't be destructured until one of the nested
elements was accessed). This is now not the case; patterns are applied
immediately, and thus any destructuring will occur immediately. This was done
to simplify the behavior, though with more thorough design with regard to
other pattern functions, it may change back to being delayed in the future.
For now, if you were relying on this behavior to be delayed, you should access
elements directly by index, e.g.
map:key
(which is still delayed). match
is now a function in the standard library, so what was beforeshould now bematch [[value]] { [[pattern]] = [[expression]], [[pattern2]] = [[expression2]], ...}
Note that the pattern/expression pairs are just normal functions (which is whystd:match [[value]] ([[pattern]] -> [[expression]]) ([[pattern2]] -> [[expression2]]) ... # Or, to keep things line-separated std:match [[value]] ^[ [[pattern]] -> [[expression]] [[pattern2]] -> [[expression2]] ]
match
can itself be a function).fn
is now a binding function. Syntactically this doesn't mean much (it still looks likefn [[args]] -> [[expression]]
), but it does mean that function arguments all need:
preceding them, just like binding patterns:fn a b ^rest -> ...
should now befn :a :b ^:rest -> ...
.- This also means that if you had a function without arguments (
fn -> ...
), this needs to be changed to either(fn) -> ...
orfn: -> ...
.
- This also means that if you had a function without arguments (
- Patterns no longer support the
=[expression]
form for literal comparison. Instead, strings are literals by default, and any other literal value can be preceded by a!
:!
in patterns means to interpret the following expression as if it were a normal expression, not applying the special interpretation rules of pattern bindings. Note that this mainly changes the interpretation of:v
: in a binding,:v
means to setv
in the current scope, whereas!:v
means to use the value in:v
. - In patterns, commands are interpreted as bind commands. Previously,
(a b c) = 1
would match the literal output of(a b c)
. Now, you need!(a b c) = 1
to achieve the same effect. It's unlikely this was used much at all though... - Array merges now occur immediately, so any code relying on their previous delayed behavior will need to be updated.
- Instead of
:script-dir
, use(std:script:dir)
(it's a function).
- Fix deadlock occurring from task execution.
- Deadlocks are no longer possible, however other functions must indicate whether they want a task to be considered active across specific await points.
- Add a bunch of new functions:
script:dir
to get the currently executing script's directoryscript:path
to get the currently executing script's pathscript:load-path
to get the current load-pathpath:name
to get the final component of a pathvalue:dynamic
to create an explicitly-dynamic valuematch
to replace the previously parsed match expression
- Add the
type
module, with the following functions:new
to create new types from an interface definitionAny
/Unit
/String
/Path
/Map
/Array
/Function
to match each type
- Add
-e
/--expression
flags to evaluate the arguments as an expression without precedingergo
. - Fix evaluation when pipe operators are present in the command-line arguments.
- Change the first
:
to|>:
in command-line arguments for convenience.
- No changes!
- Fix log pausing to correctly clear the rendered content.
- Fix mac plugin detection.
- Fix unit-type returns (using new runtime unit type).
- Improve task work tracking; previously it only started tracking after the task is started.
- Improve task tracking and UI display of running tasks.
- Change the application log to be written to the data local directory. Support
ERGO_LOG_FILE
environment variable to override this. - Improve error logging to accurately track pending errors.
- Add
-d
/--doc
flags for getting documentation for the final value. - Add
-p
/--page
flags for paging the final output. - Improve
ergo
use in scripts to not always apply functions when they are loaded. Instead, the final value at the top level will, if a function, be applied (with no arguments) to refine the final value. - Support calling
ergo
without arguments. This evaluates to thecommand
workspace key.
- Add
task-count
keyword argument totask
, allowing one to specify how many task slots the task should consume when running. - Track work of active tasks (displayed in progress statistics in log output).
- Add
value:doc:{get,set}
andvalue:meta:{get,set}
for getting and setting documentation and metadata on values.
- Add the
!
operator, which may precede any expression or argument to evaluate the result immediately.- If the expression evaluates to a dynamically-typed value, it will evaluate the value to the inner value once.
- If the expression evaluates to a typed value, it will shallowly evaluate the value by content.
- Add
if
as a syntactic operator.- Now the
if
cases are conditionally evaluated, as opposed to the prior function which evaluated them immediately.
- Now the
- Ensure parenthesized commands allow newlines between arguments.
- Properly (and minimally) capture environment variables in fn/match/if blocks.
- No longer rely on environment bindings when loading scripts.
- Rename
work-dir
toscript-dir
in script default bindings to more accurately describe the value. - Allow merge operator (
^
) to prefix command expressions without parentheses. - Add
-c
/--clean
command-line parameter to clear the storage directory prior to execution.
- Rename
value:force
tovalue:by-content
. - Add
collection:get
to index values without causing errors to occur.- If a key/index doesn't exist, the function returns
()
.
- If a key/index doesn't exist, the function returns
- Remove
if
function as it is now a syntactic operator. - Add
script
module andscript:bindings
function to return a map of all current bindings. - Add
script:set-load-path
(previously one could setload-path
in the environment). - Improve
fs:copy
to create parent destination directories if missing.
- Support interactive subprocesses by suspending logging while they run.
- Support dynamically-typed values, and change indexing, array merging, match
expressions, and set expressions to lazily perform their actions.
- When values are constants or derived from constants, they are still eagerly evaluated.
- Fix a critical soundness bug around plugin unloading that was causing crashes.
- Change indexing to require the indexed value to exist (rather than returning a unit value).
- Add a warning when a string literal is used which matches a key in the
environment. This is only enabled with the
--lint
flag, and when this flag is present no evaluation of the final value is done. - Change maps to be keyed based on values rather than string literals (a superset of prior functionality).
- Change workspace interactions:
prelude
is now loaded directly as if the ancestor workspace was specified. This is a subtle difference, but differentiates prelude loading from fallback behavior.- Fallback behavior now first applies
command
to the ancestor workspace, and whatever is returned by that will receive additional arguments to the load command (rather than applying these arguments directly to the ancestor workspace return value).
- Improve byte streams to support async io, allowing
io:stdin
,io:stdout
, andio:stderr
to be implemented. - Change
exec
to produce asynchronous byte streams, allowing interactive processes to be run with concurrent IO. - Update
if
,collection:fold
, anderror:catch
to produce dynamically-typed values. This fixes a critical soundness bug that previously existed incollection:fold
, assuming the returned value was the same type as the base value without checking it. - Add
collection:has
to check whether a map/array has a given index, which complements indexing being changed to error when an index is missing.- This is only possible now that index expressions aren't evaluated
immediately, such that
if
with an index operation will not evaluate until after the condition is first checked.
- This is only possible now that index expressions aren't evaluated
immediately, such that
- Change script syntax, adding pipe operators and indexing/accessing bindings
with
:
. - Support calling functions without arguments.
- Add support for
dir.ergo
, which behaves likeworkspace.ergo
(and is preferred) when a directory path is provided, but otherwise behaves like a normal script. - Change storage command-line option to use furthest ancestor workspace.
- Add syntax highlighting files in
contrib
for vim and highlight.js. - Use better syntax highlighting in user guide.
- Improve error output.
- Add
self-file-path
pre-defined binding at script entry.
- Add
fs:read
,fs:write
,fs:remove
. - Rename
fs:mount
asfs:unarchive
. - Change
path
module to be a real module (rather than a function hack as it was before). This is possible since we can now call functions with no arguments (forpath:new
). - Add
env:current-dir
. - Statically link liblzma, use rustls-tls to remove dynamic linking of ssl libraries.
- Change to tokio runtime.
- Fix numerous bugs encountered in standard library.
- Initial release.