Compare commits
4 Commits
27115ab4f2
...
34aeabdd99
| Author | SHA1 | Date | |
|---|---|---|---|
| 34aeabdd99 | |||
| fb47e6ecdd | |||
| 4faf309752 | |||
| 3f0a860a03 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,2 +1,4 @@
|
||||
_build
|
||||
*~
|
||||
.direnv
|
||||
result
|
||||
|
||||
9
bin/dune
9
bin/dune
@@ -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))
|
||||
|
||||
@@ -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
|
||||
;;
|
||||
@@ -1,2 +1,5 @@
|
||||
(lang dune 3.7)
|
||||
(using menhir 2.1)
|
||||
|
||||
(package
|
||||
(name ollisp))
|
||||
|
||||
27
flake.lock
generated
Normal file
27
flake.lock
generated
Normal 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
27
flake.nix
Normal 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
|
||||
];
|
||||
};
|
||||
};
|
||||
}
|
||||
25
lib/compiler/compilation.ml
Normal file
25
lib/compiler/compilation.ml
Normal 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
3
lib/compiler/dune
Normal file
@@ -0,0 +1,3 @@
|
||||
(library
|
||||
(name compiler)
|
||||
(libraries parser))
|
||||
7
lib/dune
7
lib/dune
@@ -1,7 +0,0 @@
|
||||
(library
|
||||
(name lisp))
|
||||
|
||||
(include_subdirs unqualified)
|
||||
|
||||
(menhir (modules parser))
|
||||
(ocamllex lexer)
|
||||
@@ -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
4
lib/interpreter/dune
Normal file
@@ -0,0 +1,4 @@
|
||||
(library
|
||||
(name interpreter)
|
||||
(libraries parser)
|
||||
(package ollisp))
|
||||
@@ -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
10
lib/parser/ast.ml
Normal 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
7
lib/parser/dune
Normal file
@@ -0,0 +1,7 @@
|
||||
(library
|
||||
(name parser)
|
||||
(modules parser lex parse ast)
|
||||
(package ollisp))
|
||||
|
||||
(menhir (modules parse))
|
||||
(ocamllex lex)
|
||||
@@ -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);;
|
||||
@@ -12,7 +12,7 @@
|
||||
%token DOT
|
||||
%token EOF
|
||||
|
||||
%start <Ast.lisp_val option> prog
|
||||
%start <lisp_ast option> prog
|
||||
%%
|
||||
|
||||
prog:
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user