about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMalte Voos <git@mal.tc>2024-02-16 00:43:04 +0100
committerMalte Voos <git@mal.tc>2024-02-16 00:43:04 +0100
commit06d52c8ba30b1bd6e1174ebffbd6cc5ba668ecc2 (patch)
treec558e81d84fd12ef66e99c558e5b7dd1322e5c03
parent2bc6cae2458ba5f9573985791536618a00cbed8a (diff)
downloadtoytt-06d52c8ba30b1bd6e1174ebffbd6cc5ba668ecc2.tar.gz
toytt-06d52c8ba30b1bd6e1174ebffbd6cc5ba668ecc2.zip
basic lexer and parser
-rw-r--r--bin/main.ml15
-rw-r--r--dune-project6
-rw-r--r--flake.lock19
-rw-r--r--flake.nix11
-rw-r--r--lib/Ast.ml70
-rw-r--r--lib/Lexer.mll31
-rw-r--r--lib/Parser.mly66
-rw-r--r--lib/dune7
-rw-r--r--toytt.opam3
9 files changed, 199 insertions, 29 deletions
diff --git a/bin/main.ml b/bin/main.ml
index 732b852..1607ec4 100644
--- a/bin/main.ml
+++ b/bin/main.ml
@@ -1 +1,14 @@
-let () = print_ndline "Hello, World!"
+open Toytt
+
+let parse (s : string) : Ast.expr =
+  let lexbuf = Lexing.from_string s in
+  let ast = Parser.parse Lexer.lex lexbuf in
+  ast
+
+let rec repl () =
+  let input = read_line () in
+  let ast = parse input in
+  Format.printf "%a\n%!" Ast.dump_expr ast;
+  repl ()
+
+let () = repl ()
diff --git a/dune-project b/dune-project
index c3564ad..ede6aa8 100644
--- a/dune-project
+++ b/dune-project
@@ -1,7 +1,7 @@
-(lang dune 3.7)
+(lang dune 3.13)
 (generate_opam_files true)
 
-(using menhir 2.1)
+(using menhir 3.0)
 
 (name toytt)
 (source
@@ -15,7 +15,7 @@
  (name toytt)
  (synopsis "A short synopsis")
  (description "A longer description")
- (depends ocaml dune asai)
+ (depends ocaml dune ppx_deriving asai)
  (tags
   (topics "to describe" your project)))
 
diff --git a/flake.lock b/flake.lock
index 1475898..7816aa0 100644
--- a/flake.lock
+++ b/flake.lock
@@ -67,15 +67,15 @@
     },
     "nixpkgs": {
       "locked": {
-        "lastModified": 1682362401,
-        "narHash": "sha256-/UMUHtF2CyYNl4b60Z2y4wwTTdIWGKhj9H301EDcT9M=",
-        "owner": "nixos",
+        "lastModified": 1707689078,
+        "narHash": "sha256-UUGmRa84ZJHpGZ1WZEBEUOzaPOWG8LZ0yPg1pdDF/yM=",
+        "owner": "NixOS",
         "repo": "nixpkgs",
-        "rev": "884ac294018409e0d1adc0cae185439a44bd6b0b",
+        "rev": "f9d39fb9aff0efee4a3d5f4a6d7c17701d38a1d8",
         "type": "github"
       },
       "original": {
-        "owner": "nixos",
+        "owner": "NixOS",
         "ref": "nixos-unstable",
         "repo": "nixpkgs",
         "type": "github"
@@ -86,7 +86,9 @@
         "flake-compat": "flake-compat",
         "flake-utils": "flake-utils_2",
         "mirage-opam-overlays": "mirage-opam-overlays",
-        "nixpkgs": "nixpkgs",
+        "nixpkgs": [
+          "nixpkgs"
+        ],
         "opam-overlays": "opam-overlays",
         "opam-repository": [
           "opam-repository"
@@ -163,10 +165,7 @@
     "root": {
       "inputs": {
         "flake-utils": "flake-utils",
-        "nixpkgs": [
-          "opam-nix",
-          "nixpkgs"
-        ],
+        "nixpkgs": "nixpkgs",
         "opam-nix": "opam-nix",
         "opam-repository": "opam-repository"
       }
diff --git a/flake.nix b/flake.nix
index fa15c13..6be9e8b 100644
--- a/flake.nix
+++ b/flake.nix
@@ -1,13 +1,18 @@
 {
   inputs = {
+    nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
     opam-repository = {
       url = "github:ocaml/opam-repository";
       flake = false;
     };
-    opam-nix.url = "github:tweag/opam-nix";
-    opam-nix.inputs.opam-repository.follows = "opam-repository";
+    opam-nix = {
+      url = "github:tweag/opam-nix";
+      inputs = {
+        nixpkgs.follows = "nixpkgs";
+        opam-repository.follows = "opam-repository";
+      };
+    };
     flake-utils.url = "github:numtide/flake-utils";
-    nixpkgs.follows = "opam-nix/nixpkgs";
   };
 
   outputs = { flake-utils, opam-nix, nixpkgs, ... }:
diff --git a/lib/Ast.ml b/lib/Ast.ml
index 4ca7899..002dfff 100644
--- a/lib/Ast.ml
+++ b/lib/Ast.ml
@@ -1,8 +1,62 @@
-type expr' =
-  | Var of string
-| Bool
-| True
-| False
-| BoolElim of string
-
-type expr = expr' Asai.Range.located
\ No newline at end of file
+type raw_ident = string
+type ident = raw_ident Asai.Range.located
+
+type raw_arg = { name : ident; ty : expr }
+and arg = raw_arg Asai.Range.located
+
+and raw_expr =
+  | Var of raw_ident
+  | Bool
+  | True
+  | False
+  | BoolElim of {
+      motive_var : ident;
+      motive_body : expr;
+      true_case : expr;
+      false_case : expr;
+      scrut : expr;
+    }
+  | Pi of arg * expr
+  | Lam of ident * expr
+  | App of expr * expr
+  | Sg of arg * expr
+  | Pair of expr * expr
+  | Fst of expr
+  | Snd of expr
+
+and expr = raw_expr Asai.Range.located
+
+let dump_raw_ident fmt (id : raw_ident) = Format.fprintf fmt "@[%s@]" id
+let dump_ident fmt ({ value; _ } : ident) = dump_raw_ident fmt value
+
+let rec dump_raw_arg fmt ({ name; ty } : raw_arg) =
+  Format.fprintf fmt "@[@[%a@]@ :@ @[%a@]@]" dump_ident name dump_expr ty
+
+and dump_arg fmt ({ value; _ } : arg) = dump_raw_arg fmt value
+
+and dump_raw_expr fmt = function
+  | Var id -> Format.fprintf fmt "Var @[%a@]" dump_raw_ident id
+  | Bool -> Format.pp_print_string fmt "Bool"
+  | True -> Format.pp_print_string fmt "True"
+  | False -> Format.pp_print_string fmt "False"
+  | BoolElim { motive_var; motive_body; true_case; false_case; scrut } ->
+      Format.fprintf fmt
+        "@[<10>BoolElim (@[%a@] ->@ @[%a@],@ @[%a@],@ @[%a@],@ @[%a@])@]" dump_ident
+        motive_var dump_expr motive_body dump_expr true_case dump_expr
+        false_case dump_expr scrut
+  | Pi (dom, cod) ->
+      Format.fprintf fmt "@[<4>Pi (@[%a@],@ @[%a@])@]" dump_arg dom dump_expr cod
+  | Lam (var, body) ->
+      Format.fprintf fmt "@[<5>Lam (@[%a@].@ @[%a@])@]" dump_ident var dump_expr
+        body
+  | App (fn, arg) ->
+      Format.fprintf fmt "@[<5>App (@[%a@],@ @[%a@])@]" dump_expr fn dump_expr arg
+  | Sg (fst, snd) ->
+      Format.fprintf fmt "@[<4>Sg (@[%a@],@ @[%a@])@]" dump_arg fst dump_expr snd
+  | Pair (fst, snd) ->
+      Format.fprintf fmt "@[<6>Pair (@[%a@],@ @[%a@])@]" dump_expr fst dump_expr
+        snd
+  | Fst p -> Format.fprintf fmt "@[<5>Fst (@[%a@])@]" dump_expr p
+  | Snd p -> Format.fprintf fmt "@[<5>Snd (@[%a@])@]" dump_expr p
+
+and dump_expr fmt ({ value; _ } : expr) = dump_raw_expr fmt value
diff --git a/lib/Lexer.mll b/lib/Lexer.mll
new file mode 100644
index 0000000..55a22c2
--- /dev/null
+++ b/lib/Lexer.mll
@@ -0,0 +1,31 @@
+{
+open Parser
+}
+
+let whitespace = [' ' '\t' '\r' '\n']+
+let letter = ['a'-'z' 'A'-'Z']
+let ident = letter+
+
+rule lex =
+  parse
+  | whitespace { lex lexbuf }
+  | "(" { LPR }
+  | ")" { RPR }
+  | "[" { LBR }
+  | "]" { RBR }
+  | "->" { ARROW }
+  | "*" { ASTERISK }
+  | "\\" { BACKSLASH }
+  | ":" { COLON }
+  | "," { COMMA }
+  | "." { DOT }
+  | "=>" { FATARROW }
+  | "bool" { BOOL }
+  | "true" { TRUE }
+  | "false" { FALSE }
+  | "bool-elim" { BOOL_ELIM }
+  | "at" { AT }
+  | "fst" { FST }
+  | "snd" { SND }
+  | ident { IDENT (Lexing.lexeme lexbuf) }
+  | eof { EOF }
diff --git a/lib/Parser.mly b/lib/Parser.mly
new file mode 100644
index 0000000..db2a9e2
--- /dev/null
+++ b/lib/Parser.mly
@@ -0,0 +1,66 @@
+%{
+open Ast
+%}
+
+%token <string> IDENT
+%token LPR RPR
+%token LBR RBR
+%token ARROW ASTERISK BACKSLASH COLON COMMA DOT FATARROW
+%token BOOL TRUE FALSE BOOL_ELIM AT
+%token FST SND
+%token EOF
+
+%right ARROW ASTERISK
+%left IDENT LPR APP BACKSLASH FST SND BOOL TRUE FALSE BOOL_ELIM
+
+%start <Ast.expr> parse
+
+%%
+
+%inline
+locate(X): e = X { Asai.Range.locate_lex $loc e }
+
+%inline
+ident: id = locate(IDENT) { id }
+
+raw_arg: LPR; name = ident; COLON; ty = expr; RPR
+	{ { name; ty } }
+
+%inline
+arg: a = locate(raw_arg) { a }
+
+raw_expr:
+  | name = IDENT
+	{ Var name }
+  | LPR; e = raw_expr; RPR
+	{ e }
+  | BOOL
+	{ Bool }
+  | TRUE
+	{ True }
+  | FALSE
+	{ False }
+  | BOOL_ELIM; scrut = expr; AT; motive_var = ident; ARROW; motive_body = expr;
+	LBR; TRUE; FATARROW; true_case = expr; COMMA; FALSE; FATARROW; false_case = expr; RBR
+	{ BoolElim { motive_var; motive_body; true_case; false_case; scrut } }
+
+  | a = arg; ARROW; b = expr
+	{ Pi (a, b) }
+  | BACKSLASH; a = ident; ARROW; b = expr
+	{ Lam (a, b) }
+  | a = expr; b = expr %prec APP
+	{ App (a, b) }
+
+  | a = arg; ASTERISK; b = expr
+	{ Sg (a, b) }
+  | LPR; a = expr; COMMA; b = expr; RPR
+	{ Pair (a, b) }
+  | FST; p = expr
+	{ Fst p }
+  | SND; p = expr
+	{ Snd p }
+
+%inline
+expr: e = locate(raw_expr) { e }
+
+parse: e = expr; EOF { e }
diff --git a/lib/dune b/lib/dune
index a844074..7a54f53 100644
--- a/lib/dune
+++ b/lib/dune
@@ -1,9 +1,10 @@
 (menhir
- (flags --explain)
+ (explain true)
  (modules Parser))
 
-; (ocamllex Lexer)
+(ocamllex Lexer)
 
 (library
  (name toytt)
- (libraries asai))
+ (libraries asai)
+ (preprocess (pps ppx_deriving.std)))
diff --git a/toytt.opam b/toytt.opam
index c126fcb..1a4a45c 100644
--- a/toytt.opam
+++ b/toytt.opam
@@ -11,7 +11,8 @@ doc: "https://url/to/documentation"
 bug-reports: "https://github.com/username/reponame/issues"
 depends: [
   "ocaml"
-  "dune" {>= "3.7"}
+  "dune" {>= "3.13"}
+  "ppx_deriving"
   "asai"
   "odoc" {with-doc}
 ]