Adds the beginning of a paths library and updates a few list index oriented things to allow negative indexing

This commit is contained in:
sloum 2023-11-27 23:17:33 -08:00
parent 8906ca9280
commit f0df7bba14
5 changed files with 42 additions and 5 deletions

View File

@ -37,9 +37,9 @@ var kwDocstrings = map[string]string {
"=>!": "Alias. See `list-append!`.",
"append": "Stack: LIST/STRING ANY\nRead :\nPush : LIST/STRING\nNotes: Appends ANY to LIST/STRING and leaves LIST/STRING on TOS. If LIST/STRING is STRING, ANY will be cast to string before appending.",
"append!": "Stack: ANY\nRead : SYMBOL\nPush :\nNotes: SYMBOL should represent a LIST or STRING. Appends ANY to the given LIST or STRING. If SYMBOL represents STRING then ANY will be cast to STRING before appending.",
"list-get": "Stack: LIST INT\nRead :\nPush : ANY\nNotes: The INT represents the index of the item being retrieved from the LIST. Remember that indexing starts at 1 (not 0). The list item at the given index will be placed on TOS.",
"list-set": "Stack: LIST INT ANY\nRead :\nPush : LIST\nNotes: Sets ANY item to INT index of LIST and puts the list back TOS.",
"list-set!": "Stack: INT ANY\nRead : SYMBOL\nPush :\nNotes: Reads a SYMBOL that must represent a LIST (or an error will be thrown). Sets ANY item to INT index of that list and updates it in memory (in the environment/scope that the variable is first encountered).",
"list-get": "Stack: LIST INT\nRead :\nPush : ANY\nNotes: The INT represents the index of the item being retrieved from the LIST. Remember that indexing starts at 1 (not 0). A negative number can be used to work from the end of the list, with -1 being the last item. The list item at the given index will be placed on TOS.",
"list-set": "Stack: LIST INT ANY\nRead :\nPush : LIST\nNotes: Sets ANY item to INT index of LIST and puts the list back TOS. INT can be negative to index from the end of the list.",
"list-set!": "Stack: INT ANY\nRead : SYMBOL\nPush :\nNotes: Reads a SYMBOL that must represent a LIST (or an error will be thrown). Sets ANY item to INT index of that list and updates it in memory (in the environment/scope that the variable is first encountered). INT can be negative to index from the end of the list.",
"file-write": "Stack: ANY STRING\nRead :\nPush :\nNotes: Takes a path as a STRING from TOS, then takes ANY from TOS. ANY will be cast to STRING and written to the path if possible.",
"file-remove": "Docstring coming soon.",
"file-exists?": "Stack: STRING\nRead :\nPush : BOOL\nNotes: Checks the file-system to see if the path referenced by STRING exists and leaves a BOOL on TOS.",
@ -49,7 +49,7 @@ var kwDocstrings = map[string]string {
"re-match?": "Docstring coming soon.",
"re-find": "Docstring coming soon.",
"re-replace": "Stack: ANY ANY ANY\nRead :\nPush : STRING\nNotes: Replaces values in a string based on a regex pattern (prn str rep -- STRING)",
"slice": "Docstring coming soon.",
"slice": "Stack: LIST INT INT\nRead :\nPush : LIST\nNotes: TOS is the index to slice until (inclusive), which can be negative (with -1 representing the last list item). The INT under TOS is the from index.",
"stackdepth": "Stack:\nRead :\nPush : INT\nNotes: Places the stack depth, as an INT, on TOS.",
"net-get": "Docstring coming soon.",
"try": "Notes: 'try is a special construct in the interpreter. Anything between the KEYWORD 'try' and the KEYWORD 'catch' will be executed and if an error is encountered the code between 'catch' and '.' will be executed. For example, to add two numbers... but not accept an error and instead leave 0 on TOS if there is an error:\n\ttry + catch 0 .\nInside the 'catch' portion of the construct a variable will be available in the environment called 'catch-error' that contains the text of the error.",

View File

@ -1228,6 +1228,9 @@ func libSlice(line int, fp string) error {
switch data.kind {
case STRING:
s := data.val.(string)
if t < 0 {
t = len(s) + t + 1
}
if t > len(s) {
t = len(s)
}
@ -1241,6 +1244,9 @@ func libSlice(line int, fp string) error {
case LIST:
li := data.val.(list)
l := li.body
if t < 0 {
t = len(l) + t + 1
}
if t > len(l) {
t = len(l)
}
@ -1405,6 +1411,12 @@ func libImport(line int, fp string, en *env) error {
return err
}
en.imports[t.val.(string)] = true
case "paths":
err = lexParseInterpret(pathsImport, en, "paths")
if err != nil {
return err
}
en.imports[t.val.(string)] = true
default:
p := ExpandedAbsFilepath(t.val.(string))
s, err := readFile(p)

15
lib/paths.fe Normal file
View File

@ -0,0 +1,15 @@
# paths contains procedures for working with
# file paths and URLs
"std" import
proc path-join
| Stack: STRING STRING
Read :
Push : STRING
Notes: Joins the two STRINGs on TOS as filepaths seperated by unix style file separators |
"/" / swap "/" / swap +
proc remove-nil BOOL cast end
filter! remove-nil
"/" * "/" swap +
end

View File

@ -45,7 +45,8 @@ var completions = []string{
"list-set", "list-set!", "split", "join", "file-write", "file-remove",
"file-exists?", "file-read", "docstring!", "input", "re-match?",
"re-find", "re-replace", "slice", "stackdepth", "net-get", "try", "throw",
"catch", "import", "rot", "each!", "filter!",
"catch", "import", "rot", "each!", "filter!", "INT", "STRING", "FLOAT",
"LIST", "BOOL",
}
//go:embed lib/std.fe
@ -57,6 +58,9 @@ var mathImport string
//go:embed lib/stack.fe
var stackImport string
//go:embed lib/paths.fe
var pathsImport string
func prompt(l *ln.State, cont bool) string {
p := "> "

View File

@ -60,6 +60,9 @@ func (l *list) Append(val token) error {
}
func (l list) Get(ind int) (token, error) {
if ind < 0 {
ind = len(l.body) + ind + 1
}
if ind > len(l.body) || ind < 1 {
return token{}, fmt.Errorf("Invalid index %d for length %d", ind, len(l.body))
}
@ -67,6 +70,9 @@ func (l list) Get(ind int) (token, error) {
}
func (l *list) Set(ind int, val token) error {
if ind < 0 {
ind = len(l.body) + ind + 1
}
if ind > len(l.body) || ind < 1 {
return fmt.Errorf("Invalid index %d for length %d", ind, len(l.body))
}