Compare commits

...

4 Commits

21 changed files with 156 additions and 26 deletions

1
.envrc Normal file
View File

@@ -0,0 +1 @@
use flake

2
.gitignore vendored
View File

@@ -1,2 +1,4 @@
_build
*~
.direnv
result

View File

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

View File

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

View File

@@ -1,2 +1,5 @@
(lang dune 3.7)
(using menhir 2.1)
(package
(name ollisp))

27
flake.lock generated Normal file
View File

@@ -0,0 +1,27 @@
{
"nodes": {
"nixpkgs": {
"locked": {
"lastModified": 1764950072,
"narHash": "sha256-BmPWzogsG2GsXZtlT+MTcAWeDK5hkbGRZTeZNW42fwA=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "f61125a668a320878494449750330ca58b78c557",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"nixpkgs": "nixpkgs"
}
}
},
"root": "root",
"version": 7
}

27
flake.nix Normal file
View File

@@ -0,0 +1,27 @@
{
description = "a lisp interpreter/compiler in ocaml";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
};
outputs = {self, nixpkgs}:
let
pkgs = nixpkgs.legacyPackages.x86_64-linux;
in
{
packages.x86_64-linux.default = pkgs.ocamlPackages.buildDunePackage {
pname = "ollisp";
version = "0.0.1";
src = pkgs.lib.cleanSource ./.;
preBuildPhase = "ls -R";
nativeBuildInputs = with pkgs; [
ocamlPackages.menhir
];
};
devShells.x86_64-linux.default = pkgs.mkShell {
nativeBuildInputs = with pkgs.ocamlPackages; [
menhir merlin dune_3
];
};
};
}

View File

@@ -0,0 +1,25 @@
open Parser.Ast;;
(* This type represents an intermediate step between the AST and opcodes in our
compiler. We need this extra step to resolve addresses, e.g. how do you know
what exact address an if expression needs to jump to before you compile it?
you don't, you just keep a symbolic label there, resolve later.
*)
type intermediate_opcode =
| ISelect of string * string
| ILDF of string
| ILD of int (* an index into the constant table *)
| INil
| IRet
| IAdd
| IJoin
| ILabel of string (* does not emit any byte code *)
(* TODO: Complete *)
let (compile : lisp_ast -> intermediate_opcode list) = function
| LInt x -> [ILD x]
| _ -> [];;

3
lib/compiler/dune Normal file
View File

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

View File

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

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 =
| LInt of int
| LDouble of float
@@ -17,7 +31,7 @@ type lisp_val =
| LLambda of environment * lisp_val * lisp_val
(* a macro is exactly the same as a function, with the distinction
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
| LUnnamedMacro of environment * lisp_val * lisp_val
| LQuoted of lisp_val
@@ -113,3 +127,16 @@ let pretty_print_all vs =
let dbg_print_all vs =
let pr v = Printf.printf "%s\n" (dbg_print_one v) in
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)

4
lib/interpreter/dune Normal file
View File

@@ -0,0 +1,4 @@
(library
(name interpreter)
(libraries parser)
(package ollisp))

View File

@@ -200,5 +200,5 @@ let init_default_env () =
Idea: maybe put this in a file instead of putting
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));
()

10
lib/parser/ast.ml Normal file
View File

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

7
lib/parser/dune Normal file
View File

@@ -0,0 +1,7 @@
(library
(name parser)
(modules parser lex parse ast)
(package ollisp))
(menhir (modules parse))
(ocamllex lex)

View File

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

View File

@@ -12,7 +12,7 @@
%token DOT
%token EOF
%start <Ast.lisp_val option> prog
%start <lisp_ast option> prog
%%
prog:
@@ -22,7 +22,7 @@ prog:
expr:
| i = INT { LInt i }
| d = DOUBLE {LDouble d}
| d = DOUBLE { LDouble d}
| s = SYM { LSymbol s }
| s = STR { LString (String.uppercase_ascii s) }
| 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 rec helper () =
@@ -11,3 +11,6 @@ let parse lb =
let parse_str s =
parse (Lexing.from_string s)
module Ast = Ast
module Parse = Parse

View File