new way to add to hidden lib; getopt clone

This commit is contained in:
ESL 2024-07-18 20:18:35 -04:00
parent 0edd2255e3
commit 020c0613b5
4 changed files with 197 additions and 49 deletions

33
s.c
View file

@ -1156,5 +1156,38 @@ char *s_code[] = {
"lues)[02},.3,&1{%1${k0,.0,${.6,&1{%0:0,R9]1},:0[01}_1_3}[10},@(y22:wit"
"h-exception-handler)[02}_1_3}[00},.1P60.0]3",
"P", "get-next-command-line-option",
"%3,,,#0#1#2@(y5:error).!0&0{%2,#0'2,.2S3=?{@(y4:cadr)}{@(y5:caddr)}.!0"
"${.4,.4,.4,&2{%1:1,${.3,:0^[01}S=]1},@(y4:memp)[02},.0?{.0aa,.1adddac]"
"4}f]4}.!1&0{%2.1?{.0S3,.2,,'(i-1)<;<?{.1,.1S4]2}f]2}f]2}.!2.3u?{.3,f,f"
",.8[63}'(s2:--),.4aS=?{.3d,f,f,.8[63}'(s1:-),.4aS=?{.3,f,f,.8[63}'(c-)"
",${'0,.7a,.7^[02}v~?{.3,f,f,.8[63}'(c-),${'0,.7a,.7^[02}v?{'(c-),${'1,"
".7a,.7^[02}v}{f}?{.3a,.0,'(c=)S8,,,#0#1.2?{${.4,'0,.7,@(y11:string-cop"
"y)[03}}{.3}.!0${.(i10),.3^,.9^[02}.!1.1^?{.1^a?{.2}{f}}{f}?{.7d,${.5,'"
"1+,.7,@(y11:string-copy)[02},.3^d,.(i12)[(i10)3}.1^?{.1^a?{.7dp}{f}}{f"
"}?{.7dd,.8da,.3^d,.(i12)[(i10)3}.1^?{.1^a}{f}?{.0^,'(s23:missing optio"
"n argument),.6^[(i10)2}.1^?{.1^a~?{.2~}{f}}{f}?{.7d,f,.3^d,.(i12)[(i10"
")3}.1^?{.1^a~?{.2}{f}}{f}?{.3,'(s26:unexpected option argument),.6^[(i"
"10)2}.0^,'(s14:unknown option),.6^[(i10)2}.3a,.0S3,,,#0#1${'2,'0,.7,@("
"y11:string-copy)[03}.!0${.(i10),.3^,.9^[02}.!1.1^?{.1^a?{'2,.3>}{f}}{f"
"}?{.7d,${'2,.7,@(y11:string-copy)[02},.3^d,.(i12)[(i10)3}.1^?{.1^a?{'2"
",.3=?{.7dp}{f}}{f}}{f}?{.7dd,.8da,.3^d,.(i12)[(i10)3}.1^?{.1^a}{f}?{.0"
"^,'(s23:missing option argument),.6^[(i10)2}.1^?{.1^a~?{'2,.3>}{f}}{f}"
"?{.7d,${'2,.7,@(y11:string-copy)[02},'(s1:-)S6c,f,.3^d,.(i12)[(i10)3}."
"1^?{.1^a~}{f}?{.7d,f,.3^d,.(i12)[(i10)3}.0^,'(s14:unknown option),.6^["
"(i10)2",
"P", "print-command-line-options",
"%!1,,,,#0#1#2#3.4p?{.0^a}{P12}.!0&0{%1.0ddda,.1dda,.2da,,,,#0#1#2.3?{."
"3S3}{'0}.!0.4?{.4S3}{'0}.!1.5?{.5S3}{'0}.!2'0,.2^,.2^+=?{${.8,'(s22:in"
"valid options record),@(y5:error)[02}}'0,.3^=?{'0}{'1,.3^+},'0,.2^>?{'"
"0,.3^>}{f}?{'2,.3^,.3^++}{.2^,.2^+}+]7}.!1${.7,.4^,@(y5:%25map1)[02}.!"
"2${.4^,'0c,@(y3:max),@(y13:apply-to-list)[02}.!3${.4^,.8,,#0.0,.6,.(i1"
"0),&3{%2.0u~?{.1a,.1a,:1^,'(s2: )W4.0dddda,.1ddda,.2dda,.3da,.0?{.1}{"
"f}?{:1^,.1W4:1^,'(s2:, )W4:1^,.2W4.2?{:1^,'(s1:=)W4:1^,.3W4}}{.0?{:1^,"
".1W4.2?{:1^,'(s1: )W4:1^,.3W4}}{.1?{:1^,.2W4.2?{:1^,'(s1:=)W4:1^,.3W4}"
"}{f}}}:1^,'(c ),.7,:0^-S2W4:1^,'(s4: )W4:1^,.4W4:1^W6.7d,.7d,:2^[82"
"}]2}.!0.0^_1[02}'4,.4^,'2++]6",
0, 0, 0
};

View file

@ -2120,4 +2120,81 @@
(close-input-port p)
obj))
; simple AT&T-like command-line options parser
; calls (return keysym optarg restargs) where opt is #f on end-of-options
; optmap is a list of the following opt info records:
; ([keysym "-f" "--foo" needsarg? "foo help"] ...)
(define (get-next-command-line-option args optmap return)
(define opterr error)
(define (opt-lookup opt optmap) ;=> #f | (needsarg? keysym)
(define iref (if (= (string-length opt) 2) cadr caddr))
(let ([r (memp (lambda (i) (string=? (iref i) opt)) optmap)])
(and r (cons (cadddr (car r)) (caar r)))))
(define (ssref s i) ; safe-string-ref
(and i (< -1 i (string-length s)) (string-ref s i)))
(cond [(null? args) (return #f #f args)]
[(string=? (car args) "--") (return #f #f (cdr args))]
[(string=? (car args) "-") (return #f #f args)]
[(not (eqv? (ssref (car args) 0) #\-)) (return #f #f args)]
[(and (eqv? (ssref (car args) 0) #\-) (eqv? (ssref (car args) 1) #\-))
(let* ([s (car args)] [p (string-position #\= s)])
(define opt (if p (string-copy s 0 p) s)) ; "--longopt"
(define ank (opt-lookup opt optmap)) ; #f or (needarg? . keysym)
(cond [(and ank (car ank) p) ; needs arg, and it is in s
(return (cdr ank) (string-copy s (+ 1 p)) (cdr args))]
[(and ank (car ank) (pair? (cdr args)))
(return (cdr ank) (cadr args) (cddr args))]
[(and ank (car ank))
(opterr "missing option argument" opt)]
[(and ank (not (car ank)) (not p))
(return (cdr ank) #f (cdr args))]
[(and ank (not (car ank)) p)
(opterr "unexpected option argument" s)]
[else (opterr "unknown option" opt)]))]
[else ; char option (with arg or joined with next one)
(let* ([s (car args)] [l (string-length s)])
(define opt (string-copy s 0 2)) ; "-o"
(define ank (opt-lookup opt optmap)) ; #f or (needarg? . keysym)
(cond [(and ank (car ank) (> l 2)) ; needs arg, and it is in s
(return (cdr ank) (string-copy s 2) (cdr args))]
[(and ank (car ank) (= l 2) (pair? (cdr args)))
(return (cdr ank) (cadr args) (cddr args))]
[(and ank (car ank))
(opterr "missing option argument" opt)]
[(and ank (not (car ank)) (> l 2))
(return (cdr ank) #f ; form option string without opt
(cons (string-append "-" (string-copy s 2)) (cdr args)))]
[(and ank (not (car ank)))
(return (cdr ank) #f (cdr args))]
[else (opterr "unknown option" opt)]))]))
; printer for optmap options used for --help; returns offset of help lines
(define (print-command-line-options optmap . ?port)
(define port (if (pair? ?port) (car port) (standard-error-port)))
(define (optlen i)
(let ([co (cadr i)] [lo (caddr i)] [oa (cadddr i)])
(define colen (if co (string-length co) 0))
(define lolen (if lo (string-length lo) 0))
(define oalen (if oa (string-length oa) 0))
(when (= (+ colen lolen) 0) (error "invalid options record" i))
(+ (if (and (> colen 0) (> lolen 0)) (+ colen lolen 2) (+ colen lolen))
(if (= oalen 0) 0 (+ oalen 1)))))
(define optlens (map optlen optmap))
(define max-optlen (apply max (cons 0 optlens)))
(let loop ([optmap optmap] [optlens optlens])
(unless (null? optmap)
(let ([i (car optmap)] [optlen (car optlens)])
(display " " port)
(let ([co (cadr i)] [lo (caddr i)] [oa (cadddr i)] [hl (car (cddddr i))])
(cond [(and co lo)
(display co port) (display ", " port) (display lo port)
(when oa (display "=" port) (display oa port))]
[co (display co port) (when oa (display " " port) (display oa port))]
[lo (display lo port) (when oa (display "=" port) (display oa port))])
(display (make-string (- max-optlen optlen) #\space) port)
(display " " port) (display hl port) (newline port)
(loop (cdr optmap) (cdr optlens))))))
(+ 2 max-optlen 4))

View file

@ -1889,11 +1889,10 @@
(define (get-loc name)
(name-lookup *root-name-registry* name (lambda (name) (list 'const name))))
(let loop ([name (car r)] [keys (cdr r)])
(cond [(null? keys) ; all go to (skint)
(put-loc! (get-library! '(skint)) name (get-loc name))]
[else
(put-loc! (get-library! (key->listname (car keys))) name (get-loc name))
(loop name (cdr keys))])))
(cond [(null? keys) (put-loc! (get-library! '(skint)) name (get-loc name))]
[(not (pair? keys)) (put-loc! (get-library! `(skint ,keys)) name (get-loc name))]
[else (put-loc! (get-library! (key->listname (car keys))) name (get-loc name))
(loop name (cdr keys))])))
'((* v b) (+ v b) (- v b) (... v u b) (/ v b) (< v b) (<= v b) (= v b) (=> v u b) (> v b) (>= v b)
(_ b) (abs v b) (and v u b) (append v b) (apply v b) (assoc v b) (assq v b) (assv v b) (begin v u b)
(binary-port? b) (boolean=? b) (boolean? v b) (bytevector b) (bytevector-append b)
@ -1974,11 +1973,11 @@
(list*) (char-cmp) (char-ci-cmp) (string-cat) (string-position) (string-cmp) (string-ci-cmp)
(vector-cat) (bytevector=?) (bytevector->list) (list->bytevector) (subbytevector)
(standard-input-port) (standard-output-port) (standard-error-port) (tty-port?)
(port-fold-case?) (set-port-fold-case!) (rename-file) (void) (void?) (global-store)
(run-script)
; temporarily here for debugging purposes
;(xform) (compile-and-run-core-expr) (compile-to-thunk-code) (deserialize-code)
;(closure) (repl-environment)
(port-fold-case?) (set-port-fold-case!) (rename-file) (void) (void?) (global-store . hidden)
(run-script . hidden) (get-next-command-line-option . hidden) (print-command-line-options . hidden)
(xform . hidden) (compile-and-run-core-expr . hidden) (compile-to-thunk-code . hidden)
(deserialize-code . hidden) (closure . hidden) (repl-environment . hidden)
(*skint-options* . hidden)
))
; clean up root environment by moving all symbolic bindings not in (skint) library
@ -1995,8 +1994,12 @@
(loop prev (cdr lst))]))))
; make hidden bindings available via (skint hidden) library
(name-install! *root-name-registry* '(skint hidden)
(make-location (make-library '(begin) (vector-ref *hidden-name-registry* 0))))
(let* ([mklib (lambda (ln) (make-library '(begin) '()))]
[loc (name-lookup *root-name-registry* '(skint hidden) mklib)]
[lib (location-val loc)] [eal (vector-ref *hidden-name-registry* 0)]
[combeal (adjoin-eals eal (library-exports lib))])
;(vector-set! *hidden-name-registry* 0 combeal)
(library-set-exports! lib combeal))
; private registry for names introduced in repl
(define *user-name-registry* (make-name-registry 200))
@ -2438,14 +2441,6 @@
(define *repl-first-time* #t)
(define (repl-main)
; todo: here we can process command line by ourselves!
(when (and (tty-port? (current-input-port)) (tty-port? (current-output-port)))
; quick check for non-interactive use failed, greet
(display "SKINT Scheme Interpreter v0.0.9\n")
(display "Copyright (c) 2024 False Schemers\n"))
#t) ; exited normally
(define (repl)
(define ip (current-input-port))
(define op (current-output-port))
@ -2453,8 +2448,33 @@
(set-current-file-stack! '())
(when *repl-first-time*
(set! *repl-first-time* #f)
(repl-main))
(skint-main))
; capture cc to handle unhandled exceptions
(letcc k (set-reset-handler! k)
(repl-from-port ip repl-environment prompt op))
#t) ; exited normally via end-of-input
;--------------------------------------------------------------------------------------------------
; Main
;--------------------------------------------------------------------------------------------------
(define *skint-options*
'([verbose "-v" "--verbose" #f "Increase output verbosity"]
[quiet "-q" "--quiet" #f "Suppress nonessential messages"]
[append-libdir "-A" "--append-libdir" "<DIR>" "Append a library search directory"]
[prepend-libdir "-I" "--prepend-libdir" "<DIR>" "Prepend a library search directory"]
[eval "-e" "--eval" "<SEXP>" "Evaluate and print an expression"]
[script "-s" "--script" "<FILE>" "Run file as a Scheme script"]
[program "-p" "--program" "<FILE>" "Run file as a Scheme program"]
[version "-V" "--version" #f "Display version info"]
[help "-h" "--help" #f "Display this help"]
))
(define (skint-main)
; todo: here we can process command line by ourselves!
(when (and (tty-port? (current-input-port)) (tty-port? (current-output-port)))
; quick check for non-interactive use failed, greet
(display "SKINT Scheme Interpreter v0.0.9\n")
(display "Copyright (c) 2024 False Schemers\n"))
#t) ; exited normally

74
t.c
View file

@ -1088,7 +1088,7 @@ char *t_code[] = {
"0:*root-name-registry*),@(y11:name-lookup)[03}",
"C", 0,
"${'(l483:l3:y1:*;y1:v;y1:b;;l3:y1:+;y1:v;y1:b;;l3:y1:-;y1:v;y1:b;;l4:y"
"${'(l492:l3:y1:*;y1:v;y1:b;;l3:y1:+;y1:v;y1:b;;l3:y1:-;y1:v;y1:b;;l4:y"
"3:...;y1:v;y1:u;y1:b;;l3:y1:/;y1:v;y1:b;;l3:y1:<;y1:v;y1:b;;l3:y2:<=;y"
"1:v;y1:b;;l3:y1:=;y1:v;y1:b;;l4:y2:=>;y1:v;y1:u;y1:b;;l3:y1:>;y1:v;y1:"
"b;;l3:y2:>=;y1:v;y1:b;;l2:y1:_;y1:b;;l3:y3:abs;y1:v;y1:b;;l4:y3:and;y1"
@ -1251,25 +1251,30 @@ char *t_code[] = {
";l1:y13:subbytevector;;l1:y19:standard-input-port;;l1:y20:standard-out"
"put-port;;l1:y19:standard-error-port;;l1:y9:tty-port?;;l1:y15:port-fol"
"d-case?;;l1:y19:set-port-fold-case!;;l1:y11:rename-file;;l1:y4:void;;l"
"1:y5:void?;;l1:y12:global-store;;l1:y10:run-script;;),&0{%1,,,,#0#1#2#"
"3&0{%1.0,'(y1:w),.1v?{'(l2:y6:scheme;y5:write;)]2}'(y1:t),.1v?{'(l2:y6"
":scheme;y4:time;)]2}'(y1:p),.1v?{'(l2:y6:scheme;y4:repl;)]2}'(y1:r),.1"
"v?{'(l2:y6:scheme;y4:read;)]2}'(y1:v),.1v?{'(l2:y6:scheme;y4:r5rs;)]2}"
"'(y1:u),.1v?{'(l2:y6:scheme;y9:r5rs-null;)]2}'(y1:d),.1v?{'(l2:y6:sche"
"me;y4:load;)]2}'(y1:z),.1v?{'(l2:y6:scheme;y4:lazy;)]2}'(y1:s),.1v?{'("
"l2:y6:scheme;y15:process-context;)]2}'(y1:i),.1v?{'(l2:y6:scheme;y7:in"
"exact;)]2}'(y1:f),.1v?{'(l2:y6:scheme;y4:file;)]2}'(y1:e),.1v?{'(l2:y6"
":scheme;y4:eval;)]2}'(y1:o),.1v?{'(l2:y6:scheme;y7:complex;)]2}'(y1:h)"
",.1v?{'(l2:y6:scheme;y4:char;)]2}'(y1:l),.1v?{'(l2:y6:scheme;y11:case-"
"lambda;)]2}'(y1:a),.1v?{'(l2:y6:scheme;y3:cxr;)]2}'(y1:b),.1v?{'(l2:y6"
":scheme;y4:base;)]2}'(y1:x),.1v?{'(l2:y6:scheme;y3:box;)]2}.1I0?{.1,'("
"y4:srfi),l2]2}.1,l1]2}.!0&0{%1${&0{%1n,'(l1:y5:begin;),V12]1},.3,@(y20"
":*root-name-registry*),@(y11:name-lookup)[03}z]1}.!1&0{%3'1,.1V4,.0,.3"
"A3,.0?{.4,.1sd]5}.1,.5,.5cc,'1,.4V5]5}.!2&0{%1&0{%1.0,'(y5:const),l2]1"
"},.1,@(y20:*root-name-registry*),@(y11:name-lookup)[13}.!3.4d,.5a,,#0."
"0,.6,.5,.7,.(i10),&5{%2.1u?{${.2,:0^[01},.1,${'(l1:y5:skint;),:1^[01},"
":3^[23}${${.4,:0^[01},.3,${${.9a,:2^[01},:1^[01},:3^[03}.1d,.1,:4^[22}"
".!0.0^_1[52},@(y10:%25for-each1)[02}",
"1:y5:void?;;py12:global-store;y6:hidden;;py10:run-script;y6:hidden;;py"
"28:get-next-command-line-option;y6:hidden;;py26:print-command-line-opt"
"ions;y6:hidden;;py5:xform;y6:hidden;;py25:compile-and-run-core-expr;y6"
":hidden;;py21:compile-to-thunk-code;y6:hidden;;py16:deserialize-code;y"
"6:hidden;;py7:closure;y6:hidden;;py16:repl-environment;y6:hidden;;py15"
":*skint-options*;y6:hidden;;),&0{%1,,,,#0#1#2#3&0{%1.0,'(y1:w),.1v?{'("
"l2:y6:scheme;y5:write;)]2}'(y1:t),.1v?{'(l2:y6:scheme;y4:time;)]2}'(y1"
":p),.1v?{'(l2:y6:scheme;y4:repl;)]2}'(y1:r),.1v?{'(l2:y6:scheme;y4:rea"
"d;)]2}'(y1:v),.1v?{'(l2:y6:scheme;y4:r5rs;)]2}'(y1:u),.1v?{'(l2:y6:sch"
"eme;y9:r5rs-null;)]2}'(y1:d),.1v?{'(l2:y6:scheme;y4:load;)]2}'(y1:z),."
"1v?{'(l2:y6:scheme;y4:lazy;)]2}'(y1:s),.1v?{'(l2:y6:scheme;y15:process"
"-context;)]2}'(y1:i),.1v?{'(l2:y6:scheme;y7:inexact;)]2}'(y1:f),.1v?{'"
"(l2:y6:scheme;y4:file;)]2}'(y1:e),.1v?{'(l2:y6:scheme;y4:eval;)]2}'(y1"
":o),.1v?{'(l2:y6:scheme;y7:complex;)]2}'(y1:h),.1v?{'(l2:y6:scheme;y4:"
"char;)]2}'(y1:l),.1v?{'(l2:y6:scheme;y11:case-lambda;)]2}'(y1:a),.1v?{"
"'(l2:y6:scheme;y3:cxr;)]2}'(y1:b),.1v?{'(l2:y6:scheme;y4:base;)]2}'(y1"
":x),.1v?{'(l2:y6:scheme;y3:box;)]2}.1I0?{.1,'(y4:srfi),l2]2}.1,l1]2}.!"
"0&0{%1${&0{%1n,'(l1:y5:begin;),V12]1},.3,@(y20:*root-name-registry*),@"
"(y11:name-lookup)[03}z]1}.!1&0{%3'1,.1V4,.0,.3A3,.0?{.4,.1sd]5}.1,.5,."
"5cc,'1,.4V5]5}.!2&0{%1&0{%1.0,'(y5:const),l2]1},.1,@(y20:*root-name-re"
"gistry*),@(y11:name-lookup)[13}.!3.4d,.5a,,#0.0,.6,.5,.7,.(i10),&5{%2."
"1u?{${.2,:0^[01},.1,${'(l1:y5:skint;),:1^[01},:3^[23}.1p~?{${.2,:0^[01"
"},.1,${n,.6c,'(y5:skint)c,:1^[01},:3^[23}${${.4,:0^[01},.3,${${.9a,:2^"
"[01},:1^[01},:3^[03}.1d,.1,:4^[22}.!0.0^_1[52},@(y10:%25for-each1)[02}",
"C", 0,
"@(y20:*root-name-registry*),${f,'(l1:y5:skint;),.4,@(y11:name-lookup)["
@ -1279,8 +1284,9 @@ char *t_code[] = {
"tall!)[03}.2d,.2,:0^[32}.!0.0^_1[02}'1,.1+,:3^[11}.!0.0^_1[01}_1_1_1_1",
"C", 0,
"${'0,@(y22:*hidden-name-registry*)V4,'(l1:y5:begin;),V12b,'(l2:y5:skin"
"t;y6:hidden;),@(y20:*root-name-registry*),@(y13:name-install!)[03}",
"&0{%1n,'(l1:y5:begin;),V12]1},${.2,'(l2:y5:skint;y6:hidden;),@(y20:*ro"
"ot-name-registry*),@(y11:name-lookup)[03},.0z,'0,@(y22:*hidden-name-re"
"gistry*)V4,${'1,.4V4,.3,@(y11:adjoin-eals)[02},.0,'1,.4V5_1_1_1_1_1",
"C", 0,
"${'(i200),@(y18:make-name-registry)[01}@!(y20:*user-name-registry*)",
@ -1545,15 +1551,27 @@ char *t_code[] = {
"C", 0,
"t@!(y17:*repl-first-time*)",
"P", "repl-main",
"%0PiP09?{PoP09}{f}?{Po,'(s32:SKINT Scheme Interpreter v0.0.9%0a)W4Po,'"
"(s34:Copyright (c) 2024 False Schemers%0a)W4}t]0",
"P", "repl",
"%0,,,#0#1#2Pi.!0Po.!1.0^P09?{'(s6:skint])}{f}.!2${n,@(y23:set-current-"
"file-stack!)[01}@(y17:*repl-first-time*)?{f@!(y17:*repl-first-time*)${"
"@(y9:repl-main)[00}}${k0,${.2,@(y18:set-reset-handler!)[01}${.6^,.8^,@"
"(y16:repl-environment),.8^,@(y14:repl-from-port)[04}_3}t]3",
"@(y10:skint-main)[00}}${k0,${.2,@(y18:set-reset-handler!)[01}${.6^,.8^"
",@(y16:repl-environment),.8^,@(y14:repl-from-port)[04}_3}t]3",
"C", 0,
"'(l9:l5:y7:verbose;s2:-v;s9:--verbose;f;s25:Increase output verbosity;"
";l5:y5:quiet;s2:-q;s7:--quiet;f;s30:Suppress nonessential messages;;l5"
":y13:append-libdir;s2:-A;s15:--append-libdir;s5:<DIR>;s33:Append a lib"
"rary search directory;;l5:y14:prepend-libdir;s2:-I;s16:--prepend-libdi"
"r;s5:<DIR>;s34:Prepend a library search directory;;l5:y4:eval;s2:-e;s6"
":--eval;s6:<SEXP>;s32:Evaluate and print an expression;;l5:y6:script;s"
"2:-s;s8:--script;s6:<FILE>;s27:Run file as a Scheme script;;l5:y7:prog"
"ram;s2:-p;s9:--program;s6:<FILE>;s28:Run file as a Scheme program;;l5:"
"y7:version;s2:-V;s9:--version;f;s20:Display version info;;l5:y4:help;s"
"2:-h;s6:--help;f;s17:Display this help;;)@!(y15:*skint-options*)",
"P", "skint-main",
"%0PiP09?{PoP09}{f}?{Po,'(s32:SKINT Scheme Interpreter v0.0.9%0a)W4Po,'"
"(s34:Copyright (c) 2024 False Schemers%0a)W4}t]0",
0, 0, 0
};