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

Messages - iNPRwANG

#16
newLISP in the real world / Catch form problem
June 14, 2012, 02:23:09 AM
The newLisp document said:
Quote
In the second syntax, catch evaluates the expression exp, stores the result in symbol, and returns true. If an error occurs during evaluation, catch returns nil and stores the error message in symbol. This form can be useful when errors are expected as a normal potential outcome of a function and are dealt with during program execution.


And in my code, I'd throwed a exception in catch of second syntax, why it always get "true" result instead of nil?



(setq result nil)

(println (catch (dotimes (x 100)
  (if (= x 50) (throw "fin"))) 'result))
#17
I use the default makefile named "makefile_mingw_utf8_ffi", and did not to modity it. (just use the -01)

My system is Windows XP sp3 32bit, lib ffi also compile with gcc 4.6.1.

Use newlisp version is 10.4.2 in-progress.  : )



The fatal error message with a msvcrt.dll callstack, function is longjump.
#18
While I compile newlisp 10.4.2 on windows mingw gcc(4.6.1), and run the target, it looks good for all test.

But if only cause a error in code, like run a undefine function:



(aa)


That will show a error message, and make a fatal error messagebox, then program will crash.



I try to build a version with no -O1 option with gcc(4.6.1), It works better!



I try to find the error from source, it looks crash at the "longjump" function while resume from error.



I try to compile newlisp on mingw gcc(3.4.5), the result is it woks all good.
#19
OK, thx.

The difference with common lisp is: In common lisp the (length 'nil) is zero, and in newlisp is the symbols length.
#20
newLISP in the real world / The length of nil value
April 17, 2012, 08:10:04 PM
This is code:



(setq mylst '(nil nil nil nil nil nil nil nil nil nil nil nil))
(dolist (item mylst) (println (length item)))


Why the result is:



3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3

3
#21
I use the chinese locale,too. And I think that's not the newlisp's problem, because of the cmd.exe can only display characters of cp936 in general.  Write these examples in a utf-8 encoded text file and run it, will get the right result.



The "set-locale" function of newlisp is no use to change the cmd.exe's locale, if someone want to change the cmd.exe and let it can display utf-8 characters, may do like under:



1.Right click the command prompt window's caption, and click "property" on popup menu.

2.At the "Font" tabsheet, choose the "Lucida Console" font, and confirm it.

3.At the command prompt window, input "chcp 65001" command (change the codepage to utf-8).



then the command prompt window can display utf-8 characters but still has some problem, for example always display the half of the chinese character : )
#22
System is Windows xp, while loop call of the "process" function of newlisp 10.4.2, you may saw that the "Handle Count" of Task manager increment every call.



    I have readed the source of win32-util.c:69, the "CreateProcess" systemcall return a PROCESS_INFORMATION

struct, the function call return the hProcess of this struct. I try to add a "CloseHandle" function call to close the hThread of this struct and recompile the newlisp, it looks work good.



    Is this a leak?  : )




UINT winPipedProcess(char * cmd, int inpipe, int outpipe, int option)
{
STARTUPINFO si = { 0 };
PROCESS_INFORMATION process;
int result;
long fin, fout;

if(inpipe == -1 && outpipe == -1)
    {
    memset(&si, 0, sizeof(si));
    si.cb = sizeof(si);
    si.wShowWindow = option;
    memset(&process, 0, sizeof(process));
    }
else
    {
    /* GetStartupInfo(&si);  */
    si.cb = sizeof(si);
    si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
    si.wShowWindow = option; /* SW_SHOW, SW_HIDE  get additional user option in Win32 versions */

    fin = _get_osfhandle(inpipe);
    fout = _get_osfhandle(outpipe);

    si.hStdInput = (inpipe) ? (HANDLE)fin : GetStdHandle(STD_INPUT_HANDLE);
    si.hStdOutput = (outpipe) ? (HANDLE)fout : GetStdHandle(STD_OUTPUT_HANDLE);
    si.hStdError = (outpipe) ? (HANDLE)fout : GetStdHandle(STD_OUTPUT_HANDLE);
    }

if((result = CreateProcess(NULL,cmd,NULL,NULL,TRUE,DETACHED_PROCESS,NULL,NULL,&si, &process)) == 0)
    return(0);

//Try close hThread here
CloseHandle(process.hThread);
return((UINT)process.hProcess);
}


#23
Quote from: "Lutz"newLISP is single threaded, the 'fork' and 'spawn' built-in functions launch new processes not in-process threads. When a newLISP process dies, all its resources are freed.



When a newLISP process calls an imported function, there is now way it could reenter this imported function again, as newLISP will not execute until the call to that imported function returns. Most built-in primitives in newLISP itself are re-entrant, or if not, handle this case.



To do finalize cleanup in newLISP code use the function 'catch' in its second syntax. When an error occurs in the body of a 'catch' expression, 'catch' expression returns 'nil' and you can execute your finalize procedure. A result variable in the 'catch' expression is used to capture either the result of the body expression or error information.



(unless
    (catch (let (  (handle (get-handle))
                   (object (make-object handle)) )
                (if (null? object) (throw-error "cannot make object")))
           'result)
    (release-handle (object-handle object)))


The code handles errors thrown by newLISP internal functions as well as higher level errors using 'throw-error'.


Thanks, I accept these solutions can solve most of problems. But in certain cases, such as to free some resource and do some additional cleanup actions of global variables, it's helpless for me, for example:



I'd written two function for dll export:



void * alloc_mydata() {
   
    MyStruct * pdata = (MyStruct *)malloc(sizeof(MyStruct));
    pdata->hFile = CreateFile(...);
    ...
   
    return (void *)pdata;

}


void free_mydata(MyStruct * pdata) {
     
    assert(pdata);
 
    if (pdata->hFile != INVALID_HANDLE_VALUE) {
       
       DoSomeAdditionAction(pdata->hFile);                // for I must do these addition actions
       CloseHandle(pdata->hFile);
     }

    free(pdata);
}


In before case, while I alloc some data by "alloc_mydata", I must free them use "free_mydata" because of the free operate must do some addition actions.  



Yes, I may use the function "catch" to cleanup them in local state, but while I use these function to alloc many global variable for use, I must check all of these variables if them be freed. It's tired to do this of a large project.



While this case in SBCL, I can easily write a lisp function for wrapper my object and some FFI data with a "finalize" function, and do not care either, It's just like the object's destructor in C plus plus. : )
#24
For I was often to call some OS native API in newlisp, and alloc some kernel handle.

While I alloc the native handle, I should free then. Or it will cause the leak.



I known the Steel Bank Common Lisp has a extend function named "finalize", it can bind a designated function to a object and let it to be called when there are no more references to object.

I think that's a good idea for mainten FFI's alloced pointer, is it? : )

So I wish newlisp may has the similar mechanism for usage.





Under is the part of the "finalize" function of SBCL's document.



— Function: finalize [sb-ext] object function &key dont-save



    Arrange for the designated function to be called when there are no more references to object, including references in function itself.



    If dont-save is true, the finalizer will be cancelled when save-lisp-and-die is called: this is useful for finalizers deallocating system memory, which might otherwise be called with addresses from the old image.



    In a multithreaded environment function may be called in any thread. In both single and multithreaded environments function may be called in any dynamic scope: consequences are unspecified if function is not fully re-entrant.



    Errors from function are handled and cause a warning to be signalled in whichever thread the function was called in.



    Examples:

;;; GOOD, assuming RELEASE-HANDLE is re-entrant.
(let* ((handle (get-handle))
  (object (make-object handle)))
 (finalize object (lambda () (release-handle handle)))
 object)

;;; BAD, finalizer refers to object being finalized, causing
;;; it to be retained indefinitely!
(let* ((handle (get-handle))
  (object (make-object handle)))
  (finalize object
(lambda ()
 (release-handle (object-handle object)))))

;;; BAD, not re-entrant!
(defvar *rec* nil)

(defun oops ()
 (when *rec*
   (error "recursive OOPS"))
 (let ((*rec* t))
   (gc))) ; or just cons enough to cause one

(progn
  (finalize "oops" #'oops)
  (oops)) ; GC causes re-entry to #'oops due to the finalizer
 ; -> ERROR, caught, WARNING signalled

#25
Quote from: "Lutz"From the manual description of the 'trace' function:


QuoteIf an expression occurs more than once in a function, the first occurrence of the executing function will always be highlighted (bracketed).


This only affects the highlighting, the debugger will always execute expressions in correct order. For internal reasons this cannot be avoided, or would need an unreasonable amount of code to work around it.





Ps: not sure, why the hashmark brackets don't show up on Cormullion's example. Perhaps he uses 'trace-highlight' '?


I understand. Thanks. :)
#26
While run this code:



(define (hello-world a)
(letn ((tmp 10)
      (val1 (* tmp 2))
  (val2 (* tmp 2)))
)
)

(debug (hello-world 10))




(define (hello-world a)

  #(letn ((tmp 10) (val1 (* tmp 2)) (val2 (* tmp 2))))#)





[-> 3 ] s|tep n|ext c|ont q|uit > s



-----



(define (hello-world a)

  (letn ((tmp 10) (val1 #(* tmp 2)#) (val2 (* tmp 2)))))





[-> 4 ] s|tep n|ext c|ont q|uit > s



-----



(define (hello-world a)

  (letn ((tmp 10) (val1 #(* tmp 2)#) (val2 (* tmp 2)))))





RESULT: 20



[<- 4 ] s|tep n|ext c|ont q|uit > s



-----



(define (hello-world a)

  (letn ((tmp 10) (val1 #(* tmp 2)#) (val2 (* tmp 2)))))





; This cause the bracket match error.



Is it should be]






[-> 4 ] s|tep n|ext c|ont q|uit > s



-----



(define (hello-world a)

  (letn ((tmp 10) (val1 #(* tmp 2)#) (val2 (* tmp 2)))))





RESULT: 20



[<- 4 ] s|tep n|ext c|ont q|uit > s



-----



(define (hello-world a)

  #(letn ((tmp 10) (val1 (* tmp 2)) (val2 (* tmp 2))))#)





RESULT: nil



[<- 3 ] s|tep n|ext c|ont q|uit >
#27
Quote from: "Lutz"Here is a function you can use to define functions as default functors in their own space:


(define (def-static s body)
      (def-new 'body (sym s s)))


and use like this:


> (def-static 'acc (fn (x) (inc sum x)))
acc:acc
> (acc 1)
1
> (acc 1)
2
> (acc 1)
3
> (acc 5)
8
> acc:acc
(lambda (acc:x) (inc acc:sum acc:x))
>


fn is the same as lambda but quicker to write.


Thank you for the nice solution!
#28
Thanks, this solution of define function as context default functor can avoid name conflict in most case.  : )
#29
Thanks a lot!

I'v read the common lisp special, and I'v understand the newlisp uses the dynamic scope, the common lisp could use (declare (special xxx)) to let a variable's scope be dynamic.



But, had newlisp got a solution to avoid the name conflict of dynamic scope?  Such as, I often use the variable name of "tmp", and how to avoid the name confilct of another function.



I'm thinking a way about could a function to construct a function-local-context to store the function local variable, and auto destroy while the function end. (by modify the newlisp's design : P )The code like this:



(define (myfun2 fun)
   (let ((a 20))
      (apply fun '())
      )
   )

(define (myfun)
   (let ((myfun:a 10))  
      (myfun2
         (lambda ()
            (setq myfun:a 30))
         )
      myfun:a
      )
   )
       
(print (myfun))
(exit)


#30
I'm sorry for my english.  While I run under codes, I can not understand why the result is 10 unless the myfun's lambda parameter use the variable "a" defined of myfun2. And the common lisp get the right results :30.







(define (myfun2 fun)
(let ((a 20))
(apply fun '())
)
)

(define (myfun)
(let ((a 10))
(myfun2
(lambda ()
(setq a 30))
)
a
)
)
       
(print (myfun))

(exit)