epsilon-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[epsilon-devel] Interpreters in epsilon


From: Luca Saiu
Subject: [epsilon-devel] Interpreters in epsilon
Date: Fri, 28 Nov 2003 08:38:45 +0100
User-agent: Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.3a) Gecko/20021212

  Hi Matteo,

this night I wrote an interpreter for a functional language in epsilon in two versions, eager and lazy; it is amazingly simple. We could build the meta-circular interpreter on this basement. I'm attaching the source files. If you are going to some lessons about languages then you should understand it; otherwise don't mind, you will understand it soon :-). In this days I am eagerly watching the SICP video lessons; they are wonderful. SICP (the Wizard book) is a great source of ideas, also for epsilon; you should have a copy of the book on your laptop. *If* you have some spare time you can skim chapter 4; it explains meta-circular interpreters; it's a relatively complicated subject, don't be frightened if you don't get all details yet. Of course we don't have a working parser yet, and for the interpreters we are still forced to use abstract syntax, which is a pain. Damn, I must work on epsilonyacc. It's top priority.
  However the thing works really well.

When you have some time, could you please make that test on GC times which I asked a couple of days ago? Wihtout too haste, however; the garbage collector is perfectly usable even as it is now and I don't think I will modify it very soon.

  Have a good day,

--
Luca Saiu, maintainer of GNU epsilon
http://www.gnu.org/software/epsilon
/* This file is part of an experimental interpreter

Copyright (C) 2002 Luca Saiu

GNU epsilon is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 2, or (at your
option) any later version.

GNU epsilon is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
General Public License for more details.

You should have received a copy of the GNU General Public License
along with epsilon; see the file COPYING.  If not, write to the
Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */


declare abstract type environment;
/* This file is part of an experimental interpreter

Copyright (C) 2002 Luca Saiu

GNU epsilon is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 2, or (at your
option) any later version.

GNU epsilon is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
General Public License for more details.

You should have received a copy of the GNU General Public License
along with epsilon; see the file COPYING.  If not, write to the
Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */


define concrete type expression =
  INTEGER of integer
| BOOLEAN of boolean
| VARIABLE of string
| IF of expression * expression * expression
| LAMBDA of string * expression
| APPLY of expression * expression
| REC of string * string * expression;

define APPLY3 = \ x_y_z .
  APPLY(APPLY(x_y_z ^ 1, x_y_z ^ 2), x_y_z ^ 3);

define concrete type value =
  Integer of integer
| Boolean of boolean
| Cons of value * value
| Closure of string * expression * environment
| Primitive of value -> value;

define output_value = fix \ f . \ v .
  match v with
    Integer(i) -> output_integer i
  | Boolean(b) -> if b then output_string "true" else output_string "false"
  | Closure(c) -> output_string "<function>"
  | Primitive(p) -> output_string "<primitive>"
  | Cons(v1_v2) -> begin
                     output_string "( ";
                     f (v1_v2 ^ 1);
                     output_string " . ";
                     f (v1_v2 ^ 2);
                     output_string " )";
                   end;

define exception error;
define exception type_error = expression;
define exception not_a_function = value;

define extract_integer = \ v .
  match v with
    Integer(i) -> i
  | _ -> throw error;

define extract_boolean = \ v .
  match v with
    Boolean(b) -> b
  | _ -> throw error;

define extract_carcdr = \ v .
  match v with
    Cons(v1_v2) -> v1_v2
  | _ -> throw error;

define abstract type environment =
  associative_array of string, value;

define binary_to_curried_primitive = \ bop : value -> value -> value .
  Primitive(\ first . Primitive(\ second . bop first second));

define my_not = 
  Primitive(\ x . Boolean(not (extract_boolean x)));

define my_integer_bop = \ op . 
  binary_to_curried_primitive
    (\ a . \ b . Integer(op (extract_integer a) (extract_integer b)));
define my_compare_bop = \ op . 
  binary_to_curried_primitive
    (\ a . \ b . Boolean(op (extract_integer a) (extract_integer b)));
define my_connective_bop = \ op . 
  binary_to_curried_primitive
    (\ a . \ b . Boolean(op (extract_boolean a) (extract_boolean b)));

define empty_environment = 
  empty_associative_array (\ x . \ y . x <s y) (\ x . \ y . x =s y) Integer(1);
define initial_environment = insert_list_into_associative_array
  ["not", my_not;
   "+", my_integer_bop (\ x . \ y . x + y);
   "-", my_integer_bop (\ x . \ y . x - y);
   "*", my_integer_bop (\ x . \ y . x * y);
   "/", my_integer_bop (\ x . \ y . x / y);
   "and", my_connective_bop (\ x . \ y . x and y);
   "or", my_connective_bop (\ x . \ y . x or y);
   "xor", my_connective_bop (\ x . \ y . x xor y);
   "<", my_compare_bop (\ x . \ y . x < y);
   "<=", my_compare_bop (\ x . \ y . x <= y);
   ">", my_compare_bop (\ x . \ y . x > y);
   ">=", my_compare_bop (\ x . \ y . x >= y);
   "=", my_compare_bop (\ x . \ y . x = y);
   "=/=", my_compare_bop (\ x . \ y . x =/= y);
   "cons", binary_to_curried_primitive(\ x . \ y . Cons(x, y));
   "car", Primitive(\ x . (extract_carcdr x) ^ 1);
   "cdr", Primitive(\ x . (extract_carcdr x) ^ 2);
  ]
  empty_environment;

define bind = \ n . \ v . \ env : environment .
  insert_into_associative_array n v env;

define lookup = \ n . \ env : environment .
  lookup_associative_array n env;


declare eval : expression -> environment -> value;
declare my_apply : value -> value -> value;
declare make_rec : string -> string -> expression -> environment -> value;
define eval = fix \ f . \ exp . \ env .
  match exp with
    INTEGER(i) -> Integer(i)
  | BOOLEAN(b) -> Boolean(b)
  | VARIABLE(v) -> lookup v env
  | IF(c_e1_e2) -> (match f (c_e1_e2 ^ 1) env with
                      Boolean(c) -> if c then
                                      f (c_e1_e2 ^ 2) env
                                    else
                                      f (c_e1_e2 ^ 3) env
                    | _ -> throw type_error exp)
  | LAMBDA(v_e) -> Closure(v_e ^ 1, v_e ^ 2, env)
  | APPLY(e1_e2) -> my_apply (f (e1_e2 ^ 1) env) (f (e1_e2 ^ 2) env)
  | REC(f_v_exp) -> make_rec (f_v_exp ^ 1) (f_v_exp ^ 2) (f_v_exp ^ 3) env
//  | _ -> throw error
;

define make_rec = \ func . \ v . \ exp . \ env .
  Closure(v,
          exp,
          bind func
               Primitive(\ z . my_apply (eval REC(func, v, exp) env) z)
               env);

define my_apply = \ v1 . \ v2 .
  match v1 with
    Primitive(p) -> p v2
  | Closure(var_exp_env) ->
      eval (var_exp_env ^ 2)
           (bind (var_exp_env ^ 1) v2 (var_exp_env ^ 3))
  | _ -> throw not_a_function v1;

define program1 =
  IF(BOOLEAN(false),
     INTEGER(10),
     INTEGER(23));

define program2 =
  APPLY(VARIABLE("not"), BOOLEAN(true));

define square = 
  LAMBDA("x", APPLY3(VARIABLE("*"), VARIABLE("x"), VARIABLE("x")));

define fact =
  REC("fact",
      "n",
      IF(APPLY3(VARIABLE("="), VARIABLE("n"), INTEGER(0)),
         INTEGER(1),
         APPLY3(VARIABLE("*"),
                VARIABLE("n"),
                APPLY(VARIABLE("fact"),
                      APPLY3(VARIABLE("-"), VARIABLE("n"), INTEGER(1))))));

define five =
  APPLY(APPLY(VARIABLE("+"),
              INTEGER(2)),
        INTEGER(3));

define program3 = APPLY(fact, INTEGER(10));

//define program = APPLY3(VARIABLE("cons"), INTEGER(1), INTEGER(2));

define dontstopf = REC("f", "x", APPLY(VARIABLE("f"), VARIABLE("x")));

define dontstop = APPLY(dontstopf, INTEGER(1));

define program = APPLY(dontstopf, INTEGER(1));

define main = begin
  output_value (eval program initial_environment);
  output_string "\n";
end;
/* This file is part of an experimental interpreter

Copyright (C) 2002 Luca Saiu

GNU epsilon is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 2, or (at your
option) any later version.

GNU epsilon is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
General Public License for more details.

You should have received a copy of the GNU General Public License
along with epsilon; see the file COPYING.  If not, write to the
Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */


declare abstract type environment;
/* This file is part of an experimental interpreter

Copyright (C) 2002 Luca Saiu

GNU epsilon is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 2, or (at your
option) any later version.

GNU epsilon is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
General Public License for more details.

You should have received a copy of the GNU General Public License
along with epsilon; see the file COPYING.  If not, write to the
Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */


define concrete type expression =
  INTEGER of integer
| BOOLEAN of boolean
| SYMBOL of string
| VARIABLE of string
| IF of expression * expression * expression
| LAMBDA of string * expression
| APPLY of expression * expression
| REC of string * string * expression;

define APPLY3 = \ x_y_z .
  APPLY(APPLY(x_y_z ^ 1, x_y_z ^ 2), x_y_z ^ 3);

define concrete type value =
  Integer of integer
| Boolean of boolean
| Symbol of string
| Cons of value * value
| Closure of string * expression * environment
| Primitive of value -> value
| Thunk of promise of value;

define exception error;
define exception type_error = expression;
define exception not_a_function = value;

declare eval : expression -> environment -> value;
declare my_apply : value -> value -> value;
declare make_rec : string -> string -> expression -> environment -> value;
declare force_thunk : value -> value;

define output_value = fix \ f . \ v .
  match v with
    Integer(i) -> output_integer i
  | Boolean(b) -> if b then output_string "true" else output_string "false"
  | Symbol(s) -> output_string s
  | Closure(c) -> output_string "<function>"
  | Primitive(p) -> output_string "<primitive>"
  | Cons(v1_v2) -> begin
                     output_string "(";
                     f (v1_v2 ^ 1);
                     output_string " . ";
                     f (v1_v2 ^ 2);
                     output_string ")";
                   end
  | Thunk(t) -> begin
//                  output_string "<";
                  f (force_thunk (force t));
//                  output_string "<thunk>";
//                  output_string ">";
                end;

define force_thunk = fix \ f . \ v .
  match v with
    Thunk(t) -> f (force t)
  | _ -> v; // not a thunk, return v as it is

define extract_integer = \ v .
  match force_thunk v with
    Integer(i) -> i
  | _ -> throw error;

define extract_boolean = \ v .
  match force_thunk v with
    Boolean(b) -> b
  | _ -> throw error;

define extract_carcdr = \ v .
  match force_thunk v with
    Cons(v1_v2) -> v1_v2
  | _ -> throw error;

define abstract type environment =
  associative_array of string, value;

define binary_to_curried_primitive = \ bop : value -> value -> value .
  Primitive(\ first . Primitive(\ second . bop first second));

define my_not = 
  Primitive(\ x . Boolean(not (extract_boolean x)));

define my_integer_bop = \ op . 
  binary_to_curried_primitive
    (\ a . \ b . Integer(op (extract_integer a) (extract_integer b)));
define my_compare_bop = \ op . 
  binary_to_curried_primitive
    (\ a . \ b . Boolean(op (extract_integer a) (extract_integer b)));
define my_connective_bop = \ op . 
  binary_to_curried_primitive
    (\ a . \ b . Boolean(op (extract_boolean a) (extract_boolean b)));

define empty_environment = 
  empty_associative_array (\ x . \ y . x <s y) (\ x . \ y . x =s y) Integer(1);
define initial_environment = insert_list_into_associative_array
  ["not", my_not;
   "+", my_integer_bop (\ x . \ y . x + y);
   "-", my_integer_bop (\ x . \ y . x - y);
   "*", my_integer_bop (\ x . \ y . x * y);
   "/", my_integer_bop (\ x . \ y . x / y);
   "and", my_connective_bop (\ x . \ y . x and y);
   "or", my_connective_bop (\ x . \ y . x or y);
   "xor", my_connective_bop (\ x . \ y . x xor y);
   "<", my_compare_bop (\ x . \ y . x < y);
   "<=", my_compare_bop (\ x . \ y . x <= y);
   ">", my_compare_bop (\ x . \ y . x > y);
   ">=", my_compare_bop (\ x . \ y . x >= y);
   "=", my_compare_bop (\ x . \ y . x = y);
   "=/=", my_compare_bop (\ x . \ y . x =/= y);
   "cons", binary_to_curried_primitive(\ x . \ y . Cons(x, y));
   "car", Primitive(\ x . (extract_carcdr x) ^ 1);
   "cdr", Primitive(\ x . (extract_carcdr x) ^ 2);
  ]
  empty_environment;

define bind = \ n . \ v . \ env : environment .
  insert_into_associative_array n v env;

define lookup = \ n . \ env : environment .
  lookup_associative_array n env;


define eval = fix \ f . \ exp . \ env .
  match exp with
    INTEGER(i) -> Integer(i)
  | BOOLEAN(b) -> Boolean(b)
  | SYMBOL(s) -> Symbol(s)
  | VARIABLE(v) -> lookup v env
  | IF(c_e1_e2) -> (match force_thunk (f (c_e1_e2 ^ 1) env) with
                      Boolean(c) -> if c then
                                      f (c_e1_e2 ^ 2) env
                                    else
                                      f (c_e1_e2 ^ 3) env
                    | _ -> throw type_error exp)
  | LAMBDA(v_e) -> Closure(v_e ^ 1, v_e ^ 2, env)
  | APPLY(e1_e2) -> my_apply (f (e1_e2 ^ 1) env)
                             Thunk(delay (f (e1_e2 ^ 2) env))
  | REC(f_v_exp) -> make_rec (f_v_exp ^ 1) (f_v_exp ^ 2) (f_v_exp ^ 3) env
//  | _ -> throw error
;

define make_rec = \ func . \ v . \ exp . \ env .
  Closure(v,
          exp,
          bind func
               Primitive(\ z . my_apply (eval REC(func, v, exp) env) z)
               env);

define my_apply = \ v1 . \ v2 .
  match force_thunk v1 with
    Primitive(p) -> p v2
  | Closure(var_exp_env) ->
      eval (var_exp_env ^ 2)
           (bind (var_exp_env ^ 1) v2 (var_exp_env ^ 3))
  | _ -> debug force_thunk v1 in throw not_a_function v1;

define program1 =
  IF(BOOLEAN(false),
     INTEGER(10),
     INTEGER(23));

define program2 =
  APPLY(VARIABLE("not"), BOOLEAN(true));

define square = 
  LAMBDA("x", APPLY3(VARIABLE("*"), VARIABLE("x"), VARIABLE("x")));

define fact =
  REC("fact",
      "n",
      IF(APPLY3(VARIABLE("="), VARIABLE("n"), INTEGER(0)),
         INTEGER(1),
         APPLY3(VARIABLE("*"),
                VARIABLE("n"),
                APPLY(VARIABLE("fact"),
                      APPLY3(VARIABLE("-"), VARIABLE("n"), INTEGER(1))))));

define five =
  APPLY(APPLY(VARIABLE("+"),
              INTEGER(2)),
        INTEGER(3));

define program3 = APPLY(fact, INTEGER(10));

//define program = APPLY3(VARIABLE("cons"), INTEGER(1), INTEGER(2));

define dontstopf = REC("f", "x", APPLY(VARIABLE("f"), VARIABLE("x")));

define dontstop = APPLY(dontstopf, INTEGER(1));

define cons = LAMBDA("a",
                     LAMBDA("b",
                            APPLY3(VARIABLE("cons"), 
                                   VARIABLE("a"), 
                                   VARIABLE("b"))));

define f = LAMBDA("x",
                  LAMBDA("y",
                         APPLY3(VARIABLE("+"),
                                VARIABLE("y"),
                                INTEGER(2))));

define naturals_function =
  REC("f",
      "n",
      APPLY3(cons,
             VARIABLE("n"),
             APPLY(VARIABLE("f"), APPLY3(VARIABLE("+"),
                                         VARIABLE("n"),
                                         INTEGER(1)))));
define naturals = 
  APPLY(naturals_function, INTEGER(1));

define first_n =
  REC("f",
      "xs",
      LAMBDA("n",
             IF(APPLY3(VARIABLE("="), VARIABLE("n"), INTEGER(0)),
                SYMBOL("nil"),
                APPLY3(cons,
                       APPLY(VARIABLE("car"),
                             VARIABLE("xs")),
                       APPLY3(VARIABLE("f"),
                              APPLY(VARIABLE("cdr"), VARIABLE("xs")),
                              APPLY3(VARIABLE("-"), VARIABLE("n"), 
INTEGER(1)))))));

//define program = APPLY3(first_n, naturals, INTEGER(10));
define program = naturals;

define main = begin
  output_value (eval program initial_environment);
  output_string "\n";
end;

reply via email to

[Prev in Thread] Current Thread [Next in Thread]