janestreet / ecaml

Writing Emacs plugin in OCaml
MIT License
252 stars 12 forks source link

error condition returned to emacs? #11

Open progman1 opened 3 years ago

progman1 commented 3 years ago

Is there global handling of ocaml exceptions raised from code (inside a defun) invoked from emacs ? I ask since my emacs crashes with

Fatal Error: executable program file not found

when I do invalid_arg "..." . I haven't found anything in the ecaml source yet to indicate a particular way of returning an error condition back to emacs.

I haven't wrapped my head around the control model between emacs/ecaml/user-code yet but happily I tried starting a thread before returning a result back to emacs and that continues running fine. is this safe to do or should things be done through Async (or ...) ?

thanks.

progman1 commented 3 years ago

to clarify the exception matter: though it isn't very meaningful to raise invalid_arg I first saw the issue with

let setq = "setq" |> Symbol.intern in
let _ =  Symbol.funcall1  setq (Value.of_int_exn  777) in
...

for which I earn an 'invalid function' exception/message. I'd like to turn that into an emacs level error but I have found only:

  module For_testing : sig
    exception
      Elisp_signal of
        { symbol : t
        ; data : t
        }

    exception
      Elisp_throw of
        { tag : t
        ; value : t
        }
...

and

  module Expert : sig
    val raise_if_emacs_signaled : unit -> unit
    val non_local_exit_signal : exn -> unit
  end

none of which give me any joy (although looked very unlikely to!)

for now I have the work-around of shadowing %map_open, trapping any exception and returning Value.nil. but that isn't very satisfying.

m-plamann commented 3 years ago

Ecaml should automatically convert between elisp signals/throws and ocaml exceptions.

If you call from elisp into ocaml and your ocaml code raises, you should get an elisp signal corresponding to the ocaml exception. And in the other direction, if your ocaml code calls into some elisp which signals, you should get an ocaml exception corresponding to the elisp signal.

The For_testing and Expert modules quoted above are implementation details of this, and you shouldn't have to use them directly.

I'm surprised you're seeing emacs crash with Fatal Error: executable program file not found. This isn't an error I've seen before.

Are you raising an exception from a separate thread? It's possible that doesn't work correctly. Code using Async should work fine, but Ecaml hasn't been tested with manually creating/working with threads.

progman1 commented 3 years ago

I was using native emacs plugin with a hacked dynlink module to get a reloadable main app but when it started crashing I switched to a bytecode emacs plugin. things appeared to work out until this exception issue. I rolled back what I was doing to the hello-world example and it seems to be the bytecode use itself that manifests the exception anomaly. but in the process of investigating this I found the native plugin started behaving again with the added benefit of normal exception handling. yay.

since JS probably has not run ecaml in bytecode I can only ask whether you have any notion of what the issue with bytecode and associated runtime might be. the 'executable program' error is suggestive to me of a dlopen problem but I have the plugin compiling against the .a libraries and there are no dlls beyond the standard one's such as -lm, -lc , -ldl, -lpthread and -lrt in common with the native .so no threading used either.

m-plamann commented 3 years ago

We don't use bytecode at all internally for ecaml. I didn't even realize that could work.

I'd recommend compiling to native code. I've got no idea how much of ecaml might work and how much might be broken when running in bytecode.

progman1 commented 3 years ago

thanks!

progman1 commented 3 years ago

It's a known issue and the solution is coming: https://github.com/ocaml/ocaml/pull/10159

and for now a bytecode build can be made to work by Printexc.record_backtrace false upon initialisation.

I cannot seem to close the issue....