Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add implementation of trace/0 #323

Open
Thihup opened this issue Jul 12, 2024 · 3 comments
Open

Add implementation of trace/0 #323

Thihup opened this issue Jul 12, 2024 · 3 comments

Comments

@Thihup
Copy link

Thihup commented Jul 12, 2024

Hi.

Thanks for this project!

I'm considering using it as the interpreter for the Bytecode verifier of the Java Virtual Machine Specification.

However, as this specification is very dense, sometimes it is hard to know why some predicates failed.
So my request would be to add trace/0 like SWI-Prolog and GNU Prolog include.

I also tried to use :- set_prolog_flag(debug, on). but it didn't help in the tracing.

@triska
Copy link

triska commented Jul 12, 2024

I would suggest to instead include library(debug). For instance, it is provided by Scryer Prolog, here is its documentation:

https://www.scryer.pl/debug

With library(debug), you can understand the reason why a predicate fails, by producing maximal generalizations that still fail. In this way, you can show explanations that closely adhere to the actual program, instead of introducing a completely different formalism (a trace) that takes you away from the actual program you want to understand.

@ichiban
Copy link
Owner

ichiban commented Jul 13, 2024

HI, @Thihup!

Thank you for the request! Let me break down your request first. Let's say our version of trace/0 being implemented, what would you expect it to do when it reached to the ports? Just log Call: classIsTypeSafe(Class), Exit: classIsTypeSafe(Class), etc? Or do you want an interactive debugger?

If you want an interactive debugger, I'm afraid it's probably out of the scope of this project. Since it's an embeddable scripting engine decoupled from the UI, It's not always connected to the terminal or it might not have any user interactions at all. The best we can do along this line is to provide hooks like OnCall func(goal Term, env *Env), OnExit func(goalTerm, env *Env), etc to help you implement your own interactive debugger.

If you just want logs, why don't we go with library(debug) as @triska suggests? We lack many features scryer has but we can imitate a simplified version of library(debug) today!

package main

import (
	"os"

	"github.com/ichiban/prolog"
)

func main() {
	i := prolog.New(nil, os.Stdout)

	// Simplified version of https://github.com/mthom/scryer-prolog/blob/master/src/lib/debug.pl
	if err := i.Exec(`
		:- op(900, fx, $).
		:- op(900, fx, $-).
		:- op(950, fy, *).
		
		$-Goal :-
			catch(Goal, Exception, (portray_clause(exception:Exception:Goal), throw(Exception))).
		
		$Goal :-
			portray_clause(call:Goal),
			$-Goal,
			portray_clause(exit:Goal).
		
		* _.
		
		portray_clause(Clause) :-
			write(Clause),
			nl.
	`); err != nil {
		panic(err)
	}

	if err := i.Exec(`
		classIsTypeSafe(Class) :-
			$ classClassName(Class, Name), 
			$ classDefiningLoader(Class, L),
			$ superclassChain(Name, L, Chain),
			$ Chain \= [],
			$ classSuperClassName(Class, SuperclassName),
			$ loadedClass(SuperclassName, L, Superclass),
			$ classIsNotFinal(Superclass),	 
			$ classMethods(Class, Methods), 
			$ checklist(methodIsTypeSafe(Class), Methods).
		
		classClassName(foo, 'com.example.foo.Foo').
	`); err != nil {
		panic(err)
	}

	_ = i.QuerySolution(`classIsTypeSafe(foo).`)
}
call:classClassName(foo,_73)
exit:classClassName(foo,com.example.foo.Foo)
call:classDefiningLoader(foo,_74)
exception:error(existence_error(procedure,classDefiningLoader/2),catch/3):classDefiningLoader(foo,_108)
exception:error(existence_error(procedure,classDefiningLoader/2),catch/3):classClassName(foo,_116)

Program exited.

https://go.dev/play/p/DKDRZyIeVZy

@triska
Copy link

triska commented Jul 13, 2024

I think the portray_clause/1 imitation could use writeq/1, and append . at the end so that the resulting term can be read with read/2.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants