unofficial mirror of guile-devel@gnu.org 
 help / color / mirror / Atom feed
* [BUG] Eval sets incorrect runtime metainformation
@ 2024-06-25 15:07 Andrew Tropin
  2024-06-26  9:24 ` Andy Wingo
  0 siblings, 1 reply; 14+ messages in thread
From: Andrew Tropin @ 2024-06-25 15:07 UTC (permalink / raw)
  To: guile-devel, Andy Wingo

[-- Attachment #1: Type: text/plain, Size: 3605 bytes --]

TLDR: primitive-eval ignores information provided by reader.

There are two identical snippets of code, which differ only in keyword
argument `compile?` value.  When compile? is set to #t, metainformation
for procedure is correct, but when it is set to #f resulting data is
different :)

--8<---------------cut here---------------start------------->8---
(define-module (2024-06-25-eval-string-metadata))

(use-modules (system vm program)
             (ice-9 eval-string))

(eval-string "(define (test-fn) 'hey)"
             #:module (current-module)
             #:file "hello.scm"
             #:line 1
             #:column 1
             #:compile? #f)

(format #t "~a\n" (program-sources test-fn))
;; ((0 ice-9/eval.scm 329 . 13) (12 ice-9/eval.scm 330 . 21) (44 ice-9/eval.scm 330 . 15))

(eval-string "(define (test-fn) 'hey)"
             #:module (current-module)
             #:file "hello.scm"
             #:line 1
             #:column 1
             #:compile? #t)

(format #t "~a\n" (program-sources test-fn))
;; ((0 hello.scm 1 . 1) (12 hello.scm 1 . 19))

(exit 0)
--8<---------------cut here---------------end--------------->8---


To track down the issue, I simplified the code a bit and removed
unecessary wrappers, the resulting snippet looks like this:

--8<---------------cut here---------------start------------->8---
(use-modules (system base language)
             (system vm program))

(call-with-input-string
 "(define (hello) 'hey)"
 (lambda (port)
   (set-port-filename! port "test.scm")
   (set-port-line! port 100)
   (set-port-column! port 0)

   (let ((reader (language-reader (lookup-language (current-language))))
         (eval (language-evaluator (lookup-language (current-language)))))
     (eval (pk (reader port (current-module))) (current-module)))))

(format #t "~a\n" (program-sources hello))
;;; (#<syntax:test.scm:101:0 (#<syntax:test.scm:101:1 define> #<syntax:test.scm:101:8 (#<syntax:test.scm:101:9 hello>)> #<syntax:test.scm:101:16 (quote #<syntax:test.scm:101:17 hey>)>)>)
;; ((0 ice-9/eval.scm 329 . 13) (12 ice-9/eval.scm 330 . 21) (44 ice-9/eval.scm 330 . 15))
--8<---------------cut here---------------end--------------->8---

The reader keeps all metainformation obtained from port, so the issue is
in the eval phase.

The problem is in language-evaluator (primitive-eval in our case), which
just ignores all the info from reader.

--8<---------------cut here---------------start------------->8---
(use-modules (system vm program))
(primitive-eval '(define (hello) 'hey))
(format #t "~a\n" (program-sources hello))
;; ((0 ice-9/eval.scm 329 . 13) (12 ice-9/eval.scm 330 . 21) (44 ice-9/eval.scm 330 . 15))
--8<---------------cut here---------------end--------------->8---

It leads to several shortcomings: the inability to utilize the built-in
eval for implementing interactive development tooling (IDEs with proper
eval and goto definition functionality, interactive test runners and
debuggers) and do other programmatic interactions with the running Guile
process.  I want to bring more attention to this issue, because it can
have serious negative impact on the guile ecosystem.

The another related problem is that the metainformation is stored in
prodecures properties, but not in variables, which makes it impossible
to implement a proper goto definition in general case.

Would be glad to cooperate on improving all of those points 👆 and would
be twice as glad to get some guidance or hear a word of encouragement.

-- 
Best regards,
Andrew Tropin

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 832 bytes --]

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [BUG] Eval sets incorrect runtime metainformation
  2024-06-25 15:07 [BUG] Eval sets incorrect runtime metainformation Andrew Tropin
@ 2024-06-26  9:24 ` Andy Wingo
  2024-06-26  9:36   ` Maxime Devos
  0 siblings, 1 reply; 14+ messages in thread
From: Andy Wingo @ 2024-06-26  9:24 UTC (permalink / raw)
  To: Andrew Tropin; +Cc: guile-devel

Hello,

On Tue 25 Jun 2024 17:07, Andrew Tropin <andrew@trop.in> writes:

> (use-modules (system vm program)
>              (ice-9 eval-string))
>
> (eval-string "(define (test-fn) 'hey)"
>              #:file "hello.scm"
>              #:line 1
>              #:column 1
>              #:compile? #f)
>
> (format #t "~a\n" (program-sources test-fn))
> ;; ((0 ice-9/eval.scm 329 . 13) (12 ice-9/eval.scm 330 . 21) (44 ice-9/eval.scm 330 . 15))

What you are seeing here is that in general the debugging experience is
different for interpreted and compiled procedures.  For example, you
will not be able to set a breakpoint in interpreted code, because the
code for the closure that is part of `eval` corresponds to potentially
many different functions.  program-sources will only work usefully on
compiled procedures.
https://www.gnu.org/software/guile/manual/html_node/Compiled-Procedures.html.

I would suggest that if you are working on a rich IDE, that you pass
#:compile? #t.  Nothing else will work as you like.

That said, the evaluator does attach so-called "meta-data" information
to procedures, such as the procedure name.
https://www.gnu.org/software/guile/manual/html_node/Procedure-Properties.html.
If you know that you are making a procedure you can insert some
meta-data for use by your run-time, in an initial vector alist.  See
https://www.gnu.org/software/guile/manual/html_node/Procedure-Properties.html.
But that's limited and doesn't take macros, etc into account.

Regards,

Andy



^ permalink raw reply	[flat|nested] 14+ messages in thread

* RE: [BUG] Eval sets incorrect runtime metainformation
  2024-06-26  9:24 ` Andy Wingo
@ 2024-06-26  9:36   ` Maxime Devos
  2024-06-26 11:41     ` Andrew Tropin
  2024-06-26 16:04     ` Andy Wingo
  0 siblings, 2 replies; 14+ messages in thread
From: Maxime Devos @ 2024-06-26  9:36 UTC (permalink / raw)
  To: Andy Wingo, Andrew Tropin; +Cc: guile-devel@gnu.org

[-- Attachment #1: Type: text/plain, Size: 2382 bytes --]

> (use-modules (system vm program)
>              (ice-9 eval-string))
>
> (eval-string "(define (test-fn) 'hey)"
>              #:file "hello.scm"
>              #:line 1
>              #:column 1
>              #:compile? #f)
>
> (format #t "~a\n" (program-sources test-fn))
> ;; ((0 ice-9/eval.scm 329 . 13) (12 ice-9/eval.scm 330 . 21) (44 ice-9/eval.scm 330 . 15))

>What you are seeing here is that in general the debugging experience is
different for interpreted and compiled procedures.  For example, you
will not be able to set a breakpoint in interpreted code, because the
code for the closure that is part of `eval` corresponds to potentially
many different functions.  program-sources will only work usefully on
compiled procedures.
>https://www.gnu.org/software/guile/manual/html_node/Compiled-Procedures.html.

IIRC, the question wasn’t about debugging in general, it was about source locations in particular. Surely program-sources (or, in this case, procedure-source maybe?) (why are the procedures in this family even named program-whatever, this prevents doing the same for interpreted code later) could be adjusted to also work for ‘eval’. For example, ‘eval’ could set the ‘source’ (*) procedure property when a closure is made.

Likewise for arity and procedure name.

(*) Looking at https://www.gnu.org/software/guile/manual/html_node/Procedure-Properties.html, it appears the documentation doesn’t actually document what the ‘source’ property is for – It could be interpreted in multiple ways currently.

>I would suggest that if you are working on a rich IDE, that you pass
#:compile? #t.  Nothing else will work as you like.

Something else will work as well: adjusting ‘eval’ to set procedure properties or something like that.

>That said, the evaluator does attach so-called "meta-data" information
to procedures, such as the procedure name.
https://www.gnu.org/software/guile/manual/html_node/Procedure-Properties.html.
If you know that you are making a procedure you can insert some
meta-data for use by your run-time, in an initial vector alist.  See
https://www.gnu.org/software/guile/manual/html_node/Procedure-Properties.html.
But that's limited and doesn't take macros, etc into account.

That’s the job of ‘eval’, not the user of ‘eval’.

Best regards,
Maxime Devos.

[-- Attachment #2: Type: text/html, Size: 4785 bytes --]

^ permalink raw reply	[flat|nested] 14+ messages in thread

* RE: [BUG] Eval sets incorrect runtime metainformation
  2024-06-26  9:36   ` Maxime Devos
@ 2024-06-26 11:41     ` Andrew Tropin
  2024-06-26 22:06       ` Philip McGrath
  2024-06-26 16:04     ` Andy Wingo
  1 sibling, 1 reply; 14+ messages in thread
From: Andrew Tropin @ 2024-06-26 11:41 UTC (permalink / raw)
  To: Andy Wingo; +Cc: Maxime Devos, guile-devel@gnu.org

[-- Attachment #1: Type: text/plain, Size: 4109 bytes --]

On 2024-06-26 11:36, Maxime Devos wrote:

>>> (use-modules (system vm program)
>>>              (ice-9 eval-string))
>>>
>>> (eval-string "(define (test-fn) 'hey)"
>>>              #:file "hello.scm"
>>>              #:line 1
>>>              #:column 1
>>>              #:compile? #f)
>>>
>>> (format #t "~a\n" (program-sources test-fn))
>>> ;; ((0 ice-9/eval.scm 329 . 13) (12 ice-9/eval.scm 330 . 21) (44 ice-9/eval.scm 330 . 15))
>
>>What you are seeing here is that in general the debugging experience is
>> different for interpreted and compiled procedures.  For example, you
>> will not be able to set a breakpoint in interpreted code, because the
>> code for the closure that is part of `eval` corresponds to potentially
>> many different functions.  program-sources will only work usefully on
>> compiled procedures.
>>https://www.gnu.org/software/guile/manual/html_node/Compiled-Procedures.html.
>
> IIRC, the question wasn’t about debugging in general, it was about
> source locations in particular. Surely program-sources (or, in this
> case, procedure-source maybe?) (why are the procedures in this family
> even named program-whatever, this prevents doing the same for
> interpreted code later) could be adjusted to also work for ‘eval’. For
> example, ‘eval’ could set the ‘source’ (*) procedure property when a
> closure is made.
>
> Likewise for arity and procedure name.
>
> (*) Looking at
> https://www.gnu.org/software/guile/manual/html_node/Procedure-Properties.html,
> it appears the documentation doesn’t actually document what the
> ‘source’ property is for – It could be interpreted in multiple ways
> currently.
>
>>I would suggest that if you are working on a rich IDE, that you pass
>> #:compile? #t.  Nothing else will work as you like.

I do pass (use compile directly to be more precise) :) but there is
another very important problem related to this approach:
https://yhetil.org/guile-devel/20240621164008.eEg72C00D1xd29F01Eg7DF@baptiste.telenet-ops.be/T/#t

It also leads to problem with define-once, which sets the value to
#<unspecified> in most cases, when "evaluated" with compile.

>
> Something else will work as well: adjusting ‘eval’ to set procedure
> properties or something like that.

Agree with Maxime here, and that is what I propose in the original
message.

>> That said, the evaluator does attach so-called "meta-data" information
>> to procedures, such as the procedure name.
>> https://www.gnu.org/software/guile/manual/html_node/Procedure-Properties.html.
>> If you know that you are making a procedure you can insert some
>> meta-data for use by your run-time, in an initial vector alist.  See
>> https://www.gnu.org/software/guile/manual/html_node/Procedure-Properties.html.
>> But that's limited and doesn't take macros, etc into account.

Yep, that's is why I wrote:

--8<---------------cut here---------------start------------->8---
The another related problem is that the metainformation is stored in
prodecures properties, but not in variables, which makes it impossible
to implement a proper goto definition in general case.
--8<---------------cut here---------------end--------------->8---

How hard is to make a generic metainformation, which is attachable to
macros, symbols and other objects of the language, not only to
procedures?

>> That said, the evaluator does attach so-called "meta-data" information
>> to procedures, such as the procedure name.
>> https://www.gnu.org/software/guile/manual/html_node/Procedure-Properties.html.
>> If you know that you are making a procedure you can insert some
>> meta-data for use by your run-time, in an initial vector alist.  See
>> https://www.gnu.org/software/guile/manual/html_node/Procedure-Properties.html.
>> But that's limited and doesn't take macros, etc into account.
>
> That’s the job of ‘eval’, not the user of ‘eval’.

Think the same, eval should respect information provided by reader and
attach it to corresponding objects.

-- 
Best regards,
Andrew Tropin

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 832 bytes --]

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [BUG] Eval sets incorrect runtime metainformation
  2024-06-26  9:36   ` Maxime Devos
  2024-06-26 11:41     ` Andrew Tropin
@ 2024-06-26 16:04     ` Andy Wingo
  2024-06-28 13:27       ` Andrew Tropin
  1 sibling, 1 reply; 14+ messages in thread
From: Andy Wingo @ 2024-06-26 16:04 UTC (permalink / raw)
  To: Maxime Devos; +Cc: Andrew Tropin, guile-devel@gnu.org

On Wed 26 Jun 2024 11:36, Maxime Devos <maximedevos@telenet.be> writes:

> IIRC, the question wasn’t about debugging in general, it was about
> source locations in particular. Surely program-sources (or, in this
> case, procedure-source maybe?) (why are the procedures in this family
> even named program-whatever, this prevents doing the same for
> interpreted code later) could be adjusted to also work for ‘eval’. For
> example, ‘eval’ could set the ‘source’ (*) procedure property when a
> closure is made.

I think it's really valuable to imagine how things should be but if you
are going to argue they should be different, you should first try to
understand how they are.

`program-sources` is a mapping from bytecode offsets to source
locations.  For compiled procedures we can make this mapping because
each bytecode position has a single source.  For interpreted procedures,
what you end up getting is the bytecode-to-source mapping *for eval*,
not for the code being interpreted.

Is it a great thing that there is a debugging (I use the term on purpose
to mean all kinds of run-time reflection etc) difference between eval
and compile?  No, of course not.  I would rather there not be a
difference and not have to document something that is at best
extraneous.  There are differing pressures on eval: for bootstrap times
(and macro expansion time) you want it to have the least amount of
overhead possible, whereas for debugging you want to attach meta-data
that isn't strictly needed at run-time.  Attaching that meta-data has
memory and time overheads.

If we are looking to get the source location *just of the interpreted
closure* -- that is possible; see eval.scm:581, there you would attach
some other properties.  You would have to define a different debugging
interface that looks for source location information in a way different
from program-sources.  For me it's not worth it but I encourage you to
experiment with (ice-9 eval); it's just another Scheme program.  (You
would need to take a different approach to memoization, in order to pass
through source location information.)

Andy



^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [BUG] Eval sets incorrect runtime metainformation
  2024-06-26 11:41     ` Andrew Tropin
@ 2024-06-26 22:06       ` Philip McGrath
  2024-06-28 13:20         ` Andrew Tropin
  2024-06-29 23:05         ` Maxime Devos
  0 siblings, 2 replies; 14+ messages in thread
From: Philip McGrath @ 2024-06-26 22:06 UTC (permalink / raw)
  To: Andrew Tropin, Andy Wingo; +Cc: Maxime Devos, guile-devel@gnu.org

[-- Attachment #1: Type: text/plain, Size: 2827 bytes --]

On 6/26/24 07:41, Andrew Tropin wrote:>
>>> That said, the evaluator does attach so-called "meta-data" information
>>> to procedures, such as the procedure name.
>>> https://www.gnu.org/software/guile/manual/html_node/Procedure-Properties.html.
>>> If you know that you are making a procedure you can insert some
>>> meta-data for use by your run-time, in an initial vector alist.  See
>>> https://www.gnu.org/software/guile/manual/html_node/Procedure-Properties.html.
>>> But that's limited and doesn't take macros, etc into account.
> 
> Yep, that's is why I wrote:
> 
> --8<---------------cut here---------------start------------->8---
> The another related problem is that the metainformation is stored in
> prodecures properties, but not in variables, which makes it impossible
> to implement a proper goto definition in general case.
> --8<---------------cut here---------------end--------------->8---
> 
> How hard is to make a generic metainformation, which is attachable to
> macros, symbols and other objects of the language, not only to
> procedures?
> 

Instead of run-time reflection on values, I think an IDE implementing 
jump to definition should use source location and binding information 
from syntax objects. That's how DrRacket does it.

The attached DrRacket screenshot (of [1]), in which I've tacked a bunch 
of binding arrows, shows how local definitions and complex 
macro-introduced binding structures are supported. It also works across 
modules, even with renaming: in the program `#lang racket (define one 
1)`, right-clicking on `define` and choosing "Jump to Binding 
Occurrence" will highlight `racket`, because the initial import of the 
racket language establishes the applicable binding of define, whereas 
choosing "Open Defining File" will open the racket/private/kw module, 
and then choosing "Jump to Definition (in Other File)" will jump to the 
definition of `new-define` on line 1171 of kw.rkt, which is renamed 
elsewhere to become the `define` of `#lang racket`.

Since syntax objects from the expander encode all the details of scope, 
this works mostly automatically. DrRacket makes this functionality 
available as a library, so navigation features can also be used from 
Emacs with racket-xp-mode [2] or other editors with the Language Server 
Protocol [3].

That said, if you do want to associate extra information with values at 
runtime, Guile has object properties [4], or of course you could always 
keep your own hash table on the side.

Philip

[1]: 
https://github.com/racket/racket/blob/6105332045595f8324985d7a34acc68fa5a61dcf/pkgs/racket-test/tests/json/indent.rkt#L244-L276
[2]: https://www.racket-mode.com/#racket_002dxp_002dmode
[3]: https://github.com/jeapostrophe/racket-langserver/
[4]: 
https://www.gnu.org/software/guile/manual/html_node/Object-Properties.html

[-- Attachment #2: Binding arrows from define-main for indent-test-data-cli 2024-06-26.png --]
[-- Type: image/png, Size: 571391 bytes --]

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [BUG] Eval sets incorrect runtime metainformation
  2024-06-26 22:06       ` Philip McGrath
@ 2024-06-28 13:20         ` Andrew Tropin
  2024-06-29 19:55           ` Philip McGrath
  2024-06-29 23:05         ` Maxime Devos
  1 sibling, 1 reply; 14+ messages in thread
From: Andrew Tropin @ 2024-06-28 13:20 UTC (permalink / raw)
  To: Philip McGrath, Andy Wingo; +Cc: Maxime Devos, guile-devel@gnu.org

[-- Attachment #1: Type: text/plain, Size: 3667 bytes --]

On 2024-06-26 18:06, Philip McGrath wrote:

> On 6/26/24 07:41, Andrew Tropin wrote:>
>>>> That said, the evaluator does attach so-called "meta-data" information
>>>> to procedures, such as the procedure name.
>>>> https://www.gnu.org/software/guile/manual/html_node/Procedure-Properties.html.
>>>> If you know that you are making a procedure you can insert some
>>>> meta-data for use by your run-time, in an initial vector alist.  See
>>>> https://www.gnu.org/software/guile/manual/html_node/Procedure-Properties.html.
>>>> But that's limited and doesn't take macros, etc into account.
>> 
>> Yep, that's is why I wrote:
>> 
>> --8<---------------cut here---------------start------------->8---
>> The another related problem is that the metainformation is stored in
>> prodecures properties, but not in variables, which makes it impossible
>> to implement a proper goto definition in general case.
>> --8<---------------cut here---------------end--------------->8---
>> 
>> How hard is to make a generic metainformation, which is attachable to
>> macros, symbols and other objects of the language, not only to
>> procedures?
>> 
>
> Instead of run-time reflection on values, I think an IDE implementing 
> jump to definition should use source location and binding information 
> from syntax objects. That's how DrRacket does it.

If you could share a snippet of code or link to related library or docs,
it could help to understand better the idea.  I still relatively newbie
in questions related to snyntax objects and overall scheme's expand.

>
> The attached DrRacket screenshot (of [1]), in which I've tacked a bunch 
> of binding arrows, shows how local definitions and complex 
> macro-introduced binding structures are supported. It also works across 
> modules, even with renaming: in the program `#lang racket (define one 
> 1)`, right-clicking on `define` and choosing "Jump to Binding 
> Occurrence" will highlight `racket`, because the initial import of the 
> racket language establishes the applicable binding of define, whereas 
> choosing "Open Defining File" will open the racket/private/kw module, 
> and then choosing "Jump to Definition (in Other File)" will jump to the 
> definition of `new-define` on line 1171 of kw.rkt, which is renamed 
> elsewhere to become the `define` of `#lang racket`.
>
> Since syntax objects from the expander encode all the details of scope, 
> this works mostly automatically. DrRacket makes this functionality 
> available as a library, so navigation features can also be used from 
> Emacs with racket-xp-mode [2] or other editors with the Language Server 
> Protocol [3].
>
> That said, if you do want to associate extra information with values at
> runtime, Guile has object properties [4], or of course you could always 
> keep your own hash table on the side.

Thank you for pointing to object properties!

I guess we can implement our own eval, to attach location information to
corresponding objects, I just expected it to be a part of the guile,
because we already have this information for procedures anyway.  The
another problem with our own eval is that information for already loaded
code won't be enriched with our custom stuff :/

>
> Philip
>
> [1]: 
> https://github.com/racket/racket/blob/6105332045595f8324985d7a34acc68fa5a61dcf/pkgs/racket-test/tests/json/indent.rkt#L244-L276
> [2]: https://www.racket-mode.com/#racket_002dxp_002dmode
> [3]: https://github.com/jeapostrophe/racket-langserver/
> [4]: 
> https://www.gnu.org/software/guile/manual/html_node/Object-Properties.html
> x

-- 
Best regards,
Andrew Tropin

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 832 bytes --]

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [BUG] Eval sets incorrect runtime metainformation
  2024-06-26 16:04     ` Andy Wingo
@ 2024-06-28 13:27       ` Andrew Tropin
  0 siblings, 0 replies; 14+ messages in thread
From: Andrew Tropin @ 2024-06-28 13:27 UTC (permalink / raw)
  To: Andy Wingo, Maxime Devos; +Cc: guile-devel@gnu.org

[-- Attachment #1: Type: text/plain, Size: 2483 bytes --]

On 2024-06-26 18:04, Andy Wingo wrote:

> On Wed 26 Jun 2024 11:36, Maxime Devos <maximedevos@telenet.be> writes:
>
>> IIRC, the question wasn’t about debugging in general, it was about
>> source locations in particular. Surely program-sources (or, in this
>> case, procedure-source maybe?) (why are the procedures in this family
>> even named program-whatever, this prevents doing the same for
>> interpreted code later) could be adjusted to also work for ‘eval’. For
>> example, ‘eval’ could set the ‘source’ (*) procedure property when a
>> closure is made.
>
> I think it's really valuable to imagine how things should be but if you
> are going to argue they should be different, you should first try to
> understand how they are.
>
> `program-sources` is a mapping from bytecode offsets to source
> locations.  For compiled procedures we can make this mapping because
> each bytecode position has a single source.  For interpreted procedures,
> what you end up getting is the bytecode-to-source mapping *for eval*,
> not for the code being interpreted.
>
> Is it a great thing that there is a debugging (I use the term on purpose
> to mean all kinds of run-time reflection etc) difference between eval
> and compile?  No, of course not.  I would rather there not be a
> difference and not have to document something that is at best
> extraneous.  There are differing pressures on eval: for bootstrap times
> (and macro expansion time) you want it to have the least amount of
> overhead possible, whereas for debugging you want to attach meta-data
> that isn't strictly needed at run-time.  Attaching that meta-data has
> memory and time overheads.

Does it mean, we could want another eval implementation, which is a bit
havier, but will preserve additional meta-data?

not-that-primitive-and-a-bit-fancier-eval :)

>
> If we are looking to get the source location *just of the interpreted
> closure* -- that is possible; see eval.scm:581, there you would attach
> some other properties.  You would have to define a different debugging
> interface that looks for source location information in a way different
> from program-sources.  For me it's not worth it but I encourage you to
> experiment with (ice-9 eval); it's just another Scheme program.  (You
> would need to take a different approach to memoization, in order to pass
> through source location information.)
>
> Andy

-- 
Best regards,
Andrew Tropin

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 832 bytes --]

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [BUG] Eval sets incorrect runtime metainformation
  2024-06-28 13:20         ` Andrew Tropin
@ 2024-06-29 19:55           ` Philip McGrath
  0 siblings, 0 replies; 14+ messages in thread
From: Philip McGrath @ 2024-06-29 19:55 UTC (permalink / raw)
  To: Andrew Tropin, Andy Wingo; +Cc: Maxime Devos, guile-devel@gnu.org

On 6/28/24 09:20, Andrew Tropin wrote:
> On 2024-06-26 18:06, Philip McGrath wrote:
> 
>> On 6/26/24 07:41, Andrew Tropin wrote:>
>>>>> That said, the evaluator does attach so-called "meta-data" information
>>>>> to procedures, such as the procedure name.
>>>>> https://www.gnu.org/software/guile/manual/html_node/Procedure-Properties.html.
>>>>> If you know that you are making a procedure you can insert some
>>>>> meta-data for use by your run-time, in an initial vector alist.  See
>>>>> https://www.gnu.org/software/guile/manual/html_node/Procedure-Properties.html.
>>>>> But that's limited and doesn't take macros, etc into account.
>>>
>>> Yep, that's is why I wrote:
>>>
>>> --8<---------------cut here---------------start------------->8---
>>> The another related problem is that the metainformation is stored in
>>> prodecures properties, but not in variables, which makes it impossible
>>> to implement a proper goto definition in general case.
>>> --8<---------------cut here---------------end--------------->8---
>>>
>>> How hard is to make a generic metainformation, which is attachable to
>>> macros, symbols and other objects of the language, not only to
>>> procedures?
>>>
>>
>> Instead of run-time reflection on values, I think an IDE implementing
>> jump to definition should use source location and binding information
>> from syntax objects. That's how DrRacket does it.
> 
> If you could share a snippet of code or link to related library or docs,
> it could help to understand better the idea.

I'm not intimately familiar with the implementation, but a key library 
is drracket/check-syntax, documented at [1], which is implemented in the 
[2] Git repository (mostly in the drracket-tool-text-lib directory, but 
with tests etc. elsewhere). The source for the Emacs usage is at [3]. 
You can probably get more useful advice on 
<https://racket.discourse.group>, especially from Robby Findler and Greg 
Hendershot. (Note that, while it requires one-time registration, 
Racket's Discourse instance is configured to be usable as a mailing 
list, including starting new threads by email.)

[1]: 
https://docs.racket-lang.org/drracket-tools/Accessing_Check_Syntax_Programmatically.html
[2]: https://github.com/racket/drracket
[3]: https://github.com/greghendershott/racket-mode/

> I still relatively newbie
> in questions related to snyntax objects and overall scheme's expand.
> 

The Scheme reports leave it to implementations to decide how to 
implement syntax objects and expansion more generally, so you will need 
some Guile-specific code. The procedures documented in [4] seem like a 
good place to start, especially `syntax-source`, `syntax-module`, and 
`syntax-local-binding`. I expect Guile has all of the functionality you 
would need, though some of it might be internal or awkward to use. It is 
possible, though, that you might need or want to enhance the expander: 
Racket's expander is especially feature-rich in this area, in part 
because Racket (MzScheme) was originally created to write DrRacket 
(DrScheme), so this kind of tool support has been a consideration from 
the beginning.

[4]: 
https://www.gnu.org/software/guile/manual/html_node/Syntax-Transformer-Helpers.html

Philip



^ permalink raw reply	[flat|nested] 14+ messages in thread

* RE: [BUG] Eval sets incorrect runtime metainformation
  2024-06-26 22:06       ` Philip McGrath
  2024-06-28 13:20         ` Andrew Tropin
@ 2024-06-29 23:05         ` Maxime Devos
  2024-06-30 22:27           ` Philip McGrath
  1 sibling, 1 reply; 14+ messages in thread
From: Maxime Devos @ 2024-06-29 23:05 UTC (permalink / raw)
  To: Philip McGrath, Andrew Tropin, Andy Wingo; +Cc: guile-devel@gnu.org

[-- Attachment #1: Type: text/plain, Size: 2541 bytes --]

>Instead of run-time reflection on values, I think an IDE implementing 
jump to definition should use source location and binding information 
from syntax objects. That's how DrRacket does it.

>The attached DrRacket screenshot (of [1]), in which I've tacked a bunch 
of binding arrows, shows how local definitions and complex 
macro-introduced binding structures are supported. It also works across 
modules, even with renaming: in the program `#lang racket (define one 
1)`, right-clicking on `define` and choosing "Jump to Binding 
Occurrence" will highlight `racket`, because the initial import of the 
racket language establishes the applicable binding of define, whereas 
choosing "Open Defining File" will open the racket/private/kw module, 
and then choosing "Jump to Definition (in Other File)" will jump to the 
definition of `new-define` on line 1171 of kw.rkt, which is renamed 
elsewhere to become the `define` of `#lang racket`.

>Since syntax objects from the expander encode all the details of scope, 
this works mostly automatically. DrRacket makes this functionality 
available as a library, so navigation features can also be used from 
Emacs with racket-xp-mode [2] or other editors with the Language Server 
Protocol [3].

I suppose this could work, but it seems the wrong layer of abstraction and a bit round-about to me, it also only works on languages that use Scheme-style syntax. Instead, I’d propose compiling the relevant code to Tree-IL (without optimisations, should work with most languages).  (For Scheme, this is essentially macro expansion, but the resulting object won’t technically be a syntax object.)

In Tree-IL, all syntax has been expanded (in tree form), which eliminates a lot of complications. Yet, source location information remains available (albeit not documented ...)! And the original variable names remain available (together with an unshadow-ified version, so for local variables you can move upwards to find the corresponding definition and in particular its source location.

A large upside is that this should work for most languages (not only Scheme) and is relatively straightforward to implement, a small downside is that information on definitions like (let-syntax ((f [...])) ...) aren’t available – you only see the return of (f stuff), not ‘f’ itself.

(But this downside applies to the ‘syntax’ route as well, unless you are doing complicated (but possible!) DIY partial macro expansion shenanigans.)

Best regards,
Maxime Devos.

[-- Attachment #2: Type: text/html, Size: 4342 bytes --]

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [BUG] Eval sets incorrect runtime metainformation
  2024-06-29 23:05         ` Maxime Devos
@ 2024-06-30 22:27           ` Philip McGrath
  2024-07-01  9:06             ` Maxime Devos
                               ` (2 more replies)
  0 siblings, 3 replies; 14+ messages in thread
From: Philip McGrath @ 2024-06-30 22:27 UTC (permalink / raw)
  To: Maxime Devos, Andrew Tropin, Andy Wingo; +Cc: guile-devel@gnu.org

On 6/29/24 19:05, Maxime Devos wrote:
> > Instead of run-time reflection on values, I think an IDE implementing
> > jump to definition should use source location and binding information
> > from syntax objects. That's how DrRacket does it.
> > ...
> > Since syntax objects from the expander encode all the details of scope,
> > this works mostly automatically. DrRacket makes this functionality
> > available as a library, so navigation features can also be used from
> > Emacs with racket-xp-mode [2] or other editors with the Language Server
> > Protocol [3].
> 
> I suppose this could work, but it seems the wrong layer of abstraction 
> and a bit round-about to me, it also only works on languages that use 
> Scheme-style syntax. Instead, I’d propose compiling the relevant code to 
> Tree-IL (without optimisations, should work with most languages).  (For 
> Scheme, this is essentially macro expansion, but the resulting object 
> won’t technically be a syntax object.)
> 
> In Tree-IL, all syntax has been expanded (in tree form), which 
> eliminates a lot of complications. Yet, source location information 
> remains available (albeit not documented ...)! And the original variable 
> names remain available (together with an unshadow-ified version, so for 
> local variables you can move upwards to find the corresponding 
> definition and in particular its source location.
> 
> A large upside is that this should work for most languages (not only 
> Scheme) and is relatively straightforward to implement,

I hadn't realized that other languages in Guile might compile to Tree-IL 
directly instead of generating syntax objects. Is that common and/or 
encouraged? It seems like it would require the new language's compiler 
to do a lot of work that could otherwise be delegated to Guile, and it 
would make it difficult to implement parts of the new language using macros.

> a small downside 
> is that information on definitions like (let-syntax ((f [...])) ...) 
> aren’t available – you only see the return of (f stuff), not ‘f’ itself.
> 
> (But this downside applies to the ‘syntax’ route as well, unless you are 
> doing complicated (but possible!) DIY partial macro expansion shenanigans.)
> 

This and other features, like correctly tracking the binding of `else` 
in `cond`, require cooperation from the macro expander. The explanation 
of origin tracking in 
<https://docs.racket-lang.org/reference/stxprops.html> might be one 
place to start reading about how Racket supports this (but I am not an 
expert!). Similar expander features can also enable other tools, like 
DrRacket's macro stepper: 
<https://docs.racket-lang.org/macro-debugger/index.html>

Philip



^ permalink raw reply	[flat|nested] 14+ messages in thread

* RE: [BUG] Eval sets incorrect runtime metainformation
  2024-06-30 22:27           ` Philip McGrath
@ 2024-07-01  9:06             ` Maxime Devos
  2024-07-06 16:42             ` Rob Browning
  2024-07-06 18:56             ` Matt Wette
  2 siblings, 0 replies; 14+ messages in thread
From: Maxime Devos @ 2024-07-01  9:06 UTC (permalink / raw)
  To: Philip McGrath, Andrew Tropin, Andy Wingo; +Cc: guile-devel@gnu.org

[-- Attachment #1: Type: text/plain, Size: 1006 bytes --]

>I hadn't realized that other languages in Guile might compile to Tree-IL 
directly instead of generating syntax objects. Is that common and/or 
encouraged?

I haven’t really checked, but probably? For anything that’s not Schemy in its macros, it strips a pointless layer of abstraction, and Tree-IL is straightforward to work with.

>It seems like it would require the new language's compiler 
to do a lot of work that could otherwise be delegated to Guile, and it 
would make it difficult to implement parts of the new language using macros.

I don’t see what this lot of extra work this would be (unless the language has macros that are Schemy). But yes, if implementing terms in macros, it seems pretty inevitable to use syntax objects, in which case I suppose you might compile to Scheme instead of Tree-IL.

For the mentioned IDE, it wouldn’t really matter what’s happening precisely, as long are there is a path from ‘language -> Tree-Il’.

Best regards,
Maxime Devos.

[-- Attachment #2: Type: text/html, Size: 2406 bytes --]

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [BUG] Eval sets incorrect runtime metainformation
  2024-06-30 22:27           ` Philip McGrath
  2024-07-01  9:06             ` Maxime Devos
@ 2024-07-06 16:42             ` Rob Browning
  2024-07-06 18:56             ` Matt Wette
  2 siblings, 0 replies; 14+ messages in thread
From: Rob Browning @ 2024-07-06 16:42 UTC (permalink / raw)
  To: Philip McGrath; +Cc: guile-devel@gnu.org

Philip McGrath <philip@philipmcgrath.com> writes:

> I hadn't realized that other languages in Guile might compile to Tree-IL 
> directly instead of generating syntax objects. Is that common and/or 
> encouraged? It seems like it would require the new language's compiler 
> to do a lot of work that could otherwise be delegated to Guile, and it 
> would make it difficult to implement parts of the new language using macros.

For what it's worth, Lokke (a Clojure dialect) does both.  For the most
part it compiles by producing Scheme code from its reader that's then
rewritten by macros.  But it also includes a pass or two at the Tree-IL
level to handle some things that would be difficult to get right
otherwise (while also preserving the fairly tight integration with
Scheme that's intended).

For example, they handle adding support for "keywords as functions" (in
a generalized way), and resolving Clojure's namespaced symbols to Guile
module refs.

For anyone interested in the current arrangement (the README also covers
a bunch of limitations, differences, etc.):
https://codeberg.org/lokke/lokke/src/branch/main/DESIGN.md

-- 
Rob Browning
rlb @defaultvalue.org and @debian.org
GPG as of 2011-07-10 E6A9 DA3C C9FD 1FF8 C676 D2C4 C0F0 39E9 ED1B 597A
GPG as of 2002-11-03 14DD 432F AE39 534D B592 F9A0 25C8 D377 8C7E 73A4



^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [BUG] Eval sets incorrect runtime metainformation
  2024-06-30 22:27           ` Philip McGrath
  2024-07-01  9:06             ` Maxime Devos
  2024-07-06 16:42             ` Rob Browning
@ 2024-07-06 18:56             ` Matt Wette
  2 siblings, 0 replies; 14+ messages in thread
From: Matt Wette @ 2024-07-06 18:56 UTC (permalink / raw)
  To: guile-devel



On 6/30/24 3:27 PM, Philip McGrath wrote:
>
> I hadn't realized that other languages in Guile might compile to 
> Tree-IL directly instead of generating syntax objects. Is that common 
> and/or encouraged? It seems like it would require the new language's 
> compiler to do a lot of work that could otherwise be delegated to 
> Guile, and it would make it difficult to implement parts of the new 
> language using macros.
>

I've written a LALR parser generator (based on the algorithm in the 
dragon book) and have produced
a few sample parsers and compilers.  I always compile to tree-il. See 
the javascript and mlang
subdirs under 
https://git.savannah.nongnu.org/cgit/nyacc.git/tree/examples/nyacc/lang

Matt




^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2024-07-06 18:56 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-06-25 15:07 [BUG] Eval sets incorrect runtime metainformation Andrew Tropin
2024-06-26  9:24 ` Andy Wingo
2024-06-26  9:36   ` Maxime Devos
2024-06-26 11:41     ` Andrew Tropin
2024-06-26 22:06       ` Philip McGrath
2024-06-28 13:20         ` Andrew Tropin
2024-06-29 19:55           ` Philip McGrath
2024-06-29 23:05         ` Maxime Devos
2024-06-30 22:27           ` Philip McGrath
2024-07-01  9:06             ` Maxime Devos
2024-07-06 16:42             ` Rob Browning
2024-07-06 18:56             ` Matt Wette
2024-06-26 16:04     ` Andy Wingo
2024-06-28 13:27       ` Andrew Tropin

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).