Updates append to allow merging tables

This commit is contained in:
sloum 2024-06-28 20:02:18 -07:00
parent 7549607749
commit 6e417805fd
2 changed files with 23 additions and 3 deletions

19
lib.go
View File

@ -1127,6 +1127,18 @@ var stdLibrary = vars{
case []expression:
base = append(base, a[1:]...)
return base
case table:
for i, v := range a[1:] {
if _, ok := v.(table); !ok {
return exception(fmt.Sprintf("'append' was given a table as its first item, but a non-table as its number %d item. If a table is given to append as its first item, all other items must be tables", i+2))
}
}
for _, t := range a[1:] {
for k, v := range t.(table) {
base[k] = v
}
}
return base
default:
var out strings.Builder
for i := range a {
@ -1175,6 +1187,13 @@ var stdLibrary = vars{
}
return table(out)
},
"table?": func(a ...expression) expression {
if len(a) == 0 {
return exception("'tabl?' expects an argument")
}
_, ok := a[0].(table)
return ok
},
"table-keys": func(a ...expression) expression {
if len(a) < 1 {
return exception("'table-keys' expects a value")

View File

@ -39,7 +39,7 @@ var usageStrings = map[string]string{
"~bool": "(~bool [value]) => bool\n\n`~bool` will convert a given value to a boolean value using a looser set of rules than `if` would normally use: 0, 0.0, the empty list, an empty string, and a closed io-handle will be considered falsy (in addition to #f)",
"abs": "(abs [number]) => number\n\nReturns the absolute value of a given number",
"and": "(and [expression...]) => bool\n\nChecks the truthiness of all expressions passed to it. If any expression is falsy then false is returned and no further expressions are checked; otherwise returns true",
"append": "(append [list|value] [[value...]]) => list|string\n\nAdds the given value(s) to the end of the given list|string. If a list alone is given it is simply returned. If a single value is given it will be coerced to string and returned. If multiple values are given they will be concatenated and a string will be returned; any non-string values will be coerced to string before concatenation",
"append": "(append [list|value|table] [[value...]]) => list|string|table\n\nAdds the given value(s) to the end of the given list|string. If a list alone is given it is simply returned. If a table is given all other values must also be of type table. When appending to a table all keys and values in the value... tables will be appended to the initial table, overwriting any values with shared keys. As usual with tables, all changes are done via reference to the underlying data structure. The initial table is returned. If a single value is given it will be coerced to string and returned. If multiple values are given they will be concatenated and a string will be returned; any non-string values will be coerced to string before concatenation",
"apply": "(apply [procedure] [arguments: list]) => value\n\nSpreads the list values as arguments to the given procedure. This results in behavior where the following two examples are equivalent:\n\n\t(+ 1 2 3)\n\t(apply + [1 2 3])",
"assoc": "(assoc [association-list] [key: value] [[value]] [[relative?: bool]]) => value|list\n\nIf two arguments are given then `assoc` retrieves the value of the key. If a third argument is given `assoc` will set the value for the given key to the given value, returning the updated list. If `relative?` is `#t` and an existing field is gettings set, it will be set in place via relative reference. This does not reliably function for adding a new key to the association and you should always store the new association with `set!` when adding a new key. However, execution may be faster with `relative?` set due to optimizations that can potentially exist in the underlying implementation",
"assoc?": "(assoc? [value]) => bool\n\nDetermines whether or not the given value is an association list",
@ -197,8 +197,9 @@ var usageStrings = map[string]string{
"subprocess": "(subprocess [list] [[output-redirection: io-handle|#f]] [[error-redirection: io-handle|#f]] [[input-redirection: io-handle|#f]]) => number\n\nPassing `#f` to any of the redirections will have them use the std version of the redirection (stdout, stderr, or stdin). If you want to have something redirect to devnull you must explicitly pass it",
"symbol?": "(symbol? [value]) => bool\n\nChecks if the given value is a symbol",
"sys-args": "sys-args => list\n\nsys-args is the list of arguments that were invoked to run the currently running slope program. The first argument in the list is always the name of the program that was invoked, which will not include the slope interpreter itself (if invoked directly it will be removed from the list).",
"table": "(table [string] [value]...) => table\nCreates a table. Even numbered arguments will be stringified and used as keys, odd numbered arguments will be values for the keys",
"table-keys": "(table-keys [table]) => list\nReturns a list of keys, as strings, to the given table",
"table": "(table [string] [value]...) => table\n\nCreates a table. Even numbered arguments will be stringified and used as keys, odd numbered arguments will be values for the keys",
"table?": "(table? [value]) => bool\n\nChecks if the given value us a table",
"table-keys": "(table-keys [table]) => list\n\nReturns a list of keys, as strings, to the given table",
"term-char-mode": "(term-char-mode) => ()\n\nChanges the terminal to char mode",
"term-cooked-mode": "(term-cooked-mode) => ()\n\nChanges the terminal to cooked mode",
"term-raw-mode": "(term-raw-mode) => ()\n\nChanges the terminal to raw mode",