interpl

Experiments with intepreters in Prolog
git clone https://ccx.te2000.cz/git/interpl
Log | Files | Refs | README

commit 69ad1c665bd4f7383a31bb74d8fb16c1a617c49d
parent ef83e0383499ee1b1e52d2610fa39f5ba2191d79
Author: Jan Pobrislo <ccx@te2000.cz>
Date:   Fri, 30 May 2025 15:51:49 +0000

working sexp parser

Diffstat:
Minterpreter.pl | 35++++++++++++++++++++++++++++++++++-
Mtests.pl | 26+++++++++++++++++++-------
2 files changed, 53 insertions(+), 8 deletions(-)

diff --git a/interpreter.pl b/interpreter.pl @@ -1,8 +1,12 @@ %% #!/usr/bin/env swipl :- module(interpreter, [ parse_input_expression/2 + , sexp//1 + , sexp/4 ]). :- use_module(library(debug), [assertion/1]). +:- use_module(library(dcg/basics), [blanks//0, number//1]). +:- use_module(library(quasi_quotations), [phrase_from_quasi_quotation/2, quasi_quotation_syntax/1]). :- use_module(library(pairs)). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -235,7 +239,36 @@ prolog:error_message(evaluation_error(Codes)) --> parse_input_expression(Codes, Expression) :- phrase(sexp(Expression), Codes). -sexp(_Expression) --> { false }. % TODO +sexp(List) --> `(`, blanks, sexp_list(List). +sexp(Number) --> number(Number). +sexp(Atom) --> + { ground(Atom) }, !, + { atom_codes(Atom, Codes) }, + Codes. +sexp(Atom) --> + { var(Atom) }, !, + [Initial], + { atom_start_code(Initial) }, + atom_tail(Codes), + { atom_codes(Atom, [Initial|Codes]) }. + +atom_tail([Code|Tail]) --> [Code], { atom_code(Code) }, !, atom_tail(Tail). +atom_tail([]) --> { true }. + +atom_code(Code) :- + code_type(Code, graph), % non-whitespace / non-control + Code \= 40, % open paren + Code \= 41. % close paren + +atom_start_code(Code) :- + atom_code(Code), \+ code_type(Code, digit). + +sexp_list([]) --> `)`. +sexp_list([Value|Rest]) --> sexp(Value), blanks, sexp_list(Rest). + +sexp(Content, _, _, Result) :- + phrase_from_quasi_quotation(sexp(Result), Content). +:- quasi_quotation_syntax(sexp). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Interpreter wrapper diff --git a/tests.pl b/tests.pl @@ -4,37 +4,49 @@ test_one_result(Template, Goal, Output) :- findall(Template, Goal, Results), + % write(Results), nl, assertion(length(Results, 1)), Results = [Output]. +decode(Codes, Expression) :- + test_one_result(E, parse_input_expression(Codes, E), Expression). + :- begin_tests(sexp). test(sexp_atom) :- - parse_input_expression(`a`, Expression), + decode(`a`, Expression), assertion(Expression =@= a). test(sexp_atom2) :- - parse_input_expression(`hello-world!`, Expression), + decode(`hello-world!`, Expression), assertion(Expression =@= 'hello-world!'). test(sexp_number) :- - parse_input_expression(`0`, Expression), + decode(`0`, Expression), assertion(Expression =@= 0). test(sexp_number2) :- - parse_input_expression(`31337`, Expression), + decode(`31337`, Expression), assertion(Expression =@= 31337). test(sexp_list_empty) :- - parse_input_expression(`()`, Expression), + decode(`()`, Expression), assertion(Expression =@= []). test(sexp_list_one_atom) :- - parse_input_expression(`(a)`, Expression), + decode(`(a)`, Expression), assertion(Expression =@= [a]). test(sexp_list_one_two_atoms) :- - parse_input_expression(`(a)`, Expression), + decode(`(a b)`, Expression), assertion(Expression =@= [a, b]). +test(sexp_def) :- + decode(`(define proc (lambda (e f g) (lambda () e)))`, Expression), + assertion(Expression =@= [define, proc, [lambda, [e, f, g], [lambda, [], e]]]). + +test(sexp_qq) :- + Expression = {|sexp||(define proc (lambda (e f g) (lambda () e)))|}, + assertion(Expression =@= [define, proc, [lambda, [e, f, g], [lambda, [], e]]]). + :- end_tests(sexp).