├── doc
├── overview.md
├── book
│ ├── preamble.tex
│ ├── introduction.tex
│ ├── index.tex
│ ├── postem_book.tex
│ └── grammar.tex
├── syntax_highlighting.md
├── lexer
│ └── lexer.py
└── getting_started.md
├── .ocamlformat
├── bin
├── postem.ml
├── dune
├── custom_compil.ml
└── doc.post
├── man
├── dune
└── postem.1
├── src
├── common
│ ├── enumerate
│ │ ├── enumerate.ml
│ │ ├── dune
│ │ ├── enumerate.mli
│ │ ├── base.mli
│ │ ├── builtins.mli
│ │ ├── base.ml
│ │ └── builtins.ml
│ ├── dune
│ ├── common.ml
│ ├── common.mli
│ ├── stdlib_ext.ml
│ ├── err.mli
│ ├── stdlib_ext.mli
│ ├── ctx.mli
│ ├── ctx.ml
│ └── err.ml
├── dune
├── expansion
│ ├── dune
│ ├── known.ml
│ └── default.ml
├── core
│ ├── dune
│ ├── ehandler.ml
│ ├── ehandler.mli
│ ├── args.mli
│ ├── compil_impl.mli
│ ├── compil_impl.ml
│ └── args.ml
├── ast
│ ├── expansion.mli
│ ├── dune
│ ├── types.ml
│ ├── eval.mli
│ └── eval.ml
├── checker
│ ├── dune
│ ├── checker.mli
│ └── checker.ml
├── repl.mli
├── compiler.mli
├── postem.ml
├── postem.mli
├── syntax
│ ├── lexer.mli
│ ├── dune
│ ├── syntax.mli
│ ├── parsed_ast.mli
│ ├── parsed_ast.ml
│ ├── syntax.ml
│ ├── parser.mly
│ └── lexer.ml
├── repl.ml
└── compiler.ml
├── .gitignore
├── Makefile
├── dune-project
├── postem.opam
├── README.md
└── LICENSE
/doc/overview.md:
--------------------------------------------------------------------------------
1 | # An overview of Postem features
2 |
--------------------------------------------------------------------------------
/.ocamlformat:
--------------------------------------------------------------------------------
1 | profile = default
2 | version = 0.20.1
3 |
--------------------------------------------------------------------------------
/bin/postem.ml:
--------------------------------------------------------------------------------
1 | let () = Postem__Compiler.compile ()
2 |
--------------------------------------------------------------------------------
/doc/book/preamble.tex:
--------------------------------------------------------------------------------
1 | \usepackage[epsilon, altpo]{backnaur}
2 |
--------------------------------------------------------------------------------
/man/dune:
--------------------------------------------------------------------------------
1 | (install
2 | (section man)
3 | (files postem.1))
4 |
--------------------------------------------------------------------------------
/doc/book/introduction.tex:
--------------------------------------------------------------------------------
1 | \part{Introduction}\label{part:intro}
2 |
--------------------------------------------------------------------------------
/src/common/enumerate/enumerate.ml:
--------------------------------------------------------------------------------
1 | module Base = Base
2 | module Builtins = Builtins
3 |
--------------------------------------------------------------------------------
/src/dune:
--------------------------------------------------------------------------------
1 | (library
2 | (name postem)
3 | (public_name postem)
4 | (libraries ast core))
5 |
--------------------------------------------------------------------------------
/src/common/dune:
--------------------------------------------------------------------------------
1 | (library
2 | (name common)
3 | (public_name postem.common)
4 | (libraries enumerate))
5 |
--------------------------------------------------------------------------------
/src/common/enumerate/dune:
--------------------------------------------------------------------------------
1 | (library
2 | (name enumerate)
3 | (public_name postem.common.enumerate))
4 |
--------------------------------------------------------------------------------
/src/common/common.ml:
--------------------------------------------------------------------------------
1 | include Stdlib_ext
2 | module Ctx = Ctx
3 | module Enumerate = Enumerate
4 | module Err = Err
5 |
--------------------------------------------------------------------------------
/src/expansion/dune:
--------------------------------------------------------------------------------
1 | (library
2 | (name expansion)
3 | (public_name postem.expansion)
4 | (libraries ast common))
5 |
--------------------------------------------------------------------------------
/src/common/common.mli:
--------------------------------------------------------------------------------
1 | include module type of Stdlib_ext
2 | module Ctx = Ctx
3 | module Enumerate = Enumerate
4 | module Err = Err
5 |
--------------------------------------------------------------------------------
/src/core/dune:
--------------------------------------------------------------------------------
1 | (library
2 | (name core)
3 | (public_name postem.core)
4 | (libraries ast checker common expansion sedlex syntax))
5 |
--------------------------------------------------------------------------------
/src/common/enumerate/enumerate.mli:
--------------------------------------------------------------------------------
1 | (** High level oriented object numbering library. *)
2 |
3 | module Base = Base
4 | module Builtins = Builtins
5 |
--------------------------------------------------------------------------------
/bin/dune:
--------------------------------------------------------------------------------
1 | (executables
2 | (names postem custom_compil)
3 | (libraries postem))
4 |
5 | (install
6 | (section bin)
7 | (files
8 | (postem.exe as postem)))
9 |
--------------------------------------------------------------------------------
/src/ast/expansion.mli:
--------------------------------------------------------------------------------
1 | module type S = sig
2 | val alias : Common.Ctx.AliasCtx.t
3 | val bop : Common.Ctx.BinOpCtx.t
4 | val uop : Common.Ctx.UopCtx.t
5 | end
6 |
--------------------------------------------------------------------------------
/src/checker/dune:
--------------------------------------------------------------------------------
1 | (library
2 | (name checker)
3 | (public_name postem.checker)
4 | (preprocess
5 | (pps ppx_deriving.show))
6 | (libraries ast common syntax))
7 |
--------------------------------------------------------------------------------
/src/repl.mli:
--------------------------------------------------------------------------------
1 | module type S = sig
2 | val launch : unit -> unit
3 | end
4 |
5 | module Make : functor (Compiler : Core.Compil_impl.S with type t := string) -> S
6 |
--------------------------------------------------------------------------------
/src/compiler.mli:
--------------------------------------------------------------------------------
1 | (** {1 API} *)
2 |
3 | val compile : unit -> unit
4 | (** Compile the document passed at CLI and write result on a file or on stdout
5 | according to CLI argument. *)
6 |
--------------------------------------------------------------------------------
/src/ast/dune:
--------------------------------------------------------------------------------
1 | (library
2 | (name ast)
3 | (public_name postem.ast)
4 | (modules_without_implementation expansion)
5 | (preprocess
6 | (pps ppx_deriving.show sedlex.ppx))
7 | (libraries common))
8 |
--------------------------------------------------------------------------------
/src/checker/checker.mli:
--------------------------------------------------------------------------------
1 | module type S = sig
2 | val check :
3 | Syntax.Parsed_ast.t -> (Ast.Types.doc, Common.Err.checker_err) result
4 | end
5 |
6 | module Make : functor (Expsn : Ast.Expansion.S) -> S
7 |
--------------------------------------------------------------------------------
/src/expansion/known.ml:
--------------------------------------------------------------------------------
1 | type t = (name * doc * (module Ast.Expansion.S)) list
2 | and name = string
3 | and doc = string
4 |
5 | let expansions : t = [ ("default", "output to plain text.", (module Default)) ]
6 |
--------------------------------------------------------------------------------
/doc/book/index.tex:
--------------------------------------------------------------------------------
1 | \clearpage
2 |
3 | \clearpage
4 |
5 | \tableofcontents
6 |
7 | \clearpage
8 |
9 | \input{doc/book/introduction}
10 |
11 | \clearpage
12 |
13 | \input{doc/book/grammar}
14 |
15 | \clearpage
16 |
--------------------------------------------------------------------------------
/src/postem.ml:
--------------------------------------------------------------------------------
1 | module Ast = Ast
2 | module Checker = Checker
3 | module Common = Common
4 | module Compiler = Compiler
5 | module Core = Core
6 | module Expansion = Expansion
7 | module Syntax = Syntax
8 | module Repl = Repl
9 |
--------------------------------------------------------------------------------
/src/postem.mli:
--------------------------------------------------------------------------------
1 | module Ast = Ast
2 | module Checker = Checker
3 | module Common = Common
4 | module Compiler = Compiler
5 | module Core = Core
6 | module Expansion = Expansion
7 | module Syntax = Syntax
8 | module Repl = Repl
9 |
--------------------------------------------------------------------------------
/src/syntax/lexer.mli:
--------------------------------------------------------------------------------
1 | exception IllegalChar of Sedlexing.lexbuf
2 |
3 | val read : Sedlexing.lexbuf -> Parser.token
4 | (** @raise IllegalChar *)
5 |
6 | val read_debug : Sedlexing.lexbuf -> Parser.token
7 | (** @raise IllegalChar *)
8 |
--------------------------------------------------------------------------------
/src/syntax/dune:
--------------------------------------------------------------------------------
1 | (library
2 | (name syntax)
3 | (public_name postem.syntax)
4 | (libraries ast common menhirLib sedlex)
5 | (preprocess
6 | (pps ppx_deriving.show sedlex.ppx))
7 | (flags :standard -w +39))
8 |
9 | (menhir
10 | (modules parser))
11 |
--------------------------------------------------------------------------------
/src/ast/types.ml:
--------------------------------------------------------------------------------
1 | type doc = expr list [@@deriving show]
2 |
3 | and expr =
4 | | Text of string
5 | | White of string
6 | | Unformat of string
7 | | Group of expr list
8 | | UnaryOp of { op : string; group : expr }
9 | | BinOp of { op : string; left : expr; right : expr }
10 |
--------------------------------------------------------------------------------
/doc/book/postem_book.tex:
--------------------------------------------------------------------------------
1 | \documentclass[a4paper, 11pt, UTF8, oneside]{article}
2 |
3 | \date{}
4 |
5 | \input{doc/book/preamble}
6 |
7 | \title{\textbf{The Postem book}}
8 |
9 | \author{Timéo Arnouts}
10 |
11 | \begin{document}
12 |
13 | \maketitle
14 |
15 | \input{doc/book/index}
16 |
17 | \end{document}
18 |
--------------------------------------------------------------------------------
/src/ast/eval.mli:
--------------------------------------------------------------------------------
1 | (** {1 API} *)
2 |
3 | (** Output signature of the functor [Eval_expsn.MakeWithExpsn]. *)
4 | module type S = sig
5 | type t
6 |
7 | val eval : Types.doc -> t
8 | end
9 |
10 | (** Functor building a string evaluator from an expansion. *)
11 | module MakeWithExpsn : functor (Expsn : Expansion.S) -> S with type t := string
12 |
--------------------------------------------------------------------------------
/src/syntax/syntax.mli:
--------------------------------------------------------------------------------
1 | module type S = sig
2 | val parse : Sedlexing.lexbuf -> (Parsed_ast.t, Common.Err.parser_err) result
3 | (** [parse lexbuf] returns [Ok past] if parsing goes smoothly, [Error err]
4 | otherwise. *)
5 | end
6 |
7 | module Parser : S
8 | (** Default implementation of the parser. *)
9 |
10 | module Parsed_ast = Parsed_ast
11 |
--------------------------------------------------------------------------------
/src/common/stdlib_ext.ml:
--------------------------------------------------------------------------------
1 | let prerr_with_exit err =
2 | prerr_endline err;
3 | exit 1
4 |
5 | module In_channel = struct
6 | let write filename str =
7 | let oc = open_out filename in
8 | output_string oc str;
9 | close_out oc
10 | end
11 |
12 | module Result = struct
13 | include Result
14 |
15 | let ( let+ ) = Result.bind
16 | end
17 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.annot
2 | *.cmo
3 | *.cma
4 | *.cmi
5 | *.a
6 | *.out
7 | *.o
8 | *.cmx
9 | *.cmxs
10 | *.cmxa
11 |
12 | # ocamlbuild working directory
13 | _build/
14 |
15 | # ocamlbuild targets
16 | *.byte
17 | *.native
18 |
19 | # oasis generated files
20 | setup.data
21 | setup.log
22 |
23 | # Merlin configuring file for Vim and Emacs
24 | .merlin
25 |
26 | # Dune generated files
27 | *.install
28 |
29 | # Local OPAM switch
30 | _opam/
31 |
--------------------------------------------------------------------------------
/src/syntax/parsed_ast.mli:
--------------------------------------------------------------------------------
1 | type 'a with_loc = { loc : Lexing.position * Lexing.position; value : 'a }
2 |
3 | type t = expr list
4 |
5 | and expr =
6 | | LText of string
7 | | LWhite of string
8 | | LNewline of string
9 | | LUnformat of string
10 | | LGroup of expr list
11 | | LUnaryOp of { op : string with_loc; group : expr; newline : string }
12 | | LBinOp of { op : string with_loc; left : expr; right : expr }
13 |
14 | val show : t -> string
15 |
--------------------------------------------------------------------------------
/src/core/ehandler.ml:
--------------------------------------------------------------------------------
1 | module KnownExpansions = struct
2 | type t = Expansion.Known.t
3 |
4 | let to_string t =
5 | List.map (fun (name, doc, _) -> Printf.sprintf "%s: %s" name doc) t
6 | |> String.concat "\n"
7 | end
8 |
9 | let load t name =
10 | let found_expsn = List.filter (fun (n, _, _) -> n = name) t in
11 | match found_expsn with
12 | | [] -> Error (`UnknownExpsn name)
13 | | [ (_, _, expsn) ] -> Ok expsn
14 | | _ -> Error (`ExpsnAmbiguity name)
15 |
--------------------------------------------------------------------------------
/src/syntax/parsed_ast.ml:
--------------------------------------------------------------------------------
1 | module Lexing = struct
2 | include Lexing
3 |
4 | let pp_position fmt _t = Format.fprintf fmt "loc"
5 | end
6 |
7 | type 'a with_loc = { loc : Lexing.position * Lexing.position; value : 'a }
8 | [@@deriving show]
9 |
10 | type t = expr list [@@deriving show]
11 |
12 | and expr =
13 | | LText of string
14 | | LWhite of string
15 | | LNewline of string
16 | | LUnformat of string
17 | | LGroup of expr list
18 | | LUnaryOp of { op : string with_loc; group : expr; newline : string }
19 | | LBinOp of { op : string with_loc; left : expr; right : expr }
20 |
--------------------------------------------------------------------------------
/bin/custom_compil.ml:
--------------------------------------------------------------------------------
1 | module IntEval = struct
2 | type t = int
3 |
4 | let rec eval doc = List.fold_left eval_expr 0 doc
5 |
6 | and eval_expr acc expr =
7 | match expr with
8 | | Ast.Types.Text t -> ( acc + try int_of_string t with Failure _ -> 0)
9 | | _ -> acc
10 | end
11 |
12 | module MyCompiler =
13 | Core.Compil_impl.Make (Syntax.Parser) (Checker.Make (Expansion.Default))
14 | (IntEval)
15 |
16 | let () =
17 | match MyCompiler.from_string "hello 10 world" with
18 | | Ok n -> Printf.printf "%d\n" n
19 | | Error err -> prerr_endline @@ Common.Err.to_string err
20 |
--------------------------------------------------------------------------------
/src/common/err.mli:
--------------------------------------------------------------------------------
1 | (** Containing utilities for error message formatting. *)
2 |
3 | (** {1 Types} *)
4 |
5 | type loc = Lexing.position * Lexing.position
6 | type checker_err = [ `UndefinedUop of loc ]
7 | type expsn_err = [ `ExpsnAmbiguity of string | `UnknownExpsn of string ]
8 | type parser_err = [ `IllegalCharacter of loc | `SyntaxError of loc ]
9 | type t = [ checker_err | expsn_err | parser_err | `NoSuchFile of string ]
10 |
11 | (** {2 API} *)
12 |
13 | val to_string : t -> string
14 |
15 | val pp_string : ?hint:string -> string -> string
16 | (** [pp_string msg] prettifies and returns it as string. *)
17 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | .PHONY: all build clean doc repl fmt deps
2 |
3 | all: build doc
4 |
5 | build:
6 | dune build
7 |
8 | doc:
9 | dune build @doc-private
10 | pdflatex doc/book/postem_book.tex
11 | rm postem_book.aux
12 | rm postem_book.log
13 | rm postem_book.toc
14 | mkdir doc/build
15 | mv postem_book.pdf doc/build
16 |
17 | clean:
18 | dune clean
19 | rm -rf doc/build
20 |
21 | repl:
22 | dune utop
23 |
24 | fmt:
25 | -dune build @fmt --auto-promote
26 |
27 | deps:
28 | dune external-lib-deps --missing @@default
29 |
30 | install:
31 | dune build @install
32 | dune install
33 |
34 | uninstall:
35 | dune uninstall
36 |
--------------------------------------------------------------------------------
/src/common/stdlib_ext.mli:
--------------------------------------------------------------------------------
1 | (** Some extension to OCaml stdlib. *)
2 |
3 | val prerr_with_exit : string -> 'a
4 | (** Print on stderr given string and exit with code 1. *)
5 |
6 | (** Extension to the [Result] module of the OCaml stdlib. *)
7 | module Result : sig
8 | include module type of Result
9 |
10 | val ( let+ ) : ('a, 'b) t -> ('a -> ('c, 'b) t) -> ('c, 'b) t
11 | end
12 |
13 | (** Containing utilities for in_channel io. *)
14 | module In_channel : sig
15 | val write : string -> string -> unit
16 | (** [write filename str] writes [str] in file [filename].
17 | Create file [filename] if it does not exist. *)
18 | end
19 |
--------------------------------------------------------------------------------
/src/core/ehandler.mli:
--------------------------------------------------------------------------------
1 | (** Utilities to load expansion.
2 |
3 | Expansions must be placed in [src/expansion/] folder and be registered in
4 | [src/expansion/known.ml]. *)
5 |
6 | (** {1 API} *)
7 |
8 | module KnownExpansions : sig
9 | type t = Expansion.Known.t
10 |
11 | val to_string : t -> string
12 | (** Prettify given known expansions and returns it as a string. *)
13 | end
14 |
15 | val load :
16 | KnownExpansions.t ->
17 | string ->
18 | ((module Ast.Expansion.S), Common.Err.expsn_err) result
19 | (** [load_res known_expsn name] returns [Ok e] where [e] is expansions module
20 | associated to [name], [Error err] otherwise. *)
21 |
--------------------------------------------------------------------------------
/src/syntax/syntax.ml:
--------------------------------------------------------------------------------
1 | module type S = sig
2 | val parse : Sedlexing.lexbuf -> (Parsed_ast.t, Common.Err.parser_err) result
3 | end
4 |
5 | module Parser : S = struct
6 | let parse lexbuf =
7 | let lexer = Sedlexing.with_tokenizer Lexer.read lexbuf in
8 | let parser =
9 | MenhirLib.Convert.Simplified.traditional2revised Parser.document
10 | in
11 | let open Result in
12 | try ok @@ parser lexer with
13 | | Lexer.IllegalChar lexbuf ->
14 | error @@ `IllegalCharacter (Sedlexing.lexing_positions lexbuf)
15 | | Parser.Error -> error @@ `SyntaxError (Sedlexing.lexing_positions lexbuf)
16 | end
17 |
18 | module Parsed_ast = Parsed_ast
19 |
--------------------------------------------------------------------------------
/src/repl.ml:
--------------------------------------------------------------------------------
1 | module type S = sig
2 | val launch : unit -> unit
3 | end
4 |
5 | module Make (Compiler : Core.Compil_impl.S with type t := string) = struct
6 | let prompt () = print_string "> "
7 | let print = Printf.printf "- : %s\n"
8 |
9 | let rec launch () =
10 | prompt ();
11 | let input = ref [] in
12 | try
13 | while true do
14 | input := read_line () :: !input
15 | done
16 | with End_of_file -> (
17 | match
18 | List.rev !input |> String.concat "\n"
19 | |> Compiler.from_string ~filename:"REPL"
20 | with
21 | | Ok output ->
22 | print output;
23 | launch ()
24 | | Error err -> Common.(prerr_with_exit @@ Err.to_string err))
25 | end
26 |
--------------------------------------------------------------------------------
/bin/doc.post:
--------------------------------------------------------------------------------
1 | & Postem
2 |
3 | && Philosophy
4 |
5 | P aims to be a lightweight markup language designed for note taking.
6 | It is also intended to be easily extensible by allowing extension writing in OCaml.
7 |
8 | && Features
9 |
10 | P supports alias definition and custom operator definition.
11 |
12 | && Builtins marks
13 |
14 | There are six builtins title tags:
15 | {{& for a level one title, && for a level two title, and this up to 6.}}
16 |
17 | By the way, the line above is unformated because it is put between two curly brackets.
18 | This avoids the need to individually escape each operator.
19 |
20 | > There are also quotes
21 |
22 | > On one or on
23 | > several lines
24 |
25 | -- The \-\- mark allows you to formulate a conclusion.
26 |
--------------------------------------------------------------------------------
/dune-project:
--------------------------------------------------------------------------------
1 | (lang dune 2.9)
2 |
3 | (using menhir 2.1)
4 |
5 | (version 0.0.1)
6 |
7 | (name postem)
8 |
9 | (license "GPL-3.0")
10 |
11 | (authors "The postem programmers")
12 |
13 | (maintainers "tim.arnouts@protonmail.com")
14 |
15 | (source
16 | (github Tim-ats-d/Postem-markup))
17 |
18 | (bug_reports "https://github.com/Tim-ats-d/Postem-markup/issues")
19 |
20 | (homepage "https://github.com/Tim-ats-d/Postem-markup")
21 |
22 | (documentation "https://github.com/Tim-ats-d/Postem-markup/tree/master/doc")
23 |
24 | (generate_opam_files true)
25 |
26 | (package
27 | (name postem)
28 | (synopsis "A lightweight markup language designed for quick note taking")
29 | (depends
30 | dune
31 | (ocaml
32 | (>= 4.11))
33 | (odoc :with-doc)
34 | (menhir
35 | (>= 20210419))))
36 |
--------------------------------------------------------------------------------
/src/core/args.mli:
--------------------------------------------------------------------------------
1 | (** {1 Type} *)
2 |
3 | type t =
4 | < direct_input : string
5 | ; inputf : string
6 | ; outputf : string
7 | ; expsn : string
8 | ; output_on_stdout : bool >
9 | (** Type representing CLI argument passed by user. *)
10 |
11 | (** {2 API} *)
12 |
13 | class args :
14 | object
15 | method direct_input : string
16 | method inputf : string
17 | method outputf : string
18 | method expsn : string
19 | method output_on_stdout : bool
20 | method set_direct_input : string -> unit
21 | method set_inputf : string -> unit
22 | method set_outputf : string -> unit
23 | method set_expsn : string -> unit
24 | method set_output_on_stdout : bool -> unit
25 | end
26 |
27 | val parse : unit -> t
28 | (** Returns CLI arguments passed as type [t]. *)
29 |
--------------------------------------------------------------------------------
/src/common/ctx.mli:
--------------------------------------------------------------------------------
1 | (** {1 API} *)
2 |
3 | (** Output signature of the functor [Ctx.Make]. *)
4 | module type S = sig
5 | type t
6 | type key
7 | type value
8 |
9 | val empty : t
10 | val add : key -> value -> t -> t
11 | val find : t -> key -> value
12 | val find_opt : t -> key -> value option
13 | val merge : t -> t -> t
14 | end
15 |
16 | module type VALUE = sig
17 | type t
18 | end
19 |
20 | (** Functor building a context given a totally ordered type and a value. *)
21 | module Make : functor (Ord : Map.OrderedType) (Value : VALUE) ->
22 | S with type key := Ord.t and type value := Value.t
23 |
24 | module AliasCtx : S with type key := string and type value := string
25 | module BinOpCtx : S with type key := string and type value := string -> string -> string
26 | module UopCtx : S with type key := string and type value := string -> string
27 |
--------------------------------------------------------------------------------
/doc/syntax_highlighting.md:
--------------------------------------------------------------------------------
1 | # Syntaxic color for Postem
2 |
3 | **Postem** provides a [custom lexer pygments](https://pygments.org/docs/lexerdevelopment/) ready to use located in `doc/lexer/lexer.py`.
4 |
5 | Here is an example of **Python** code using it:
6 | ```py
7 | import pygments
8 | from pygments.formatters import HtmlFormatter
9 | from pygments.lexers import load_lexer_from_file
10 |
11 | postem_input = """
12 | & Title
13 |
14 | > A quotation
15 | """
16 |
17 | formatter = HtmlFormatter()
18 |
19 | with open("styles.css", "w") as f:
20 | f.write(formatter.get_style_defs())
21 |
22 | with open("output.html", "w") as f:
23 | lexer = load_lexer_from_file("lexer.py", "PostemLexer")
24 | output = pygments.highlight(postem_input, lexer, formatter)
25 |
26 | f.write('
')
27 | f.write(output)
28 |
29 | ```
30 |
31 | See the [related Pygments documentation](https://pygments.org/docs/) for more information
32 |
--------------------------------------------------------------------------------
/postem.opam:
--------------------------------------------------------------------------------
1 | # This file is generated by dune, edit dune-project instead
2 | opam-version: "2.0"
3 | version: "0.0.1"
4 | synopsis: "A lightweight markup language designed for quick note taking"
5 | maintainer: ["tim.arnouts@protonmail.com"]
6 | authors: ["The postem programmers"]
7 | license: "GPL-3.0"
8 | homepage: "https://github.com/Tim-ats-d/Postem-markup"
9 | doc: "https://github.com/Tim-ats-d/Postem-markup/tree/master/doc"
10 | bug-reports: "https://github.com/Tim-ats-d/Postem-markup/issues"
11 | depends: [
12 | "dune" {>= "2.9"}
13 | "ocaml" {>= "4.11"}
14 | "odoc" {with-doc}
15 | "menhir" {>= "20210419"}
16 | ]
17 | build: [
18 | ["dune" "subst"] {dev}
19 | [
20 | "dune"
21 | "build"
22 | "-p"
23 | name
24 | "-j"
25 | jobs
26 | "--promote-install-files=false"
27 | "@install"
28 | "@runtest" {with-test}
29 | "@doc" {with-doc}
30 | ]
31 | ["dune" "install" "-p" name "--create-install-files" name]
32 | ]
33 | dev-repo: "git+https://github.com/Tim-ats-d/Postem-markup.git"
34 |
--------------------------------------------------------------------------------
/src/core/compil_impl.mli:
--------------------------------------------------------------------------------
1 | (** Output signature of the functor [Compil_impl.Make]. *)
2 | module type S = sig
3 | type t
4 | (** The outputed type. *)
5 |
6 | val from_lexbuf :
7 | ?filename:string -> Sedlexing.lexbuf -> (t, Common.Err.t) result
8 | (** [from_lexbuf lexbuf] returns [Ok output] if compilation goes smoothly,
9 | [Error msg] otherwise. Optional argument [filename] is used to indicate
10 | in the file name in error messages in case of an error *)
11 |
12 | val from_string : ?filename:string -> string -> (t, Common.Err.t) result
13 | (** [from_string str] does the same as [from_lexbuf] execept it compiles [str]. *)
14 |
15 | val from_channel : ?filename:string -> in_channel -> (t, Common.Err.t) result
16 | (** [from_file chan] does the same as [from_lexbuf] execept it compiles the
17 | content of file [chan]. *)
18 | end
19 |
20 | (** Build a compiler from several units. *)
21 | module Make : functor
22 | (Parser : Syntax.S)
23 | (Checker : Checker.S)
24 | (Eval : Ast.Eval.S)
25 | -> S with type t := Eval.t
26 |
--------------------------------------------------------------------------------
/src/common/ctx.ml:
--------------------------------------------------------------------------------
1 | module type S = sig
2 | type t
3 | type key
4 | type value
5 |
6 | val empty : t
7 | val add : key -> value -> t -> t
8 | val find : t -> key -> value
9 | val find_opt : t -> key -> value option
10 | val merge : t -> t -> t
11 | end
12 |
13 | module type VALUE = sig
14 | type t
15 | end
16 |
17 | module Make (Ord : Map.OrderedType) (Value : VALUE) :
18 | S with type key := Ord.t and type value := Value.t = struct
19 | module Map = Map.Make (Ord)
20 |
21 | type t = Value.t Map.t
22 |
23 | let empty = Map.empty
24 | let add = Map.add
25 | let find t x = Map.find x t
26 | let find_opt t x = Map.find_opt x t
27 |
28 | let merge a b =
29 | Map.merge (fun _ s s' -> match s with None -> s' | Some _ -> s) a b
30 | end
31 |
32 | module AliasCtx = Make (String) (String)
33 |
34 | module BinOpCtx =
35 | Make
36 | (String)
37 | (struct
38 | type t = string -> string -> string
39 | end)
40 |
41 | module UopCtx =
42 | Make
43 | (String)
44 | (struct
45 | type t = string -> string
46 | end)
47 |
--------------------------------------------------------------------------------
/src/core/compil_impl.ml:
--------------------------------------------------------------------------------
1 | module type S = sig
2 | type t
3 |
4 | val from_lexbuf :
5 | ?filename:string -> Sedlexing.lexbuf -> (t, Common.Err.t) result
6 |
7 | val from_string : ?filename:string -> string -> (t, Common.Err.t) result
8 | val from_channel : ?filename:string -> in_channel -> (t, Common.Err.t) result
9 | end
10 |
11 | module Make (Parser : Syntax.S) (Checker : Checker.S) (Eval : Ast.Eval.S) :
12 | S with type t := Eval.t = struct
13 | let from_lexbuf ?(filename = "") lexbuf =
14 | Sedlexing.set_filename lexbuf filename;
15 | let open Common.Result in
16 | match Parser.parse lexbuf with
17 | | Ok parsed_ast -> (
18 | match Checker.check parsed_ast with
19 | | Ok ast -> ok @@ Eval.eval ast
20 | | Error err -> Error (err :> Common.Err.t))
21 | | Error err -> Error (err :> Common.Err.t)
22 |
23 | let from_string ?(filename = "") str =
24 | let lexbuf = Sedlexing.Utf8.from_string str in
25 | from_lexbuf lexbuf ~filename
26 |
27 | let from_channel ?(filename = "") chan =
28 | let lexbuf = Sedlexing.Utf8.from_channel chan in
29 | from_lexbuf lexbuf ~filename
30 | end
31 |
--------------------------------------------------------------------------------
/src/common/enumerate/base.mli:
--------------------------------------------------------------------------------
1 | (** Containing utility classes to build the [Builtins] module. *)
2 |
3 | (** {1 API} *)
4 |
5 | (** A virtual class used to structure inheritance. *)
6 | class virtual numerotation :
7 | object
8 | method virtual get : string
9 | (** Returns current letter as a string. *)
10 |
11 | method virtual next : unit
12 | (** Advances in the unfolding of the alphabet. *)
13 | end
14 |
15 | (** [alphabet] takes a string array representing the letters of an alphabet.
16 |
17 | When the last letter is reached, start again at the first and so on. *)
18 | class virtual alphabet :
19 | string array
20 | -> object
21 | method get : string
22 | method next : unit
23 | end
24 |
25 | (** [roman] takes representing the different letters of the roman alphabet.
26 |
27 | When the last letter is reached, start again at the first and so on. *)
28 | class virtual roman :
29 | [< `I of string ]
30 | -> [< `V of string ]
31 | -> [< `X of string ]
32 | -> [< `L of string ]
33 | -> [< `C of string ]
34 | -> [< `D of string ]
35 | -> [< `M of string ]
36 | -> object
37 | method get : string
38 | method next : unit
39 | end
40 |
--------------------------------------------------------------------------------
/src/ast/eval.ml:
--------------------------------------------------------------------------------
1 | open Common
2 |
3 | module type S = sig
4 | type t
5 |
6 | val eval : Types.doc -> t
7 | end
8 |
9 | module EvalCtx = struct
10 | type t = { alias : Ctx.AliasCtx.t; bop : Ctx.BinOpCtx.t; uop : Ctx.UopCtx.t }
11 |
12 | let create ~alias ~bop ~uop = { alias; bop; uop }
13 | end
14 |
15 | module MakeWithExpsn (Expsn : Expansion.S) : S with type t := string = struct
16 | let rec eval doc =
17 | let ctx = Expsn.(EvalCtx.create ~alias ~bop ~uop) in
18 | List.map (eval_expr ctx) doc |> String.concat ""
19 |
20 | and eval_expr ctx expr =
21 | let open Types in
22 | match expr with
23 | | Text s | White s | Unformat s -> s
24 | | Group grp -> eval_group ctx grp
25 | | UnaryOp { op; group } -> eval_uop ctx op group
26 | | BinOp { op; left; right } -> eval_bin_op ctx op ~left ~right
27 |
28 | and eval_group ctx grp = List.map (eval_expr ctx) grp |> String.concat ""
29 |
30 | and eval_uop ctx op group =
31 | let f = Ctx.UopCtx.find ctx.EvalCtx.uop op in
32 | f @@ eval_expr ctx group
33 |
34 | and eval_bin_op ctx op ~left ~right =
35 | let f = Ctx.BinOpCtx.find ctx.EvalCtx.bop op in
36 | f (eval_expr ctx left) (eval_expr ctx right)
37 | end
38 |
--------------------------------------------------------------------------------
/src/compiler.ml:
--------------------------------------------------------------------------------
1 | open Common
2 | open Core
3 |
4 | let load_unit name =
5 | match Ehandler.load Expansion.Known.expansions name with
6 | | Ok expsn -> expsn
7 | | Error err -> prerr_with_exit @@ Err.to_string (err :> Err.t)
8 |
9 | let compile () =
10 | let args = Args.parse () in
11 | let module Expsn = (val load_unit args#expsn) in
12 | let module Eval = struct
13 | type t = string
14 |
15 | include Ast.Eval.MakeWithExpsn (Expsn)
16 | end in
17 | let module Compiler =
18 | Compil_impl.Make (Syntax.Parser) (Checker.Make (Expsn)) (Eval)
19 | in
20 | if args#direct_input = "" && args#inputf = "" then
21 | let module Repl = Repl.Make (Compiler) in
22 | Repl.launch ()
23 | else
24 | let from_src =
25 | if args#direct_input = "" then
26 | if Sys.file_exists args#inputf then
27 | Compiler.from_channel ~filename:args#inputf @@ open_in args#inputf
28 | else prerr_with_exit @@ Err.to_string (`NoSuchFile args#inputf)
29 | else Compiler.from_string ~filename:args#inputf args#inputf
30 | in
31 | match from_src with
32 | | Ok r ->
33 | if args#output_on_stdout then print_endline r
34 | else In_channel.write args#outputf r
35 | | Error err -> prerr_with_exit @@ Err.to_string err
36 |
--------------------------------------------------------------------------------
/src/common/enumerate/builtins.mli:
--------------------------------------------------------------------------------
1 | (** {1 API} *)
2 |
3 | (** The null numbering. *)
4 | class null :
5 | object
6 | method get : string
7 |
8 | method next : unit
9 | (** Returns always an empty string. *)
10 | end
11 |
12 | class numeric_arab :
13 | object
14 | method get : string
15 | method next : unit
16 | end
17 |
18 | class lower_case_numeric_roman :
19 | object
20 | method get : string
21 | method next : unit
22 | end
23 |
24 | class upper_case_numeric_roman :
25 | object
26 | method get : string
27 | method next : unit
28 | end
29 |
30 | class lower_case_latin :
31 | object
32 | method get : string
33 | method next : unit
34 | end
35 |
36 | class upper_case_latin :
37 | object
38 | method get : string
39 | method next : unit
40 | end
41 |
42 | class lower_case_greek :
43 | object
44 | method get : string
45 | method next : unit
46 | end
47 |
48 | class upper_case_greek :
49 | object
50 | method get : string
51 | method next : unit
52 | end
53 |
54 | class lower_case_cyrillic :
55 | object
56 | method get : string
57 | method next : unit
58 | end
59 |
60 | class upper_case_cyrillc :
61 | object
62 | method get : string
63 | method next : unit
64 | end
65 |
--------------------------------------------------------------------------------
/src/syntax/parser.mly:
--------------------------------------------------------------------------------
1 | %{
2 | open Parsed_ast
3 |
4 | let mk_loc loc value = { loc; value }
5 | %}
6 |
7 | %token OP
8 | %token NEWLINE
9 | %token TEXT
10 | %token WHITE
11 | %token UNFORMAT
12 |
13 | %token LBRACKET RBRACKET
14 | %token EOF
15 |
16 | %type document
17 | %start document
18 |
19 | %%
20 |
21 | let document :=
22 | | lines=line*; EOF; { lines }
23 |
24 | let line :=
25 | | expr
26 | | uop_line
27 | | n=NEWLINE; { LNewline n }
28 |
29 | let expr :=
30 | | group
31 | | terminal
32 | | op_app
33 |
34 | let terminal ==
35 | | t=TEXT; { LText t }
36 | | w=WHITE; { LWhite w }
37 | | u=UNFORMAT; { LUnformat u }
38 |
39 | let group ==
40 | | LBRACKET; grp=group_aux*; RBRACKET; { LGroup grp }
41 |
42 | let group_aux ==
43 | | expr
44 | | n=NEWLINE; { LNewline n }
45 |
46 | let op_app ==
47 | | unary_op
48 |
49 | let unary_op ==
50 | | op=OP; t=TEXT;
51 | { LUnaryOp { op = mk_loc $loc(op) op; group = LGroup [ LText t ]; newline = "" } }
52 | | op=OP; group=group;
53 | { LUnaryOp { op = mk_loc $loc(op) op; group; newline = "" } }
54 |
55 | let uop_line ==
56 | | op=OP; WHITE; grp=expr+; newline=NEWLINE;
57 | { LUnaryOp { op = mk_loc $loc(op) op; group = LGroup grp; newline } }
58 |
--------------------------------------------------------------------------------
/src/common/enumerate/base.ml:
--------------------------------------------------------------------------------
1 | class virtual numerotation =
2 | object
3 | method virtual next : unit
4 |
5 | method virtual get : string
6 | end
7 |
8 | class virtual alphabet letters =
9 | object
10 | inherit numerotation
11 |
12 | val mutable n = 0
13 |
14 | method next = if n < Array.length letters then n <- n + 1 else n <- 1
15 | (* Start again. *)
16 |
17 | method get = letters.(n - 1)
18 | end
19 |
20 | class virtual roman (`I i) (`V v) (`X x) (`L l) (`C c) (`D d) (`M m) =
21 | object (self)
22 | inherit numerotation
23 |
24 | val mutable n = 0
25 |
26 | method private digit x y z = function
27 | | 1 -> [ x ]
28 | | 2 -> [ x; x ]
29 | | 3 -> [ x; x; x ]
30 | | 4 -> [ x; y ]
31 | | 5 -> [ y ]
32 | | 6 -> [ y; x ]
33 | | 7 -> [ y; x; x ]
34 | | 8 -> [ y; x; x; x ]
35 | | 9 -> [ x; z ]
36 | | _ -> assert false
37 |
38 | method private to_roman n =
39 | if n = 0 then []
40 | else if n < 0 then assert false
41 | else if n >= 1000 then m :: self#to_roman (n - 1000)
42 | else if n >= 100 then self#digit c d m (n / 100) @ self#to_roman (n mod 100)
43 | else if n >= 10 then self#digit x l c (n / 10) @ self#to_roman (n mod 10)
44 | else self#digit i v x n
45 |
46 | method next = n <- n + 1
47 |
48 | method get = String.concat "" @@ self#to_roman n
49 | end
50 |
--------------------------------------------------------------------------------
/src/expansion/default.ml:
--------------------------------------------------------------------------------
1 | let alias = Common.Ctx.AliasCtx.(empty |> add "P" "Postem")
2 |
3 | let fmt_title ~nbring ~fmt ~chr text =
4 | nbring#next;
5 | let ftext = fmt nbring#get text in
6 | Printf.sprintf "%s\n%s" ftext @@ String.(make (length ftext)) chr
7 |
8 | let underline ~char text =
9 | Printf.sprintf "%s\n%s" text @@ String.(make (length text)) char
10 |
11 | let quote = Printf.sprintf " █ %s"
12 | let conclusion = Printf.sprintf "-> %s"
13 |
14 | let bop =
15 | let open Common.Ctx.BinOpCtx in
16 | empty
17 | |> add ">>" @@ fun qtation author ->
18 | Printf.sprintf "%s\n %s" (quote qtation) author
19 |
20 | let uop =
21 | let module Enum = Enumerate.Builtins in
22 | let open Common.Ctx.UopCtx in
23 | empty
24 | |> add "&"
25 | @@ fmt_title
26 | ~nbring:(new Enum.upper_case_numeric_roman)
27 | ~fmt:(Printf.sprintf "%s - %s") ~chr:'#'
28 | |> add "&&"
29 | @@ fmt_title
30 | ~nbring:(new Enum.upper_case_latin)
31 | ~fmt:(Printf.sprintf "%s) %s") ~chr:'*'
32 | |> add "&&&"
33 | @@ fmt_title
34 | ~nbring:(new Enum.lower_case_greek)
35 | ~fmt:(Printf.sprintf "%s. %s") ~chr:'='
36 | |> add "&&&&" @@ underline ~char:'-'
37 | |> add "&&&&&" @@ underline ~char:'^'
38 | |> add "&&&&&&" @@ underline ~char:'"'
39 | |> add ">" quote |> add "%%" Fun.id |> add "--" conclusion
40 | (* |> add ">" quote
41 | |> add "--" conclusion *)
42 |
--------------------------------------------------------------------------------
/doc/lexer/lexer.py:
--------------------------------------------------------------------------------
1 |
2 | from pygments.lexer import RegexLexer, bygroups
3 | from pygments.token import Generic, Keyword, Name, Number, String, Text
4 |
5 |
6 | class PostemLexer(RegexLexer):
7 | name = 'Postem'
8 | aliases = ['postem']
9 |
10 | tokens = {
11 | 'root': [
12 | # Integer
13 | (r'\d+', Number.Integer),
14 | # Whitespace
15 | (r'( |\t|\r)', Text),
16 | # Alias
17 | (r'(.+)( |\t|\r)*(==)( |\t|\r)*(".*")',
18 | bygroups(Name.Variable, Text, Keyword, Text, String.Double)),
19 | # Metamark with args
20 | (r'(\.\.)(.+)( |\t|\n)([^\.\.]*)(\.\.)', bygroups(Keyword,
21 | Name.Attributes, Text, Name.Attributes, Keyword)),
22 | # Metamark without args
23 | (r'@(.+)', Name.Attributes),
24 | # Unformat
25 | (r'(\{\{)(.*)(\}\})', bygroups(Keyword, Text, Keyword)),
26 | # Conclusion
27 | (r'(--)( |\t|\n)*(.*)', bygroups(Keyword, Text, Generic.Strong)),
28 | # Definition
29 | (r'(.*)( |\t|\n)*(%%)( |\t|\n)*(.*)',
30 | bygroups(Generic.Strong, Text, Keyword, Text, Generic.Emph)),
31 | # Heading
32 | (r'&.*\n', Generic.Heading),
33 | # Subheading
34 | (r'&+.*\n', Generic.Subheading),
35 | # Quotation
36 | (r'(>)(.*)', bygroups(Keyword, Generic.Emph)),
37 | # Text
38 | (r'.', Text),
39 | ]
40 | }
41 |
--------------------------------------------------------------------------------
/src/syntax/lexer.ml:
--------------------------------------------------------------------------------
1 | exception IllegalChar of Sedlexing.lexbuf
2 |
3 | let escape = [%sedlex.regexp? '\\', any]
4 | let op_char = [%sedlex.regexp? Chars "!#$%&'*+-<=>'@^_|~"]
5 | let op = [%sedlex.regexp? Plus op_char]
6 | let unformat = [%sedlex.regexp? "{{", Star any, "}}"]
7 | let white_char = [%sedlex.regexp? zs]
8 | let white = [%sedlex.regexp? Plus white_char]
9 |
10 | let text =
11 | [%sedlex.regexp? Plus (Compl (op_char | '\n' | white_char | '[' | ']'))]
12 | (* TODO: Windows newline support (\r\n) *)
13 |
14 | let newline = [%sedlex.regexp? '\n' | "\r\n"]
15 | let lexeme = Sedlexing.Utf8.lexeme
16 |
17 | let cut ?(right = 0) ~left str =
18 | String.(sub str left (length str - right - left))
19 |
20 | let read buf =
21 | let open Parser in
22 | match%sedlex buf with
23 | | escape -> TEXT (cut ~left:1 @@ lexeme buf)
24 | | '[' -> LBRACKET
25 | | ']' -> RBRACKET
26 | | op -> OP (lexeme buf)
27 | | unformat -> UNFORMAT (cut ~left:2 ~right:2 @@ lexeme buf)
28 | | white -> WHITE (lexeme buf)
29 | | text -> TEXT (lexeme buf)
30 | | newline -> NEWLINE (lexeme buf)
31 | | eof -> EOF
32 | | _ -> raise @@ IllegalChar buf
33 |
34 | let read_debug lexbuf =
35 | let token = read lexbuf in
36 | print_endline
37 | @@ Parser.(
38 | function
39 | | NEWLINE n -> Printf.sprintf "NEWLINE:%s" n
40 | | TEXT t -> Printf.sprintf "TEXT:%s" t
41 | | WHITE w -> Printf.sprintf "WHITE:%s" w
42 | | UNFORMAT u -> Printf.sprintf "UNFORMAT:%s" u
43 | | OP o -> Printf.sprintf "OP:%s" o
44 | | LBRACKET -> "LBRACKET"
45 | | RBRACKET -> "RBRACKET"
46 | | EOF -> "EOF")
47 | token;
48 | token
49 |
--------------------------------------------------------------------------------
/doc/getting_started.md:
--------------------------------------------------------------------------------
1 | # Getting started
2 |
3 | ## Command line usage
4 |
5 | ### Basics
6 |
7 | To simply print the result on stdout:
8 | ```bash
9 | $ postem -i file
10 | ```
11 |
12 | To print the result of a direct input on stdout:
13 | ```bash
14 | $ postem -c "input"
15 | ```
16 |
17 | To compile a text marked in **Postem** from a file and write result `