Menu

Show posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.

Show posts Menu

Topics - TedWalther

#1
newLISP in the real world / nonblocking read-key
December 09, 2018, 09:02:57 PM
I'm glad for the new non-blocking option for read-key (read-key true).



Lutz, is it intentional that (read-key true) returns 0 instead of nil when there is no keypress to report?
#2
Lutz, can we have a non-blocking option for a listening socket, so I can accept and also handle socket session without doing a spawn/sync dance?  I think net-select and net-peek already let me do what is needed to multiplex multiple connections in one process, just need a non-blocking net-accept.
#3
I'm using newlisp to make postscript (and thus, PDF) files for cutting things on laser cutters and CNC machines.  I love the ability to be precise and exact in my lines and angles.



For CNC cutting, I want to use plywood pieces bigger than a typical sheet of paper.  Lots of CNC software accepts PDF files where the page size is 4 feet by 8 feet, the same size as a typical sheet of plywood.



How can I specify page size using the postscript module?  If I knew how to edit the raw postscript by hand, I'd submit an updated version of postscript.lsp myself, so if someone knows how to do that in raw postscript, please post here.
#4
newLISP Graphics & Sound / PostScript atan error
July 11, 2017, 11:08:12 PM
Hi.  On macOS Sierra, I am using postscript.lsp (newlisp 10.7.0)



In the function drawto, there is a line  newy ypos sub newx xpos sub atan neg 90 add /orient exch def


So I generate my postscript instructions with ps:render.  Then it comes time to convert the postscript file to a  PDF so I can view it, and sometimes it gives an error, other times it doesn't.  I make minor tweaks to my output code and the error goes away.  But when the error is there, it stays until I change the code, but I never figured out what change I made to avoid the error.



But anyways, I can read postscript a little, but that line doesn't make sense to me.  Why is it in there?  When I hand edit the postscript file to comment out that line, I can create the PDF without problem.



Sample code that shows the error:



(define pi (mul 4 (atan 1)))
(define (rad d) (mul d (div pi 180)))
(define (deg r) (mul r (div 180 pi)))

(module "postscript.lsp")

;; I work in inches as my base unit (72 points per inch), but scale things down
;; by scalefactor so they fit on a regular sheet of paper.

(define scalefactor 4)
(ps:scale (div 72 scalefactor) (div 72 scalefactor))

(define ¼ 0.25)
(define ½ 0.5)
(define origx (mul ½ 8.5 scalefactor))
(define origy (mul ½ 11 scalefactor))
(define my-goto (lambda (x y) (ps:goto (add x origx) (add y origy))))
(define my-drawto (lambda (x y) (ps:drawto (add x origx) (add y origy))))

;; https://math.stackexchange.com/questions/76099/polar-form-of-a-superellipse
;; answered Oct 26 2011 at 17:03 by Ross Millikan
;; polar coordinate form of a superellipse
;; r = ab/(|b cos theta|^n + |a sin theta|^n)^(1/n)
;; a is half the height
;; b is half the width
;; n is the exponent of the superellipse
(define super-ellipse-radius (lambda (a b n theta)
  (div (mul a b)
       (pow (add (pow (abs (mul b (cos theta))) n)
                 (pow (abs (mul a (sin theta))) n))
            (div n)))))

(define draw-super-ellipse (lambda (a b n)
  (letn (anglestep (rad 0.1)
         ab (mul a b)
         startr (super-ellipse-radius a b n 0)
         startx (mul startr (cos 0))
         starty (mul startr (sin 0)))
    (my-goto startx starty)
    (for (theta anglestep (mul 2 pi) anglestep)
      (let (r (super-ellipse-radius a b n theta))
        (my-drawto (mul r (cos theta)) (mul r (sin theta)))))
    (my-drawto startx starty))))

(draw-super-ellipse (mul 7 (sqrt 2)) 7 2.718)

(ps:render "standing-desk2.ps")
(! "pstopdf standing-desk2.ps")

(exit)



And here is the error when trying to open the file (macOS auto-converts it to PDF, and pstopdf also has this error:



%%[ Error: undefinedresult; OffendingCommand: atan; ErrorInfo: CharOffsets %%[ Flushing: rest of job (to end-of-file) will be ignored ]%%
%%[ Warning: PostScript error. No PDF file produced. ] %%
pstopdf failed on file standing-desk2.ps with error code -31000
#5
Has anyone tried to compile newlisp statically for use on Linux or other Unix?  It may work on BSD and Mac OSX, I haven't tried.  However, the problem is always the resolver.  If you use any network functions in the program, you simply cannot get a static binary.



What is a static binary?  A static binary is one where all the libraries are compiled into one file together with your program.  So you can grab the executable file and dump it on any machine and it will run, without worrying about installing the right versions of libraries.



I looked up the problem today to see if it had a fix yet, and found this article:



http://www.macieira.org/blog/2012/01/sorry-state-of-dynamic-libraries-on-linux/">http://www.macieira.org/blog/2012/01/so ... -on-linux/">http://www.macieira.org/blog/2012/01/sorry-state-of-dynamic-libraries-on-linux/



Amazing read.  I didn't realize that Linux (and GNU) have broken things so badly.  If you link your programs to libraries, there are lots of optimizations that are missed, and lots of code is done sub-optimally.  A lot of function calls have to go through 2 levels of indirection.



I wish there was more documentation like this, where people explain what is happening at the assembly language level.  It isn't that complicated, once someone actually shows you the important bits.



Has anyone else figured out how to static link newlisp on Linux?
#6
I developed this function for some population simulations I'm running.  Newlisp has a nice built-in random number generator.  But I wanted a bit more randomness than that provides.  So I wrote this function to access the urandom device on Linux, which gives you lots of pretty good random numbers, fast.



(context '/dev/urandom)
(define max-32bit-int 4294967295)
(define fd (open "/dev/urandom" "read"))
(define /dev/urandom:/dev/urandom
  (lambda ()
    (let (random-value nil buf nil)
      (when fd
        (read fd buf 4)
        (set 'random-value (div (max 1 (first (unpack "lu" buf))) max-32bit-int)))
      random-value)))
(context MAIN)


Examples of usage:

> (/dev/urandom)
0.4954840036797067
> (/dev/urandom)
0.93390936822023


If you want really random numbers, change /dev/urandom to /dev/random everywhere in the function.  If you do that though, sometimes you will get nil as an answer, because the system didn't have enough time to build up enough "real" randomness.  That is why I switched to urandom; it gives a reasonably random number every single time, and fast.  But whenever real randomness is available, urandom uses it too.



Presumably this will work on BSD and Mac OSX, with minor or no modifications.
#7
newLISP in the real world / memory leak? antiprimes
August 02, 2016, 02:52:21 AM
I wrote some code to generate the list of antiprimes.  Had fun with it.  Sped it up by quite a large factor by using memoization.  But it blew up my memory usage beyond what I was expecting.  So I dropped back to an algorithm that I expected to not take up much memory at all, less than a megabyte.  But 2 hours in, it is taking up 20% of my system ram.  I have 8 gigs of ram.



Here is the code.



#!/usr/bin/newlisp

# Anti-primes are highly composite numbers
# Print each number that is more composite than all the numbers before it.

(define start-time (date-value))
(define maxiter 5000000)
(define lastn 1)

(define (prime? n) (= 1 (length (factor n))))

(define (combinations n k (r '()))
  (if (= (length r) k)
    (list r)
    (let (rlst '())
      (dolist (x n)
        (setq rlst (append rlst
                     (combinations ((+ 1 $idx) n) k (append r (list x))))))
      rlst)))

(define (all-factors lst)
  (let (r '())
    (for (j 1 (length lst))
      (extend r (combinations lst j)))))

(define antiprime
  (lambda ()
    (for (i 2 maxiter)
      (let (f (length (unique (sort (all-factors (factor i))))))
        (when (> f lastn)
          (println i ": " f (if (prime? f) " (prime)" ""))
          (setq lastn f))))))

(antiprime)

(println "Runtime: " (- (date-value) start-time) " seconds")

(exit)


So, is the memory leak in my code, or in newLisp?  Am I not understanding the automatic memory management correctly?



Quote

  PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND                        

23903 ted       20   0 1542988 1.456g   2624 R 100.0 18.9 130:51.61 antiprime.lsp                                                                  

Quote
#8
Since I've had problems with (process), I tried to use (exec) instead.  When I read the documentation I was very happy; it does exactly what I need.



(exec "command") => string-list


With (exec), I would run the command, and it would return the output of the command as a list of strings.  Ok, that is almost what I need, but I need to send the command some specific input.  Great!  (exec) allows that, with usage:



(exec "command" "input to command") => ?


The documentation doesn't say that (exec cmd input) has different output than (exec cmd).  But, it doesn't return a list of strings.  Instead it returns a number.  Whether it is a process id or the exit value of the program, I don't know.



Lutz, could exec with user supplied input be updated to return the same string list I've come to expect from the simpler form?



Again, this is with newLisp 10.6.2.
#9
I stored some text in a context.  That text contained a lot of cut and pasted newlisp code.



I did (save "myfile.lsp" MySnippets)



It saved it all.



Then I do (load "myfile.lsp")  Uh-oh.  Error.



ERR: symbol expected : [text] blahblahblah


There is no line number, and it is a big file.  grep doesn't work.  Pop open vi, and see the problem.  There were embedded text tags in the data.



Simple way to reproduce problem:



Make a file with more than 2048 bytes in it.  I just did this:



$ vi foo.txt
type this: i[/text]<ESC>2050Im<ESC>:wq
$ newlisp
(set 'foo (read-file "foo.txt"))
 => works correctly
(save "foo.lsp" 'foo)
=> it doesn't complain...
(load "foo.lsp")
ERR: symbol expected in function set : [/text]


Lutz, would it make sense to have "" be the default representation for strings, and let the string know internally if it is 2048 bytes or not?



Update



What I mean by that, does the programmer really need to know which internal string implementation is being used? String representation is for programmers to use.  Doesn't the interpreter have enough information to switch between a 2048 buffer, and an arbitrary sized string?
#10
I have this:


Quote
(set 'foo '("#foo" "bar" "baz" "some text"))


I expected this to work:


Quote
(foo 0 0) => "#"


Instead it returned "#foo".  A bit surprising.  I know that (foo 0) works as a list index; is newlisp supposed to ignore bogus indexes afterward?  Either newlisp should cross the list/string boundary and let the index apply to the string or array equally with the list, or return an error, no?



Using version 10.6.2
#11
Lately, when I've been using cond, I make use of a trick for cond:


Quote
(cond

  ((= a b) foo)

  (default bar))


This works, because "default" is a builtin function with an address, so it always evaluates to true.  I was actually shocked that there is a builtin function named "default".  Had to look it up to see what it did.



So, I thought, I will try this trick also for a case statement!


Quote
(case a

  (b foo)

  (default bar))


This doesn't work.  But (true bar) instead of (default bar) does work.  Lutz, if "true" is a default value for case statement, can we have "default" work as well?
#12
I'm trying to match a r or n at the end of a string.



Regex with option 0 isn't working.



Tried option 32, which says that $ only matches end of string, not newline.  That also doesn't work.



I try option 256, and it errors out:


Quote
> (set 'a "foorb" 'b "barnn")

> (regex "r|n$" a 256)



ERR: regular expression in function regex : "offset 0 unknown option bit(s) set"
#13
I wanted to make a text mode app with newlisp.  I start to make an ncurses module so I can use ncurses.  Right away I find this function has a variable number of arguments.  What is the right way to import and use these?


Quote
       int printw(const char *fmt, ...);

       int wprintw(WINDOW *win, const char *fmt, ...);

       int mvprintw(int y, int x, const char *fmt, ...);

       int mvwprintw(WINDOW *win, int y, int x, const char *fmt, ...);

       int vwprintw(WINDOW *win, const char *fmt, va_list varglist);

       int vw_printw(WINDOW *win, const char *fmt, va_list varglist);


My first guess failed:


Quote
(import LIB_NCURSES "printw" "int" "void*")

(printw "abc %d %d %d" 1 2 3)

=> ERR: mismatch in number of arguments


How to do variadic functions using libffi?  Is it possible?  If this is a feature to be added, could we have "..." to specify variadic function?



And yes, it did work with the old cdecl style of import.  Then I lose the benefit of type checking. Oh well.
#14
Going through the newLISP source code I notice a very complete (and often used) API that passes around STREAM structures.  These STREAM structures can be a file or a string.



I'm wondering, Lutz, what is the reason for this extensive API?  It doesn't seem to be needed for cross-platform stuff.  It does allow the evaluation and compilation functions to operate on strings in memory as well as files.  But then, couldn't one read the file into memory?



Also, the macro MAX_STRING set to 2048 bytes, looks like perhaps the STREAM api was (or is?) intended for a low memory situation and reading source code in chunks.  Perhaps related to the net-eval code?
#15
Hi, I've been doing FFI.  I have a C function that returns an integer.  But now from time to time, it is returning a nil.  How can this happen?  What is the right way to deal with it?
#16
I looked at the source for newlispEvalStr and just like the documentation says, it disables all printing to console.  I didn't see an option to turn it back on.  Is this a possible future feature?  I'd like my eval'd code to interact with the console just like native newlisp code.  Does newlisp have a different idiom for doing this?
#17
I was expecting that if a symbol is declared global, then all contexts will treat it as local.  Not so:



(global 'foo)
(context 'bar)
(constant 'foo 2)
=> ERR: symbol not in current context in function constant : foo


I know the manual says this:


Quote
 Only symbols from the current context can be used with constant. This prevents the overwriting of symbols that have been protected in their home context.


But if something is global, doesn't that change the rules a bit?
#18
Hi Lutz.  Trying to reconcile the documentation here can you tell which is the right one?  At the moment it appears that the Load documentation is correct.  Also, am having severe bugs with global symbols (even whole contexts) vanishing when one context calls another.



Load:



By default, files which do not contain context switches will be loaded into the MAIN context.



Context:



In the first syntax, context is used to switch to a different context namespace. Subsequent loads of newLISP source or functions like eval-string and sym will put newly created symbols and function definitions in the new context.
#19
I am importing a function from someones library that has this use pattern:



char* foo(int index, int* retval);


This function returns two things; the char* points to a string/label, and the integer retval is the value associated with it.  The int index indexes you into the table.



You are intended to iterate over the table from 0 on up, and stop when it returns the NULL pointer.



I beat my head on this for an hour, I was doing:



(import MY_LIB "foo" "char*" "int" "void*")


My code worked beautifully, but would segfault when it came to the NULL pointer.



I tried various things to detect when (foo) was returning a NULL pointer.  I tried (get-long (address)), I tried (address), I tried (get-long), I tried (get-long (get-long)), etc.



Finally I switched the import statement to void* instead of char*



(import MY_LIB "foo" "void*" "int" "void*")


Now I could detect NULL easily.



So, I'm using void* for now, but it would be nice to go back to using char*, char* works when I do regular (not extended) import of function foo, and the char* integration with native newlisp strings is really nice, not having to do the extra get-string step, especially because I'm dealing with a library that brings in binary data, and the strings are not terminated ones.
#20
Hi.  I did some searching on Google and this forum for "newlisp stack trace" and "newlisp call stack" and "newlisp traceback".



When debugging, sometimes it is very helpful to introspect and see "what combination of function calls led to where we are right now".  Especially inside of event and error handlers.



Lutz, does newlisp provide some standard way to walk the stack backwards and know how we got to where we are?  I want to make a debug function to printf the call-chain and how it got us to where we are.



Also, such a "traceback" would be helpful in general when newlisp gives an error message and drops into the debugger.



And, if you had such a traceback call, what would make it doubly sweet and miles ahead of Common Lisp and Scheme, is that it would show macros the same as functions.



And finally, it would be nice if the traceback also had an option to show the arguments as they were passed to the function call, and as the function call received them.  Ie, I might do (foo a b c) but foo sees itself being called as (foo 1 2 3).