--- /dev/null
+/*******************************************************************\r
+ *\r
+ * A Lisp compiler, written in Prolog\r
+ *\r
+ * (builtin_lisp_functions.pl)\r
+ *\r
+ * (c) Neil Smith, 2001\r
+ *\r
+ * This program provides some built-in functionality for the \r
+ * Lisp compiler. It requires that the file lisp_compiler.pl has \r
+ * already been successfully compiled.\r
+ *\r
+ *******************************************************************/\r
+\r
+\r
+\r
+:- ensure_loaded(library(writef)).\r
+:- use_module(library(lists)).\r
+\r
+\r
+first(List, Result):-\r
+ once(( List = [Result|_]\r
+ ; lisp_error_description(first_not_cons, ErrMsg),\r
+ throw(error(first_not_cons(List), context(first, ErrMsg))) )).\r
+\r
+rest(List, Result):-\r
+ once(( List = [_|Result]\r
+ ; lisp_error_description(rest_not_cons, ErrMsg),\r
+ throw(error(first_not_cons(List), context(first, ErrMsg))) )).\r
+\r
+cons(Item, List, Result):-\r
+ Result = [Item|List].\r
+\r
+null(Item, Result):-\r
+ Item = []\r
+ -> Result = t\r
+ ; Result = [].\r
+\r
+eq(Item1, Item2, Result):-\r
+ Item1 == Item2\r
+ -> Result = t\r
+ ; Result = [].\r
+\r
+equalp(Item1, Item2, Result):-\r
+ Item1 = Item2\r
+ -> Result = t\r
+ ; Result = [].\r
+\r
+\r
+plus(Num1, Num2, Result):-\r
+ Result is Num1 + Num2.\r
+minus(Num1, Num2, Result):-\r
+ Result is Num1 - Num2.\r
+times(Num1, Num2, Result):-\r
+ Result is Num1 * Num2.\r
+divide(Num1, Num2, Result):-\r
+ Result is Num1 / Num2.\r
+\r
+\r
+lisp_not(Boolean, Result):-\r
+ Boolean = []\r
+ -> Result = t\r
+ ; Result = [].\r
+\r
+or(Bool1, Bool2, Result):-\r
+ once(Bool1 \= [] ; Bool2 \= [])\r
+ -> Result = t\r
+ ; Result = [].\r
+\r
+and(Bool1, Bool2, Result):-\r
+ (Bool1 \= [] , Bool2 \= [])\r
+ -> Result = t\r
+ ; Result = [].\r
+\r
+\r
+lisp_apply(FunctionObject, Arguments, Result):-\r
+ % FunctionObject = closure(FormalArgs, Body, Environment)\r
+ FunctionObject = closure(FormalArgs, Body, ClosureEnvironment, Environment)\r
+ -> % zip_with(FormalArgs, Arguments, [Arg, Val, binding(Arg, [Val|_])]^true, Bindings),\r
+ maplist(make_binding, FormalArgs, Arguments, Bindings),\r
+ append(ClosureEnvironment, Environment, ActualEnvironment),\r
+ % apply(Body, [[Bindings|Environment], Result])\r
+ apply(Body, [[Bindings|ActualEnvironment], Result])\r
+ ; FunctionObject = function(FunctionName), \r
+ append(Arguments, [Result], ArgumentsResult),\r
+ Function =.. [FunctionName|ArgumentsResult],\r
+ call(Function).\r
+\r
+\r
+extract_variable_value([Val|Vals], FoundVal, Hole):-\r
+ var(Vals)\r
+ -> FoundVal = Val,\r
+ Hole = Vals\r
+ ; extract_variable_value(Vals, FoundVal, Hole).\r
+\r
+\r
+lisp_call(Function, Result):-\r
+ apply(Function, [Result]).\r
+\r
+\r
+\r
+/*\r
+show_special:-\r
+ setof(sv(Var, Value), special_var(Var, Value), SVs)\r
+ -> format('Variable ~tValue~n~n'),\r
+ maplist((sv(Var2, Value2), format('~w :~t~w~n', [Var2, Value2])), SVs)\r
+ ; format('No special variables~n').\r
+*/\r
+\r
+show_special:-\r
+ setof(sv(Var, Value), special_var(Var, Value), SVs),\r
+ !,\r
+ format('Variable ~tValue~20|~n~n'),\r
+ % maplist((sv(Var2, Value2), format('~w :~t~w~n', [Var2, Value2])), SVs).\r
+ maplist(show_one_special, SVs).\r
+show_special:-\r
+ format('No special variables~n').\r
+\r
+show_one_special(sv(Var, Value)):-\r
+ format('~w :~t~w~20|~n', [Var, Value]).
\ No newline at end of file
--- /dev/null
+/*******************************************************************\r
+ *\r
+ * A Lisp compiler, written in Prolog\r
+ *\r
+ * (lisp_compiler.pl)\r
+ *\r
+ * (c) Neil Smith, 2001\r
+ *\r
+ * This program, and its associated support files, forms a compiler\r
+ * for a subset of the language LISP. It supports a few simple \r
+ * built-in procedures, listed below. It also supports both special\r
+ * and lexical variables, and higher-order functions and lexical\r
+ * closures.\r
+ *\r
+ * This compiler was written in LPA Prolog v3.6 under MS Windows.\r
+ * It should run under other Prologs without too much conversion needed,\r
+ * but note the required library modules.\r
+ *\r
+ *\r
+ * Special forms\r
+ *\r
+ * [] and nil are treated as special forms, evaluating to [], and treated as 'false'\r
+ * t is a special form, evaluating to t, and treated as 'true'\r
+ * if, cond\r
+ * progn (and implicit progn in defun and let bodies)\r
+ * quote\r
+ * let\r
+ * setq\r
+ * function\r
+ * lambda\r
+ * defvar, defparameter (both with and without initial values)\r
+ * \r
+ * Built-in procedures (defined in builtin_lisp_functions.pl)\r
+ *\r
+ * cons, first, rest, null\r
+ * eq, equalp\r
+ * plus, minus, times, divide\r
+ * lisp_not, or, and\r
+ * lisp_apply\r
+ * \r
+ * Other procedures are defined in lisp_library.pl\r
+ *\r
+ *******************************************************************/\r
+\r
+/*******************************************************************\r
+ *\r
+ * Example definitions:\r
+ * second(l) <<== first(rest(l)).\r
+ * list_3(a, b, c) <<== cons(a, cons(b, cons(c, nil))).\r
+ * \r
+ * Example use:\r
+ * ?| - lisp_call(second([a,b,c]), Result).\r
+ * Result = b\r
+ *\r
+ * ?| - second([a,b,c], Result).\r
+ * Result = b\r
+ *\r
+ * ?| - lisp_call(list_3(tom, dick, harry), Result).\r
+ * Result = [tom, dick, harry]\r
+ * \r
+ * ?| - list_3(tom, dick, harry, Result).\r
+ * Result = [tom, dick, harry]\r
+ *\r
+ *******************************************************************/\r
+\r
+:- style_check([+singleton, +no_effect, +var_branches, +atom, +discontiguous, \r
+ +charset]).\r
+\r
+:- use_module(library(apply)).\r
+\r
+% :- ensure_loaded(library(higher_order)).\r
+% :- ensure_loaded(library(list_utilities)).\r
+\r
+\r
+% :- ensure_loaded(builtin_lisp_functions). % Lisp primitives: this directives is at the end of the file\r
+% :- ensure_loaded(lisp_library). % Functions defined in lisp: this directive is at the end of the file\r
+ % allowing them to be compiled correctly\r
+\r
+\r
+:- op(1200, xfx, <<== ). % function definition\r
+:- op(1200, fx, <<== ). % functional imperative definition\r
+\r
+:- dynamic special_var/2. % closure environments\r
+\r
+\r
+% Connection to LPA's built-in error handler\r
+\r
+/*\r
+'?ERROR?'(Error, Form):-\r
+ lisp_error_description(_, Error, Description),\r
+ !,\r
+ write('LISP ERROR '),\r
+ write(Description),\r
+ write(Form),\r
+ nl.\r
+'?ERROR?'(Error, Goal):-\r
+ error_hook(Error, Goal).\r
+*/\r
+\r
+lisp_error_description(unbound_atom, 'No value found for atom: ').\r
+lisp_error_description(atom_does_not_exist, 'Setq: Variable does not exist: ').\r
+lisp_error_description(first_not_cons, 'First: This is not a cons cell: ').\r
+lisp_error_description(rest_not_cons, 'Rest: This is not a cons cell: ').\r
+\r
+\r
+make_binding(Arg, Val, binding(Arg, [Val|_])).\r
+make_environment(Variable, Form, bind(Variable, Form)).\r
+\r
+\r
+% The hook into the compiler\r
+\r
+term_expansion( (FunctionHead <<== FunctionBody), \r
+ (Head :- Body) ):-\r
+ expand_function_head(FunctionHead, Head, ArgBindings, Result),\r
+ expand_function_body(implicit_progn(FunctionBody), Result, Body, [ArgBindings]).\r
+\r
+term_expansion( ( <<== FunctionBody), \r
+ ( :- Body) ):-\r
+ expand_function_body(implicit_progn(FunctionBody), _Result, Body, []).\r
+\r
+\r
+expand_function_head(FunctionHead, Head, ArgBindings, Result):-\r
+ FunctionHead =.. [FunctionName | FormalArgs],\r
+ % compound_name_arguments(FunctionHead, FunctionName, FormalArgs),\r
+ % zip_with(FormalArgs, ActualArgs, [Arg, Val, binding(Arg, [Val|_])]^true, ArgBindings),\r
+ maplist(make_binding, FormalArgs, ActualArgs, ArgBindings),\r
+ append(ActualArgs, [Result], HeadArgs),\r
+ Head =.. [FunctionName | HeadArgs].\r
+ % compound_name_arguments(Head, FunctionName, HeadArgs).\r
+\r
+\r
+% expand_function_body(Function, Result, Body, Environment).\r
+% Expands a Lisp-like function body into its Prolog equivalent\r
+expand_function_body(nil, [], true, _Environment):-\r
+ !.\r
+expand_function_body([], [], true, _Environment):-\r
+ !.\r
+expand_function_body(t, t, true, _Environment):-\r
+ !.\r
+expand_function_body(if(Test, IfTrue, IfFalse), Result, Body, Environment):-\r
+ !,\r
+ expand_function_body(Test, TestResult, TestBody, Environment),\r
+ expand_function_body(IfTrue, TrueResult, TrueBody, Environment),\r
+ expand_function_body(IfFalse, FalseResult, FalseBody, Environment),\r
+ Body = ( TestBody,\r
+ ( TestResult \= []\r
+ -> TrueBody, \r
+ Result = TrueResult\r
+ ; FalseBody, \r
+ Result = FalseResult ) ).\r
+\r
+expand_function_body(cond([]), [], true, _Environment):-\r
+ !.\r
+expand_function_body(cond([ [Test|ResultForms] |Clauses]), Result, Body, Environment):-\r
+ !,\r
+ expand_function_body(Test, TestResult, TestBody, Environment),\r
+ expand_progn(ResultForms, TestResult, ResultFormsResult, ResultFormsBody, Environment),\r
+ expand_function_body(cond(Clauses), ClausesResult, ClausesBody, Environment),\r
+ Body = ( TestBody,\r
+ ( TestResult \= []\r
+ -> ResultFormsBody,\r
+ Result = ResultFormsResult\r
+ ; ClausesBody,\r
+ Result = ClausesResult ) ).\r
+\r
+expand_function_body(progn(Forms), Result, Body, Environment):-\r
+ !,\r
+ expand_progn(Forms, [], Result, Body, Environment).\r
+\r
+expand_function_body(implicit_progn(Forms), Result, Body, Environment):-\r
+ !,\r
+ % (once (Forms = [] ; Forms = [_|_] )\r
+ is_list(Forms)\r
+ -> expand_progn(Forms, [], Result, Body, Environment)\r
+ ; expand_function_body(Forms, Result, Body, Environment).\r
+\r
+\r
+expand_function_body(setq(Atom, ValueForm), Result, Body, Environment):-\r
+ !,\r
+ lisp_error_description(atom_does_not_exist, ErrMsg),\r
+ expand_function_body(ValueForm, Result, ValueBody, Environment),\r
+ Body = ( ValueBody,\r
+ ( member(Bindings, Environment),\r
+ member(binding(Atom, Value0), Bindings)\r
+ -> extract_variable_value(Value0, _, Hole),\r
+ Hole = [Result|_]\r
+ ; special_var(Atom, Old)\r
+ -> once(retract(special_var(Atom, Old))),\r
+ assert(special_var(Atom, Result))\r
+ ; throw(error(atom_does_not_exist(Atom), context(setq, ErrMsg))) ) ).\r
+\r
+expand_function_body(quote(Item), Item, true, _Environment):-\r
+ !.\r
+\r
+expand_function_body(let(NewBindings, BodyForms), Result, Body, Environment):-\r
+ !,\r
+ % zip_with(Variables, ValueForms, [Variable, Form, bind(Variable, Form)]^true, NewBindings),\r
+ maplist(make_environment, Variables, ValueForms, NewBindings),\r
+ expand_arguments(ValueForms, ValueBody, Values, Environment),\r
+ % zip_with(Variables, Values, [Var, Val, binding(Var, [Val|_])]^true, Bindings),\r
+ maplist(make_binding, Variables, Values, Bindings),\r
+ Body = ( ValueBody, BodyFormsBody ),\r
+ expand_function_body(implicit_progn(BodyForms), Result, BodyFormsBody, \r
+ [Bindings|Environment]).\r
+\r
+expand_function_body(function(lambda(LambdaArgs, LambdaBody)), Result, Body, Environment):-\r
+ !,\r
+ expand_function_body(implicit_progn(LambdaBody), ClosureResult, ClosureBody, ClosureEnvironment),\r
+ Result = closure(LambdaArgs, \r
+ [ClosureEnvironment, ClosureResult]^ClosureBody, \r
+ Environment),\r
+ Body = true.\r
+\r
+expand_function_body(function(Function), function(Function), true, _Environment):-\r
+ !.\r
+\r
+expand_function_body(defvar(Var), Result, Body, Environment):-\r
+ !,\r
+ expand_function_body(defvar(Var, nil), Result, Body, Environment).\r
+expand_function_body(defvar(Var, Value), Result, Body, Environment):-\r
+ !,\r
+ expand_function_body(Value, Result, ValueBody, Environment),\r
+ Body = ( ValueBody,\r
+ ( special_var(Var, _)\r
+ -> true\r
+ ; assert(special_var(Var, Result)) ) ).\r
+expand_function_body(defparameter(Var), Result, Body, Environment):-\r
+ !,\r
+ expand_function_body(defparameter(Var, nil), Result, Body, Environment).\r
+expand_function_body(defparameter(Var, Value), Result, Body, Environment):-\r
+ !,\r
+ expand_function_body(Value, Result, ValueBody, Environment),\r
+ Body = ( ValueBody,\r
+ ( special_var(Var, _)\r
+ -> one(retract(special_var(Var, _)))\r
+ ; true ),\r
+ assert(special_var(Var, Result)) ).\r
+\r
+expand_function_body(Number, Number, true, _Environment):-\r
+ number(Number),\r
+ !.\r
+\r
+expand_function_body(Atom, Value, Body, Environment):-\r
+ atom(Atom),\r
+ !,\r
+ lisp_error_description(unbound_atom, ErrMsg),\r
+ Body = (once(( member(Bindings, Environment),\r
+ member(binding(Atom, Value0), Bindings),\r
+ extract_variable_value(Value0, Value, _)\r
+ ; special_var(Atom, Value)\r
+ ; throw(error(unbound_atom(Atom), context(atom, ErrMsg))) )) ). \r
+\r
+% Non built-in function expands into an explicit function call\r
+expand_function_body(Function, Result, Body, Environment):-\r
+ !,\r
+ Function =.. [FunctionName | FunctionArgs],\r
+ % compound_name_arguments(Function, FunctionName, FunctionArgs),\r
+ expand_arguments(FunctionArgs, ArgBody, Args, Environment),\r
+ append(Args, [Result], ArgsResult),\r
+ ExpandedFunction =.. [FunctionName | ArgsResult],\r
+ % compound_name_arguments(ExpandedFunction, FunctionName, ArgsResult),\r
+ Body = ( ArgBody,\r
+ ExpandedFunction ).\r
+\r
+ expand_arguments([], true, [], _Environment).\r
+ expand_arguments([Arg|Args], Body, [Result|Results], Environment):-\r
+ expand_function_body(Arg, Result, ArgBody, Environment),\r
+ Body = (ArgBody, ArgsBody),\r
+ expand_arguments(Args, ArgsBody, Results, Environment).\r
+\r
+\r
+expand_progn([], Result, Result, true, _Environment).\r
+expand_progn([Form | Forms], _PreviousResult, Result, Body, Environment):-\r
+ expand_function_body(Form, FormResult, FormBody, Environment),\r
+ Body = (FormBody, FormsBody),\r
+ expand_progn(Forms, FormResult, Result, FormsBody, Environment).\r
+\r
+\r
+% Now Prolog can understand them, compile the additional library files\r
+\r
+:- ensure_loaded(builtin_lisp_functions).\r
+:- ensure_loaded(lisp_library).\r