added
authorRalph Ronnquist <ralph.ronnquist@gmail.com>
Tue, 16 May 2023 13:16:39 +0000 (23:16 +1000)
committerRalph Ronnquist <ralph.ronnquist@gmail.com>
Tue, 16 May 2023 13:16:39 +0000 (23:16 +1000)
Makefile [new file with mode: 0644]
foop.lsp [new file with mode: 0644]
misc.lsp [new file with mode: 0644]
newlisp-libmisc.a.8.adoc [new file with mode: 0644]

diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..bc3fa26
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,20 @@
+# Create the newlisp library foop.lsplib
+
+ARCHIVE = newlisp-libmisc.a
+ARFILES = foop.lsp misc.lsp 
+
+BUILD = ${ARCHIVE} ${ARCHIVE}.8 
+
+default: ${BUILD}
+
+${ARCHIVE}: ${ARFILES}
+
+%.a:
+       ar r $@ $^
+
+%.8: %.8.adoc
+       asciidoctor -b manpage $<
+
+clean:
+       rm -f ${BUILD}
+
diff --git a/foop.lsp b/foop.lsp
new file mode 100644 (file)
index 0000000..1724d3c
--- /dev/null
+++ b/foop.lsp
@@ -0,0 +1,61 @@
+;; This newlisp module provides FOOP modelling support
+;;
+;; Functional Object-Oriented Programming (FOOP) is an abstraction
+;; overlay using the newlisp context notion as similar to the class
+;; notion in genuine object-oriented programming languages. This is
+;; set out in newlisp by means of the representation principle that an
+;; instance of a FOOP "class" (i.e. context) is a list headed by the
+;; context itself, and followed by the "member values".
+;;
+;; FOOP further includes by the "method invocation" syntax where a
+;; function is preceded by ':' and then followed by the instance
+;; concerned before actual function arguments. That instance is then
+;; stoved away as implicitly available via the (self) function, and
+;; the member values accessible via index, e.g. the term (self 3)
+;; refers to the third member of the instance. The self references are
+;; destructively assignable with setf.
+;;
+;; This modelling support adds member name declaration together with
+;; automatic getter and setter defintions. The (FOOP ...) term is used
+;; for declaring member names in order. For example:
+;;
+;; (context 'MAIN:EX")
+;; (FOOP a b c)
+;; (define (EX:EX n) (list (context) (+ n 4) 3 2))
+;;
+;; That would declare a FOOP context EX with instances having three
+;; members named a, b and c. The declaratin results in a variable EX:.
+;; whose value is (FOOP a b c), as well as three access functions for
+;; each member: the member position index (.member), a getter
+;; (%member) and a setter (!member V).
+;;
+;; As indicated in the example, (FOOP a b c) does not define the
+;; "constructor". It only defines the access functions. 
+
+(context 'FOOP)
+
+;; Helper function to make a new symbol for the context of S by
+;; preceeding it with string P.
+(define (name P S) (sym (string P (term S)) (prefix S)))
+
+;; (FOOP name ...)
+; foop is a language extension to declare the field names of a FOOP
+; object type, and thereby gain getter and setter functions with the
+; naming formats (:%name obj) and (:!name obj value) respectively .
+(define-macro (FOOP:FOOP)
+  (let ((K (sym "." (prefix (first (args)))))
+        (V (cons (context) (args)))
+        (I 0))
+    (set K V)
+    (dolist (S (args))
+      (letex ((GET (name "%" S))
+              (SET (name "!" S))
+              (IT (name "." S))
+              (V (sym "V" (prefix S)))
+              (I (inc I)))
+        (define (IT) I)
+        (define (GET) (self I))
+        (define (SET V) (setf (self I) V))))
+    ))
+
+"foop.lsp"
diff --git a/misc.lsp b/misc.lsp
new file mode 100644 (file)
index 0000000..8a6309a
--- /dev/null
+++ b/misc.lsp
@@ -0,0 +1,50 @@
+;; This module provides some utility functions.
+
+(define (prog1 X) X)
+(global 'prog1)
+
+(define (die N)
+  (when (args) (write-line 2 (join (map string (args)) " ")))
+  (and (number? N) (exit N)))
+(global 'die)
+
+;; Prepend with C onto S so as to fill width W, if it's a number.
+(define (pre-fill C S W)
+  (while (and (number? W) (< (length S) W))
+    (setf S (string C S)))
+  S)
+(global 'pre-fill)
+
+;; Make a hex string from a data block pad with "0" to W if non-nil
+(define (char2hex STR W)
+  (pre-fill "0" (join (map (curry format "%2x") (map char (explode STR)))) W))
+(global 'char2hex)
+
+;; Print binary byte as octal or as ASCII character [32-126]
+(define (octal-byte x)
+  (if (and (> x 31) (< x 127)) (char x) (format "\\%o" x)))
+(global 'octal-byte)
+
+;; Print string as binary octals
+(define (octals-string S)
+  (join (map octal-byte (unpack (dup "b" (length S)) S))))
+(global 'octals-string)
+
+;; Return byte code as printable or as decimal number.
+(define (human-byte B)
+  (if (and (> B 32) (< B 127)) (char B) B))
+(global 'human-byte)
+
+;; Return a packed encoding of a list of bytes, joining its string elements
+(define (human-bytes BL)
+  (let ((OUT '()) (X nil))
+    (dolist (B (map human-byte BL))
+      (if (string? B) (if X (extend X B) (setf X B))
+        (begin (when (string? X) (push X OUT -1))
+             (push B OUT -1)
+             (setf X nil))))
+    (when (string? X) (push X OUT -1))
+    OUT))
+(global 'human-bytes)
+
+"misc.lsp"
diff --git a/newlisp-libmisc.a.8.adoc b/newlisp-libmisc.a.8.adoc
new file mode 100644 (file)
index 0000000..d5ce49c
--- /dev/null
@@ -0,0 +1,139 @@
+= newlisp-libmisc.a(8)
+:doctype: manpage
+:revdate: {sys:date "+%Y-%m-%d %H:%M:%S"}
+
+== NAME
+
+newlisp-libmisc.a - Newlisp archive comprosing useful functions.
+
+== SYNOPSIS
+
+.With packnl (example)
+packnl _main.lsp_ *-A newlisp-libmisc.a*
+
+
+.With incore.lsp
+(load "incore.lsp") +
+(archive "newlisp-libmisc.a") +
+(load "misc.lsp")
+
+== DESCRIPTION
+
+*newlisp-libmisc.a* is a newlisp archive file that provides loadable
+modules with utility functions.
+
+=== misc.lsp API
+
+(prog1 [_term_]*)::
+
+The *prog1* function is like a *begin* function except that it returns
+the value of the first term rather than the last.
+
+(die _N_ [_term_]*)::
+
+The *die* function printes to stderr the join of term values as
+strings with space separation, and if _N_ is a number, then the
+function exits the program with that return code.
++
+.Example of stderr logging
+(die nil 'This "is" 'printed "to stderr")
+
+(octal-byte _B_)::
+Print binary byte as octal or as ASCII character [32-126].
+
+(octals-string _S_)::
+Print string as a succesion of +octal-byte+.
+
+(human-byte _B_)::
+Return byte code as printable (string) or as code (number).
+
+(human-bytes _BL_)::
+
+Return a list of human-byte elements from a list of byte codes but
+also joining consecutive string elements to form packed strings.
+
+=== foop.lsp API
+
+This newlisp module provides Functional Object-Oriented Programming
+(FOOP) modelling support.
+
+FOOP is an abstraction overlay using the newlisp context notion as a
+simile to the _class_ notion in genuine object-oriented programming
+languages. This is set out in newlisp by means of the representation
+principle that an instance of a FOOP "class" (i.e. context) is a list
+headed by the context itself, and followed by the "member values".
+
+FOOP further includes by the "method invocation" syntax where a
+function is preceded by ':' and then followed by the instance
+concerned before actual function arguments. That instance is then
+stoved away as implicitly available via the (self) function, and the
+member values accessible via index, e.g. the term (self 3) refers to
+the third member of the instance. The self references are
+destructively assignable with setf.
+
+This modelling support adds member name declaration together with
+automatic getter and setter defintions. The (FOOP ...) term is used
+for declaring member names in order. For example:
+
+(FOOP [_name_])::
+
+*FOOP* is like a language extension to declare the field names of a
+FOOP class, and thereby gain "get" and "set" functions generated with
+the respective naming formats (:%name obj) and (:!name obj value).
+
+.illustration 
+----
+(context 'MAIN:EX)
+(FOOP here there more)
+(define (EX HERE THERE MORE) (list (context) HERE THERE MORE))
+
+(context MAIN)
+(setf A (EX 1 2 3))
+--> A = (EX 1 2 3)
+(:!there A 4)
+--> A = (EX 1 4 3)
+----
+
+=== mmap.lsp API
+
+This newlisp module implements a small FOOP model based memory mapping
+API that links in the _libc6_ functions _mmap_, _munmap_, _msync_ and
+_lseek_.
+
+(*MMap* _FD_ _LENGTH_ [_OFFSET_ [_PROT_]])::
+
+This function creates a FOOP object that represents the memory mapping
+of the given file descriptor. _FD_ may be the pathname string of a
+file to memory map or an already opened file descriptor. The MMap
+object represents the memory block starting at (:%base) and (%len)
+bytes in length where the file is memory mapped.
++
+.Access example (from test.lsp)
+[caption=""]
+----
+(println (setf X (MMap "mmap.lsp")))
+(println (get-string (:%base X)))
+----
++
+Note that only a plain text file would be accessed with _get-string_.
+A binary file would rather be accessed with _unpack_. The memory
+mapping provides read-only "random access" to the file content.
++
+To set up read-write acces requires an _OFFSET_ and the _PROT_
+argument 0x3, and writing should be accompanied by _MMap:msync_ calls
+so as to synchronize with the backing file.
++
+The FOOP object includes get and set methods for the fields (in
+order): _base_, _len_, _prot_, _flags_, _fd_ and _offset_.
+
+=== test.lsp
+
+This file is a small test of the MMap memory mapping.
+
+== SEE ALSO
+
+*newlisp*
+
+== AUTHOR
+
+Ralph Ronnquist <ralph.ronnquist@gmail.com>