% -*- 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).