packages feed

cpsa-3.3.0: src/cpsa.pl

% -*- mode: prolog -*-

%% CPSA tools in Prolog

%% This module contains a Prolog implementation of the CPSA specific
%% S-expression pretty printer algorithm used in the Haskell program.
%% It also contains a translator between an S-expression and an
%% internal representation that eases transformations on CPSA data
%% structures.

%% Known to work in SWI-Prolog, but not with GNU Prolog.

%% Copyright (c) 2009 The MITRE Corporation
%%
%% This program is free software: you can redistribute it and/or
%% modify it under the terms of the BSD License as published by the
%% University of California.

:- module(cpsa, [cpsa_sexprs_pp/2, cpsa/2, sexprs_to_cpsas/2,
                 cpsas_to_sexprs/2]).

:- use_module(pp).
:- use_module(sexpr).

%% PRETTY PRINTER

%% cpsa_sexprs_pp(+Out, +Sexprs)
%% Pretty print a list of S-expressions to stream Out.
cpsa_sexprs_pp(_, []).
cpsa_sexprs_pp(Out, [Sexpr|Sexprs]) :-
	cpsa_sexpr_pp(Out, Sexpr),
	nl(Out),
	cpsa_sexprs_pp(Out, Sexprs).

cpsa_sexpr_pp(Out, Sexpr) :-
	cpsa_sexpr_to_pretty(Sexpr, Pretty),
	pp:pr(Out, 72, Pretty),
	nl(Out).

%% Create a pretty printing tree for each top-level CPSA form.
cpsa_sexpr_to_pretty([comment|X], Pretty) :-
	sexpr:sexpr_to_pretty([comment|X], Pretty).
cpsa_sexpr_to_pretty([herald|X], Pretty) :-
	sexpr:sexpr_to_pretty([herald|X], Pretty).
cpsa_sexpr_to_pretty([defskeleton|X], Pretty) :-
	sexpr_to_cpsa_pretty([defskeleton|X], Pretty).
cpsa_sexpr_to_pretty([defprotocol, Name, Alg|Roles], Pretty) :-
	pp:atm(defprotocol, X),
	pp:atm(Name, Y),
	pp:atm(Alg, Z),
	pp:atm('(', P),
	pp:atm(' ', S),
	sexpr_to_role_pretty(Roles, Pretties),
	pp:grp(2, [P, X, S, Y, S, Z, S|Pretties], Pretty).

%% CPSA role specific pretty printing support.
sexpr_to_role_pretty([[defrole|X]|Roles], [Space, Pretty|Pretties]) :-
	!,
	pp:brk(1, Space),
	sexpr_to_cpsa_pretty([defrole|X], Pretty),
	sexpr_to_role_pretty(Roles, Pretties).
sexpr_to_role_pretty(Sexprs, Pretties) :-
	sexprs_to_pretty(Sexprs, Pretties).

%% Creates a group in which breaks are allowed only before lists.
sexpr_to_cpsa_pretty(Thing, Pretty) :-
	atomic(Thing),
	!,
	sexpr:atom_to_pretty(Thing, Pretty).
sexpr_to_cpsa_pretty([Sexpr|Sexprs], Pretty) :-
	pp:atm('(', First),
	sexpr:sexpr_to_pretty(Sexpr, Second),
	sexprs_to_cpsa_pretty(Sexprs, Rest),
	pp:grp(2, [First, Second|Rest], Pretty).

sexprs_to_cpsa_pretty([], [Pretty]) :-
	pp:atm(')', Pretty).
sexprs_to_cpsa_pretty([Sexpr|Sexprs], [Space, Pretty|Pretties]) :-
	atomic(Sexpr),
	!,
	pp:atm(' ', Space),
	sexpr:sexpr_to_pretty(Sexpr, Pretty),
	sexprs_to_cpsa_pretty(Sexprs, Pretties).
sexprs_to_cpsa_pretty([Sexpr|Sexprs], [Space, Pretty|Pretties]) :-
	pp:brk(1, Space),
	sexpr:sexpr_to_pretty(Sexpr, Pretty),
	sexprs_to_cpsa_pretty(Sexprs, Pretties).

%% S-EXPRESSION TO INTERNAL FORM TRANSLATION

%% Programmer's hint--test translations with the query:
%%   cpsa:cpsa('../tst/blanchet.scm',A),
%%   cpsa:cpsas_to_sexprs(A, B),
%%   current_output(Out),
%%   cpsa:cpsa_sexprs_pp(Out, B).

%% Translate the contents of a file into the internal form
cpsa(File, Cpsas) :-
	sexpr:read_sexpr_list(File, Sexprs),
	sexprs_to_cpsas(Sexprs, Cpsas).

sexprs_to_cpsas([], []).
sexprs_to_cpsas([Sexpr|Sexprs], [Cpsa|Cpsas]) :-
	sexpr_to_cpsa(Sexpr, Cpsa),
	sexprs_to_cpsas(Sexprs, Cpsas).

%% Internal Form

%% There are four top-level forms in CPSA, comment, herald,
%% defprotocol, and defskeleton.
%%
%% Top ::= c(Comment)             -- Comment
%%      |  h(Name, Alist)         -- Herald
%%      |  p(Name, Alg, Roles)    -- Defprotocol
%%      |  k(Prot, Decls, Strands, Precedes, Nons, Uniqs).
%%                                -- Defskeleton
%% Role ::= r(Name, Decls, Trace, Nons, Uniqs).
%%                                -- Defrole
%% Decl ::= d(Sort, Vars).
%%
%% Trace ::= [Event].
%%
%% Event ::= send(Term) | recv(Term).
%%
%% Nons ::= [Term].
%%
%% Uniqs ::= [Term].
%%
%% Strand ::= s(RoleName, Height, Map).
%%
%% Height ::= Int.
%%
%% Map ::= [Maplet].
%%
%% Maplet ::= (Var, Term).
%%
%% Precede ::= ((Int, Int), (Int, Int)).
%%
%% Term ::= Var | Tag | invk(Term) | pubk(Term) | privk(Term)
%%       |  pubk(Term, Term) | privk(Term, Term) | ltk(Term, Term)
%%       |  cat(Term, Term) | enc(Term, Term) | hash(Term).
%%
%% Var ::= Atom.
%%
%% Tag ::= String.

sexpr_to_cpsa([comment|X], c(X)).
sexpr_to_cpsa([herald, Name|Alist], h(Name, Alist)).
sexpr_to_cpsa([defprotocol, Name, Alg|Rest],
	p(Name, Alg, Roles)) :-
	atom(Name), atom(Alg),
	sexpr_to_roles(Rest, Roles).
sexpr_to_cpsa([defskeleton, Prot, [vars|Vars]|Rest],
	k(Prot, Decls, Strands, Precedes, Nons, Uniqs)) :-
	atom(Prot),
	decls(Vars, Decls),
	sexpr_to_strands(Rest, Strands, Alist),
	lookup(precedes, Alist, Values),
	edges(Values, Precedes),
	lookup('non-orig', Alist, Snons),
	sexprs_to_terms(Snons, Nons),
	lookup('uniq-orig', Alist, Suniqs),
	sexprs_to_terms(Suniqs, Uniqs).

sexpr_to_roles([[defrole|Sexpr]|Rest], [Role|Roles]) :-
	!,
	sexpr_to_role(Sexpr, Role),
	sexpr_to_roles(Rest, Roles).
sexpr_to_roles(_, []).

sexpr_to_role([Name, [vars|Vars], [trace|Strace]|Alist],
	r(Name, Decls, Trace, Nons, Uniqs)) :-
	decls(Vars, Decls),
	sexprs_to_trace(Strace, Trace),
	lookup('non-orig', Alist, Snons),
	sexprs_to_terms(Snons, Nons),
	lookup('uniq-orig', Alist, Suniqs),
	sexprs_to_terms(Suniqs, Uniqs).

sexprs_to_trace([], []).
sexprs_to_trace([[send, Sexpr]|Strace], [send(Term)|Trace]) :-
	sexpr_to_term(Sexpr, Term),
	sexprs_to_trace(Strace, Trace).
sexprs_to_trace([[recv, Sexpr]|Strace], [recv(Term)|Trace]) :-
	sexpr_to_term(Sexpr, Term),
	sexprs_to_trace(Strace, Trace).

sexprs_to_terms([], []).
sexprs_to_terms([Sterm|Sterms], [Term|Terms]) :-
	sexpr_to_term(Sterm, Term),
	sexprs_to_terms(Sterms, Terms).

sexpr_to_term(Term, Term) :-
	atom(Term).
sexpr_to_term(Term, Term) :-
	string(Term).
sexpr_to_term([cat, Sterm], Term) :-
	sexpr_to_term(Sterm, Term).
sexpr_to_term([cat, Sterm1, Sterm2|Sterms], cat(Term1, Term)) :-
	sexpr_to_term(Sterm1, Term1),
	sexpr_to_term([cat, Sterm2|Sterms], Term).
sexpr_to_term([hash|Sterms], hash(Term)) :-
	sexpr_to_term([cat|Sterms], Term).
sexpr_to_term([enc|Sterms], enc(Term, Key)) :-
	split(Sterms, Cats, Sexpr),
	sexpr_to_term(Sexpr, Key),
	sexpr_to_term([cat|Cats], Term).
sexpr_to_term([privk|Sterms], invk(Term)) :-
	sexpr_to_term([pubk|Sterms], Term).
sexpr_to_term([Fun|Sterms], Term) :-
	atom(Fun),
	Fun \= cat,
	Fun \= hash,
	Fun \= enc,
	Fun \= privk,
	sexprs_to_terms(Sterms, Terms),
	Term =.. [Fun|Terms].

split([X, Y], [X], Y).
split([X, Y|Z], [X|U], V) :-
	split([Y|Z], U, V).

sexpr_to_strands([[defstrand|Sexpr]|Rest], [Strand|Strands], Alist) :-
	!,
	sexpr_to_strand([defstrand|Sexpr], Strand),
	sexpr_to_strands(Rest, Strands, Alist).
sexpr_to_strands([[deflistener|Sexpr]|Rest], [Strand|Strands], Alist) :-
	!,
	sexpr_to_strand([deflistener|Sexpr], Strand),
	sexpr_to_strands(Rest, Strands, Alist).
sexpr_to_strands(Alist, [], Alist).

sexpr_to_strand([defstrand, Role, Height|Sexprs], s(Role, Height, Map)) :-
	atom(Role),
	integer(Height),
	sexprs_to_map(Sexprs, Map).
sexpr_to_strand([deflistener, Sexpr], l(Term)) :-
	sexpr_to_term(Sexpr, Term).

decls([], []).
decls([Sexpr|Sexprs], [Decl|Decls]) :-
	decl(Sexpr, Decl),
	decls(Sexprs, Decls).

decl(Sexprs, d(Type, Vars)) :-
	decl_vars(Sexprs, Type, Vars).

decl_vars([Type], Type, []) :-
	!,
	atom(Type).
decl_vars([Var|Decl], Type, [Var|Vars]) :-
	atom(Var),
	decl_vars(Decl, Type, Vars).

sexprs_to_map([], []).
sexprs_to_map([[Key, Svalue]|Sexprs], [(Key, Value)|Map]) :-
	sexpr_to_term(Svalue, Value),
	sexprs_to_map(Sexprs, Map).

lookup(_, [], []).
lookup(Key, [[Key|Value]|Alist], Values) :-
	!,
	append(Value, Rest, Values),
	lookup(Key, Alist, Rest).
lookup(Key, [[_|_]|Alist], Values) :-
	lookup(Key, Alist, Values).

edges([], []).
edges([Sexpr|Sexprs], [Edge|Edges]) :-
	edge(Sexpr, Edge),
	edges(Sexprs, Edges).

edge([S0, S1], (N0, N1)) :-
	node(S0, N0),
	node(S1, N1).

node([S, P], (S, P)) :-
	integer(S),
	integer(P).

%% INTERNAL FORM TO S-EXPRESSION TRANSLATION

cpsas_to_sexprs([], []).
cpsas_to_sexprs([Cpsa|Cpsas], [Sexpr|Sexprs]) :-
	cpsa_to_sexpr(Cpsa, Sexpr),
	cpsas_to_sexprs(Cpsas, Sexprs).

cpsa_to_sexpr(c(X), [comment|X]).
cpsa_to_sexpr(h(Name, Alist), [herald, Name|Alist]).
cpsa_to_sexpr(p(Name, Alg, Roles), [defprotocol, Name, Alg|Rest]) :-
	roles_to_sexprs(Roles, Rest).
cpsa_to_sexpr(k(Prot, Decls, Strands, Precedes, Nons, Uniqs),
	[defskeleton, Prot, [vars|Vars]|Rest]) :-
	decls(Vars, Decls),
	preds(Precedes, Nons, Uniqs, Alist),
	strands_to_sexprs(Strands, Alist, Rest).

preds([], Nons, Uniqs, Alist) :-
	!,
	origs(Nons, Uniqs, Alist).
preds(Precedes, Nons, Uniqs, [[precedes|Sexprs]|Alist]) :-
	edges(Sexprs, Precedes),
	origs(Nons, Uniqs, Alist).

strands_to_sexprs([], Alist, Alist).
strands_to_sexprs([Strand|Strands], Alist, [Sexpr|Sexprs]) :-
	strand_to_sexpr(Strand, Sexpr),
	strands_to_sexprs(Strands, Alist, Sexprs).

strand_to_sexpr(s(Role, Height, Map), [defstrand, Role, Height|Sexprs]) :-
	map_to_sexprs(Map, Sexprs).
strand_to_sexpr(l(Term), [deflistener, Sexpr]) :-
	term_to_sexpr(Term, Sexpr).

map_to_sexprs([], []).
map_to_sexprs([(Key, Value)|Map], [[Key, Svalue]|Sexprs]) :-
	term_to_sexpr(Value, Svalue),
	map_to_sexprs(Map, Sexprs).

roles_to_sexprs([], []).
roles_to_sexprs([Role|Roles], [Sexpr|Sexprs]) :-
	role_to_sexpr(Role, Sexpr),
	roles_to_sexprs(Roles, Sexprs).

role_to_sexpr(r(Name, Decls, Trace, Nons, Uniqs),
	[defrole, Name, [vars|Vars], [trace|Strace]|Alist]) :-
	decls(Vars, Decls),
	traces_to_sexprs(Trace, Strace),
	origs(Nons, Uniqs, Alist).

traces_to_sexprs([], []).
traces_to_sexprs([send(Term)|Trace], [[send, Sterm]|Straces]) :-
	term_to_sexpr(Term, Sterm),
	traces_to_sexprs(Trace, Straces).
traces_to_sexprs([recv(Term)|Trace], [[recv, Sterm]|Straces]) :-
	term_to_sexpr(Term, Sterm),
	traces_to_sexprs(Trace, Straces).

origs([], Uniqs, Alist) :-
	!,
	uniq_origs(Uniqs, Alist).
origs(Nons, Uniqs, [['non-orig'|Snons]|Alist]) :-
	terms_to_sexprs(Nons, Snons),
	uniq_origs(Uniqs, Alist).

uniq_origs([], []) :- !.
uniq_origs(Uniqs, [['uniq-orig'|Suniqs]]) :-
	terms_to_sexprs(Uniqs, Suniqs).

terms_to_sexprs([], []).
terms_to_sexprs([Term|Terms], [Sexpr|Sexprs]) :-
	term_to_sexpr(Term, Sexpr),
	terms_to_sexprs(Terms, Sexprs).

term_to_sexpr(Term, Term) :-
	atom(Term).
term_to_sexpr(Term, Term) :-
	string(Term).
term_to_sexpr(cat(Term1, Term2), [cat, Sterm1|Sterms]) :-
	term_to_sexpr(Term1, Sterm1),
	term_to_sexprs(Term2, Sterms).
term_to_sexpr(hash(Term), [hash|Sterms]) :-
	term_to_sexprs(Term, Sterms).
term_to_sexpr(enc(Term, Key), [enc|All]) :-
	term_to_sexpr(Key, Sexpr),
	term_to_sexprs(Term, Sterms),
	split(All, Sterms, Sexpr).
term_to_sexpr(invk(Term), [privk|Sterms]) :-
	Term =.. [pubk|Args],
	!,
	terms_to_sexprs(Args, Sterms).
term_to_sexpr(Term, [Fun, Sterm|Sterms]) :-
	Term =.. [Fun, Arg|Args],
	Fun \= cat,
	Fun \= hash,
	Fun \= enc,
	term_to_sexpr(Arg, Sterm),
	terms_to_sexprs(Args, Sterms).

term_to_sexprs(cat(Term1, Term2), [Sterm1|Sterms]) :-
	!,
	term_to_sexpr(Term1, Sterm1),
	term_to_sexprs(Term2, Sterms).
term_to_sexprs(Term, [Sterm]) :-
	term_to_sexpr(Term, Sterm).