forked from slope-lang/slope
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
170 lines
23 KiB
170 lines
23 KiB
package main
|
|
|
|
const licenseText string = `
|
|
Copyright © 2021 sloum <sloum@rawtext.club>
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
`
|
|
|
|
const historyFilename string = "slope-repl.history"
|
|
|
|
var usageStrings = map[string]string{
|
|
"!": "(! [exception-text: string]) => exception",
|
|
"+": "(+ [number...]) => number",
|
|
"-": "(- [number...]) => number",
|
|
"*": "(* [number...]) => number",
|
|
"/": "(/ [number...]) => number",
|
|
">": "(> [number] [number]) => bool",
|
|
">=": "(>= [number] [number]) => bool",
|
|
"<": "(< [number] [number]) => bool",
|
|
"<=": "(<= [number] [number]) => bool",
|
|
"~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",
|
|
"and": "(and [expression...]) => bool",
|
|
"append": "(append [list] [value...]) => list",
|
|
"apply": "(apply [procedure] [arguments: list]) => value",
|
|
"assoc": "(assoc [association-list] [key: value] [[value]]) => 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",
|
|
"assoc?": "(assoc? [value]) => bool",
|
|
"atom?": "(atom? [value]) => bool",
|
|
"begin": "(begin [expression...]) => value\n\nEvaluates a series of expressions and returns the value of the last expression that is evaluated",
|
|
"begin0": "(begin [expression...]) => value\n\nEvaluates a series of expressions and returns the value of the first expression that is evaluated",
|
|
"bool?": "(bool? [value]) => bool",
|
|
"car": "(car [list]) => value|list",
|
|
"cdr": "(cdr [list]) => list",
|
|
"ceil": "(ceil [number]) => number",
|
|
"chdir": "(chdir [filepath: string]) => ()",
|
|
"chmod": "(chmod [filepath: string] [file-mode: number]) => ()",
|
|
"close": "(close [IOHandle]) => ()",
|
|
"cond": "(cond [([condition: expression] [#t-branch: expression])...]) => value\n\nWill evaluate each condition in turn and evaluate to the #t-branch of the first condition that is truthy. If no condition is truthy then an empty list will be returned. The value `else` is a sepcial case allowed as the final condition expression, the #t-branch of this condition list will be returned if no other condition is found to be truthy",
|
|
"cons": "(cons [value] [list]) => list",
|
|
"date": "(date): date => string",
|
|
"date-format": "(date-format [start-format: string] [date: string] [end-format: string]) => string\n\nDate format/pattern substitutions:\n\t%a - 12 hour segment, lowercase: pm\n\t%A - 12 hour segment, uppercase: PM\n\t%d - Day without leading zero: 4\n\t%D - Day with leading zero: 04\n\t%e - Day without leading zero, but with space padding: 4\n\t%f - Month name, short: Jan\n\t%F - Month name, long: January\n\t%g or %G - Hour, 24 hour format: 15\n\t%h - Hour, 12 hour format without leading zero: 2\n\t%H - Hour, 12 hour format with leading zero: 02\n\t%i - Minutes without leading zero: 4\n\t%I - Minutes with leading zero: 04\n\t%m - Month number, without leading zero: 6\n\t%M - Month number, with leading zero: 06\n\t%o - Timezone offset, without minutes: -07\n\t%O - Timezone offset, with minutes: -0700\n\t%s - Seconds, without leading zero: 5\n\t%S - Seconds, with leading zero: 05\n\t%w - Short weekeday: Wed\n\t%W - Long weekday: Wednesday\n\t%y - Two digit year: 21\n\t%Y - Four digit year: 2021\n\t%Z - Time zone, as three chars: UTC, PST, etc.\n\t%% - Will yield a literal percent sign: %\n\tanything else - A percent followed by an unrecognized char will yield a ?, as will a hanging % as the last char in the string\n\nSo the string: \"%F %e, %Y %h:%I%a\" would be equivalend to something like: \"August 8, 2021 4:03pm\"\n\nWhen a string is converted to a date and no time zone information is present, slope will assume the user's local time.",
|
|
"date->timestamp": "(date->timestamp [date: string] [format: string]) => number (timestamp)\n\nDate format/pattern substitutions:\n\t%a - 12 hour segment, lowercase: pm\n\t%A - 12 hour segment, uppercase: PM\n\t%d - Day without leading zero: 4\n\t%D - Day with leading zero: 04\n\t%e - Day without leading zero, but with space padding: 4\n\t%f - Month name, short: Jan\n\t%F - Month name, long: January\n\t%g or %G - Hour, 24 hour format: 15\n\t%h - Hour, 12 hour format without leading zero: 2\n\t%H - Hour, 12 hour format with leading zero: 02\n\t%i - Minutes without leading zero: 4\n\t%I - Minutes with leading zero: 04\n\t%m - Month number, without leading zero: 6\n\t%M - Month number, with leading zero: 06\n\t%o - Timezone offset, without minutes: -07\n\t%O - Timezone offset, with minutes: -0700\n\t%s - Seconds, without leading zero: 5\n\t%S - Seconds, with leading zero: 05\n\t%w - Short weekeday: Wed\n\t%W - Long weekday: Wednesday\n\t%y - Two digit year: 21\n\t%Y - Four digit year: 2021\n\t%Z - Time zone, as three chars: UTC, PST, etc.\n\t%% - Will yield a literal percent sign: %\n\tanything else - A percent followed by an unrecognized char will yield a ?, as will a hanging % as the last char in the string\n\nSo the string: \"%F %e, %Y %h:%I%a\" would be equivalend to something like: \"August 8, 2021 4:03pm\"\n\nWhen a string is converted to a date and no time zone information is present, slope will assume the user's local time.",
|
|
"date-default-format": "(date-default-format) => string\n\nReturns a format string for the default format produced by 'date'",
|
|
"define": "(define [var-name] [value|expression|procedure]) => value | expression | procedure\n\nReturns the value that var-name was set to, in addition to creating the var symbol and setting it to the given value. Define is lexically scoped (using define within a lambda will create a variable that is only visible to that lambda and its child scopes, but not to any parent scopes)",
|
|
"devnull": "devnull => io-handle (file: write-only)",
|
|
"display": "(display [value...]) => ()",
|
|
"display-lines": "(display-lines [value...]) => ()",
|
|
"E": "E => number",
|
|
"env": "(env [[env-key: string]] [[env-value: string]]) => list|string|()",
|
|
"equal?": "(equal? [value] [value]) => bool",
|
|
"eval": "(eval [expression|value] [[treat-string-as-code: bool]]) => value\n\ntreat-string-as-code defaults to #f. As such, a string will be evaluated to itself, a string. If true is passed, then the string will be parsed as code and the first, hopefully only, top level expression in the string will be evaluated. Aside from evaluating string it is common to use eval to evaluate quoted code: `(eval '(1 2 3))` would result in the list (1 2 3)",
|
|
"exception-mode-panic": "(exception-mode-panic) => ()",
|
|
"exception-mode-panic?": "(exception-mode-panic?) => bool",
|
|
"exception-mode-pass": "(exception-mode-pass) => ()",
|
|
"exception-mode-pass?": "(exception-mode-pass?) => bool",
|
|
"exit": "(exit [[number]]) => ()",
|
|
"file-append-to": "(file-append-to [filepath: string] [string...]) => ()",
|
|
"file-create": "(file-create [filepath: string]) => IOHandle",
|
|
"file-create-temp": "(file-create-temp [filename-pattern: string]) => IOHandle",
|
|
"file-name": "(file-name [IOHandle]) => string",
|
|
"file-open-read": "(file-open-read [filepath: string]) => IOHandle",
|
|
"file-open-write": "(file-open-write [filepath: string]) => IOHandle",
|
|
"file-stat": "(file-stat [filepath: string]) => assoc-list|#f\n\n#f will be returned if the file does not exist; all other file access errors will raise an exception.\n\nAssociative list will have the following keys:\n\tname (string)\n\tsize (bytes: number)\n\tmode (number)\n\tmod-time (number)\n\tis-dir? (bool)\n\tis-symlink? (bool)\n\tpath (string)\n\n'mode' will default to decimal,as all numbers do in slope, but it can be cast to an octal string with 'number->string'.\n\n'path' will be an absolute path after following a symlink, if present, or the path as provided to 'stat' in the absense of a symlink",
|
|
"filter": "(filter [test: procedure] [list]) => list\n\nThe test procedure supplied to filter should take one value and will have its return value treated as a bool. Any value in the list that returns a true when fed to the test procedure will be added to the list that filter returns",
|
|
"floor": "(floor [number]) => number",
|
|
"for-each": "(for-each [procedure] [list...]) => empty-list\n\nWorks via the same rules as `map`, but is used specifically for its side effects, rather than return values. See `map` for further details",
|
|
"hostname": "(hostname) => string",
|
|
"if": "(if [condition: expression] [#t-branch: expression] [[#f-branch: expression]]) => value\n\nAny value other than #f is considered true for the purposes of the `condition`, any expression given to `if` as a `condition` will be evaluated and its value will be taken as truthy or falsy by the above truthiness rule",
|
|
"io-handle?": "(io-handle? [value]) => bool",
|
|
"lambda": "(lambda [([[argument: sumbol...]])] [expression...]) => procedure\n\n`lambda` creates its own scope and any define statements within the lambda will be scoped to the lambda (available to it and any child scopes)",
|
|
"length": "(length [list|string|exception|IOHandle>string-buf]) => number",
|
|
"license": "(license) => ()",
|
|
"list": "(list [value...]) => list",
|
|
"list?": "(list? [value]) => bool",
|
|
"list-ref": "(list-ref [list] [index: number] [[set: value]]) => value|list\n\nList indexing starts at 0. When the optional `set` argument is provided the list will be returned with the value at the given index replaced by the `set` value that was given",
|
|
"list-seed": "(list-seed [length: number] [value]) => list\n\nUsing list seed to create lists filled with a certain element is more efficient than recursion for large lists and will not overflow the stack\n\n`length` should be a positive number larger than zero. If a floating point number is given, it will be floored",
|
|
"list-sort": "(list-sort [list] [[sub-list-index: number]]) => list\n\nIf `list` is a list of lists, sorting can be done by the index value of a sublist if desired. `list-sort` always sorts the list in ascending order, but can be reversed with `reverse`",
|
|
"list->string": "(list->string [list] [[join-on: string]]) => string",
|
|
"load": "(load [filepath: string...]) => symbol\n\n`load` will open the file represented by filepath and evaluate its contents as slope . It will run any within the file. `load` can accept a relative reference, which will be treated as relative to the current working directory. Any `define` statements within the laoded file will result in the symbol getting added to the global environment",
|
|
"load-mod": "(load-mod [module-name: string...]) => symbol\n\n`load-mod` will search the module path for the given module. If found, the file 'main.slo' within the module folder will be parsed. Arbitrary will not be executed, only `define`, `load-mod`, and `load-mod-file` statements will be evaluated",
|
|
"load-mod-file": "(load-mod-file [filepath: string]) => symbol\n\n`load-mod-file` is used within modules to do a relative load of files that are a part of the module, but are not 'main.slo'. The same evaluation rules as `load-mod` apply to `load-mod-file`",
|
|
"map": "(map [procedure] [list...]) => list\n\n`map` will pass the values of each list as arguments to the given prcedure and a new list will be created from the results. If multiple lists are given, they should be the same length and their values will be given as arguments such that the first argument of each list will be provided to the given procedure (as two arguments in the case of two lists, three in the case of three etc), then the second argument, and so on",
|
|
"max": "(max [number...]) => number",
|
|
"member?": "(member? [list] [value]) => bool",
|
|
"min": "(min [number...]) => number",
|
|
"mkdir": "(mkdir [path: string] [permissions: number] [[make-all: bool]]) => ()",
|
|
"mod-path": "(mod-path) => string\n\nReturns the current module path. The module path is calculated each time, in order to detect changes. As such, this is more expensive than a runtime constant",
|
|
"mv": "(mv [from-path: string] [to-path: string]) => ()",
|
|
"negative?": "(negative? [number]) => bool",
|
|
"not": "(not [value]) => bool\n\n`not` will invert the truthiness of the value it is given",
|
|
"net-conn": "(net-conn [host: string] [port: string|number] [[use-tls: bool]] [[timeout-seconds: number]]) => IOHandle",
|
|
"newline": "(newline) => ()",
|
|
"null?": "(null? [value]) => bool",
|
|
"number?": "(number? [value]) => bool",
|
|
"number->string": "(number->string [number] [[base: number]]) => string\n\nThe value for `base` defaults to 10 (decimal). If a value other than 10 is provided then the number will be parsed as an integer and output in the given base. If the value for `base` is 10 or is not given, the number will be parsed as a floating point number",
|
|
"or": "(or [expression...]) => bool",
|
|
"pair?": "(pair? [value]) => bool",
|
|
"path-abs": "(path-abs [filepath: string]) => string",
|
|
"path-base": "(path-base [filepath: string]) => string",
|
|
"path-dir": "(path-dir [filepath: string]) => string",
|
|
"path-exists?": "(path-exists? [filepath: string]) => bool",
|
|
"path-extension": "(path-extension [filepath: string] [[replacement-extension: string]]) => string",
|
|
"path-glob": "(path-glob [filepath: string]) => list",
|
|
"path-is-dir?": "(path-is-dir? [filepath: string]) => bool",
|
|
"path-join": "(path-join [string]) => string",
|
|
"PHI": "PHI => number",
|
|
"PI": "PI => number",
|
|
"positive?": "(positive? [number]) => bool",
|
|
"procedure?": "(procedure? [value]) => bool",
|
|
"pwd": "(pwd): path => string",
|
|
"quote": "(quote [expression...]) => bool",
|
|
"read-all": "(read-all [[IOHandle]]) => string",
|
|
"read-all-lines": "(read-all-lines [[IOHandle]]) => list",
|
|
"read-char": "(read-char [[IOHandle]]) => string",
|
|
"read-line": "(read-line [[IOHandle]]) => string|symbol: EOF",
|
|
"regex-find": "(regex-find [pattern: string] [string]) => list",
|
|
"regex-match?": "(regex-match? [pattern: string] [string]) => bool",
|
|
"regex-replace": "(regex-replace [string (pattern)] [string]) => string",
|
|
"rand": "(rand [[max]] [[min]]) => number\n\nIf no arguments are given `rand` will produce a floating point number between 0 and 1. If only `max` is given, `rand` will produce a floating point number between 0 and `max`. If `max` and `min` are both given, `rand` will produce a floating point number between `min` and `max`. `max` is always exclusive (the value produced will always be less than `max`), while `min` is inclusize. To obtain integers use `floor`, `ceil`, or `round` on the result or `rand`",
|
|
"reverse": "(reverse [list|string]) => list|string\n\n`reverse` will reverse a list or a string and return the same type of value it was given, but with the contents reversed",
|
|
"rm": "(rm [path: string] [[make-all: bool]]) => ()",
|
|
"round": "(round [number] [[decimals-to-round-to: number]]) => number",
|
|
"set!": "(set! [var-name: symbol] [value|expression|procedure]) => value | expression | procedure\n\nReturns the value that var-name was set to, in addition to creating the var symbol and setting it to the given value. Only an existing variable can be set with `set!`, trying to set a non-existant variable will result in an exception. `set!` will always set the value for the variable in the nearest scope",
|
|
"signal-catch-sigint": "(signal-catch-sigint [procedure]) => bool\n\nThe procedure passed to signal-catch-sigint should take no arguments and will be run upon sigint being received. This will override all default behavior: if you still want the program to exit you will need to call (exit) from within the procedure. This procedure (signal-catch-sigint) should be called at the root level of your program as it will only have access to the global environment.",
|
|
"sleep": "(sleep [[milliseconds: number]]) => ()",
|
|
"stderr": "stdin => io-handle (file: write-only)",
|
|
"stdin": "stdin => io-handle(file: read-only)",
|
|
"stdout": "stdin => io-handle (file: write-only)",
|
|
"string?": "(string? [value]) => bool",
|
|
"string->list": "(string->list [string] [[split-on: value]] [[count: number]]) => list\n\nSplits the string at each instance of `split-on` value. If `split-on` is not a string it will be case to string for the purposes of splitting the string into a list\n\nIf a count is provided the string will be split into no more than _count_ list elements.",
|
|
"string->md5": "(string->md5 [string]) => string",
|
|
"string->sha256": "(string->sha256 [string]) => string",
|
|
"string->number": "(string->number [string] [[base: number]]) => number/#f\n\nIf a non-decimal base is supplied, the input string will be parsed as an integer and any flaoting point value will be floored. A valid base passed with a string that does not parse to a number will return #f",
|
|
"string-append": "(string-append [value...]) => string\n\n'string-append' will stringify any non-string values passed to it and append them. To have finer grain control of number conversion use 'number->string' and pass the result to 'string-append'",
|
|
"string-buf?": "(string-buf? [value]) => bool",
|
|
"string-buf-clear": "(string-buf-clear [IOHandle: string-buf]) => ()",
|
|
"string-fields": "(string-fields [string]) => list\n\nSplits a string around each instance of one or more consecutive white space characters",
|
|
"string-format": "(string-format [template: string] [value...]) => string\n\nReplaces values designated by `%v` in the template string with successive values (`value...`).\n\nWidth can be set by adding an integer between the `%` and the `v`: `%10v`, or left aligned: `%-10v`",
|
|
"string-index-of": "(string-index-of [string] [search-value: string]) => number\n\nReturns -1 if `search-value` does not appear in `string`",
|
|
"string-lower": "(string-lower [string]) => string",
|
|
"string-make-buf": "(string-make-buf) => IOHandle: string-buf",
|
|
"string-ref": "(string-ref [string] [number]) => string",
|
|
"string-trim-space": "(string-trim-space [string]) => string\n\nRemoves any leading or trailing white-space from `string`",
|
|
"string-upper": "(string-upper [string]) => string",
|
|
"subprocess": "(subprocess [list] [[output-redirection: IOHandle|#f]] [[error-redirection: IOHandle|#f]]) => number\n\nPassing `#f` to output redirection allows you to do stdout while still redirecting stderr. The `#f` for stderr only exists for symetry, and will not redirect stderr",
|
|
"substring": "(substring [string] [start-index: number] [end-index: number]) => string\n\n`end-index` is exclusive",
|
|
"symbol?": "(symbol? [value]) => bool",
|
|
"term-char-mode": "(term-char-mode) => ()",
|
|
"term-cooked-mode": "(term-cooked-mode) => ()",
|
|
"term-raw-mode": "(term-raw-mode) => ()",
|
|
"term-restore": "(term-restore) => ()",
|
|
"term-sane-mode": "(term-sane-mode) => ()",
|
|
"term-size": "(term-size) => list",
|
|
"timestamp": "(timestamp) => number (timestamp)",
|
|
"timestamp->date": "(timestamp->date [timestamp: string|number] [[format: string]]) => string\n\nDate format/pattern substitutions:\n\t%a - 12 hour segment, lowercase: pm\n\t%A - 12 hour segment, uppercase: PM\n\t%d - Day without leading zero: 4\n\t%D - Day with leading zero: 04\n\t%e - Day without leading zero, but with space padding: 4\n\t%f - Month name, short: Jan\n\t%F - Month name, long: January\n\t%g or %G - Hour, 24 hour format: 15\n\t%h - Hour, 12 hour format without leading zero: 2\n\t%H - Hour, 12 hour format with leading zero: 02\n\t%i - Minutes without leading zero: 4\n\t%I - Minutes with leading zero: 04\n\t%m - Month number, without leading zero: 6\n\t%M - Month number, with leading zero: 06\n\t%o - Timezone offset, without minutes: -07\n\t%O - Timezone offset, with minutes: -0700\n\t%s - Seconds, without leading zero: 5\n\t%S - Seconds, with leading zero: 05\n\t%w - Short weekeday: Wed\n\t%W - Long weekday: Wednesday\n\t%y - Two digit year: 21\n\t%Y - Four digit year: 2021\n\t%Z - Time zone, as three chars: UTC, PST, etc.\n\t%% - Will yield a literal percent sign: %\n\tanything else - A percent followed by an unrecognized char will yield a ?, as will a hanging % as the last char in the string\n\nSo the string: \"%F %e, %Y %h:%I%a\" would be equivalend to something like: \"August 8, 2021 4:03pm\"\n\nWhen a string is converted to a date and no time zone information is present, slope will assume the user's local time.",
|
|
"url-host": "(url-host [url: string] [[new-host: string]]) => string",
|
|
"url-path": "(url-path [url: string] [[new-path: string]]) => string",
|
|
"url-port": "(url-port [url: string] [[new-port: string]]) => string",
|
|
"url-query": "(url-query [url: string] [[new-query: string]]) => string",
|
|
"url-scheme": "(url-scheme [url: string] [[new-scheme: string]]) => string",
|
|
"usage": "(usage [[built-in-name: string]]) => ()\n\nIf not passed a value, usage will display a list of all known built-in procedures. When given a value a description of that value will be output to stdout.",
|
|
"write": "(write [string] [[IOHandle]]) => ()|IOHandle",
|
|
"write-raw": "(write-raw [string] [[IOHandle]]) => ()|IOHandle",
|
|
"zero?": "(zero? [number]) => bool",
|
|
}
|