A => index.janet +35 -0
@@ 1,35 @@
+(defn render-pantagruel
+ [pant]
+ (defn replace-unicode
+ [line]
+ (->> line
+ (string/replace-all "all" "∀")
+ (string/replace-all "_" "-")
+ (string/replace-all "=>" "⇒")
+ (string/replace-all "<=" "⇐")
+ (string/replace-all "->" "→")
+ (string/replace-all "---" "<hr>")
+ (string/replace-all ";" "<hr><hr>")))
+
+ (defn render-line
+ [line]
+ (if-not (string/has-prefix? "//" line)
+ (string (replace-unicode line) "<br>")
+ (bagatto/markdown->html (string "> " (string/trim line "/")))))
+
+ (as-> pant .
+ (string/split "\n" .)
+ (filter (complement empty?) .)
+ (map render-line .)
+ (string/join . "\n")))
+
+(def data {:index {:attrs {:title "Pantagruel: An Extremely Lightweight Specification Language"}}
+ :pant {:src "index.pant"
+ :attrs bagatto/parse-base}
+ :static {:src (bagatto/* "static/*")
+ :attrs bagatto/parse-base}})
+
+(def site {:index {:dest "site/index.html"
+ :out (bagatto/renderer "/index")}
+ :static {:each :static
+ :dest (bagatto/path-copier "site/static")}})
A => index.pant +44 -0
@@ 1,44 @@
+Thought.
+Specification <= [String].
+
+// Pantagruel is a language for writing *system specifications*.
+
+pantagruel thoughts: [Thought] => Specification.
+---
+
+// It's a computer language, but not as you might think of it.
+
+// The effects of evaluating a specification are *nil*---Pantagruel has no semantics.
+
+eval spec = Nil.
+
+;
+
+eval spec: Specification.
+check spec: Specification => Bool.
+---
+
+// However, Pantagruel specifications can be checked to ensure that certain conditions have been met.
+
+// For instance, that you've defined all your terms by the end of your document.
+check spec = all symbol: invoked_symbols spec =>
+ symbol in (head spec) -> bound_as_of? symbol (first_appearance symbol)
+ symbol in (body spec) -> bound_as_of? symbol (next_chapter (first_appearance symbol)).
+
+;
+
+(Head, Body) <= [String].
+Chapter <= [Head, Body].
+Specification <= [Chapter].
+
+// This allows a structured form of description where terms can be explained in gradually greater detail.
+
+invoked_symbols <= {String}.
+chapter head: Head, body: Body => Chapter.
+first_appearance symbol: String => Nat.
+bound_as_of? symbol: String, Nat => Bool.
+
+next_chapter n: Nat => Nat.
+---
+
+invoked_symbols spec = {all s: String => s in spec}.
A => index.temple +47 -0
@@ 1,47 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<title>Pantagruel</title>
+<meta charset="utf-8">
+<meta name="viewport" content="width=device-width, initial-scale=1">
+<meta name="Description" content="A useful desk calculator, including vectors and quotations.">
+<link rel="preconnect" href="https://fonts.googleapis.com">
+<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
+<link href="https://fonts.googleapis.com/css2?family=Alegreya:ital@1&display=swap" rel="stylesheet">
+
+<link href="static/style.css" rel="stylesheet" />
+</head>
+
+<body>
+
+<div class="header">
+ <h1>{{ (get-in args [:index :title]) }}</h1>
+</div>
+
+<nav>
+</nav>
+
+<div class="row">
+ <div class="narrow"> </div>
+ <div class="column">
+ {- (render-pantagruel (get-in args [:pant :contents])) -}
+ </div>
+ <div class="narrow"> </div>
+</div>
+
+<div class="row" align="center">
+<h2>Learn More</h2>
+ <img src="static/dore.jpg" width=300px/>
+ <p>
+ <a href="https://github.com/subsetpark/pantagruel">Pantagruel on GitHub</a>
+ </p>
+</div>
+
+<div class="footer">
+ <div class="narrow">Z. D. Smith, 2021.</div>
+ <div class="column"> </div>
+ <div class="narrow">Built with <a href="https://bagatto.co">Bagatto</a>.</div>
+</div>
+</body>
+</html>
+
A => static/dore.jpg +0 -0
A => static/style.css +100 -0
@@ 1,100 @@
+* {
+ box-sizing: border-box;
+}
+
+nav {
+ text-align: center;
+}
+
+body {
+ font-family: serif;
+ background-color: #fff;
+}
+
+code {
+ font-family: "Courier", monospace;
+}
+
+.ornament {
+ text-align: center;
+}
+
+a:normal {
+ color: 'RoyalBlue';
+}
+
+a:visited {
+ color: #2F4F4F;
+}
+
+blockquote {
+ color: #444;
+}
+
+/* Style the header */
+.header {
+ padding: 1em;
+ text-align: center;
+ font-size: 2em;
+ font-family: "Alegreya", monospace;
+ border-style: none none none none;
+ background-color: beige;
+}
+
+h2 {
+ font-family: "Alegreya";
+}
+
+.double-line {
+ text-decoration: underline overline darkgrey;
+}
+
+.column {
+ float: left;
+ width: 60%;
+ padding: 10px;
+}
+
+.narrow {
+ float: left;
+ width: 15%;
+ padding: 10px;
+}
+
+.nav {
+ padding: 12px;
+ text-decoration: none !important;
+ color: #000 !important;
+ display: inline;
+ width: 50%;
+ font-size: 25px;
+ font-family: "Courier", monospace;
+ font-weight: bold;
+}
+
+/* Clear floats after the columns */
+.row:after {
+ content: "";
+ display: table;
+ clear: both;
+}
+
+/* Style the footer */
+.footer {
+ padding: 10px;
+ text-align: center;
+ background-position: center;
+ background-repeat: no-repeat;
+ background-size: cover;
+ position: relative;
+}
+
+/* Responsive layout - makes the three columns stack on top of each other instead of next to each other */
+@media (max-width: 600px) {
+ .column {
+ width: 100%;
+ }
+}
+
+
+