Reorganized basically everything, making way for the compiler

This commit is contained in:
2025-11-15 13:06:16 +03:00
parent 27115ab4f2
commit 3f0a860a03
15 changed files with 84 additions and 25 deletions

View File

@@ -1,6 +1,5 @@
(executable (executable
(name main) (name inter)
(public_name main) (public_name inter)
(libraries str lisp unix)) (libraries str interpreter unix)
(include_subdirs unqualified) (package main))

View File

@@ -1,11 +1,10 @@
open Lisp.Ast;; open Interpreter.Ast;;
open Printf;; open Printf;;
open Lisp;; open Interpreter;;
open Env;; open Env;;
open Eval;; open Eval;;
open Read;;
let () = InterpreterStdlib.init_default_env () let () = Stdlib.init_default_env ()
let rec repl env c = let rec repl env c =
let () = printf ">>> "; Out_channel.flush Out_channel.stdout; in let () = printf ">>> "; Out_channel.flush Out_channel.stdout; in
@@ -14,7 +13,7 @@ let rec repl env c =
| Some "exit" -> () | Some "exit" -> ()
| Some l -> | Some l ->
try try
let vals = (parse_str l) in let vals = (read_from_str l) in
(* dbg_print_all vals; *) (* dbg_print_all vals; *)
pretty_print_all (eval_all env vals); pretty_print_all (eval_all env vals);
Out_channel.flush Out_channel.stdout; Out_channel.flush Out_channel.stdout;
@@ -23,7 +22,7 @@ let rec repl env c =
| Invalid_argument s -> | Invalid_argument s ->
printf "%s\nResuming repl\n" s; printf "%s\nResuming repl\n" s;
repl env c repl env c
| Parser.Error -> | Parser.Parse.Error ->
printf "Expression '%s' couldn't be parsed, try again\n" l; printf "Expression '%s' couldn't be parsed, try again\n" l;
repl env c repl env c
;; ;;

View File

@@ -1,3 +1,17 @@
(* This is different from the lisp_ast data returned by the parser!
We will first need to translate that into this in order to use it.
This representation includes things that can only occur during runtime,
like the various kinds of functions and macros.
Additionally, since this is an interpreter, macros tend to be a little
awkward in that they behave exactly like the macro gets expanded just
before the result gets executed. This is different from the compiled
behaviour where the macro is evaluated at compile time.
Though of course, with the dynamic nature of lisp, and its capability
to compile more code at runtime, there will naturally be complications.
*)
type lisp_val = type lisp_val =
| LInt of int | LInt of int
| LDouble of float | LDouble of float
@@ -16,8 +30,8 @@ type lisp_val =
| LFunction of string * environment * lisp_val * lisp_val | LFunction of string * environment * lisp_val * lisp_val
| LLambda of environment * lisp_val * lisp_val | LLambda of environment * lisp_val * lisp_val
(* a macro is exactly the same as a function, with the distinction (* a macro is exactly the same as a function, with the distinction
that it receives all of its arguments completely unevaluated that it receives all of its arguments completely unevaluated
in a compiled lisp this would probably make more of a difference *) *)
| LMacro of string * environment * lisp_val * lisp_val | LMacro of string * environment * lisp_val * lisp_val
| LUnnamedMacro of environment * lisp_val * lisp_val | LUnnamedMacro of environment * lisp_val * lisp_val
| LQuoted of lisp_val | LQuoted of lisp_val
@@ -113,3 +127,16 @@ let pretty_print_all vs =
let dbg_print_all vs = let dbg_print_all vs =
let pr v = Printf.printf "%s\n" (dbg_print_one v) in let pr v = Printf.printf "%s\n" (dbg_print_one v) in
List.iter pr vs List.iter pr vs
let rec convert_one = function
| Parser.Ast.LInt x -> LInt x
| Parser.Ast.LDouble x -> LDouble x
| Parser.Ast.LNil -> LNil
| Parser.Ast.LString s -> LString s
| Parser.Ast.LSymbol s -> LSymbol s
| Parser.Ast.LCons (a, b) -> LCons (convert_one a, convert_one b)
let read_from_str s =
List.map convert_one (Parser.parse_str s)

3
interpreter/dune Normal file
View File

@@ -0,0 +1,3 @@
(library
(name interpreter)
(libraries parser))

View File

@@ -200,5 +200,5 @@ let init_default_env () =
Idea: maybe put this in a file instead of putting Idea: maybe put this in a file instead of putting
literally the entire standard library in a constant string literally the entire standard library in a constant string
*) *)
ignore (Eval.eval_all default_env (Read.parse_str init_script)); ignore (Eval.eval_all default_env (read_from_str init_script));
() ()

View File

@@ -1,7 +0,0 @@
(library
(name lisp))
(include_subdirs unqualified)
(menhir (modules parser))
(ocamllex lexer)

0
parser.opam Normal file
View File

9
parser/ast.ml Normal file
View File

@@ -0,0 +1,9 @@
type lisp_ast =
| LInt of int
| LDouble of float
| LSymbol of string
| LString of string
| LNil
| LCons of lisp_ast * lisp_ast

18
parser/ast.mli Normal file
View File

@@ -0,0 +1,18 @@
(** This is a simplified representation for the source code.
Note that this is different from the data representation used
during execution - that must naturally include things like
functions, structs, classes, etc.
This is used just to represent source code in an easy to process
manner. We translate this before actually using it.
The interpreter directly translates to its value type, the
compiler uses this to optimise and compile.
**)
type lisp_ast =
| LInt of int
| LDouble of float
| LSymbol of string
| LString of string
| LNil
| LCons of lisp_ast * lisp_ast

8
parser/dune Normal file
View File

@@ -0,0 +1,8 @@
(library
(name parser)
(public_name parser)
(modules parser lex parse ast)
)
(menhir (modules parse))
(ocamllex lex)

View File

@@ -1,6 +1,6 @@
{ {
open Lexing open Lexing
open Parser open Parse
exception SyntaxError of string exception SyntaxError of string
let strip_quotes s = String.sub s 1 (String.length s - 2);; let strip_quotes s = String.sub s 1 (String.length s - 2);;

View File

@@ -12,7 +12,7 @@
%token DOT %token DOT
%token EOF %token EOF
%start <Ast.lisp_val option> prog %start <lisp_ast option> prog
%% %%
prog: prog:
@@ -22,7 +22,7 @@ prog:
expr: expr:
| i = INT { LInt i } | i = INT { LInt i }
| d = DOUBLE {LDouble d} | d = DOUBLE { LDouble d}
| s = SYM { LSymbol s } | s = SYM { LSymbol s }
| s = STR { LString (String.uppercase_ascii s) } | s = STR { LString (String.uppercase_ascii s) }
| LPAREN; l = lisp_list_rest { l } | LPAREN; l = lisp_list_rest { l }

View File

@@ -1,4 +1,4 @@
let parse_one lb = Parser.prog (Lexer.read) lb let parse_one lb = Parse.prog (Lex.read) lb
let parse lb = let parse lb =
let rec helper () = let rec helper () =
@@ -11,3 +11,6 @@ let parse lb =
let parse_str s = let parse_str s =
parse (Lexing.from_string s) parse (Lexing.from_string s)
module Ast = Ast
module Parse = Parse