commit 69ad1c665bd4f7383a31bb74d8fb16c1a617c49d
parent ef83e0383499ee1b1e52d2610fa39f5ba2191d79
Author: Jan Pobrislo <ccx@te2000.cz>
Date: Fri, 30 May 2025 15:51:49 +0000
working sexp parser
Diffstat:
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).