Big project dir refactor

* split into multi member workspace in preparation for a no_std core
* env and posix stuff neatly crammed into a seperate shell project
* some pokes at interactive-devel.f
* updated ci
* removed 'l' shortcut for 'load' and update docs
* remove out of date readme content
* updated tests
* more sensible cond implementation and extra tests
* substr stdlib function with tests

Signed-off-by: Ava Affine <ava@sunnypup.io>
This commit is contained in:
Ava Apples Affine 2024-07-10 13:22:28 -07:00
parent aa56570d7d
commit 6d2925984f
44 changed files with 967 additions and 779 deletions

View file

@ -21,9 +21,9 @@
;; username, and percentages for all batteries on the system.
;; -> requires CFG_FLESH_POSIX=true and userlib.
(def _batteries 'paths to batteries powering system'
(def _batteries "paths to batteries powering system"
(lambda ()
(let ((power-srcs-dir '/sys/class/power_supply')
(let ((power-srcs-dir "/sys/class/power_supply")
(power-srcs
(split (load-to-string find /sys/class/power_supply -printf "%p ")
" "))
@ -39,7 +39,7 @@
(set (q pwr-iter) (pop rem))))
pwr-list)))
(def display-batteries 'display battery capacity'
(def display-batteries "display battery capacity"
(lambda ()
(let ((bat-iter (pop (_batteries)))
(display ""))
@ -53,14 +53,14 @@
(set (q bat-iter) (pop rem))))
display)))
(def CFG_FLESH_R_PROMPT 'display battery info'
(def CFG_FLESH_R_PROMPT "display battery info"
()
(display-batteries))
(def _fancy-cwd 'prints (up to) last three segments of current path'
(def _fancy-cwd "prints (up to) last three segments of current path"
()
(let ((cdir (load-to-string pwd))
(dir-segs (split cdir '/'))
(dir-segs (split cdir "/"))
(dir-iter (dq dir-segs))
(i 0))
(if (lte? (len dir-segs) 4)
@ -73,14 +73,14 @@
(concat "..." final)))))
(def in-a-git-repo?
'returns true or false depending on if currently in a git repo'
"returns true or false depending on if currently in a git repo"
() (eq? (load-to-string git rev-parse --is-inside-work-tree) "true"))
(def git-repo-is-dirty?
'returns true or false depending on if current dir is a dirty git repo'
() (not (eq? (load-to-string git diff '--stat') "")))
"returns true or false depending on if current dir is a dirty git repo"
() (not (eq? (load-to-string git diff "--stat") "")))
(def git-status 'returns "(git:<branch>{!,})" if dir is in a git repository'
(def git-status "returns '(git:<branch>{!,})' if dir is in a git repository"
()
(if (in-a-git-repo?)
(concat
@ -90,9 +90,9 @@
"!"
"")
")")
''))
""))
(def CFG_FLESH_L_PROMPT 'display user and dir (git info in future)'
(def CFG_FLESH_L_PROMPT "display user and dir (git info in future)"
()
(concat
"[" USER "]" "\t"

View file

@ -52,6 +52,6 @@ Or, a more advanced use:
(cons while (cons gt? (cons len (q arg-iter)) 1)
(cons set (cons q (q func-call)) (cons cons (q func-call) (cons car (q arg-iter))))
(cons set (cons q (q arg-iter)) (cons pop (cons cdr (q arg-iter)))))
(cons echo '+ ' (cons cdr (cons pop (q func-call))))
(cons echo "+ " (cons cdr (cons pop (q func-call))))
(cons eval (q func-call))))))
(eval lam)))

View file

@ -0,0 +1,20 @@
#!/bin/flesh
;; Flesh: Flexible Shell
;; Copyright (C) 2021 Ava Affine
;;
;; This program is free software: you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;;
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;;
;; You should have received a copy of the GNU General Public License
;; along with this program. If not, see <http://www.gnu.org/licenses/>.
;; INTERACTIVE DEVELOPMENT TESTS
;; This file contains test cases for interactive-devel.f

View file

@ -18,19 +18,31 @@
;; INTERACTIVE DEVELOPMENT
;; This file contains features that help you develop new features at the REPL
;; TODO: Need an is_symbol impl or some way to reflect
;; lib setup
(if (not (set? reduce))
((echo "need map. Include userlib.f")
(exit -1)))
;; basic goals
;; (def get-sym-deps
;; 'gets all global symbols referenced by the definition of a symbol'
;; (sym) ;; probably just iter over and call 'set?' on symbols
;; ()) ;; then return a stack of symbols
;; (def get-tree-deps
;; 'Gets all global symbols referenced by the definition of a symbol.
;; assumes symbol is passed in quoted. Essentially this function expects
;; a tree.'
;; (sym)
;; (reduce (lambda (res elem) (cond ((sym? elem) ;; symbol case
;; ()
;; ((list? elem) ;; list case
;; (extend results (get-tree-deps (eval elem)))))))
;; sym)) ;; then return a stack of symbols
;; (def dump-sym
;; (def dump-tree
;; 'writes a symbol to a library file'
;; (sym lib) ;; check if lib exists
;; ()) ;; write to lib
;; (def dump-sym-with-deps
;; (def dump-tree-with-deps
;; 'writes a symbol, with all its dependencies, to a file'
;; (sym lib) ;; make a list of sym and all its deps
;; ()) ;; iterate over that list and add new elements that are deps of iter

View file

@ -20,44 +20,44 @@
;; this file implements unit tests for handwritten userlib functions
(def passed
'prints if a test has passed'
"prints if a test has passed"
(test)
(echo (concat "PASSED: " test)))
(def failed
'prints if a test has failed'
"prints if a test has failed"
(test)
(let (())
(echo (concat "FAILED: " test))
(exit 1)))
(def test-cases 'all test cases'
(('set updates var'
(def test-cases "all test cases"
(("set updates var"
(quote
(let ((test-val 0))
(set (q test-val) 3)
(eq? test-val 3))))
('prepend prepends to list'
("prepend prepends to list"
(quote
(let ((list (2 3 4))
(list (prepend 1 list))
(list-head (pop list)))
(eq? (car list-head) 1))))
('map applies function across list'
("map applies function across list"
(quote
(let ((list (1 2 3))
(adder (lambda (x) (add 1 x))))
(eq? (map adder list) (2 3 4)))))
('reduce function adds numbers'
("reduce function adds numbers"
(quote
(let ((list (1 2 3))
(adder (lambda (x y) (add x y))))
(eq? (reduce adder list) (add 1 2 3)))))
('cond evaluates the first branch that returns true'
("cond evaluates the first branch that returns true"
(quote
(let ((switch-one false)
(switch-two false)
@ -68,7 +68,7 @@
(true (toggle switch-three)))))
(and (not switch-one) switch-two (not switch-three)))))
('cond doesnt do anything if all the branches are false'
("cond doesnt do anything if all the branches are false"
(quote
(let ((switch-one false)
(switch-two false)
@ -79,27 +79,32 @@
(false (toggle switch-three)))))
(and (not switch-one) (not switch-two) (not switch-three)))))
('cond returns the result of the branch that is evaluated'
("cond returns the result of the branch that is evaluated"
(quote
(let ((variable false))
(let ((variable "2"))
(set (q variable)
(cond (q
((true true)))))
variable)))
((true "1")))))
(eq? variable "1"))))
('contains? finds elem in list'
("cond does not choke on nil evaluated result"
(quote
(cdr ((cond (q ((true (assert true)))))
true))))
("contains? finds elem in list"
(quote
(contains? (1 2 3) 1)))
('contains? finds last elem in list'
("contains? finds last elem in list"
(quote
(contains? (1 2 3) 3)))
('contains? doesnt find elem not in list'
("contains? doesnt find elem not in list"
(quote
(not (contains? (1 2 3) 4))))
('get-paths properly splits path into segments'
("get-paths properly splits path into segments"
(quote
(let ((PATH "/seg1:/seg2")
(split-path (get-paths)))
@ -107,20 +112,20 @@
(contains? split-path "/seg1")
(contains? split-path "/seg2")))))
('add-path properly adds a new path segment to PATH'
("add-path properly adds a new path segment to PATH"
(quote
(let ((PATH "/seg1:/seg2")
(new-path "/seg3"))
(add-path new-path)
(contains? (get-paths) new-path))))
('join operates as expected'
("join operates as expected"
(quote
(let ((l ("1" 2 (3))))
(eq? (join l ".")
"1.2.(3)"))))
('extend extends sets'
("extend extends sets"
(quote
(let ((s1 (1 2 3))
(s2 (4 5 6)))

View file

@ -36,13 +36,13 @@
;; this would be way faster as code in stl
;; but stl already suffers scope creep
(def prepend
'takes a list and appends an element to the back of it.
returns prepended list'
"takes a list and appends an element to the back of it.
returns prepended list"
(elem list)
(reverse (cons (reverse list) elem)))
(def set
'sets an existing variable without touching its docstring.
"sets an existing variable without touching its docstring.
WARNING:
If you find yourself struggling to debug a complex error in state access,
@ -56,89 +56,90 @@
A cozy script in flesh is one where each root level form (or eval at repl)
is self contained, and does not permanently modify any other one.
See the userlib tests for an easy to follow example of this.'
See the userlib tests for an easy to follow example of this."
(var val)
(let ((doc (get-doc var)))
(def (eval var) doc val)))
(def map
'Takes two arguments: a function and a list.
"Takes two arguments: a function and a list.
for each element in the list, the function is applied and the
result is added to a new list. Returns the new list.'
result is added to a new list. Returns the new list."
(func list)
(let ((list-iter (pop list))
(result ()))
(while (gt? (len list-iter) 1)
(let ((current (car list-iter))
(remaining (cdr list-iter))
(let ((current (car list-iter))
(remaining (cdr list-iter))
(current-res (func current)))
(set (q result) (cons result current-res))
(set (q result) (cons result current-res))
(set (q list-iter) (pop remaining))))
result))
(def reduce
'Takes two arguments: a function and a list.
"Takes two arguments: a function and a list.
The function is expected to take two arguments:
* the current list item
* the previous result
Initially the function will take element1 and element2, outputting result1.
Then the function will take result1 and element3, outputting result2.
this will continue iuntil the list is exhausted.'
this will continue iuntil the list is exhausted."
(func list)
(let ((list-iter (pop list))
(result (car list-iter)))
(result (car list-iter)))
(set (q list-iter) (pop (cdr list-iter)))
(if (lt? (len list) 2)
(echo "list too short!")
(while (gt? (len list-iter) 1)
(let ((current (car list-iter))
(let ((current (car list-iter))
(remaining (cdr list-iter)))
(set (q result) (func result current))
(set (q result) (func result current))
(set (q list-iter) (pop remaining)))))
result))
(def cond
'Takes one argument: a list of pairs consisting of a form returning a bool and a form to execute
The function iterates over the list checking if the first form of a pair evaluates to true, in which
case it will execute the second form of the pair, returning its result, and stop the loop.'
"Takes one argument: a list of pairs consisting of a form containing a bool and a form to execute
The function iterates over the list checking if the first element of each form evaluates to true, if so it will execute the second form of the pair, returning its result, and stop the loop."
(list)
(let ((iter list))
(while (gt? (len iter) 0)
(let ((current (car iter))
(remaining (pop iter)))
(if (eval (car current))
(car (pop ((set (q iter) ())
(eval (cdr current)))))
(set (q iter) (cdr remaining)))))))
(let ((iter list))
(while (gt? (len iter) 0)
(let ((current (car iter))
(remaining (pop iter)))
(if (eval (car current))
(let ((res (eval (cdr current))))
(set (q iter) ())
res)
(set (q iter) (cdr remaining)))))))
(def contains?
'Takes two arguments: a list and an element.
Returns true if the list contains the element.'
"Takes two arguments: a list and an element.
Returns true if the list contains the element."
(list elem)
(let ((found false)
(let ((found false)
(list-iter (pop list)))
(while (and (gt? (len list-iter) 1)
(not found))
(let ((current (car list-iter))
(let ((current (car list-iter))
(remaining (cdr list-iter)))
(if (eq? current elem)
(set (q found) true)
(set (q found) true)
(set (q list-iter) (pop remaining)))))
found))
(def get-paths
'returns each individual directory in PATH'
() (split PATH ':'))
"returns each individual directory in PATH"
() (split PATH ":"))
(def add-path
'Takes one argument.
adds a directory to PATH'
"Takes one argument.
adds a directory to PATH"
(path) (set (q PATH)
(concat PATH ':' path)))
(concat PATH ":" path)))
(def display-paths
'prints out each element of $PATH one by one'
"prints out each element of $PATH one by one"
()
(let ((path-iter (pop (get-paths))))
(while (gt? (len path-iter) 1)
@ -148,17 +149,17 @@ adds a directory to PATH'
(set (q path-iter) (pop rem))))))
(def join
'concatenates list elements into a string, while
interspersing a provided delimiter in between elements'
"concatenates list elements into a string, while
interspersing a provided delimiter in between elements"
(list delim)
(reduce (lambda (res elem)
(if (eq? (strlen res) 0)
(string elem)
(string elem)
(concat res delim elem)))
list))
(def extend
'adds all elements in set2 to set1'
"adds all elements in set2 to set1"
(set1 set2)
(reduce (lambda (res elem) (cons res elem))
(prepend set1 set2)))